Initial sloppy setup for customizable line layout

master
Allen Webster 2019-10-28 21:27:20 -07:00
parent af78a9966e
commit 187f91084a
21 changed files with 613 additions and 442 deletions

View File

@ -356,64 +356,84 @@ buffer_seek_character_class(Application_Links *app, Buffer_ID buffer, Character_
} }
api(custom) function f32 api(custom) function f32
buffer_line_y_difference(Application_Links *app, Buffer_ID buffer_id, f32 width, Face_ID face_id, i64 line_a, i64 line_b){ buffer_line_y_difference(Application_Links *app, Buffer_ID buffer_id,
f32 width, Face_ID face_id,
i64 line_a, i64 line_b){
Models *models = (Models*)app->cmd_context; Models *models = (Models*)app->cmd_context;
Editing_File *file = imp_get_file(models, buffer_id); Editing_File *file = imp_get_file(models, buffer_id);
f32 result = {}; f32 result = {};
if (api_check_buffer(file)){ if (api_check_buffer(file)){
Face *face = font_set_face_from_id(&models->font_set, face_id); Face *face = font_set_face_from_id(&models->font_set, face_id);
if (face != 0){ if (face != 0){
result = file_line_y_difference(app->tctx, models, file, width, face, line_a, line_b); Layout_Function *layout_func = models->layout_func;
result = file_line_y_difference(app->tctx, models, file,
layout_func, width, face,
line_a, line_b);
} }
} }
return(result); return(result);
} }
api(custom) function Line_Shift_Vertical api(custom) function Line_Shift_Vertical
buffer_line_shift_y(Application_Links *app, Buffer_ID buffer_id, f32 width, Face_ID face_id, i64 line, f32 y_shift){ buffer_line_shift_y(Application_Links *app, Buffer_ID buffer_id,
f32 width, Face_ID face_id,
i64 line, f32 y_shift){
Models *models = (Models*)app->cmd_context; Models *models = (Models*)app->cmd_context;
Editing_File *file = imp_get_file(models, buffer_id); Editing_File *file = imp_get_file(models, buffer_id);
Line_Shift_Vertical result = {}; Line_Shift_Vertical result = {};
if (api_check_buffer(file)){ if (api_check_buffer(file)){
Face *face = font_set_face_from_id(&models->font_set, face_id); Face *face = font_set_face_from_id(&models->font_set, face_id);
if (face != 0){ if (face != 0){
result = file_line_shift_y(app->tctx, models, file, width, face, line, y_shift); Layout_Function *layout_func = models->layout_func;
result = file_line_shift_y(app->tctx, models, file,
layout_func, width, face,
line, y_shift);
} }
} }
return(result); return(result);
} }
api(custom) function i64 api(custom) function i64
buffer_pos_at_relative_xy(Application_Links *app, Buffer_ID buffer_id, f32 width, Face_ID face_id, i64 base_line, Vec2_f32 relative_xy){ buffer_pos_at_relative_xy(Application_Links *app, Buffer_ID buffer_id,
f32 width, Face_ID face_id,
i64 base_line, Vec2_f32 relative_xy){
Models *models = (Models*)app->cmd_context; Models *models = (Models*)app->cmd_context;
Editing_File *file = imp_get_file(models, buffer_id); Editing_File *file = imp_get_file(models, buffer_id);
i64 result = -1; i64 result = -1;
if (api_check_buffer(file)){ if (api_check_buffer(file)){
Face *face = font_set_face_from_id(&models->font_set, face_id); Face *face = font_set_face_from_id(&models->font_set, face_id);
if (face != 0){ if (face != 0){
result = file_pos_at_relative_xy(app->tctx, models, file, width, face, base_line, relative_xy); Layout_Function *layout_func = models->layout_func;
result = file_pos_at_relative_xy(app->tctx, models, file,
layout_func, width, face,
base_line, relative_xy);
} }
} }
return(result); return(result);
} }
api(custom) function Vec2_f32 api(custom) function Vec2_f32
buffer_relative_xy_of_pos(Application_Links *app, Buffer_ID buffer_id, f32 width, Face_ID face_id, i64 base_line, i64 pos) buffer_relative_xy_of_pos(Application_Links *app, Buffer_ID buffer_id,
{ f32 width, Face_ID face_id,
i64 base_line, i64 pos){
Models *models = (Models*)app->cmd_context; Models *models = (Models*)app->cmd_context;
Editing_File *file = imp_get_file(models, buffer_id); Editing_File *file = imp_get_file(models, buffer_id);
Vec2_f32 result = {}; Vec2_f32 result = {};
if (api_check_buffer(file)){ if (api_check_buffer(file)){
Face *face = font_set_face_from_id(&models->font_set, face_id); Face *face = font_set_face_from_id(&models->font_set, face_id);
if (face != 0){ if (face != 0){
result = file_relative_xy_of_pos(app->tctx, models, file, width, face, base_line, pos); Layout_Function *layout_func = models->layout_func;
result = file_relative_xy_of_pos(app->tctx, models, file,
layout_func, width, face,
base_line, pos);
} }
} }
return(result); return(result);
} }
api(custom) function i64 api(custom) function i64
buffer_relative_character_from_pos(Application_Links *app, Buffer_ID buffer_id, f32 width, Face_ID face_id, i64 base_line, i64 pos) buffer_relative_character_from_pos(Application_Links *app, Buffer_ID buffer_id,
f32 width, Face_ID face_id, i64 base_line, i64 pos)
{ {
Models *models = (Models*)app->cmd_context; Models *models = (Models*)app->cmd_context;
Editing_File *file = imp_get_file(models, buffer_id); Editing_File *file = imp_get_file(models, buffer_id);
@ -421,7 +441,10 @@ buffer_relative_character_from_pos(Application_Links *app, Buffer_ID buffer_id,
if (api_check_buffer(file)){ if (api_check_buffer(file)){
Face *face = font_set_face_from_id(&models->font_set, face_id); Face *face = font_set_face_from_id(&models->font_set, face_id);
if (face != 0){ if (face != 0){
result = file_relative_character_from_pos(app->tctx, models, file, width, face, base_line, pos); Layout_Function *layout_func = models->layout_func;
result = file_relative_character_from_pos(app->tctx, models, file,
layout_func, width, face,
base_line, pos);
} }
} }
return(result); return(result);
@ -436,7 +459,10 @@ buffer_pos_from_relative_character(Application_Links *app, Buffer_ID buffer_id,
if (api_check_buffer(file)){ if (api_check_buffer(file)){
Face *face = font_set_face_from_id(&models->font_set, face_id); Face *face = font_set_face_from_id(&models->font_set, face_id);
if (face != 0){ if (face != 0){
result = file_pos_from_relative_character(app->tctx, models, file, width, face, base_line, relative_character); Layout_Function *layout_func = models->layout_func;
result = file_pos_from_relative_character(app->tctx, models, file,
layout_func, width, face,
base_line, relative_character);
} }
} }
return(result); return(result);
@ -1497,8 +1523,10 @@ view_set_buffer_scroll(Application_Links *app, View_ID view_id, Buffer_Scroll sc
scroll.target.pixel_shift.x = f32_round32(scroll.target.pixel_shift.x); scroll.target.pixel_shift.x = f32_round32(scroll.target.pixel_shift.x);
scroll.target.pixel_shift.y = f32_round32(scroll.target.pixel_shift.y); scroll.target.pixel_shift.y = f32_round32(scroll.target.pixel_shift.y);
scroll.target.pixel_shift.x = clamp_bot(0.f, scroll.target.pixel_shift.x); scroll.target.pixel_shift.x = clamp_bot(0.f, scroll.target.pixel_shift.x);
Buffer_Layout_Item_List line = view_get_line_layout(tctx, models, view, scroll.target.line_number); Layout_Item_List line = view_get_line_layout(tctx, models, view,
scroll.target.pixel_shift.y = clamp(0.f, scroll.target.pixel_shift.y, line.height); scroll.target.line_number);
scroll.target.pixel_shift.y =
clamp(0.f, scroll.target.pixel_shift.y, line.height);
if (rule == SetBufferScroll_SnapCursorIntoView){ if (rule == SetBufferScroll_SnapCursorIntoView){
view_set_scroll(tctx, models, view, scroll); view_set_scroll(tctx, models, view, scroll);
} }
@ -2139,6 +2167,10 @@ set_custom_hook(Application_Links *app, Hook_ID hook_id, Void_Func *func_ptr){
{ {
models->buffer_region = (Buffer_Region_Function*)func_ptr; models->buffer_region = (Buffer_Region_Function*)func_ptr;
}break; }break;
case HookID_Layout:
{
models->layout_func = (Layout_Function*)func_ptr;
}break;
} }
} }
@ -2483,13 +2515,20 @@ get_face_metrics(Application_Links *app, Face_ID face_id){
if (face_id != 0){ if (face_id != 0){
Face *face = font_set_face_from_id(&models->font_set, face_id); Face *face = font_set_face_from_id(&models->font_set, face_id);
if (face != 0){ if (face != 0){
result.text_height = face->text_height; result = face->metrics;
result.line_height = face->line_height; }
result.max_advance = face->max_advance; }
result.normal_advance = face->typical_advance; return(result);
result.space_advance = face->space_advance; }
result.decimal_digit_advance = face->digit_advance;
result.hex_digit_advance = face->hex_advance; api(custom) function Face_Advance_Map
get_face_advance_map(Application_Links *app, Face_ID face_id){
Models *models = (Models*)app->cmd_context;
Face_Advance_Map result = {};
if (face_id != 0){
Face *face = font_set_face_from_id(&models->font_set, face_id);
if (face != 0){
result = face->advance_map;
} }
} }
return(result); return(result);
@ -2717,6 +2756,8 @@ text_layout_create(Application_Links *app, Buffer_ID buffer_id, Rect_f32 rect, B
Gap_Buffer *buffer = &file->state.buffer; Gap_Buffer *buffer = &file->state.buffer;
Layout_Function *layout_func = models->layout_func;
Vec2_f32 dim = rect_dim(rect); Vec2_f32 dim = rect_dim(rect);
i64 line_count = buffer_line_count(buffer); i64 line_count = buffer_line_count(buffer);
@ -2724,7 +2765,9 @@ text_layout_create(Application_Links *app, Buffer_ID buffer_id, Rect_f32 rect, B
f32 y = -buffer_point.pixel_shift.y; f32 y = -buffer_point.pixel_shift.y;
for (;line_number <= line_count; for (;line_number <= line_count;
line_number += 1){ line_number += 1){
Buffer_Layout_Item_List line = file_get_line_layout(tctx, models, file, dim.x, face, line_number); Layout_Item_List line = file_get_line_layout(tctx, models, file,
layout_func, dim.x, face,
line_number);
f32 next_y = y + line.height; f32 next_y = y + line.height;
if (next_y >= dim.y){ if (next_y >= dim.y){
break; break;
@ -2743,7 +2786,8 @@ text_layout_create(Application_Links *app, Buffer_ID buffer_id, Rect_f32 rect, B
colors_array[i].id = Stag_Default; colors_array[i].id = Stag_Default;
} }
result = text_layout_new(&models->text_layouts, arena, buffer_id, buffer_point, result = text_layout_new(&models->text_layouts, arena, buffer_id, buffer_point,
visible_range, visible_line_number_range, rect, colors_array); visible_range, visible_line_number_range, rect, colors_array,
layout_func);
} }
return(result); return(result);
} }
@ -2789,6 +2833,9 @@ text_layout_line_on_screen(Application_Links *app, Text_Layout_ID layout_id, i64
if (layout == 0){ if (layout == 0){
return(result); return(result);
} }
Layout_Function *layout_func = layout->layout_func;
Rect_f32 rect = layout->rect; Rect_f32 rect = layout->rect;
if (range_contains_inclusive(layout->visible_line_number_range, line_number)){ if (range_contains_inclusive(layout->visible_line_number_range, line_number)){
Editing_File *file = imp_get_file(models, layout->buffer_id); Editing_File *file = imp_get_file(models, layout->buffer_id);
@ -2798,7 +2845,9 @@ text_layout_line_on_screen(Application_Links *app, Text_Layout_ID layout_id, i64
for (i64 line_number_it = layout->visible_line_number_range.first;; for (i64 line_number_it = layout->visible_line_number_range.first;;
line_number_it += 1){ line_number_it += 1){
Buffer_Layout_Item_List line = file_get_line_layout(app->tctx, models, file, width, face, line_number_it); Layout_Item_List line = file_get_line_layout(app->tctx, models, file,
layout_func, width, face,
line_number_it);
result.max += line.height; result.max += line.height;
if (line_number_it == line_number){ if (line_number_it == line_number){
break; break;
@ -2816,6 +2865,7 @@ text_layout_line_on_screen(Application_Links *app, Text_Layout_ID layout_id, i64
else if (line_number > layout->visible_line_number_range.max){ else if (line_number > layout->visible_line_number_range.max){
result = If32(rect.y1, rect.y1); result = If32(rect.y1, rect.y1);
} }
return(result); return(result);
} }
@ -2835,11 +2885,15 @@ text_layout_character_on_screen(Application_Links *app, Text_Layout_ID layout_id
f32 width = rect_width(rect); f32 width = rect_width(rect);
Face *face = file_get_face(models, file); Face *face = file_get_face(models, file);
Layout_Function *layout_func = layout->layout_func;
f32 y = 0.f; f32 y = 0.f;
Buffer_Layout_Item_List line = {}; Layout_Item_List line = {};
for (i64 line_number_it = layout->visible_line_number_range.first;; for (i64 line_number_it = layout->visible_line_number_range.first;;
line_number_it += 1){ line_number_it += 1){
line = file_get_line_layout(app->tctx, models, file, width, face, line_number_it); line = file_get_line_layout(app->tctx, models, file,
layout_func, width, face,
line_number_it);
if (line_number_it == line_number){ if (line_number_it == line_number){
break; break;
} }
@ -2851,10 +2905,10 @@ text_layout_character_on_screen(Application_Links *app, Text_Layout_ID layout_id
// Buffer_Layout_Item_List. // Buffer_Layout_Item_List.
b32 is_first_item = true; b32 is_first_item = true;
result = Rf32_negative_infinity; result = Rf32_negative_infinity;
for (Buffer_Layout_Item_Block *block = line.first; for (Layout_Item_Block *block = line.first;
block != 0; block != 0;
block = block->next){ block = block->next){
Buffer_Layout_Item *item_ptr = block->items; Layout_Item *item_ptr = block->items;
i64 count = block->count; i64 count = block->count;
for (i32 i = 0; i < count; i += 1, item_ptr += 1){ for (i32 i = 0; i < count; i += 1, item_ptr += 1){
i64 index = item_ptr->index; i64 index = item_ptr->index;

View File

@ -62,6 +62,7 @@ struct Models{
Buffer_Hook_Function *save_file; Buffer_Hook_Function *save_file;
Buffer_Edit_Range_Function *buffer_edit_range; Buffer_Edit_Range_Function *buffer_edit_range;
Buffer_Region_Function *buffer_region; Buffer_Region_Function *buffer_region;
Layout_Function *layout_func;
Color_Table fallback_color_table; Color_Table fallback_color_table;
Color_Table color_table; Color_Table color_table;

View File

@ -74,6 +74,7 @@
#include "4coder_log.cpp" #include "4coder_log.cpp"
#include "4coder_buffer_seek_constructors.cpp" #include "4coder_buffer_seek_constructors.cpp"
#include "4coder_command_map.cpp" #include "4coder_command_map.cpp"
#include "4coder_codepoint_map.cpp"
#include "generated/custom_api.cpp" #include "generated/custom_api.cpp"
#define DYNAMIC_LINK_API #define DYNAMIC_LINK_API
@ -87,7 +88,6 @@
#include "4ed_coroutine.cpp" #include "4ed_coroutine.cpp"
#include "4ed_mem.cpp" #include "4ed_mem.cpp"
#include "4ed_dynamic_variables.cpp" #include "4ed_dynamic_variables.cpp"
#include "4ed_font_face.cpp"
#include "4ed_font_set.cpp" #include "4ed_font_set.cpp"
#include "4ed_translation.cpp" #include "4ed_translation.cpp"
#include "4ed_render_target.cpp" #include "4ed_render_target.cpp"

View File

@ -856,194 +856,8 @@ buffer_chunk_position_iterate(String_Const_u8_Array chunks, Buffer_Chunk_Positio
//////////////////////////////// ////////////////////////////////
internal void
buffer_layout__write(Arena *arena, Buffer_Layout_Item_List *list, i64 index, u32 codepoint,
Buffer_Layout_Flag flags, Rect_f32 rect){
Temp_Memory restore_point = begin_temp(arena);
Buffer_Layout_Item *item = push_array(arena, Buffer_Layout_Item, 1);
Buffer_Layout_Item_Block *block = list->first;
if (block != 0){
if (block->items + block->count == item){
block->count += 1;
}
else{
block = 0;
}
}
if (block == 0){
end_temp(restore_point);
block = push_array(arena, Buffer_Layout_Item_Block, 1);
item = push_array(arena, Buffer_Layout_Item, 1);
sll_queue_push(list->first, list->last, block);
list->node_count += 1;
block->items = item;
block->count = 1;
}
list->total_count += 1;
if (index > list->index_range.max){
block->character_count += 1;
list->character_count += 1;
list->index_range.max = index;
}
item->index = index;
item->codepoint = codepoint;
item->flags = flags;
item->rect = rect;
list->height = max(list->height, rect.y1);
}
internal Buffer_Layout_Item_List
buffer_layout(Thread_Context *tctx, Arena *arena, Gap_Buffer *buffer, Interval_i64 range, Face *face, f32 width){
Scratch_Block scratch(tctx);
Buffer_Layout_Item_List list = {};
list.index_range.first = range.first;
list.index_range.one_past_last = range.first - 1;
List_String_Const_u8 chunks = buffer_get_chunks(scratch, buffer);
buffer_chunks_clamp(&chunks, range);
f32 line_height = face->line_height;
f32 text_height = face->text_height;
f32 line_to_text_shift = text_height - line_height;
f32 space_advance = face->space_advance;
if (chunks.node_count == 0){
f32 next_x = space_advance;
buffer_layout__write(arena, &list, range.first, ' ', 0,
Rf32(V2(0.f, 0.f), V2f32(next_x, text_height)));
}
else{
Vec2_f32 p = {};
f32 line_y = line_height;
f32 text_y = text_height;
String_Const_u8 text = {};
if (chunks.node_count == 1){
text = chunks.first->string;
}
else{
text = string_list_flatten(scratch, chunks);
}
i64 index = range.first;
b32 first_of_the_line = true;
b32 consuming_newline_characters = false;
i64 newline_character_index = -1;
b32 prev_did_emit_newline = false;
u8 *ptr = text.str;
u8 *end_ptr = ptr + text.size;
for (;ptr < end_ptr;){
Character_Consume_Result consume = utf8_consume(ptr, (umem)(end_ptr - ptr));
u32 render_codepoint = consume.codepoint;
b32 emit_newline = false;
switch (consume.codepoint){
case '\t':
{
render_codepoint = ' ';
}//fallthrough;
default:
{
f32 advance = font_get_glyph_advance(face, consume.codepoint);
f32 next_x = p.x + advance;
if (!first_of_the_line && next_x >= width){
p.y = line_y;
p.x = 0.f;
line_y += line_height;
text_y = line_y + line_to_text_shift;
next_x = p.x + advance;
}
buffer_layout__write(arena, &list, index, render_codepoint, 0,
Rf32(p, V2f32(next_x, text_y)));
p.x = next_x;
ptr += consume.inc;
index += consume.inc;
first_of_the_line = false;
}break;
case '\r':
{
if (!consuming_newline_characters){
consuming_newline_characters = true;
newline_character_index = index;
}
ptr += 1;
index += 1;
}break;
case '\n':
{
if (!consuming_newline_characters){
consuming_newline_characters = true;
newline_character_index = index;
}
emit_newline = true;
ptr += 1;
index += 1;
}break;
case max_u32:
{
f32 next_x = p.x + face->byte_advance;
if (!first_of_the_line && next_x >= width){
p.y = line_y;
p.x = 0.f;
line_y += line_height;
text_y = line_y + line_to_text_shift;
next_x = p.x + face->byte_advance;
}
u32 v = *ptr;
u32 lo = v&0xF;
u32 hi = (v >> 4)&0xF;
f32 advance = face->byte_sub_advances[0];
buffer_layout__write(arena, &list, index, '\\', 0,
Rf32(p, V2f32(p.x + advance, text_y)));
p.x += advance;
advance = face->byte_sub_advances[1];
buffer_layout__write(arena, &list, index, integer_symbols[lo], 0,
Rf32(p, V2f32(p.x + advance, text_y)));
p.x += advance;
face->byte_sub_advances[2];
buffer_layout__write(arena, &list, index, integer_symbols[hi], 0,
Rf32(p, V2f32(p.x + advance, text_y)));
p.x = next_x;
ptr += 1;
index += 1;
first_of_the_line = false;
}break;
}
prev_did_emit_newline = false;
if (emit_newline){
f32 next_x = p.x + space_advance;
buffer_layout__write(arena, &list, newline_character_index, ' ', 0,
Rf32(p, V2f32(next_x, text_y)));
p.y = line_y;
p.x = 0.f;
line_y += line_height;
text_y = line_y + line_to_text_shift;
first_of_the_line = true;
prev_did_emit_newline = true;
}
}
if (!prev_did_emit_newline){
f32 next_x = p.x + space_advance;
buffer_layout__write(arena, &list, index, ' ', 0, Rf32(p, V2f32(next_x, text_y)));
}
}
list.bottom_extension = -line_to_text_shift;
list.height += list.bottom_extension;
return(list);
}
internal i64 internal i64
buffer_layout_nearest_pos_to_xy(Buffer_Layout_Item_List list, Vec2_f32 p){ buffer_layout_nearest_pos_to_xy(Layout_Item_List list, Vec2_f32 p){
i64 closest_match = 0; i64 closest_match = 0;
if (p.y < 0.f){ if (p.y < 0.f){
closest_match = list.index_range.min; closest_match = list.index_range.min;
@ -1055,11 +869,11 @@ buffer_layout_nearest_pos_to_xy(Buffer_Layout_Item_List list, Vec2_f32 p){
if (0.f < p.x && p.x < max_f32){ if (0.f < p.x && p.x < max_f32){
f32 bottom_extension = list.bottom_extension; f32 bottom_extension = list.bottom_extension;
f32 closest_x = -max_f32; f32 closest_x = -max_f32;
for (Buffer_Layout_Item_Block *block = list.first; for (Layout_Item_Block *block = list.first;
block != 0; block != 0;
block = block->next){ block = block->next){
i64 count = block->count; i64 count = block->count;
Buffer_Layout_Item *item = block->items; Layout_Item *item = block->items;
for (i32 i = 0; i < count; i += 1, item += 1){ for (i32 i = 0; i < count; i += 1, item += 1){
// NOTE(allen): This only works if we build layouts in y-sorted order. // NOTE(allen): This only works if we build layouts in y-sorted order.
if (p.y < item->rect.y0){ if (p.y < item->rect.y0){
@ -1088,12 +902,12 @@ buffer_layout_nearest_pos_to_xy(Buffer_Layout_Item_List list, Vec2_f32 p){
} }
else{ else{
if (p.x == max_f32){ if (p.x == max_f32){
Buffer_Layout_Item *prev_item = 0; Layout_Item *prev_item = 0;
for (Buffer_Layout_Item_Block *block = list.first; for (Layout_Item_Block *block = list.first;
block != 0; block != 0;
block = block->next){ block = block->next){
i64 count = block->count; i64 count = block->count;
Buffer_Layout_Item *item = block->items; Layout_Item *item = block->items;
for (i32 i = 0; i < count; i += 1, item += 1){ for (i32 i = 0; i < count; i += 1, item += 1){
if (p.y < item->rect.y0){ if (p.y < item->rect.y0){
goto double_break_2; goto double_break_2;
@ -1113,12 +927,12 @@ buffer_layout_nearest_pos_to_xy(Buffer_Layout_Item_List list, Vec2_f32 p){
} }
} }
else{ else{
Buffer_Layout_Item *closest_item = 0; Layout_Item *closest_item = 0;
for (Buffer_Layout_Item_Block *block = list.first; for (Layout_Item_Block *block = list.first;
block != 0; block != 0;
block = block->next){ block = block->next){
i64 count = block->count; i64 count = block->count;
Buffer_Layout_Item *item = block->items; Layout_Item *item = block->items;
for (i32 i = 0; i < count; i += 1, item += 1){ for (i32 i = 0; i < count; i += 1, item += 1){
// NOTE(allen): This only works if we build layouts in y-sorted order. // NOTE(allen): This only works if we build layouts in y-sorted order.
if (p.y < item->rect.y0){ if (p.y < item->rect.y0){
@ -1145,7 +959,7 @@ buffer_layout_nearest_pos_to_xy(Buffer_Layout_Item_List list, Vec2_f32 p){
} }
internal i64 internal i64
buffer_layout_get_pos_at_character(Buffer_Layout_Item_List list, i64 character){ buffer_layout_get_pos_at_character(Layout_Item_List list, i64 character){
i64 result = 0; i64 result = 0;
if (character <= 0){ if (character <= 0){
result = list.index_range.min; result = list.index_range.min;
@ -1155,7 +969,7 @@ buffer_layout_get_pos_at_character(Buffer_Layout_Item_List list, i64 character){
} }
else{ else{
i64 counter = 0; i64 counter = 0;
for (Buffer_Layout_Item_Block *node = list.first; for (Layout_Item_Block *node = list.first;
node != 0; node != 0;
node = node->next){ node = node->next){
i64 next_counter = counter + node->character_count; i64 next_counter = counter + node->character_count;
@ -1164,7 +978,7 @@ buffer_layout_get_pos_at_character(Buffer_Layout_Item_List list, i64 character){
i64 relative_character = character - counter; i64 relative_character = character - counter;
i64 relative_character_counter = 0; i64 relative_character_counter = 0;
i64 prev_index = -1; i64 prev_index = -1;
Buffer_Layout_Item *item = node->items; Layout_Item *item = node->items;
for (i64 i = 0; i < count; i += 1, item += 1){ for (i64 i = 0; i < count; i += 1, item += 1){
if (prev_index != item->index){ if (prev_index != item->index){
prev_index = item->index; prev_index = item->index;
@ -1183,15 +997,15 @@ buffer_layout_get_pos_at_character(Buffer_Layout_Item_List list, i64 character){
return(result); return(result);
} }
internal Buffer_Layout_Item* internal Layout_Item*
buffer_layout_get_first_with_index(Buffer_Layout_Item_List list, i64 index){ buffer_layout_get_first_with_index(Layout_Item_List list, i64 index){
Buffer_Layout_Item *result = 0; Layout_Item *result = 0;
Buffer_Layout_Item *prev = 0; Layout_Item *prev = 0;
for (Buffer_Layout_Item_Block *block = list.first; for (Layout_Item_Block *block = list.first;
block != 0; block != 0;
block = block->next){ block = block->next){
i64 count = block->count; i64 count = block->count;
Buffer_Layout_Item *item = block->items; Layout_Item *item = block->items;
for (i32 i = 0; i < count; i += 1, item += 1){ for (i32 i = 0; i < count; i += 1, item += 1){
if (item->index > index){ if (item->index > index){
result = prev; result = prev;
@ -1212,9 +1026,9 @@ buffer_layout_get_first_with_index(Buffer_Layout_Item_List list, i64 index){
} }
internal Vec2_f32 internal Vec2_f32
buffer_layout_xy_center_of_pos(Buffer_Layout_Item_List list, i64 index){ buffer_layout_xy_center_of_pos(Layout_Item_List list, i64 index){
Vec2_f32 result = {}; Vec2_f32 result = {};
Buffer_Layout_Item *item = buffer_layout_get_first_with_index(list, index); Layout_Item *item = buffer_layout_get_first_with_index(list, index);
if (item != 0){ if (item != 0){
result = rect_center(item->rect); result = rect_center(item->rect);
} }
@ -1222,7 +1036,7 @@ buffer_layout_xy_center_of_pos(Buffer_Layout_Item_List list, i64 index){
} }
internal i64 internal i64
buffer_layout_character_from_pos(Buffer_Layout_Item_List list, i64 index){ buffer_layout_character_from_pos(Layout_Item_List list, i64 index){
i64 result = 0; i64 result = 0;
i64 character_count = 0; i64 character_count = 0;
i64 prev_index = -1; i64 prev_index = -1;
@ -1233,10 +1047,10 @@ buffer_layout_character_from_pos(Buffer_Layout_Item_List list, i64 index){
result = list.character_count - 1; result = list.character_count - 1;
} }
else{ else{
for (Buffer_Layout_Item_Block *node = list.first; for (Layout_Item_Block *node = list.first;
node != 0; node != 0;
node = node->next){ node = node->next){
Buffer_Layout_Item *item = node->items; Layout_Item *item = node->items;
i64 count = node->count; i64 count = node->count;
for (i64 i = 0; i < count; i += 1, item += 1){ for (i64 i = 0; i < count; i += 1, item += 1){
if (item->index == index){ if (item->index == index){

View File

@ -63,44 +63,6 @@ struct Line_Move{
}; };
}; };
typedef u32 Buffer_Layout_Flag;
enum{
BRFlag_Special_Character = (1 << 0),
BRFlag_Ghost_Character = (1 << 1)
};
struct Buffer_Layout_Item{
i64 index;
u32 codepoint;
Buffer_Layout_Flag flags;
Rect_f32 rect;
};
struct Buffer_Layout_Item_Block{
Buffer_Layout_Item_Block *next;
Buffer_Layout_Item *items;
i64 count;
i64 character_count;
};
struct Buffer_Layout_Item_List{
Buffer_Layout_Item_Block *first;
Buffer_Layout_Item_Block *last;
i32 node_count;
i32 total_count;
f32 height;
f32 bottom_extension;
i64 character_count;
Interval_i64 index_range;
};
#if 0
struct Edit_Array{
Edit *vals;
i32 count;
};
#endif
#endif #endif
// BOTTOM // BOTTOM

View File

@ -292,9 +292,10 @@ file_get_managed_scope(Editing_File *file){
//////////////////////////////// ////////////////////////////////
internal Buffer_Layout_Item_List internal Layout_Item_List
file_get_line_layout(Thread_Context *tctx, Models *models, Editing_File *file, f32 width, Face *face, i64 line_number){ file_get_line_layout(Thread_Context *tctx, Models *models, Editing_File *file,
Buffer_Layout_Item_List result = {}; Layout_Function *layout_func, f32 width, Face *face, i64 line_number){
Layout_Item_List result = {};
i64 line_count = buffer_line_count(&file->state.buffer); i64 line_count = buffer_line_count(&file->state.buffer);
if (1 <= line_number && line_number <= line_count){ if (1 <= line_number && line_number <= line_count){
@ -306,19 +307,23 @@ file_get_line_layout(Thread_Context *tctx, Models *models, Editing_File *file, f
Data key_data = make_data_struct(&key); Data key_data = make_data_struct(&key);
Buffer_Layout_Item_List *list = 0; Layout_Item_List *list = 0;
Table_Lookup lookup = table_lookup(&file->state.line_layout_table, key_data); Table_Lookup lookup = table_lookup(&file->state.line_layout_table, key_data);
if (lookup.found_match){ if (lookup.found_match){
u64 val = 0; u64 val = 0;
table_read(&file->state.line_layout_table, lookup, &val); table_read(&file->state.line_layout_table, lookup, &val);
list = (Buffer_Layout_Item_List*)IntAsPtr(val); list = (Layout_Item_List*)IntAsPtr(val);
} }
else{ else{
list = push_array(&file->state.cached_layouts_arena, Buffer_Layout_Item_List, 1); list = push_array(&file->state.cached_layouts_arena, Layout_Item_List, 1);
Interval_i64 line_range = buffer_get_pos_range_from_line_number(&file->state.buffer, line_number); Range_i64 line_range = buffer_get_pos_range_from_line_number(&file->state.buffer, line_number);
*list = buffer_layout(tctx, &file->state.cached_layouts_arena,
&file->state.buffer, line_range, face, width); Application_Links app = {};
app.tctx = tctx;
app.cmd_context = models;
*list = layout_func(&app, &file->state.cached_layouts_arena,
file->id, line_range, face->id, width);
key_data = push_data_copy(&file->state.cached_layouts_arena, key_data); key_data = push_data_copy(&file->state.cached_layouts_arena, key_data);
table_insert(&file->state.line_layout_table, key_data, (u64)PtrAsInt(list)); table_insert(&file->state.line_layout_table, key_data, (u64)PtrAsInt(list));
} }
@ -335,7 +340,9 @@ file_clear_layout_cache(Editing_File *file){
} }
internal Line_Shift_Vertical internal Line_Shift_Vertical
file_line_shift_y(Thread_Context *tctx, Models *models, Editing_File *file, f32 width, Face *face, i64 line_number, f32 y_delta){ file_line_shift_y(Thread_Context *tctx, Models *models, Editing_File *file,
Layout_Function *layout_func, f32 width, Face *face,
i64 line_number, f32 y_delta){
Line_Shift_Vertical result = {}; Line_Shift_Vertical result = {};
f32 line_y = 0.f; f32 line_y = 0.f;
@ -355,7 +362,8 @@ file_line_shift_y(Thread_Context *tctx, Models *models, Editing_File *file, f32
line_number = 1; line_number = 1;
break; break;
} }
Buffer_Layout_Item_List line = file_get_line_layout(tctx, models, file, width, face, line_number); Layout_Item_List line = file_get_line_layout(tctx, models, file, layout_func,
width, face, line_number);
line_y -= line.height; line_y -= line.height;
} }
if (!has_result){ if (!has_result){
@ -368,7 +376,8 @@ file_line_shift_y(Thread_Context *tctx, Models *models, Editing_File *file, f32
b32 has_result = false; b32 has_result = false;
i64 line_count = buffer_line_count(&file->state.buffer); i64 line_count = buffer_line_count(&file->state.buffer);
for (;;line_number += 1){ for (;;line_number += 1){
Buffer_Layout_Item_List line = file_get_line_layout(tctx, models, file, width, face, line_number); Layout_Item_List line = file_get_line_layout(tctx, models, file, layout_func,
width, face, line_number);
f32 next_y = line_y + line.height; f32 next_y = line_y + line.height;
if (y_delta < next_y){ if (y_delta < next_y){
has_result = true; has_result = true;
@ -391,12 +400,15 @@ file_line_shift_y(Thread_Context *tctx, Models *models, Editing_File *file, f32
} }
internal f32 internal f32
file_line_y_difference(Thread_Context *tctx, Models *models, Editing_File *file, f32 width, Face *face, i64 line_a, i64 line_b){ file_line_y_difference(Thread_Context *tctx, Models *models, Editing_File *file,
Layout_Function *layout_func, f32 width, Face *face,
i64 line_a, i64 line_b){
f32 result = 0.f; f32 result = 0.f;
if (line_a != line_b){ if (line_a != line_b){
Interval_i64 line_range = Ii64(line_a, line_b); Interval_i64 line_range = Ii64(line_a, line_b);
for (i64 i = line_range.min; i < line_range.max; i += 1){ for (i64 i = line_range.min; i < line_range.max; i += 1){
Buffer_Layout_Item_List line = file_get_line_layout(tctx, models, file, width, face, i); Layout_Item_List line = file_get_line_layout(tctx, models, file, layout_func,
width, face, i);
result += line.height; result += line.height;
} }
if (line_a < line_b){ if (line_a < line_b){
@ -407,25 +419,40 @@ file_line_y_difference(Thread_Context *tctx, Models *models, Editing_File *file,
} }
internal i64 internal i64
file_pos_at_relative_xy(Thread_Context *tctx, Models *models, Editing_File *file, f32 width, Face *face, i64 base_line, Vec2_f32 relative_xy){ file_pos_at_relative_xy(Thread_Context *tctx, Models *models, Editing_File *file,
Line_Shift_Vertical shift = file_line_shift_y(tctx, models, file, width, face, base_line, relative_xy.y); Layout_Function *layout_func, f32 width, Face *face,
i64 base_line, Vec2_f32 relative_xy){
Line_Shift_Vertical shift = file_line_shift_y(tctx, models, file,
layout_func, width, face, base_line,
relative_xy.y);
relative_xy.y -= shift.y_delta; relative_xy.y -= shift.y_delta;
Buffer_Layout_Item_List line = file_get_line_layout(tctx, models, file, width, face, shift.line); Layout_Item_List line = file_get_line_layout(tctx, models, file,
layout_func, width, face,
shift.line);
return(buffer_layout_nearest_pos_to_xy(line, relative_xy)); return(buffer_layout_nearest_pos_to_xy(line, relative_xy));
} }
internal Vec2_f32 internal Vec2_f32
file_relative_xy_of_pos(Thread_Context *tctx, Models *models, Editing_File *file, f32 width, Face *face, i64 base_line, i64 pos){ file_relative_xy_of_pos(Thread_Context *tctx, Models *models, Editing_File *file,
Layout_Function *layout_func, f32 width, Face *face,
i64 base_line, i64 pos){
i64 line_number = buffer_get_line_index(&file->state.buffer, pos) + 1; i64 line_number = buffer_get_line_index(&file->state.buffer, pos) + 1;
Buffer_Layout_Item_List line = file_get_line_layout(tctx, models, file, width, face, line_number); Layout_Item_List line = file_get_line_layout(tctx, models, file,
layout_func, width, face,
line_number);
Vec2_f32 result = buffer_layout_xy_center_of_pos(line, pos); Vec2_f32 result = buffer_layout_xy_center_of_pos(line, pos);
result.y += file_line_y_difference(tctx, models, file, width, face, line_number, base_line); result.y += file_line_y_difference(tctx, models, file,
layout_func, width, face, line_number, base_line);
return(result); return(result);
} }
internal Buffer_Point internal Buffer_Point
file_normalize_buffer_point(Thread_Context *tctx, Models *models, Editing_File *file, f32 width, Face *face, Buffer_Point point){ file_normalize_buffer_point(Thread_Context *tctx, Models *models, Editing_File *file,
Line_Shift_Vertical shift = file_line_shift_y(tctx, models, file, width, face, point.line_number, point.pixel_shift.y); Layout_Function *layout_func, f32 width, Face *face,
Buffer_Point point){
Line_Shift_Vertical shift = file_line_shift_y(tctx, models, file,
layout_func, width, face, point.line_number,
point.pixel_shift.y);
point.line_number = shift.line; point.line_number = shift.line;
point.pixel_shift.y -= shift.y_delta; point.pixel_shift.y -= shift.y_delta;
point.pixel_shift.x = clamp_bot(0.f, point.pixel_shift.x); point.pixel_shift.x = clamp_bot(0.f, point.pixel_shift.x);
@ -434,15 +461,21 @@ file_normalize_buffer_point(Thread_Context *tctx, Models *models, Editing_File *
} }
internal Vec2_f32 internal Vec2_f32
file_buffer_point_difference(Thread_Context *tctx, Models *models, Editing_File *file, f32 width, Face *face, Buffer_Point a, Buffer_Point b){ file_buffer_point_difference(Thread_Context *tctx, Models *models, Editing_File *file,
f32 y_difference = file_line_y_difference(tctx, models, file, width, face, a.line_number, b.line_number); Layout_Function *layout_func, f32 width, Face *face,
Buffer_Point a, Buffer_Point b){
f32 y_difference = file_line_y_difference(tctx, models, file,
layout_func, width, face,
a.line_number, b.line_number);
Vec2_f32 result = a.pixel_shift - b.pixel_shift; Vec2_f32 result = a.pixel_shift - b.pixel_shift;
result.y += y_difference; result.y += y_difference;
return(result); return(result);
} }
internal Line_Shift_Character internal Line_Shift_Character
file_line_shift_characters(Thread_Context *tctx, Models *models, Editing_File *file, f32 width, Face *face, i64 line_number, i64 character_delta){ file_line_shift_characters(Thread_Context *tctx, Models *models, Editing_File *file,
Layout_Function *layout_func, f32 width, Face *face,
i64 line_number, i64 character_delta){
Line_Shift_Character result = {}; Line_Shift_Character result = {};
i64 line_character = 0; i64 line_character = 0;
@ -462,7 +495,9 @@ file_line_shift_characters(Thread_Context *tctx, Models *models, Editing_File *f
line_number = 1; line_number = 1;
break; break;
} }
Buffer_Layout_Item_List line = file_get_line_layout(tctx, models, file, width, face, line_number); Layout_Item_List line = file_get_line_layout(tctx, models, file,
layout_func, width, face,
line_number);
line_character -= line.character_count; line_character -= line.character_count;
} }
if (!has_result){ if (!has_result){
@ -475,7 +510,9 @@ file_line_shift_characters(Thread_Context *tctx, Models *models, Editing_File *f
b32 has_result = false; b32 has_result = false;
i64 line_count = buffer_line_count(&file->state.buffer); i64 line_count = buffer_line_count(&file->state.buffer);
for (;;line_number += 1){ for (;;line_number += 1){
Buffer_Layout_Item_List line = file_get_line_layout(tctx, models, file, width, face, line_number); Layout_Item_List line = file_get_line_layout(tctx, models, file,
layout_func, width, face,
line_number);
i64 next_character = line_character + line.character_count; i64 next_character = line_character + line.character_count;
if (character_delta < next_character){ if (character_delta < next_character){
has_result = true; has_result = true;
@ -498,12 +535,15 @@ file_line_shift_characters(Thread_Context *tctx, Models *models, Editing_File *f
} }
internal i64 internal i64
file_line_character_difference(Thread_Context *tctx, Models *models, Editing_File *file, f32 width, Face *face, i64 line_a, i64 line_b){ file_line_character_difference(Thread_Context *tctx, Models *models, Editing_File *file,
Layout_Function *layout_func, f32 width, Face *face,
i64 line_a, i64 line_b){
i64 result = 0; i64 result = 0;
if (line_a != line_b){ if (line_a != line_b){
Interval_i64 line_range = Ii64(line_a, line_b); Interval_i64 line_range = Ii64(line_a, line_b);
for (i64 i = line_range.min; i < line_range.max; i += 1){ for (i64 i = line_range.min; i < line_range.max; i += 1){
Buffer_Layout_Item_List line = file_get_line_layout(tctx, models, file, width, face, i); Layout_Item_List line = file_get_line_layout(tctx, models, file,
layout_func, width, face, i);
result += line.character_count; result += line.character_count;
} }
if (line_a < line_b){ if (line_a < line_b){
@ -514,19 +554,29 @@ file_line_character_difference(Thread_Context *tctx, Models *models, Editing_Fil
} }
internal i64 internal i64
file_pos_from_relative_character(Thread_Context *tctx, Models *models, Editing_File *file, f32 width, Face *face, i64 base_line, i64 relative_character){ file_pos_from_relative_character(Thread_Context *tctx, Models *models, Editing_File *file,
Line_Shift_Character shift = file_line_shift_characters(tctx, models, file, width, face, base_line, relative_character); Layout_Function *layout_func, f32 width, Face *face,
i64 base_line, i64 relative_character){
Line_Shift_Character shift = file_line_shift_characters(tctx, models, file,
layout_func, width, face,
base_line, relative_character);
relative_character -= shift.character_delta; relative_character -= shift.character_delta;
Buffer_Layout_Item_List line = file_get_line_layout(tctx, models, file, width, face, shift.line); Layout_Item_List line = file_get_line_layout(tctx, models, file,
layout_func, width, face,
shift.line);
return(buffer_layout_get_pos_at_character(line, relative_character)); return(buffer_layout_get_pos_at_character(line, relative_character));
} }
internal i64 internal i64
file_relative_character_from_pos(Thread_Context *tctx, Models *models, Editing_File *file, f32 width, Face *face, i64 base_line, i64 pos){ file_relative_character_from_pos(Thread_Context *tctx, Models *models, Editing_File *file, Layout_Function *layout_func, f32 width, Face *face,
i64 base_line, i64 pos){
i64 line_number = buffer_get_line_index(&file->state.buffer, pos) + 1; i64 line_number = buffer_get_line_index(&file->state.buffer, pos) + 1;
Buffer_Layout_Item_List line = file_get_line_layout(tctx, models, file, width, face, line_number); Layout_Item_List line = file_get_line_layout(tctx, models, file,
layout_func, width, face,
line_number);
i64 result = buffer_layout_character_from_pos(line, pos); i64 result = buffer_layout_character_from_pos(line, pos);
result += file_line_character_difference(tctx, models, file, width, face, line_number, base_line); result += file_line_character_difference(tctx, models, file,
layout_func, width, face, line_number, base_line);
return(result); return(result);
} }

View File

@ -30,43 +30,17 @@ struct Glyph_Bounds{
Rect_f32 xy_off; Rect_f32 xy_off;
}; };
struct Codepoint_Index_Map{
b32 has_zero_index;
u16 zero_index;
u16 max_index;
Table_u32_u16 table;
};
struct Face{ struct Face{
Face_Description description; Face_Description description;
Face_ID id; Face_ID id;
i32 version_number; i32 version_number;
// NOTE(allen): Metrics // NOTE(allen): Metrics
f32 text_height; Face_Metrics metrics;
f32 line_height;
f32 ascent;
f32 descent;
f32 line_skip;
f32 max_advance;
f32 underline_yoff1;
f32 underline_yoff2;
f32 space_advance;
f32 digit_advance;
f32 hex_advance;
f32 byte_advance;
f32 byte_sub_advances[3];
f32 typical_lowercase_advance;
f32 typical_uppercase_advance;
f32 typical_advance;
// NOTE(allen): Glyph data // NOTE(allen): Glyph data
Codepoint_Index_Map codepoint_to_index_map; Face_Advance_Map advance_map;
u16 index_count;
Glyph_Bounds *bounds; Glyph_Bounds *bounds;
f32 *advance;
Glyph_Bounds white; Glyph_Bounds white;
Texture_Kind texture_kind; Texture_Kind texture_kind;

View File

@ -194,31 +194,35 @@ ft__font_make_face(Arena *arena, Face_Description *description, f32 scale_factor
face->description = *description; face->description = *description;
face->description.font.file_name = file_name; face->description.font.file_name = file_name;
face->max_advance = f32_ceil32(ft_face->size->metrics.max_advance/64.f); Face_Metrics *met = &face->metrics;
face->ascent = f32_ceil32(ft_face->size->metrics.ascender/64.f);
face->descent = f32_floor32(ft_face->size->metrics.descender/64.f); met->max_advance = f32_ceil32(ft_face->size->metrics.max_advance/64.f);
face->text_height = f32_ceil32(ft_face->size->metrics.height/64.f); met->ascent = f32_ceil32(ft_face->size->metrics.ascender/64.f);
face->line_skip = face->text_height - face->ascent + face->descent; met->descent = f32_floor32(ft_face->size->metrics.descender/64.f);
face->line_skip = clamp_bot(1.f, face->line_skip); met->text_height = f32_ceil32(ft_face->size->metrics.height/64.f);
face->line_height = face->text_height + face->line_skip; met->line_skip = met->text_height - met->ascent + met->descent;
met->line_skip = clamp_bot(1.f, met->line_skip);
met->line_height = met->text_height + met->line_skip;
{ {
f32 real_over_notional = face->line_height/(f32)ft_face->height; f32 real_over_notional = met->line_height/(f32)ft_face->height;
f32 relative_center = -1.f*real_over_notional*ft_face->underline_position; f32 relative_center = -1.f*real_over_notional*ft_face->underline_position;
f32 relative_thickness = real_over_notional*ft_face->underline_thickness; f32 relative_thickness = real_over_notional*ft_face->underline_thickness;
f32 center = f32_floor32(face->ascent + relative_center); f32 center = f32_floor32(met->ascent + relative_center);
f32 thickness = clamp_bot(1.f, relative_thickness); f32 thickness = clamp_bot(1.f, relative_thickness);
face->underline_yoff1 = center - thickness*0.5f; met->underline_yoff1 = center - thickness*0.5f;
face->underline_yoff2 = center + thickness*0.5f; met->underline_yoff2 = center + thickness*0.5f;
} }
face->codepoint_to_index_map = ft__get_codepoint_index_map(arena->base_allocator, ft_face); face->advance_map.codepoint_to_index =
u16 index_count = codepoint_index_map_count(&face->codepoint_to_index_map); ft__get_codepoint_index_map(arena->base_allocator, ft_face);
face->index_count = index_count; u16 index_count =
codepoint_index_map_count(&face->advance_map.codepoint_to_index);
face->advance_map.index_count = index_count;
face->advance_map.advance = push_array_zero(arena, f32, index_count);
face->bounds = push_array(arena, Glyph_Bounds, index_count); face->bounds = push_array(arena, Glyph_Bounds, index_count);
face->advance = push_array_zero(arena, f32, index_count);
struct FT_Bitmap{ struct FT_Bitmap{
Vec2_i32 dim; Vec2_i32 dim;
@ -238,7 +242,7 @@ ft__font_make_face(Arena *arena, Face_Description *description, f32 scale_factor
bitmap->data = push_array(arena, u8, dim.x*dim.y); bitmap->data = push_array(arena, u8, dim.x*dim.y);
face->bounds[i].xy_off.x0 = (f32)(ft_face->glyph->bitmap_left); face->bounds[i].xy_off.x0 = (f32)(ft_face->glyph->bitmap_left);
face->bounds[i].xy_off.y0 = (f32)(face->ascent - ft_face->glyph->bitmap_top); face->bounds[i].xy_off.y0 = (f32)(met->ascent - ft_face->glyph->bitmap_top);
face->bounds[i].xy_off.x1 = (f32)(face->bounds[i].xy_off.x0 + dim.x); face->bounds[i].xy_off.x1 = (f32)(face->bounds[i].xy_off.x0 + dim.x);
face->bounds[i].xy_off.y1 = (f32)(face->bounds[i].xy_off.y0 + dim.y); face->bounds[i].xy_off.y1 = (f32)(face->bounds[i].xy_off.y0 + dim.y);
@ -272,7 +276,7 @@ ft__font_make_face(Arena *arena, Face_Description *description, f32 scale_factor
}break; }break;
} }
face->advance[i] = f32_ceil32(ft_glyph->advance.x/64.0f); face->advance_map.advance[i] = f32_ceil32(ft_glyph->advance.x/64.0f);
} }
} }
@ -327,22 +331,30 @@ ft__font_make_face(Arena *arena, Face_Description *description, f32 scale_factor
} }
{ {
face->space_advance = font_get_glyph_advance(face, ' '); Face_Advance_Map *advance_map = &face->advance_map;
face->digit_advance = font_get_max_glyph_advance_range(face, '0', '9');
face->hex_advance = font_get_max_glyph_advance_range(face, 'A', 'F'); met->space_advance = font_get_glyph_advance(advance_map, met, ' ');
face->hex_advance = Max(face->hex_advance, face->digit_advance); met->decimal_digit_advance =
face->byte_sub_advances[0] = font_get_glyph_advance(face, '\\'); font_get_max_glyph_advance_range(advance_map, met, '0', '9');
face->byte_sub_advances[1] = face->hex_advance; met->hex_digit_advance =
face->byte_sub_advances[2] = face->hex_advance; font_get_max_glyph_advance_range(advance_map, met, 'A', 'F');
face->byte_advance = met->hex_digit_advance =
face->byte_sub_advances[0] + max(met->hex_digit_advance, met->decimal_digit_advance);
face->byte_sub_advances[1] + met->byte_sub_advances[0] =
face->byte_sub_advances[2]; font_get_glyph_advance(advance_map, met, '\\');
face->typical_lowercase_advance = font_get_average_glyph_advance_range(face, 'a', 'z'); met->byte_sub_advances[1] = met->hex_digit_advance;
face->typical_uppercase_advance = font_get_average_glyph_advance_range(face, 'A', 'Z'); met->byte_sub_advances[2] = met->hex_digit_advance;
face->typical_advance = (26*face->typical_lowercase_advance + met->byte_advance =
26*face->typical_uppercase_advance + met->byte_sub_advances[0] +
10*face->digit_advance)/62.f; met->byte_sub_advances[1] +
met->byte_sub_advances[2];
met->normal_lowercase_advance =
font_get_average_glyph_advance_range(advance_map, met, 'a', 'z');
met->normal_uppercase_advance =
font_get_average_glyph_advance_range(advance_map, met, 'A', 'Z');
met->normal_advance = (26*met->normal_lowercase_advance +
26*met->normal_uppercase_advance +
10*met->decimal_digit_advance)/62.f;
} }
} }

View File

@ -167,8 +167,8 @@ draw_font_glyph(Render_Target *target, Face *face, u32 codepoint, Vec2_f32 p,
draw__set_face_id(target, face->id); draw__set_face_id(target, face->id);
u16 glyph_index = 0; u16 glyph_index = 0;
if (!codepoint_index_map_read(&face->codepoint_to_index_map, codepoint, if (!codepoint_index_map_read(&face->advance_map.codepoint_to_index,
&glyph_index)){ codepoint, &glyph_index)){
glyph_index = 0; glyph_index = 0;
} }
Glyph_Bounds bounds = face->bounds[glyph_index]; Glyph_Bounds bounds = face->bounds[glyph_index];
@ -230,8 +230,8 @@ draw_string(Render_Target *target, Face *face, String_Const_u8 string, Vec2_f32
if (face != 0){ if (face != 0){
point = floor32(point); point = floor32(point);
f32 byte_advance = face->byte_advance; f32 byte_advance = face->metrics.byte_advance;
f32 *byte_sub_advances = face->byte_sub_advances; f32 *byte_sub_advances = face->metrics.byte_sub_advances;
u8 *str = (u8*)string.str; u8 *str = (u8*)string.str;
u8 *str_end = str + string.size; u8 *str_end = str + string.size;
@ -250,7 +250,9 @@ draw_string(Render_Target *target, Face *face, String_Const_u8 string, Vec2_f32
if (color != 0){ if (color != 0){
draw_font_glyph(target, face, codepoint, point, color, flags); draw_font_glyph(target, face, codepoint, point, color, flags);
} }
f32 d = font_get_glyph_advance(face, codepoint); f32 d = font_get_glyph_advance(&face->advance_map,
&face->metrics,
codepoint);
point += d*delta; point += d*delta;
total_delta += d; total_delta += d;
} }

View File

@ -37,8 +37,8 @@ text_layout_release(Thread_Context *tctx, Models *models, Text_Layout_Container
internal Text_Layout_ID internal Text_Layout_ID
text_layout_new(Text_Layout_Container *container, Arena *arena, text_layout_new(Text_Layout_Container *container, Arena *arena,
Buffer_ID buffer_id, Buffer_Point point, Buffer_ID buffer_id, Buffer_Point point,
Interval_i64 visible_range, Interval_i64 visible_line_number_range, Range_i64 visible_range, Interval_i64 visible_line_number_range,
Rect_f32 rect, FColor *item_colors){ Rect_f32 rect, FColor *item_colors, Layout_Function *layout_func){
Text_Layout *new_layout_data = text_layout_new__alloc_layout(container); Text_Layout *new_layout_data = text_layout_new__alloc_layout(container);
new_layout_data->arena = arena; new_layout_data->arena = arena;
new_layout_data->buffer_id = buffer_id; new_layout_data->buffer_id = buffer_id;
@ -47,6 +47,7 @@ text_layout_new(Text_Layout_Container *container, Arena *arena,
new_layout_data->visible_line_number_range = visible_line_number_range; new_layout_data->visible_line_number_range = visible_line_number_range;
new_layout_data->rect = rect; new_layout_data->rect = rect;
new_layout_data->item_colors = item_colors; new_layout_data->item_colors = item_colors;
new_layout_data->layout_func = layout_func;
Text_Layout_ID new_id = ++container->id_counter; Text_Layout_ID new_id = ++container->id_counter;
table_insert(&container->table, new_id, (u64)PtrAsInt(new_layout_data)); table_insert(&container->table, new_id, (u64)PtrAsInt(new_layout_data));
return(new_id); return(new_id);
@ -97,21 +98,24 @@ text_layout_render(Thread_Context *tctx, Models *models, Text_Layout *layout){
i64 first_index = layout->visible_range.first; i64 first_index = layout->visible_range.first;
i64 line_number = layout->visible_line_number_range.min; i64 line_number = layout->visible_line_number_range.min;
i64 line_number_last = layout->visible_line_number_range.max; i64 line_number_last = layout->visible_line_number_range.max;
Layout_Function *layout_func = layout->layout_func;
for (;line_number <= line_number_last; line_number += 1){ for (;line_number <= line_number_last; line_number += 1){
Buffer_Layout_Item_List line = file_get_line_layout(tctx, models, file, width, face, line_number); Layout_Item_List line = file_get_line_layout(tctx, models, file,
for (Buffer_Layout_Item_Block *block = line.first; layout_func, width, face,
line_number);
for (Layout_Item_Block *block = line.first;
block != 0; block != 0;
block = block->next){ block = block->next){
Buffer_Layout_Item *item = block->items; Layout_Item *item = block->items;
i64 count = block->count; i64 count = block->count;
FColor *item_colors = layout->item_colors; FColor *item_colors = layout->item_colors;
for (i32 i = 0; i < count; i += 1, item += 1){ for (i32 i = 0; i < count; i += 1, item += 1){
if (item->codepoint != 0){ if (item->codepoint != 0){
ARGB_Color color = 0; ARGB_Color color = 0;
if (HasFlag(item->flags, BRFlag_Special_Character)){ if (HasFlag(item->flags, LayoutItemFlag_Special_Character)){
color = special_color; color = special_color;
} }
else if (HasFlag(item->flags, BRFlag_Ghost_Character)){ else if (HasFlag(item->flags, LayoutItemFlag_Ghost_Character)){
color = ghost_color; color = ghost_color;
} }
else{ else{

View File

@ -22,6 +22,7 @@ union Text_Layout{
Interval_i64 visible_line_number_range; Interval_i64 visible_line_number_range;
Rect_f32 rect; Rect_f32 rect;
FColor *item_colors; FColor *item_colors;
Layout_Function *layout_func;
}; };
}; };

View File

@ -177,66 +177,91 @@ view_height(Thread_Context *tctx, Models *models, View *view){
return(rect_height(view_get_buffer_rect(tctx, models, view))); return(rect_height(view_get_buffer_rect(tctx, models, view)));
} }
function Layout_Function*
view_get_layout_func(View *view){
return(view->layout_func);
}
//////////////////////////////// ////////////////////////////////
internal Buffer_Layout_Item_List internal Layout_Item_List
view_get_line_layout(Thread_Context *tctx, Models *models, View *view, i64 line_number){ view_get_line_layout(Thread_Context *tctx, Models *models, View *view, i64 line_number){
Editing_File *file = view->file; Editing_File *file = view->file;
Face *face = file_get_face(models, file); Face *face = file_get_face(models, file);
f32 width = view_width(tctx, models, view); f32 width = view_width(tctx, models, view);
return(file_get_line_layout(tctx, models, file, width, face, line_number)); Layout_Function *layout_func = view_get_layout_func(view);
return(file_get_line_layout(tctx, models, file, layout_func, width, face, line_number));
} }
internal Line_Shift_Vertical internal Line_Shift_Vertical
view_line_shift_y(Thread_Context *tctx, Models *models, View *view, i64 line_number, f32 y_delta){ view_line_shift_y(Thread_Context *tctx, Models *models, View *view,
i64 line_number, f32 y_delta){
Editing_File *file = view->file; Editing_File *file = view->file;
Face *face = file_get_face(models, file); Face *face = file_get_face(models, file);
f32 width = view_width(tctx, models, view); f32 width = view_width(tctx, models, view);
return(file_line_shift_y(tctx, models, file, width, face, line_number, y_delta)); Layout_Function *layout_func = view_get_layout_func(view);
return(file_line_shift_y(tctx, models, file, layout_func, width, face,
line_number, y_delta));
} }
internal f32 internal f32
view_line_y_difference(Thread_Context *tctx, Models *models, View *view, i64 line_a, i64 line_b){ view_line_y_difference(Thread_Context *tctx, Models *models, View *view,
i64 line_a, i64 line_b){
Editing_File *file = view->file; Editing_File *file = view->file;
Face *face = file_get_face(models, file); Face *face = file_get_face(models, file);
f32 width = view_width(tctx, models, view); f32 width = view_width(tctx, models, view);
return(file_line_y_difference(tctx, models, file, width, face, line_a, line_b)); Layout_Function *layout_func = view_get_layout_func(view);
return(file_line_y_difference(tctx, models, file,
layout_func, width, face, line_a, line_b));
} }
internal i64 internal i64
view_pos_at_relative_xy(Thread_Context *tctx, Models *models, View *view, i64 base_line, Vec2_f32 relative_xy){ view_pos_at_relative_xy(Thread_Context *tctx, Models *models, View *view,
i64 base_line, Vec2_f32 relative_xy){
Editing_File *file = view->file; Editing_File *file = view->file;
Face *face = file_get_face(models, file); Face *face = file_get_face(models, file);
f32 width = view_width(tctx, models, view); f32 width = view_width(tctx, models, view);
return(file_pos_at_relative_xy(tctx, models, file, width, face, base_line, relative_xy)); Layout_Function *layout_func = view_get_layout_func(view);
return(file_pos_at_relative_xy(tctx, models, file,
layout_func, width, face, base_line, relative_xy));
} }
internal Vec2_f32 internal Vec2_f32
view_relative_xy_of_pos(Thread_Context *tctx, Models *models, View *view, i64 base_line, i64 pos){ view_relative_xy_of_pos(Thread_Context *tctx, Models *models, View *view,
i64 base_line, i64 pos){
Editing_File *file = view->file; Editing_File *file = view->file;
Face *face = file_get_face(models, file); Face *face = file_get_face(models, file);
f32 width = view_width(tctx, models, view); f32 width = view_width(tctx, models, view);
return(file_relative_xy_of_pos(tctx, models, file, width, face, base_line, pos)); Layout_Function *layout_func = view_get_layout_func(view);
return(file_relative_xy_of_pos(tctx, models, file,
layout_func, width, face, base_line, pos));
} }
internal Buffer_Point internal Buffer_Point
view_normalize_buffer_point(Thread_Context *tctx, Models *models, View *view, Buffer_Point point){ view_normalize_buffer_point(Thread_Context *tctx, Models *models, View *view,
Buffer_Point point){
Editing_File *file = view->file; Editing_File *file = view->file;
Face *face = file_get_face(models, file); Face *face = file_get_face(models, file);
f32 width = view_width(tctx, models, view); f32 width = view_width(tctx, models, view);
return(file_normalize_buffer_point(tctx, models, file, width, face, point)); Layout_Function *layout_func = view_get_layout_func(view);
return(file_normalize_buffer_point(tctx, models, file,
layout_func, width, face, point));
} }
internal Vec2_f32 internal Vec2_f32
view_buffer_point_difference(Thread_Context *tctx, Models *models, View *view, Buffer_Point a, Buffer_Point b){ view_buffer_point_difference(Thread_Context *tctx, Models *models, View *view,
Buffer_Point a, Buffer_Point b){
Editing_File *file = view->file; Editing_File *file = view->file;
Face *face = file_get_face(models, file); Face *face = file_get_face(models, file);
f32 width = view_width(tctx, models, view); f32 width = view_width(tctx, models, view);
return(file_buffer_point_difference(tctx, models, file, width, face, a, b)); Layout_Function *layout_func = view_get_layout_func(view);
return(file_buffer_point_difference(tctx, models, file,
layout_func, width, face, a, b));
} }
internal Buffer_Point internal Buffer_Point
view_move_buffer_point(Thread_Context *tctx, Models *models, View *view, Buffer_Point buffer_point, Vec2_f32 delta){ view_move_buffer_point(Thread_Context *tctx, Models *models, View *view,
Buffer_Point buffer_point, Vec2_f32 delta){
delta += buffer_point.pixel_shift; delta += buffer_point.pixel_shift;
Line_Shift_Vertical shift = view_line_shift_y(tctx, models, view, buffer_point.line_number, delta.y); Line_Shift_Vertical shift = view_line_shift_y(tctx, models, view, buffer_point.line_number, delta.y);
buffer_point.line_number = shift.line; buffer_point.line_number = shift.line;
@ -245,35 +270,47 @@ view_move_buffer_point(Thread_Context *tctx, Models *models, View *view, Buffer_
} }
internal Line_Shift_Character internal Line_Shift_Character
view_line_shift_characters(Thread_Context *tctx, Models *models, View *view, i64 line_number, i64 character_delta){ view_line_shift_characters(Thread_Context *tctx, Models *models, View *view,
i64 line_number, i64 character_delta){
Editing_File *file = view->file; Editing_File *file = view->file;
Face *face = file_get_face(models, file); Face *face = file_get_face(models, file);
f32 width = view_width(tctx, models, view); f32 width = view_width(tctx, models, view);
return(file_line_shift_characters(tctx, models, file, width, face, line_number, character_delta)); Layout_Function *layout_func = view_get_layout_func(view);
return(file_line_shift_characters(tctx, models, file,
layout_func, width, face, line_number, character_delta));
} }
internal i64 internal i64
view_line_character_difference(Thread_Context *tctx, Models *models, View *view, i64 line_a, i64 line_b){ view_line_character_difference(Thread_Context *tctx, Models *models, View *view,
i64 line_a, i64 line_b){
Editing_File *file = view->file; Editing_File *file = view->file;
Face *face = file_get_face(models, file); Face *face = file_get_face(models, file);
f32 width = view_width(tctx, models, view); f32 width = view_width(tctx, models, view);
return(file_line_character_difference(tctx, models, file, width, face, line_a, line_b)); Layout_Function *layout_func = view_get_layout_func(view);
return(file_line_character_difference(tctx, models, file, layout_func, width, face,
line_a, line_b));
} }
internal i64 internal i64
view_pos_from_relative_character(Thread_Context *tctx, Models *models, View *view, i64 base_line, i64 relative_character){ view_pos_from_relative_character(Thread_Context *tctx, Models *models, View *view,
i64 base_line, i64 relative_character){
Editing_File *file = view->file; Editing_File *file = view->file;
Face *face = file_get_face(models, file); Face *face = file_get_face(models, file);
f32 width = view_width(tctx, models, view); f32 width = view_width(tctx, models, view);
return(file_pos_from_relative_character(tctx, models, file, width, face, base_line, relative_character)); Layout_Function *layout_func = view_get_layout_func(view);
return(file_pos_from_relative_character(tctx, models, file, layout_func, width, face,
base_line, relative_character));
} }
internal i64 internal i64
view_relative_character_from_pos(Thread_Context *tctx, Models *models, View *view, i64 base_line, i64 pos){ view_relative_character_from_pos(Thread_Context *tctx, Models *models, View *view,
i64 base_line, i64 pos){
Editing_File *file = view->file; Editing_File *file = view->file;
Face *face = file_get_face(models, file); Face *face = file_get_face(models, file);
f32 width = view_width(tctx, models, view); f32 width = view_width(tctx, models, view);
return(file_relative_character_from_pos(tctx, models, file, width, face, base_line, pos)); Layout_Function *layout_func = view_get_layout_func(view);
return(file_relative_character_from_pos(tctx, models, file,
layout_func, width, face, base_line, pos));
} }
internal Buffer_Cursor internal Buffer_Cursor
@ -291,13 +328,16 @@ view_move_view_to_cursor(Thread_Context *tctx, Models *models, View *view, Buffe
Rect_f32 rect = view_get_buffer_rect(tctx, models, view); Rect_f32 rect = view_get_buffer_rect(tctx, models, view);
Vec2_f32 view_dim = rect_dim(rect); Vec2_f32 view_dim = rect_dim(rect);
Layout_Function *layout_func = view_get_layout_func(view);
File_Edit_Positions edit_pos = view_get_edit_pos(view); File_Edit_Positions edit_pos = view_get_edit_pos(view);
Vec2_f32 p = file_relative_xy_of_pos(tctx, models, file, view_dim.x, face, scroll->target.line_number, Vec2_f32 p = file_relative_xy_of_pos(tctx, models, file,
edit_pos.cursor_pos); layout_func, view_dim.x, face,
scroll->target.line_number, edit_pos.cursor_pos);
p -= scroll->target.pixel_shift; p -= scroll->target.pixel_shift;
f32 line_height = face->line_height; f32 line_height = face->metrics.line_height;
f32 typical_advance = face->typical_advance; f32 normal_advance = face->metrics.normal_advance;
Vec2_f32 target_p_relative = {}; Vec2_f32 target_p_relative = {};
if (p.y < 0.f){ if (p.y < 0.f){
@ -307,10 +347,10 @@ view_move_view_to_cursor(Thread_Context *tctx, Models *models, View *view, Buffe
target_p_relative.y = (p.y + line_height*1.5f) - view_dim.y; target_p_relative.y = (p.y + line_height*1.5f) - view_dim.y;
} }
if (p.x < 0.f){ if (p.x < 0.f){
target_p_relative.x = p.x - typical_advance*1.5f; target_p_relative.x = p.x - normal_advance*1.5f;
} }
else if (p.x > view_dim.x){ else if (p.x > view_dim.x){
target_p_relative.x = (p.x + typical_advance*1.5f) - view_dim.x; target_p_relative.x = (p.x + normal_advance*1.5f) - view_dim.x;
} }
scroll->target.pixel_shift += target_p_relative; scroll->target.pixel_shift += target_p_relative;
scroll->target = view_normalize_buffer_point(tctx, models, view, scroll->target); scroll->target = view_normalize_buffer_point(tctx, models, view, scroll->target);
@ -327,10 +367,14 @@ view_move_cursor_to_view(Thread_Context *tctx, Models *models, View *view, Buffe
Rect_f32 rect = view_get_buffer_rect(tctx, models, view); Rect_f32 rect = view_get_buffer_rect(tctx, models, view);
Vec2_f32 view_dim = rect_dim(rect); Vec2_f32 view_dim = rect_dim(rect);
Vec2_f32 p = file_relative_xy_of_pos(tctx, models, file, view_dim.x, face, scroll.target.line_number, *pos_in_out); Layout_Function *layout_func = view_get_layout_func(view);
Vec2_f32 p = file_relative_xy_of_pos(tctx, models, file,
layout_func, view_dim.x, face,
scroll.target.line_number, *pos_in_out);
p -= scroll.target.pixel_shift; p -= scroll.target.pixel_shift;
f32 line_height = face->line_height; f32 line_height = face->metrics.line_height;
b32 adjusted_y = true; b32 adjusted_y = true;
if (p.y < 0.f){ if (p.y < 0.f){
@ -346,7 +390,9 @@ view_move_cursor_to_view(Thread_Context *tctx, Models *models, View *view, Buffe
b32 result = false; b32 result = false;
if (adjusted_y){ if (adjusted_y){
p += scroll.target.pixel_shift; p += scroll.target.pixel_shift;
*pos_in_out = file_pos_at_relative_xy(tctx, models, file, view_dim.x, face, scroll.target.line_number, p); *pos_in_out = file_pos_at_relative_xy(tctx, models, file,
layout_func, view_dim.x, face,
scroll.target.line_number, p);
result = true; result = true;
} }
@ -515,6 +561,7 @@ view_event_context_base__inner(Coroutine *coroutine){
function void function void
view_init(Thread_Context *tctx, Models *models, View *view, Editing_File *initial_buffer, view_init(Thread_Context *tctx, Models *models, View *view, Editing_File *initial_buffer,
Custom_Command_Function *event_context_base){ Custom_Command_Function *event_context_base){
view->layout_func = models->layout_func;
view_set_file(tctx, models, view, initial_buffer); view_set_file(tctx, models, view, initial_buffer);
view->node_arena = reserve_arena(tctx); view->node_arena = reserve_arena(tctx);

View File

@ -75,6 +75,7 @@ struct View{
File_Edit_Positions edit_pos_; File_Edit_Positions edit_pos_;
i64 mark; i64 mark;
f32 preferred_x; f32 preferred_x;
Layout_Function *layout_func;
b8 new_scroll_target; b8 new_scroll_target;

View File

@ -1,15 +1,10 @@
/* /*
* Mr. 4th Dimention - Allen Webster 4coder_codepoint_map.cpp - Codepoint map to index
* */
* 23.07.2019
*
* Face basic operations.
*
*/
// TOP // TOP
internal b32 function b32
codepoint_index_map_read(Codepoint_Index_Map *map, u32 codepoint, u16 *index_out){ codepoint_index_map_read(Codepoint_Index_Map *map, u32 codepoint, u16 *index_out){
b32 success = true; b32 success = true;
if (codepoint == 0 && map->has_zero_index){ if (codepoint == 0 && map->has_zero_index){
@ -24,46 +19,48 @@ codepoint_index_map_read(Codepoint_Index_Map *map, u32 codepoint, u16 *index_out
return(success); return(success);
} }
internal u16 function u16
codepoint_index_map_count(Codepoint_Index_Map *map){ codepoint_index_map_count(Codepoint_Index_Map *map){
return(map->max_index + 1); return(map->max_index + 1);
} }
internal f32 function f32
font_get_glyph_advance(Face *face, u32 codepoint){ font_get_glyph_advance(Face_Advance_Map *map, Face_Metrics *metrics, u32 codepoint){
f32 result = 0.f; f32 result = 0.f;
if (codepoint == '\t'){ if (codepoint == '\t'){
result = face->space_advance*4.f; result = metrics->space_advance*4.f;
} }
else{ else{
if (character_is_whitespace(codepoint)){ if (character_is_whitespace(codepoint)){
codepoint = ' '; codepoint = ' ';
} }
u16 index = 0; u16 index = 0;
if (codepoint_index_map_read(&face->codepoint_to_index_map, codepoint, &index)){ if (codepoint_index_map_read(&map->codepoint_to_index, codepoint, &index)){
if (index < face->index_count){ if (index < map->index_count){
result = face->advance[index]; result = map->advance[index];
} }
} }
} }
return(result); return(result);
} }
internal f32 function f32
font_get_max_glyph_advance_range(Face *face, u32 codepoint_first, u32 codepoint_last){ font_get_max_glyph_advance_range(Face_Advance_Map *map, Face_Metrics *metrics,
f32 result = font_get_glyph_advance(face, codepoint_first); u32 codepoint_first, u32 codepoint_last){
f32 result = font_get_glyph_advance(map, metrics, codepoint_first);
for (u32 i = codepoint_first + 1; i <= codepoint_last; i += 1){ for (u32 i = codepoint_first + 1; i <= codepoint_last; i += 1){
f32 a = font_get_glyph_advance(face, i); f32 a = font_get_glyph_advance(map, metrics, i);
result = Max(a, result); result = Max(a, result);
} }
return(result); return(result);
} }
internal f32 function f32
font_get_average_glyph_advance_range(Face *face, u32 codepoint_first, u32 codepoint_last){ font_get_average_glyph_advance_range(Face_Advance_Map *map, Face_Metrics *metrics,
u32 codepoint_first, u32 codepoint_last){
f32 result = 0.f; f32 result = 0.f;
for (u32 i = codepoint_first; i <= codepoint_last; i += 1){ for (u32 i = codepoint_first; i <= codepoint_last; i += 1){
result += font_get_glyph_advance(face, i); result += font_get_glyph_advance(map, metrics, i);
} }
result /= (f32)(codepoint_last - codepoint_first + 1); result /= (f32)(codepoint_last - codepoint_first + 1);
return(result); return(result);

View File

@ -281,6 +281,188 @@ default_buffer_region(Application_Links *app, View_ID view_id, Rect_f32 region){
return(region); return(region);
} }
internal void
buffer_layout__write(Arena *arena, Layout_Item_List *list,
i64 index, u32 codepoint, Layout_Item_Flag flags, Rect_f32 rect){
Temp_Memory restore_point = begin_temp(arena);
Layout_Item *item = push_array(arena, Layout_Item, 1);
Layout_Item_Block *block = list->first;
if (block != 0){
if (block->items + block->count == item){
block->count += 1;
}
else{
block = 0;
}
}
if (block == 0){
end_temp(restore_point);
block = push_array(arena, Layout_Item_Block, 1);
item = push_array(arena, Layout_Item, 1);
sll_queue_push(list->first, list->last, block);
list->node_count += 1;
block->items = item;
block->count = 1;
}
list->total_count += 1;
if (index > list->index_range.max){
block->character_count += 1;
list->character_count += 1;
list->index_range.max = index;
}
item->index = index;
item->codepoint = codepoint;
item->flags = flags;
item->rect = rect;
list->height = max(list->height, rect.y1);
}
function Layout_Item_List
default_buffer_layout(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range,
Face_ID face, f32 width){
Scratch_Block scratch(app);
Layout_Item_List list = {};
list.index_range.first = range.first;
list.index_range.one_past_last = range.first - 1;
String_Const_u8 text = push_buffer_range(app, scratch, buffer, range);
Face_Metrics metrics = get_face_metrics(app, face);
f32 line_height = metrics.line_height;
f32 text_height = metrics.text_height;
f32 line_to_text_shift = text_height - line_height;
f32 space_advance = metrics.space_advance;
Face_Advance_Map advance_map = get_face_advance_map(app, face);
if (text.size == 0){
f32 next_x = space_advance;
buffer_layout__write(arena, &list, range.first, ' ', 0,
Rf32(V2(0.f, 0.f), V2f32(next_x, text_height)));
}
else{
Vec2_f32 p = {};
f32 line_y = line_height;
f32 text_y = text_height;
i64 index = range.first;
b32 first_of_the_line = true;
b32 consuming_newline_characters = false;
i64 newline_character_index = -1;
b32 prev_did_emit_newline = false;
u8 *ptr = text.str;
u8 *end_ptr = ptr + text.size;
for (;ptr < end_ptr;){
Character_Consume_Result consume = utf8_consume(ptr, (umem)(end_ptr - ptr));
u32 render_codepoint = consume.codepoint;
b32 emit_newline = false;
switch (consume.codepoint){
case '\t':
{
render_codepoint = ' ';
}//fallthrough;
default:
{
f32 advance = font_get_glyph_advance(&advance_map, &metrics,
consume.codepoint);
f32 next_x = p.x + advance;
if (!first_of_the_line && next_x >= width){
p.y = line_y;
p.x = 0.f;
line_y += line_height;
text_y = line_y + line_to_text_shift;
next_x = p.x + advance;
}
buffer_layout__write(arena, &list, index, render_codepoint, 0,
Rf32(p, V2f32(next_x, text_y)));
p.x = next_x;
ptr += consume.inc;
index += consume.inc;
first_of_the_line = false;
}break;
case '\r':
{
if (!consuming_newline_characters){
consuming_newline_characters = true;
newline_character_index = index;
}
ptr += 1;
index += 1;
}break;
case '\n':
{
if (!consuming_newline_characters){
consuming_newline_characters = true;
newline_character_index = index;
}
emit_newline = true;
ptr += 1;
index += 1;
}break;
case max_u32:
{
f32 next_x = p.x + metrics.byte_advance;
if (!first_of_the_line && next_x >= width){
p.y = line_y;
p.x = 0.f;
line_y += line_height;
text_y = line_y + line_to_text_shift;
next_x = p.x + metrics.byte_advance;
}
u32 v = *ptr;
u32 lo = v&0xF;
u32 hi = (v >> 4)&0xF;
f32 advance = metrics.byte_sub_advances[0];
buffer_layout__write(arena, &list, index, '\\', 0,
Rf32(p, V2f32(p.x + advance, text_y)));
p.x += advance;
advance = metrics.byte_sub_advances[1];
buffer_layout__write(arena, &list, index, integer_symbols[lo], 0,
Rf32(p, V2f32(p.x + advance, text_y)));
p.x += advance;
advance = metrics.byte_sub_advances[2];
buffer_layout__write(arena, &list, index, integer_symbols[hi], 0,
Rf32(p, V2f32(p.x + advance, text_y)));
p.x = next_x;
ptr += 1;
index += 1;
first_of_the_line = false;
}break;
}
prev_did_emit_newline = false;
if (emit_newline){
f32 next_x = p.x + space_advance;
buffer_layout__write(arena, &list, newline_character_index, ' ', 0,
Rf32(p, V2f32(next_x, text_y)));
p.y = line_y;
p.x = 0.f;
line_y += line_height;
text_y = line_y + line_to_text_shift;
first_of_the_line = true;
prev_did_emit_newline = true;
}
}
if (!prev_did_emit_newline){
f32 next_x = p.x + space_advance;
buffer_layout__write(arena, &list, index, ' ', 0, Rf32(p, V2f32(next_x, text_y)));
}
}
list.bottom_extension = -line_to_text_shift;
list.height += list.bottom_extension;
return(list);
}
function void function void
default_render_buffer(Application_Links *app, View_ID view_id, b32 is_active_view, default_render_buffer(Application_Links *app, View_ID view_id, b32 is_active_view,
Buffer_ID buffer, Text_Layout_ID text_layout_id, Buffer_ID buffer, Text_Layout_ID text_layout_id,
@ -931,6 +1113,7 @@ set_all_default_hooks(Application_Links *app){
set_custom_hook(app, HookID_SaveFile, default_file_save); set_custom_hook(app, HookID_SaveFile, default_file_save);
set_custom_hook(app, HookID_BufferEditRange, default_buffer_edit_range); set_custom_hook(app, HookID_BufferEditRange, default_buffer_edit_range);
set_custom_hook(app, HookID_BufferRegion, default_buffer_region); set_custom_hook(app, HookID_BufferRegion, default_buffer_region);
set_custom_hook(app, HookID_Layout, default_buffer_layout);
} }
// BOTTOM // BOTTOM

View File

@ -64,6 +64,7 @@
#include "4coder_log.cpp" #include "4coder_log.cpp"
#include "4coder_hash_functions.cpp" #include "4coder_hash_functions.cpp"
#include "4coder_table.cpp" #include "4coder_table.cpp"
#include "4coder_codepoint_map.cpp"
#include "4coder_async_tasks.cpp" #include "4coder_async_tasks.cpp"
#include "4coder_string_match.cpp" #include "4coder_string_match.cpp"
#include "4coder_buffer_seek_constructors.cpp" #include "4coder_buffer_seek_constructors.cpp"

View File

@ -448,11 +448,35 @@ struct Face_Description{
struct Face_Metrics{ struct Face_Metrics{
f32 text_height; f32 text_height;
f32 line_height; f32 line_height;
f32 ascent;
f32 descent;
f32 line_skip;
f32 underline_yoff1;
f32 underline_yoff2;
f32 max_advance; f32 max_advance;
f32 normal_advance;
f32 space_advance; f32 space_advance;
f32 decimal_digit_advance; f32 decimal_digit_advance;
f32 hex_digit_advance; f32 hex_digit_advance;
f32 byte_advance;
f32 byte_sub_advances[3];
f32 normal_lowercase_advance;
f32 normal_uppercase_advance;
f32 normal_advance;
};
struct Codepoint_Index_Map{
b32 has_zero_index;
u16 zero_index;
u16 max_index;
Table_u32_u16 table;
};
struct Face_Advance_Map{
Codepoint_Index_Map codepoint_to_index;
f32 *advance;
u16 index_count;
}; };
struct Edit{ struct Edit{
@ -542,6 +566,7 @@ enum{
HookID_SaveFile, HookID_SaveFile,
HookID_BufferEditRange, HookID_BufferEditRange,
HookID_BufferRegion, HookID_BufferRegion,
HookID_Layout,
}; };
typedef i32 Hook_Function(Application_Links *app); typedef i32 Hook_Function(Application_Links *app);
@ -559,7 +584,7 @@ struct Buffer_Name_Conflict_Entry{
typedef void Buffer_Name_Resolver_Function(Application_Links *app, Buffer_Name_Conflict_Entry *conflicts, i32 conflict_count); typedef void Buffer_Name_Resolver_Function(Application_Links *app, Buffer_Name_Conflict_Entry *conflicts, i32 conflict_count);
#define BUFFER_NAME_RESOLVER_SIG(n) \ #define BUFFER_NAME_RESOLVER_SIG(n) \
void n(Application_Links *app, Buffer_Name_Conflict_Entry *conflicts, \ void n(Application_Links *app, Buffer_Name_Conflict_Entry *conflicts, \
i32 conflict_count) i32 conflict_count)
typedef i32 Buffer_Hook_Function(Application_Links *app, Buffer_ID buffer_id); typedef i32 Buffer_Hook_Function(Application_Links *app, Buffer_ID buffer_id);
#define BUFFER_HOOK_SIG(name) i32 name(Application_Links *app, Buffer_ID buffer_id) #define BUFFER_HOOK_SIG(name) i32 name(Application_Links *app, Buffer_ID buffer_id)
@ -568,7 +593,7 @@ typedef i32 Buffer_Edit_Range_Function(Application_Links *app, Buffer_ID buffer_
Range_i64 new_range, umem original_size); Range_i64 new_range, umem original_size);
#define BUFFER_EDIT_RANGE_SIG(name) \ #define BUFFER_EDIT_RANGE_SIG(name) \
i32 name(Application_Links *app, Buffer_ID buffer_id, \ i32 name(Application_Links *app, Buffer_ID buffer_id, \
Interval_i64 new_range, umem original_size) Interval_i64 new_range, umem original_size)
typedef Vec2_f32 Delta_Rule_Function(Vec2_f32 pending, b32 is_new_target, f32 dt, void *data); typedef Vec2_f32 Delta_Rule_Function(Vec2_f32 pending, b32 is_new_target, f32 dt, void *data);
#define DELTA_RULE_SIG(name) \ #define DELTA_RULE_SIG(name) \
@ -584,6 +609,41 @@ typedef void Render_Caller_Function(Application_Links *app, Frame_Info frame_inf
#define RENDER_CALLER_SIG(name) \ #define RENDER_CALLER_SIG(name) \
void name(Application_Links *app, Frame_Info frame_info, View_ID view) void name(Application_Links *app, Frame_Info frame_info, View_ID view)
typedef u32 Layout_Item_Flag;
enum{
LayoutItemFlag_Special_Character = (1 << 0),
LayoutItemFlag_Ghost_Character = (1 << 1)
};
struct Layout_Item{
i64 index;
u32 codepoint;
Layout_Item_Flag flags;
Rect_f32 rect;
};
struct Layout_Item_Block{
Layout_Item_Block *next;
Layout_Item *items;
i64 count;
i64 character_count;
};
struct Layout_Item_List{
Layout_Item_Block *first;
Layout_Item_Block *last;
i32 node_count;
i32 total_count;
f32 height;
f32 bottom_extension;
i64 character_count;
Interval_i64 index_range;
};
typedef Layout_Item_List Layout_Function(Application_Links *app, Arena *arena,
Buffer_ID buffer, Range_i64 range,
Face_ID face, f32 width);
typedef i64 Command_Map_ID; typedef i64 Command_Map_ID;
struct Command_Trigger{ struct Command_Trigger{

View File

@ -143,6 +143,7 @@ vtable->global_history_edit_group_end = global_history_edit_group_end;
vtable->buffer_set_face = buffer_set_face; vtable->buffer_set_face = buffer_set_face;
vtable->get_face_description = get_face_description; vtable->get_face_description = get_face_description;
vtable->get_face_metrics = get_face_metrics; vtable->get_face_metrics = get_face_metrics;
vtable->get_face_advance_map = get_face_advance_map;
vtable->get_face_id = get_face_id; vtable->get_face_id = get_face_id;
vtable->try_create_new_face = try_create_new_face; vtable->try_create_new_face = try_create_new_face;
vtable->try_modify_face = try_modify_face; vtable->try_modify_face = try_modify_face;
@ -319,6 +320,7 @@ global_history_edit_group_end = vtable->global_history_edit_group_end;
buffer_set_face = vtable->buffer_set_face; buffer_set_face = vtable->buffer_set_face;
get_face_description = vtable->get_face_description; get_face_description = vtable->get_face_description;
get_face_metrics = vtable->get_face_metrics; get_face_metrics = vtable->get_face_metrics;
get_face_advance_map = vtable->get_face_advance_map;
get_face_id = vtable->get_face_id; get_face_id = vtable->get_face_id;
try_create_new_face = vtable->try_create_new_face; try_create_new_face = vtable->try_create_new_face;
try_modify_face = vtable->try_modify_face; try_modify_face = vtable->try_modify_face;

View File

@ -141,6 +141,7 @@
#define custom_buffer_set_face_sig() b32 custom_buffer_set_face(Application_Links* app, Buffer_ID buffer_id, Face_ID id) #define custom_buffer_set_face_sig() b32 custom_buffer_set_face(Application_Links* app, Buffer_ID buffer_id, Face_ID id)
#define custom_get_face_description_sig() Face_Description custom_get_face_description(Application_Links* app, Face_ID face_id) #define custom_get_face_description_sig() Face_Description custom_get_face_description(Application_Links* app, Face_ID face_id)
#define custom_get_face_metrics_sig() Face_Metrics custom_get_face_metrics(Application_Links* app, Face_ID face_id) #define custom_get_face_metrics_sig() Face_Metrics custom_get_face_metrics(Application_Links* app, Face_ID face_id)
#define custom_get_face_advance_map_sig() Face_Advance_Map custom_get_face_advance_map(Application_Links* app, Face_ID face_id)
#define custom_get_face_id_sig() Face_ID custom_get_face_id(Application_Links* app, Buffer_ID buffer_id) #define custom_get_face_id_sig() Face_ID custom_get_face_id(Application_Links* app, Buffer_ID buffer_id)
#define custom_try_create_new_face_sig() Face_ID custom_try_create_new_face(Application_Links* app, Face_Description* description) #define custom_try_create_new_face_sig() Face_ID custom_try_create_new_face(Application_Links* app, Face_Description* description)
#define custom_try_modify_face_sig() b32 custom_try_modify_face(Application_Links* app, Face_ID id, Face_Description* description) #define custom_try_modify_face_sig() b32 custom_try_modify_face(Application_Links* app, Face_ID id, Face_Description* description)
@ -313,6 +314,7 @@ typedef void custom_global_history_edit_group_end_type(Application_Links* app);
typedef b32 custom_buffer_set_face_type(Application_Links* app, Buffer_ID buffer_id, Face_ID id); typedef b32 custom_buffer_set_face_type(Application_Links* app, Buffer_ID buffer_id, Face_ID id);
typedef Face_Description custom_get_face_description_type(Application_Links* app, Face_ID face_id); typedef Face_Description custom_get_face_description_type(Application_Links* app, Face_ID face_id);
typedef Face_Metrics custom_get_face_metrics_type(Application_Links* app, Face_ID face_id); typedef Face_Metrics custom_get_face_metrics_type(Application_Links* app, Face_ID face_id);
typedef Face_Advance_Map custom_get_face_advance_map_type(Application_Links* app, Face_ID face_id);
typedef Face_ID custom_get_face_id_type(Application_Links* app, Buffer_ID buffer_id); typedef Face_ID custom_get_face_id_type(Application_Links* app, Buffer_ID buffer_id);
typedef Face_ID custom_try_create_new_face_type(Application_Links* app, Face_Description* description); typedef Face_ID custom_try_create_new_face_type(Application_Links* app, Face_Description* description);
typedef b32 custom_try_modify_face_type(Application_Links* app, Face_ID id, Face_Description* description); typedef b32 custom_try_modify_face_type(Application_Links* app, Face_ID id, Face_Description* description);
@ -486,6 +488,7 @@ custom_global_history_edit_group_end_type *global_history_edit_group_end;
custom_buffer_set_face_type *buffer_set_face; custom_buffer_set_face_type *buffer_set_face;
custom_get_face_description_type *get_face_description; custom_get_face_description_type *get_face_description;
custom_get_face_metrics_type *get_face_metrics; custom_get_face_metrics_type *get_face_metrics;
custom_get_face_advance_map_type *get_face_advance_map;
custom_get_face_id_type *get_face_id; custom_get_face_id_type *get_face_id;
custom_try_create_new_face_type *try_create_new_face; custom_try_create_new_face_type *try_create_new_face;
custom_try_modify_face_type *try_modify_face; custom_try_modify_face_type *try_modify_face;
@ -660,6 +663,7 @@ internal void global_history_edit_group_end(Application_Links* app);
internal b32 buffer_set_face(Application_Links* app, Buffer_ID buffer_id, Face_ID id); internal b32 buffer_set_face(Application_Links* app, Buffer_ID buffer_id, Face_ID id);
internal Face_Description get_face_description(Application_Links* app, Face_ID face_id); internal Face_Description get_face_description(Application_Links* app, Face_ID face_id);
internal Face_Metrics get_face_metrics(Application_Links* app, Face_ID face_id); internal Face_Metrics get_face_metrics(Application_Links* app, Face_ID face_id);
internal Face_Advance_Map get_face_advance_map(Application_Links* app, Face_ID face_id);
internal Face_ID get_face_id(Application_Links* app, Buffer_ID buffer_id); internal Face_ID get_face_id(Application_Links* app, Buffer_ID buffer_id);
internal Face_ID try_create_new_face(Application_Links* app, Face_Description* description); internal Face_ID try_create_new_face(Application_Links* app, Face_Description* description);
internal b32 try_modify_face(Application_Links* app, Face_ID id, Face_Description* description); internal b32 try_modify_face(Application_Links* app, Face_ID id, Face_Description* description);
@ -834,6 +838,7 @@ global custom_global_history_edit_group_end_type *global_history_edit_group_end
global custom_buffer_set_face_type *buffer_set_face = 0; global custom_buffer_set_face_type *buffer_set_face = 0;
global custom_get_face_description_type *get_face_description = 0; global custom_get_face_description_type *get_face_description = 0;
global custom_get_face_metrics_type *get_face_metrics = 0; global custom_get_face_metrics_type *get_face_metrics = 0;
global custom_get_face_advance_map_type *get_face_advance_map = 0;
global custom_get_face_id_type *get_face_id = 0; global custom_get_face_id_type *get_face_id = 0;
global custom_try_create_new_face_type *try_create_new_face = 0; global custom_try_create_new_face_type *try_create_new_face = 0;
global custom_try_modify_face_type *try_modify_face = 0; global custom_try_modify_face_type *try_modify_face = 0;

View File

@ -141,6 +141,7 @@ api(custom) function void global_history_edit_group_end(Application_Links* app);
api(custom) function b32 buffer_set_face(Application_Links* app, Buffer_ID buffer_id, Face_ID id); api(custom) function b32 buffer_set_face(Application_Links* app, Buffer_ID buffer_id, Face_ID id);
api(custom) function Face_Description get_face_description(Application_Links* app, Face_ID face_id); api(custom) function Face_Description get_face_description(Application_Links* app, Face_ID face_id);
api(custom) function Face_Metrics get_face_metrics(Application_Links* app, Face_ID face_id); api(custom) function Face_Metrics get_face_metrics(Application_Links* app, Face_ID face_id);
api(custom) function Face_Advance_Map get_face_advance_map(Application_Links* app, Face_ID face_id);
api(custom) function Face_ID get_face_id(Application_Links* app, Buffer_ID buffer_id); api(custom) function Face_ID get_face_id(Application_Links* app, Buffer_ID buffer_id);
api(custom) function Face_ID try_create_new_face(Application_Links* app, Face_Description* description); api(custom) function Face_ID try_create_new_face(Application_Links* app, Face_Description* description);
api(custom) function b32 try_modify_face(Application_Links* app, Face_ID id, Face_Description* description); api(custom) function b32 try_modify_face(Application_Links* app, Face_ID id, Face_Description* description);

View File

@ -108,8 +108,8 @@ struct Win32_Input_Chunk{
#include "4coder_hash_functions.cpp" #include "4coder_hash_functions.cpp"
#include "4coder_system_allocator.cpp" #include "4coder_system_allocator.cpp"
#include "4coder_codepoint_map.cpp"
#include "4ed_font_face.cpp"
#include "4ed_mem.cpp" #include "4ed_mem.cpp"
#include "4ed_font_set.cpp" #include "4ed_font_set.cpp"