fixed EOF paste/scroll bugs - robust against render buffer overflows
parent
965500424e
commit
93ab33ee84
|
@ -636,6 +636,22 @@ view_compute_lowest_line(View *view){
|
||||||
return lowest_line;
|
return lowest_line;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline f32
|
||||||
|
view_compute_max_target_y(i32 lowest_line, i32 line_height, f32 view_height){
|
||||||
|
f32 max_target_y = ((lowest_line+.5f)*line_height) - view_height*.5f;
|
||||||
|
max_target_y = clamp_bottom(0.f, max_target_y);
|
||||||
|
return(max_target_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline f32
|
||||||
|
view_compute_max_target_y(View *view){
|
||||||
|
i32 lowest_line = view_compute_lowest_line(view);
|
||||||
|
i32 line_height = view->font_height;
|
||||||
|
f32 view_height = view_file_height(view);
|
||||||
|
f32 max_target_y = view_compute_max_target_y(lowest_line, line_height, view_height);
|
||||||
|
return(max_target_y);
|
||||||
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
view_measure_wraps(General_Memory *general, View *view){
|
view_measure_wraps(General_Memory *general, View *view){
|
||||||
Buffer_Type *buffer;
|
Buffer_Type *buffer;
|
||||||
|
@ -1477,12 +1493,12 @@ view_get_cursor_y(View *view){
|
||||||
#define CursorMinY(m,h) (CursorMinY_(m,h) > 0)?(CursorMinY_(m,h)):(0)
|
#define CursorMinY(m,h) (CursorMinY_(m,h) > 0)?(CursorMinY_(m,h)):(0)
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
view_move_cursor_to_view(View *view){
|
view_move_cursor_to_view(View *view, GUI_Scroll_Vars scroll){
|
||||||
f32 min_target_y = 0;
|
f32 min_target_y = 0;
|
||||||
i32 line_height = view->font_height;
|
i32 line_height = view->font_height;
|
||||||
f32 old_cursor_y = view_get_cursor_y(view);
|
f32 old_cursor_y = view_get_cursor_y(view);
|
||||||
f32 cursor_y = old_cursor_y;
|
f32 cursor_y = old_cursor_y;
|
||||||
f32 target_y = view->recent->scroll.target_y;
|
f32 target_y = scroll.target_y;
|
||||||
f32 cursor_max_y = CursorMaxY(view_file_height(view), line_height);
|
f32 cursor_max_y = CursorMaxY(view_file_height(view), line_height);
|
||||||
f32 cursor_min_y = CursorMinY(min_target_y, line_height);
|
f32 cursor_min_y = CursorMinY(min_target_y, line_height);
|
||||||
|
|
||||||
|
@ -1554,22 +1570,6 @@ file_view_nullify_file(View *view){
|
||||||
view->file_data = file_viewing_data_zero();
|
view->file_data = file_viewing_data_zero();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline f32
|
|
||||||
view_compute_max_target_y(i32 lowest_line, i32 line_height, f32 view_height){
|
|
||||||
f32 max_target_y = ((lowest_line+.5f)*line_height) - view_height*.5f;
|
|
||||||
max_target_y = clamp_bottom(0.f, max_target_y);
|
|
||||||
return(max_target_y);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal f32
|
|
||||||
view_compute_max_target_y(View *view){
|
|
||||||
i32 lowest_line = view_compute_lowest_line(view);
|
|
||||||
i32 line_height = view->font_height;
|
|
||||||
f32 view_height = view_file_height(view);
|
|
||||||
f32 max_target_y = view_compute_max_target_y(lowest_line, line_height, view_height);
|
|
||||||
return(max_target_y);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
view_set_file(View *view, Editing_File *file, Models *models){
|
view_set_file(View *view, Editing_File *file, Models *models){
|
||||||
Font_Info *fnt_info;
|
Font_Info *fnt_info;
|
||||||
|
@ -3561,12 +3561,15 @@ view_end_cursor_scroll_updates(View *view){
|
||||||
|
|
||||||
case CursorScroll_Cursor:
|
case CursorScroll_Cursor:
|
||||||
case CursorScroll_Cursor|CursorScroll_Scroll:
|
case CursorScroll_Cursor|CursorScroll_Scroll:
|
||||||
|
if (view->gui_target.did_file){
|
||||||
|
view->recent->scroll.max_y = view_compute_max_target_y(view);
|
||||||
|
}
|
||||||
view_move_view_to_cursor(view, view->current_scroll);
|
view_move_view_to_cursor(view, view->current_scroll);
|
||||||
gui_post_scroll_vars(&view->gui_target, view->current_scroll, view->scroll_region);
|
gui_post_scroll_vars(&view->gui_target, view->current_scroll, view->scroll_region);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CursorScroll_Scroll:
|
case CursorScroll_Scroll:
|
||||||
view_move_cursor_to_view(view);
|
view_move_cursor_to_view(view, view->recent->scroll);
|
||||||
gui_post_scroll_vars(&view->gui_target, view->current_scroll, view->scroll_region);
|
gui_post_scroll_vars(&view->gui_target, view->current_scroll, view->scroll_region);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,28 +34,36 @@ draw_set_color(Render_Target *target, u32 color){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PutStruct(s,x) *(s*)(target->push_buffer + target->size) = x; target->size += sizeof(s)
|
inline void
|
||||||
|
draw_safe_push(Render_Target *target, i32 size, void *x){
|
||||||
|
if (size + target->size <= target->max){
|
||||||
|
memcpy(target->push_buffer + target->size, x, size);
|
||||||
|
target->size += size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PutStruct(s,x) draw_safe_push(target, sizeof(s), &x)
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
draw_push_piece(Render_Target *target, Render_Piece_Combined piece){
|
draw_push_piece(Render_Target *target, Render_Piece_Combined piece){
|
||||||
PutStruct(Render_Piece_Header, piece.header);
|
PutStruct(Render_Piece_Header, piece.header);
|
||||||
|
|
||||||
switch (piece.header.type){
|
switch (piece.header.type){
|
||||||
case piece_type_rectangle:
|
case piece_type_rectangle:
|
||||||
case piece_type_outline:
|
case piece_type_outline:
|
||||||
PutStruct(Render_Piece_Rectangle, piece.rectangle);
|
PutStruct(Render_Piece_Rectangle, piece.rectangle);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case piece_type_gradient:
|
case piece_type_gradient:
|
||||||
PutStruct(Render_Piece_Gradient, piece.gradient);
|
PutStruct(Render_Piece_Gradient, piece.gradient);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case piece_type_glyph:
|
case piece_type_glyph:
|
||||||
case piece_type_mono_glyph:
|
case piece_type_mono_glyph:
|
||||||
PutStruct(Render_Piece_Glyph, piece.glyph);
|
PutStruct(Render_Piece_Glyph, piece.glyph);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case piece_type_mono_glyph_advance:
|
case piece_type_mono_glyph_advance:
|
||||||
PutStruct(Render_Piece_Glyph_Advance, piece.glyph_advance);
|
PutStruct(Render_Piece_Glyph_Advance, piece.glyph_advance);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1313,6 +1313,42 @@ buffer_get_start_cursor(Buffer_Type *buffer, float *wraps, float scroll_y,
|
||||||
return(result);
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define BRFlag_Special_Character (1 << 0)
|
||||||
|
|
||||||
|
typedef struct Buffer_Render_Item{
|
||||||
|
int index;
|
||||||
|
unsigned short glyphid;
|
||||||
|
unsigned short flags;
|
||||||
|
float x0, y0;
|
||||||
|
float x1, y1;
|
||||||
|
} Buffer_Render_Item;
|
||||||
|
|
||||||
|
inline_4tech void
|
||||||
|
write_render_item(Buffer_Render_Item *item,
|
||||||
|
int index,
|
||||||
|
unsigned short glyphid,
|
||||||
|
float x, float y,
|
||||||
|
float w, float h){
|
||||||
|
item->index = index;
|
||||||
|
item->glyphid = glyphid;
|
||||||
|
item->x0 = x;
|
||||||
|
item->y0 = y;
|
||||||
|
item->x1 = x + w;
|
||||||
|
item->y1 = y + h;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline_4tech float
|
||||||
|
write_render_item_inline(Buffer_Render_Item *item,
|
||||||
|
int index,
|
||||||
|
unsigned short glyphid,
|
||||||
|
float x, float y,
|
||||||
|
float *advance_data, float h){
|
||||||
|
float ch_width;
|
||||||
|
ch_width = measure_character(advance_data, (char)glyphid);
|
||||||
|
write_render_item(item, index, glyphid, x, y, ch_width, h);
|
||||||
|
return(ch_width);
|
||||||
|
}
|
||||||
|
|
||||||
internal_4tech void
|
internal_4tech void
|
||||||
buffer_get_render_data(Buffer_Type *buffer, Buffer_Render_Item *items, int max, int *count,
|
buffer_get_render_data(Buffer_Type *buffer, Buffer_Render_Item *items, int max, int *count,
|
||||||
float port_x, float port_y,
|
float port_x, float port_y,
|
||||||
|
@ -1324,6 +1360,7 @@ buffer_get_render_data(Buffer_Type *buffer, Buffer_Render_Item *items, int max,
|
||||||
|
|
||||||
Buffer_Stringify_Type loop;
|
Buffer_Stringify_Type loop;
|
||||||
Buffer_Render_Item *item;
|
Buffer_Render_Item *item;
|
||||||
|
Buffer_Render_Item *item_end;
|
||||||
char *data;
|
char *data;
|
||||||
int size, end;
|
int size, end;
|
||||||
float shift_x, shift_y;
|
float shift_x, shift_y;
|
||||||
|
@ -1343,10 +1380,15 @@ buffer_get_render_data(Buffer_Type *buffer, Buffer_Render_Item *items, int max,
|
||||||
y = shift_y;
|
y = shift_y;
|
||||||
item_i = 0;
|
item_i = 0;
|
||||||
item = items + item_i;
|
item = items + item_i;
|
||||||
|
item_end = items + max;
|
||||||
|
|
||||||
|
// TODO(allen): What's the plan for when there is not enough space to store
|
||||||
|
// more render items? It seems like we should be able to use the view_x
|
||||||
|
// to skip items that are not in view right? That way I think it would
|
||||||
|
// just always fit in the buffer.
|
||||||
if (advance_data){
|
if (advance_data){
|
||||||
for (loop = buffer_stringify_loop(buffer, start_cursor.pos, size);
|
for (loop = buffer_stringify_loop(buffer, start_cursor.pos, size);
|
||||||
buffer_stringify_good(&loop);
|
buffer_stringify_good(&loop) && item < item_end;
|
||||||
buffer_stringify_next(&loop)){
|
buffer_stringify_next(&loop)){
|
||||||
|
|
||||||
end = loop.size + loop.absolute_pos;
|
end = loop.size + loop.absolute_pos;
|
||||||
|
@ -1363,96 +1405,116 @@ buffer_get_render_data(Buffer_Type *buffer, Buffer_Render_Item *items, int max,
|
||||||
if (y > height + shift_y) goto buffer_get_render_data_end;
|
if (y > height + shift_y) goto buffer_get_render_data_end;
|
||||||
|
|
||||||
switch (ch){
|
switch (ch){
|
||||||
case '\n':
|
case '\n':
|
||||||
write_render_item_inline(item, i, ' ', x, y, advance_data, font_height);
|
if (item < item_end){
|
||||||
item->flags = 0;
|
|
||||||
++item_i;
|
|
||||||
++item;
|
|
||||||
|
|
||||||
x = shift_x;
|
|
||||||
y += font_height;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0:
|
|
||||||
ch_width = write_render_item_inline(item, i, '\\', x, y, advance_data, font_height);
|
|
||||||
item->flags = BRFlag_Special_Character;
|
|
||||||
++item_i;
|
|
||||||
++item;
|
|
||||||
x += ch_width;
|
|
||||||
|
|
||||||
ch_width = write_render_item_inline(item, i, '0', x, y, advance_data, font_height);
|
|
||||||
item->flags = BRFlag_Special_Character;
|
|
||||||
++item_i;
|
|
||||||
++item;
|
|
||||||
x += ch_width;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '\r':
|
|
||||||
ch_width = write_render_item_inline(item, i, '\\', x, y, advance_data, font_height);
|
|
||||||
item->flags = BRFlag_Special_Character;
|
|
||||||
++item_i;
|
|
||||||
++item;
|
|
||||||
x += ch_width;
|
|
||||||
|
|
||||||
ch_width = write_render_item_inline(item, i, 'r', x, y, advance_data, font_height);
|
|
||||||
item->flags = BRFlag_Special_Character;
|
|
||||||
++item_i;
|
|
||||||
++item;
|
|
||||||
x += ch_width;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '\t':
|
|
||||||
if (opts.show_slash_t){
|
|
||||||
ch_width_sub = write_render_item_inline(item, i, '\\', x, y, advance_data, font_height);
|
|
||||||
item->flags = BRFlag_Special_Character;
|
|
||||||
++item_i;
|
|
||||||
++item;
|
|
||||||
|
|
||||||
write_render_item_inline(item, i, 't', x + ch_width_sub, y, advance_data, font_height);
|
|
||||||
item->flags = BRFlag_Special_Character;
|
|
||||||
++item_i;
|
|
||||||
++item;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
write_render_item_inline(item, i, ' ', x, y, advance_data, font_height);
|
write_render_item_inline(item, i, ' ', x, y, advance_data, font_height);
|
||||||
item->flags = 0;
|
item->flags = 0;
|
||||||
++item_i;
|
++item_i;
|
||||||
++item;
|
++item;
|
||||||
|
|
||||||
|
x = shift_x;
|
||||||
|
y += font_height;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
if (item < item_end){
|
||||||
|
ch_width = write_render_item_inline(item, i, '\\', x, y, advance_data, font_height);
|
||||||
|
item->flags = BRFlag_Special_Character;
|
||||||
|
++item_i;
|
||||||
|
++item;
|
||||||
|
x += ch_width;
|
||||||
|
|
||||||
|
if (item < item_end){
|
||||||
|
ch_width = write_render_item_inline(item, i, '0', x, y, advance_data, font_height);
|
||||||
|
item->flags = BRFlag_Special_Character;
|
||||||
|
++item_i;
|
||||||
|
++item;
|
||||||
|
x += ch_width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\r':
|
||||||
|
if (item < item_end){
|
||||||
|
ch_width = write_render_item_inline(item, i, '\\', x, y, advance_data, font_height);
|
||||||
|
item->flags = BRFlag_Special_Character;
|
||||||
|
++item_i;
|
||||||
|
++item;
|
||||||
|
x += ch_width;
|
||||||
|
|
||||||
|
if (item < item_end){
|
||||||
|
ch_width = write_render_item_inline(item, i, 'r', x, y, advance_data, font_height);
|
||||||
|
item->flags = BRFlag_Special_Character;
|
||||||
|
++item_i;
|
||||||
|
++item;
|
||||||
|
x += ch_width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\t':
|
||||||
|
if (opts.show_slash_t){
|
||||||
|
if (item < item_end){
|
||||||
|
ch_width_sub = write_render_item_inline(item, i, '\\', x, y, advance_data, font_height);
|
||||||
|
item->flags = BRFlag_Special_Character;
|
||||||
|
++item_i;
|
||||||
|
++item;
|
||||||
|
if (item < item_end){
|
||||||
|
write_render_item_inline(item, i, 't', x + ch_width_sub, y, advance_data, font_height);
|
||||||
|
item->flags = BRFlag_Special_Character;
|
||||||
|
++item_i;
|
||||||
|
++item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if (item < item_end){
|
||||||
|
write_render_item_inline(item, i, ' ', x, y, advance_data, font_height);
|
||||||
|
item->flags = 0;
|
||||||
|
++item_i;
|
||||||
|
++item;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
x += ch_width;
|
x += ch_width;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
write_render_item(item, i, ch, x, y, ch_width, font_height);
|
if (item < item_end){
|
||||||
item->flags = 0;
|
write_render_item(item, i, ch, x, y, ch_width, font_height);
|
||||||
++item_i;
|
item->flags = 0;
|
||||||
++item;
|
++item_i;
|
||||||
x += ch_width;
|
++item;
|
||||||
|
x += ch_width;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (y > height + shift_y) goto buffer_get_render_data_end;
|
if (y > height + shift_y) goto buffer_get_render_data_end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer_get_render_data_end:
|
buffer_get_render_data_end:
|
||||||
if (y <= height + shift_y || item == items){
|
if (y <= height + shift_y || item == items){
|
||||||
|
if (item < item_end){
|
||||||
|
ch = 0;
|
||||||
|
ch_width = measure_character(advance_data, ' ');
|
||||||
|
write_render_item(item, size, ch, x, y, ch_width, font_height);
|
||||||
|
++item_i;
|
||||||
|
++item;
|
||||||
|
x += ch_width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if (item < item_end){
|
||||||
ch = 0;
|
ch = 0;
|
||||||
ch_width = measure_character(advance_data, ' ');
|
ch_width = 0;
|
||||||
write_render_item(item, size, ch, x, y, ch_width, font_height);
|
write_render_item(item, size, ch, x, y, ch_width, font_height);
|
||||||
++item_i;
|
++item_i;
|
||||||
++item;
|
++item;
|
||||||
x += ch_width;
|
x += ch_width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else{
|
|
||||||
ch = 0;
|
|
||||||
ch_width = 0;
|
|
||||||
write_render_item(item, size, ch, x, y, ch_width, font_height);
|
|
||||||
++item_i;
|
|
||||||
++item;
|
|
||||||
x += ch_width;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(allen): handle this with a control state
|
// TODO(allen): handle this with a control state
|
||||||
assert_4tech(item_i <= max);
|
assert_4tech(item_i <= max);
|
||||||
|
|
|
@ -88,36 +88,6 @@ typedef struct Buffer_Batch_State{
|
||||||
int shift_total;
|
int shift_total;
|
||||||
} Buffer_Batch_State;
|
} Buffer_Batch_State;
|
||||||
|
|
||||||
#define BRFlag_Special_Character (1 << 0)
|
|
||||||
|
|
||||||
typedef struct Buffer_Render_Item{
|
|
||||||
int index;
|
|
||||||
unsigned short glyphid;
|
|
||||||
unsigned short flags;
|
|
||||||
float x0, y0;
|
|
||||||
float x1, y1;
|
|
||||||
} Buffer_Render_Item;
|
|
||||||
|
|
||||||
inline_4tech void
|
|
||||||
write_render_item(Buffer_Render_Item *item, int index, unsigned short glyphid,
|
|
||||||
float x, float y, float w, float h){
|
|
||||||
item->index = index;
|
|
||||||
item->glyphid = glyphid;
|
|
||||||
item->x0 = x;
|
|
||||||
item->y0 = y;
|
|
||||||
item->x1 = x + w;
|
|
||||||
item->y1 = y + h;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline_4tech float
|
|
||||||
write_render_item_inline(Buffer_Render_Item *item, int index, unsigned short glyphid,
|
|
||||||
float x, float y, float *advance_data, float h){
|
|
||||||
float ch_width;
|
|
||||||
ch_width = measure_character(advance_data, (char)glyphid);
|
|
||||||
write_render_item(item, index, glyphid, x, y, ch_width, h);
|
|
||||||
return(ch_width);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline_4tech Full_Cursor
|
inline_4tech Full_Cursor
|
||||||
make_cursor_hint(int line_index, int *starts, float *wrap_ys, float font_height){
|
make_cursor_hint(int line_index, int *starts, float *wrap_ys, float font_height){
|
||||||
Full_Cursor hint;
|
Full_Cursor hint;
|
||||||
|
|
Loading…
Reference in New Issue