From 93ab33ee844993ae6487e83474d2d34ee0a93bea Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Thu, 2 Jun 2016 08:41:30 -0400 Subject: [PATCH] fixed EOF paste/scroll bugs - robust against render buffer overflows --- 4ed_file_view.cpp | 41 +++--- 4ed_rendering.cpp | 22 +++- buffer/4coder_buffer_abstract.cpp | 212 +++++++++++++++++++----------- buffer/4coder_shared.cpp | 30 ----- 4 files changed, 174 insertions(+), 131 deletions(-) diff --git a/4ed_file_view.cpp b/4ed_file_view.cpp index ca97d0f2..7b717eb8 100644 --- a/4ed_file_view.cpp +++ b/4ed_file_view.cpp @@ -636,6 +636,22 @@ view_compute_lowest_line(View *view){ 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 view_measure_wraps(General_Memory *general, View *view){ 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) 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; i32 line_height = view->font_height; f32 old_cursor_y = view_get_cursor_y(view); 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_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(); } -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 view_set_file(View *view, Editing_File *file, Models *models){ Font_Info *fnt_info; @@ -3561,12 +3561,15 @@ view_end_cursor_scroll_updates(View *view){ case CursorScroll_Cursor: 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); gui_post_scroll_vars(&view->gui_target, view->current_scroll, view->scroll_region); break; 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); break; } diff --git a/4ed_rendering.cpp b/4ed_rendering.cpp index 8a13f632..26a210a8 100644 --- a/4ed_rendering.cpp +++ b/4ed_rendering.cpp @@ -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 draw_push_piece(Render_Target *target, Render_Piece_Combined piece){ PutStruct(Render_Piece_Header, piece.header); switch (piece.header.type){ - case piece_type_rectangle: - case piece_type_outline: + case piece_type_rectangle: + case piece_type_outline: PutStruct(Render_Piece_Rectangle, piece.rectangle); break; - case piece_type_gradient: + case piece_type_gradient: PutStruct(Render_Piece_Gradient, piece.gradient); break; - case piece_type_glyph: - case piece_type_mono_glyph: + case piece_type_glyph: + case piece_type_mono_glyph: PutStruct(Render_Piece_Glyph, piece.glyph); break; - case piece_type_mono_glyph_advance: + case piece_type_mono_glyph_advance: PutStruct(Render_Piece_Glyph_Advance, piece.glyph_advance); break; } diff --git a/buffer/4coder_buffer_abstract.cpp b/buffer/4coder_buffer_abstract.cpp index 32ab27f9..f7ec17a3 100644 --- a/buffer/4coder_buffer_abstract.cpp +++ b/buffer/4coder_buffer_abstract.cpp @@ -1313,6 +1313,42 @@ buffer_get_start_cursor(Buffer_Type *buffer, float *wraps, float scroll_y, 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 buffer_get_render_data(Buffer_Type *buffer, Buffer_Render_Item *items, int max, int *count, 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_Render_Item *item; + Buffer_Render_Item *item_end; char *data; int size, end; float shift_x, shift_y; @@ -1343,116 +1380,141 @@ buffer_get_render_data(Buffer_Type *buffer, Buffer_Render_Item *items, int max, y = shift_y; item_i = 0; 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){ 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)){ - + end = loop.size + loop.absolute_pos; data = loop.data - loop.absolute_pos; - + for (i = loop.absolute_pos; i < end; ++i){ ch = data[i]; ch_width = measure_character(advance_data, ch); - + if (ch_width + x > width + shift_x && wrapped && ch != '\n'){ x = shift_x; y += font_height; } if (y > height + shift_y) goto buffer_get_render_data_end; - - switch (ch){ - case '\n': - write_render_item_inline(item, i, ' ', x, y, advance_data, font_height); - 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{ + switch (ch){ + case '\n': + if (item < item_end){ write_render_item_inline(item, i, ' ', x, y, advance_data, font_height); item->flags = 0; ++item_i; ++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; break; - - default: - write_render_item(item, i, ch, x, y, ch_width, font_height); - item->flags = 0; - ++item_i; - ++item; - x += ch_width; - + + default: + if (item < item_end){ + write_render_item(item, i, ch, x, y, ch_width, font_height); + item->flags = 0; + ++item_i; + ++item; + x += ch_width; + } break; } 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 (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_width = measure_character(advance_data, ' '); + ch_width = 0; write_render_item(item, size, ch, x, y, ch_width, font_height); ++item_i; ++item; 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 assert_4tech(item_i <= max); diff --git a/buffer/4coder_shared.cpp b/buffer/4coder_shared.cpp index afb630be..8a70e3e1 100644 --- a/buffer/4coder_shared.cpp +++ b/buffer/4coder_shared.cpp @@ -88,36 +88,6 @@ typedef struct Buffer_Batch_State{ int shift_total; } 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 make_cursor_hint(int line_index, int *starts, float *wrap_ys, float font_height){ Full_Cursor hint;