summaryrefslogtreecommitdiff
path: root/src/ui/documentwidget.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/documentwidget.c')
-rw-r--r--src/ui/documentwidget.c138
1 files changed, 84 insertions, 54 deletions
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index 42018e19..2229b7f7 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -157,14 +157,14 @@ struct Impl_DrawBufs {
157 int flags; 157 int flags;
158 SDL_Texture * sideIconBuf; 158 SDL_Texture * sideIconBuf;
159 iTextBuf * timestampBuf; 159 iTextBuf * timestampBuf;
160 iRangei lastVis; 160 uint32_t lastRenderTime;
161}; 161};
162 162
163static void init_DrawBufs(iDrawBufs *d) { 163static void init_DrawBufs(iDrawBufs *d) {
164 d->flags = 0; 164 d->flags = 0;
165 d->sideIconBuf = NULL; 165 d->sideIconBuf = NULL;
166 d->timestampBuf = NULL; 166 d->timestampBuf = NULL;
167 iZap(d->lastVis); 167 d->lastRenderTime = 0;
168} 168}
169 169
170static void deinit_DrawBufs(iDrawBufs *d) { 170static void deinit_DrawBufs(iDrawBufs *d) {
@@ -794,14 +794,6 @@ static void updateVisible_DocumentWidget_(iDocumentWidget *d) {
794 !isSuccess_GmStatusCode(d->sourceStatus)); 794 !isSuccess_GmStatusCode(d->sourceStatus));
795 const iRangei visRange = visibleRange_DocumentWidget_(d); 795 const iRangei visRange = visibleRange_DocumentWidget_(d);
796 const iRect bounds = bounds_Widget(as_Widget(d)); 796 const iRect bounds = bounds_Widget(as_Widget(d));
797 if (!equal_Rangei(visRange, d->drawBufs->lastVis)) {
798 /* After scrolling/resizing stops, begin prendering the visbuf contents.
799 `Periodic` is used for detecting when the visible range has been modified. */
800 removeTicker_App(prerender_DocumentWidget_, d);
801 remove_Periodic(periodic_App(), d);
802 add_Periodic(periodic_App(), d,
803 format_CStr("document.render from:%d to:%d", visRange.start, visRange.end));
804 }
805 setRange_ScrollWidget(d->scroll, (iRangei){ 0, scrollMax_DocumentWidget_(d) }); 797 setRange_ScrollWidget(d->scroll, (iRangei){ 0, scrollMax_DocumentWidget_(d) });
806 const int docSize = size_GmDocument(d->doc).y; 798 const int docSize = size_GmDocument(d->doc).y;
807 setThumb_ScrollWidget(d->scroll, 799 setThumb_ScrollWidget(d->scroll,
@@ -829,6 +821,11 @@ static void updateVisible_DocumentWidget_(iDocumentWidget *d) {
829 recent->normScrollY = normScrollPos_DocumentWidget_(d); 821 recent->normScrollY = normScrollPos_DocumentWidget_(d);
830 } 822 }
831 } 823 }
824 /* After scrolling/resizing stops, begin pre-rendering the visbuf contents. */ {
825 removeTicker_App(prerender_DocumentWidget_, d);
826 remove_Periodic(periodic_App(), d);
827 add_Periodic(periodic_App(), d, "document.render");
828 }
832} 829}
833 830
834static void updateWindowTitle_DocumentWidget_(const iDocumentWidget *d) { 831static void updateWindowTitle_DocumentWidget_(const iDocumentWidget *d) {
@@ -1763,10 +1760,9 @@ static iBool handlePinch_DocumentWidget_(iDocumentWidget *d, const char *cmd) {
1763 1760
1764static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) { 1761static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) {
1765 iWidget *w = as_Widget(d); 1762 iWidget *w = as_Widget(d);
1766 if (equal_Command(cmd, "document.render")) { 1763 if (equal_Command(cmd, "document.render")) /* Periodic makes direct dispatch to here */ {
1767 const iRangei vis = { argLabel_Command(cmd, "from"), argLabel_Command(cmd, "to") }; 1764// printf("%u: document.render\n", SDL_GetTicks());
1768 const iRangei current = visibleRange_DocumentWidget_(d); 1765 if (SDL_GetTicks() - d->drawBufs->lastRenderTime > 150) {
1769 if (equal_Rangei(vis, current)) {
1770 remove_Periodic(periodic_App(), d); 1766 remove_Periodic(periodic_App(), d);
1771 /* Scrolling has stopped, begin filling up the buffer. */ 1767 /* Scrolling has stopped, begin filling up the buffer. */
1772 if (d->visBuf->buffers[0].texture) { 1768 if (d->visBuf->buffers[0].texture) {
@@ -1824,6 +1820,8 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)
1824 updateWindowTitle_DocumentWidget_(d); 1820 updateWindowTitle_DocumentWidget_(d);
1825 allocVisBuffer_DocumentWidget_(d); 1821 allocVisBuffer_DocumentWidget_(d);
1826 animateMedia_DocumentWidget_(d); 1822 animateMedia_DocumentWidget_(d);
1823 remove_Periodic(periodic_App(), d);
1824 removeTicker_App(prerender_DocumentWidget_, d);
1827 return iFalse; 1825 return iFalse;
1828 } 1826 }
1829 else if (equal_Command(cmd, "tab.created")) { 1827 else if (equal_Command(cmd, "tab.created")) {
@@ -3704,6 +3702,13 @@ static void drawPin_(iPaint *p, iRect rangeRect, int dir) {
3704 init1_I2(gap_UI * 2)), pinColor); 3702 init1_I2(gap_UI * 2)), pinColor);
3705} 3703}
3706 3704
3705static void extend_GmRunRange_(iGmRunRange *runs) {
3706 if (runs->start) {
3707 runs->start--;
3708 runs->end++;
3709 }
3710}
3711
3707static iBool render_DocumentWidget_(const iDocumentWidget *d, iDrawContext *ctx, iBool prerenderExtra) { 3712static iBool render_DocumentWidget_(const iDocumentWidget *d, iDrawContext *ctx, iBool prerenderExtra) {
3708 iBool didDraw = iFalse; 3713 iBool didDraw = iFalse;
3709 const iRect bounds = bounds_Widget(constAs_Widget(d)); 3714 const iRect bounds = bounds_Widget(constAs_Widget(d));
@@ -3712,6 +3717,7 @@ static iBool render_DocumentWidget_(const iDocumentWidget *d, iDrawContext *ctx,
3712 const iRangei full = { 0, size_GmDocument(d->doc).y }; 3717 const iRangei full = { 0, size_GmDocument(d->doc).y };
3713 const iRangei vis = ctx->vis; 3718 const iRangei vis = ctx->vis;
3714 iVisBuf *visBuf = d->visBuf; /* will be updated now */ 3719 iVisBuf *visBuf = d->visBuf; /* will be updated now */
3720 d->drawBufs->lastRenderTime = SDL_GetTicks();
3715 /* Swap buffers around to have room available both before and after the visible region. */ 3721 /* Swap buffers around to have room available both before and after the visible region. */
3716 allocVisBuffer_DocumentWidget_(d); 3722 allocVisBuffer_DocumentWidget_(d);
3717 reposition_VisBuf(visBuf, vis); 3723 reposition_VisBuf(visBuf, vis);
@@ -3721,11 +3727,11 @@ static iBool render_DocumentWidget_(const iDocumentWidget *d, iDrawContext *ctx,
3721 iForIndices(i, visBuf->buffers) { 3727 iForIndices(i, visBuf->buffers) {
3722 iVisBufTexture *buf = &visBuf->buffers[i]; 3728 iVisBufTexture *buf = &visBuf->buffers[i];
3723 iVisBufMeta * meta = buf->user; 3729 iVisBufMeta * meta = buf->user;
3724 const iRangei bufRange = bufferRange_VisBuf(visBuf, i); 3730 const iRangei bufRange = intersect_Rangei(bufferRange_VisBuf(visBuf, i), full);
3725 const iRangei bufVisRange = intersect_Rangei(bufRange, vis); 3731 const iRangei bufVisRange = intersect_Rangei(bufRange, vis);
3726 ctx->widgetBounds = moved_Rect(ctxWidgetBounds, init_I2(0, -buf->origin)); 3732 ctx->widgetBounds = moved_Rect(ctxWidgetBounds, init_I2(0, -buf->origin));
3727 ctx->viewPos = init_I2(left_Rect(ctx->docBounds) - left_Rect(bounds), -buf->origin); 3733 ctx->viewPos = init_I2(left_Rect(ctx->docBounds) - left_Rect(bounds), -buf->origin);
3728 //printf(" buffer %zu: invalid range %d...%d\n", i, invalidRange[i].start, invalidRange[i].end); 3734// printf(" buffer %zu: buf vis range %d...%d\n", i, bufVisRange.start, bufVisRange.end);
3729 if (!prerenderExtra && !isEmpty_Range(&bufVisRange)) { 3735 if (!prerenderExtra && !isEmpty_Range(&bufVisRange)) {
3730 didDraw = iTrue; 3736 didDraw = iTrue;
3731 if (isEmpty_Rangei(buf->validRange)) { 3737 if (isEmpty_Rangei(buf->validRange)) {
@@ -3737,10 +3743,7 @@ static iBool render_DocumentWidget_(const iDocumentWidget *d, iDrawContext *ctx,
3737 iZap(ctx->runsDrawn); 3743 iZap(ctx->runsDrawn);
3738 render_GmDocument(d->doc, bufVisRange, drawRun_DrawContext_, ctx); 3744 render_GmDocument(d->doc, bufVisRange, drawRun_DrawContext_, ctx);
3739 meta->runsDrawn = ctx->runsDrawn; 3745 meta->runsDrawn = ctx->runsDrawn;
3740 if (meta->runsDrawn.start) { 3746 extend_GmRunRange_(&meta->runsDrawn);
3741 meta->runsDrawn.start--;
3742 meta->runsDrawn.end++;
3743 }
3744 buf->validRange = bufVisRange; 3747 buf->validRange = bufVisRange;
3745 // printf(" buffer %zu valid %d...%d\n", i, bufRange.start, bufRange.end); 3748 // printf(" buffer %zu valid %d...%d\n", i, bufRange.start, bufRange.end);
3746 } 3749 }
@@ -3750,19 +3753,19 @@ static iBool render_DocumentWidget_(const iDocumentWidget *d, iDrawContext *ctx,
3750 if (meta->runsDrawn.start) { 3753 if (meta->runsDrawn.start) {
3751 beginTarget_Paint(p, buf->texture); 3754 beginTarget_Paint(p, buf->texture);
3752 meta->runsDrawn.start = renderProgressive_GmDocument(d->doc, meta->runsDrawn.start, 3755 meta->runsDrawn.start = renderProgressive_GmDocument(d->doc, meta->runsDrawn.start,
3753 -1, iInvalidSize, 3756 -1, iInvalidSize,
3754 bufVisRange, 3757 bufVisRange,
3755 drawRun_DrawContext_, 3758 drawRun_DrawContext_,
3756 ctx); 3759 ctx);
3757 buf->validRange.start = bufVisRange.start; 3760 buf->validRange.start = bufVisRange.start;
3758 } 3761 }
3759 if (meta->runsDrawn.end) { 3762 if (meta->runsDrawn.end) {
3760 beginTarget_Paint(p, buf->texture); 3763 beginTarget_Paint(p, buf->texture);
3761 meta->runsDrawn.end = renderProgressive_GmDocument(d->doc, meta->runsDrawn.end, 3764 meta->runsDrawn.end = renderProgressive_GmDocument(d->doc, meta->runsDrawn.end,
3762 +1, iInvalidSize, 3765 +1, iInvalidSize,
3763 bufVisRange, 3766 bufVisRange,
3764 drawRun_DrawContext_, 3767 drawRun_DrawContext_,
3765 ctx); 3768 ctx);
3766 buf->validRange.end = bufVisRange.end; 3769 buf->validRange.end = bufVisRange.end;
3767 } 3770 }
3768 } 3771 }
@@ -3770,38 +3773,62 @@ static iBool render_DocumentWidget_(const iDocumentWidget *d, iDrawContext *ctx,
3770 /* Progressively draw the rest of the buffer if it isn't fully valid. */ 3773 /* Progressively draw the rest of the buffer if it isn't fully valid. */
3771 if (prerenderExtra && !equal_Rangei(bufRange, buf->validRange)) { 3774 if (prerenderExtra && !equal_Rangei(bufRange, buf->validRange)) {
3772 const iGmRun *next; 3775 const iGmRun *next;
3773 if (meta->runsDrawn.start) { 3776// printf("%zu: prerenderExtra (start:%p end:%p)\n", i, meta->runsDrawn.start, meta->runsDrawn.end);
3774 const iRangei upper = intersect_Rangei(bufRange, (iRangei){ full.start, buf->validRange.start }); 3777 if (meta->runsDrawn.start == NULL) {
3775 if (upper.end > upper.start) { 3778 /* Haven't drawn anything yet in this buffer, so let's try seeding it. */
3776 beginTarget_Paint(p, buf->texture); 3779 const int rh = lineHeight_Text(paragraph_FontId);
3777 next = renderProgressive_GmDocument(d->doc, meta->runsDrawn.start, 3780 const int y = i >= iElemCount(visBuf->buffers) / 2 ? bufRange.start : (bufRange.end - rh);
3778 -1, 1, upper, 3781 beginTarget_Paint(p, buf->texture);
3779 drawRun_DrawContext_, 3782 fillRect_Paint(p, (iRect){ zero_I2(), visBuf->texSize }, tmBackground_ColorId);
3780 ctx); 3783 buf->validRange = (iRangei){ y, y + rh };
3781 if (meta->runsDrawn.start != next) { 3784 iZap(ctx->runsDrawn);
3782 meta->runsDrawn.start = next; 3785 render_GmDocument(d->doc, buf->validRange, drawRun_DrawContext_, ctx);
3783 didDraw = iTrue; 3786 meta->runsDrawn = ctx->runsDrawn;
3787 extend_GmRunRange_(&meta->runsDrawn);
3788// printf("%zu: seeded, next %p:%p\n", i, meta->runsDrawn.start, meta->runsDrawn.end);
3789 didDraw = iTrue;
3790 }
3791 else {
3792 if (meta->runsDrawn.start) {
3793 const iRangei upper = intersect_Rangei(bufRange, (iRangei){ full.start, buf->validRange.start });
3794 if (upper.end > upper.start) {
3795 beginTarget_Paint(p, buf->texture);
3796 next = renderProgressive_GmDocument(d->doc, meta->runsDrawn.start,
3797 -1, 1, upper,
3798 drawRun_DrawContext_,
3799 ctx);
3800 if (next && meta->runsDrawn.start != next) {
3801 meta->runsDrawn.start = next;
3802 buf->validRange.start = bottom_Rect(next->visBounds);
3803 didDraw = iTrue;
3804 }
3805 else {
3806 buf->validRange.start = bufRange.start;
3807 }
3784 } 3808 }
3785 buf->validRange.start = bufRange.start;
3786 } 3809 }
3787 } 3810 if (!didDraw && meta->runsDrawn.end) {
3788 if (meta->runsDrawn.end) { 3811 const iRangei lower = intersect_Rangei(bufRange, (iRangei){ buf->validRange.end, full.end });
3789 const iRangei lower = intersect_Rangei(bufRange, (iRangei){ buf->validRange.end, full.end }); 3812 if (lower.end > lower.start) {
3790 if (lower.end > lower.start) { 3813 beginTarget_Paint(p, buf->texture);
3791 beginTarget_Paint(p, buf->texture); 3814 next = renderProgressive_GmDocument(d->doc, meta->runsDrawn.end,
3792 next = renderProgressive_GmDocument(d->doc, meta->runsDrawn.end, 3815 +1, 1, lower,
3793 +1, 1, lower, 3816 drawRun_DrawContext_,
3794 drawRun_DrawContext_, 3817 ctx);
3795 ctx); 3818 if (next && meta->runsDrawn.end != next) {
3796 if (meta->runsDrawn.end != next) { 3819 meta->runsDrawn.end = next;
3797 meta->runsDrawn.end = next; 3820 buf->validRange.end = top_Rect(next->visBounds);
3798 didDraw = iTrue; 3821 didDraw = iTrue;
3822 }
3823 else {
3824 buf->validRange.end = bufRange.end;
3825 }
3799 } 3826 }
3800 buf->validRange.end = bufRange.end;
3801 } 3827 }
3802 } 3828 }
3803 } 3829 }
3804 /* Draw any invalidated runs that fall within this buffer. */ { 3830 /* Draw any invalidated runs that fall within this buffer. */
3831 if (!prerenderExtra) {
3805 const iRangei bufRange = { buf->origin, buf->origin + visBuf->texSize.y }; 3832 const iRangei bufRange = { buf->origin, buf->origin + visBuf->texSize.y };
3806 /* Clear full-width backgrounds first in case there are any dynamic elements. */ { 3833 /* Clear full-width backgrounds first in case there are any dynamic elements. */ {
3807 iConstForEach(PtrSet, r, d->invalidRuns) { 3834 iConstForEach(PtrSet, r, d->invalidRuns) {
@@ -3826,6 +3853,9 @@ static iBool render_DocumentWidget_(const iDocumentWidget *d, iDrawContext *ctx,
3826 } 3853 }
3827 } 3854 }
3828 endTarget_Paint(p); 3855 endTarget_Paint(p);
3856 if (prerenderExtra && didDraw) {
3857 return iTrue;
3858 }
3829 } 3859 }
3830 clear_PtrSet(d->invalidRuns); 3860 clear_PtrSet(d->invalidRuns);
3831 } 3861 }