fixed EOF paste/scroll bugs - robust against render buffer overflows

master
Allen Webster 2016-06-02 08:41:30 -04:00
parent 965500424e
commit 93ab33ee84
4 changed files with 174 additions and 131 deletions

View File

@ -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;
} }

View File

@ -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;
} }

View File

@ -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);

View File

@ -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;