From 52915ba4bcb8f82a7d8249df07130e4fc0e5bd32 Mon Sep 17 00:00:00 2001 From: Jeffrey Armstrong Date: Mon, 8 Jun 2020 14:36:34 -0400 Subject: Line wrapping now computed only once for proportional text unless requested by the renderer, providing better performance. --- render.f90 | 122 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 118 insertions(+), 4 deletions(-) (limited to 'render.f90') diff --git a/render.f90 b/render.f90 index ff9ed7f..335cbcb 100644 --- a/render.f90 +++ b/render.f90 @@ -27,7 +27,10 @@ implicit none integer, parameter::render_action_goto = 2 integer, parameter::render_action_layout = 3 integer, parameter::render_action_back = 4 - integer, parameter::render_action_quit = 5 + integer, parameter::render_action_rewrap = 5 + integer, parameter::render_action_quit = 6 + + integer, parameter::last_break = -1 character(11), dimension(2)::base_supported_types = & ["text/plain ", & @@ -316,16 +319,115 @@ contains end function wrap_line - subroutine render_proportional(r, text) + function calculate_wrapping(r, text) result(breaks) + implicit none + + class(renderer)::r + character(*), intent(in)::text + integer, dimension(:), pointer::breaks + + integer::startpos, endpos + integer::heading_level + logical::list_item + + integer::current_allocation + integer::break_count + integer, dimension(:), pointer::realloc + + current_allocation = 16 + break_count = 0 + allocate(breaks(current_allocation)) + + if(len_trim(text) > 0) then + + startpos = 1 + + ! Check for headings first + heading_level = 0 + do while(text(startpos:startpos) == '#') + heading_level = heading_level + 1 + startpos = startpos + 1 + end do + + ! Or a list item + list_item = .FALSE. + if(heading_level == 0) then + list_item = (text(1:1) == '*') + if(list_item) then + startpos = startpos + 1 + end if + end if + + ! If either occurred, advance past whitespace + if(heading_level > 0 .or. list_item) then + do while(text(startpos:startpos) == ' ' .or. text(startpos:startpos) == char(9)) + startpos = startpos + 1 + end do + end if + + endpos = wrap_line(r, text, startpos, heading_level, list_item) + do while(endpos > startpos) + + ! Save this break + break_count = break_count + 1 + + ! Messy memory handling... + if(break_count > current_allocation) then + realloc => breaks + breaks => null() + + allocate(breaks(current_allocation + 16)) + breaks(1:current_allocation) = realloc + current_allocation = current_allocation + 16 + deallocate(realloc) + end if + + ! Now actually save it + breaks(break_count) = endpos + + ! Advance string positions + startpos = endpos+1 + do while(text(startpos:startpos) == ' ') + startpos = startpos + 1 + end do + + ! Do not mark as a list item for subsequent lines + list_item = .FALSE. + endpos = wrap_line(r, text, startpos, heading_level, list_item) + end do + end if + + break_count = break_count + 1 + + ! Messy memory handling... + if(break_count > current_allocation) then + realloc => breaks + breaks => null() + + allocate(breaks(current_allocation + 16)) + breaks(1:current_allocation) = realloc + current_allocation = current_allocation + 16 + deallocate(realloc) + end if + + ! Save an ending indicator + breaks(break_count) = last_break + + end function calculate_wrapping + + subroutine render_proportional(r, text, breaks) implicit none class(renderer)::r character(*)::text + integer, dimension(:)::breaks integer::startpos, endpos integer::heading_level logical::list_item + integer::break_index + if(len_trim(text) == 0) then if(r%is_text_visible(" ")) then @@ -360,7 +462,12 @@ contains end do end if - endpos = wrap_line(r, text, startpos, heading_level, list_item) + break_index = 1 + endpos = breaks(break_index) + if(endpos == last_break) then + endpos = len_trim(text) + end if + do while(endpos > startpos) if(r%is_text_visible(text(startpos:endpos))) then call r%draw_porportional(text(startpos:endpos), & @@ -380,7 +487,14 @@ contains ! Do not mark as a list item for subsequent lines list_item = .FALSE. - endpos = wrap_line(r, text, startpos, heading_level, list_item) + if(breaks(break_index) /= last_break) then + break_index = break_index + 1 + endpos = breaks(break_index) + if(endpos == last_break) then + endpos = len_trim(text) + end if + end if + end do end if -- cgit v1.2.3