From 8e8e486a2969dbc20b3c3a08023267e9eab53265 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Sat, 3 Apr 2021 15:22:02 +0300 Subject: Drawing only during window update Glyphs were inadvertently being cached already during measuring for layout. DocumentWidget was buffering graphics too early. Now buffered draws are prepared during normal drawing, when needed. --- src/app.c | 2 +- src/ui/documentwidget.c | 131 ++++++++++++++++++++++++++++++++---------------- src/ui/text.c | 4 +- src/ui/window.c | 4 -- src/ui/window.h | 5 ++ 5 files changed, 96 insertions(+), 50 deletions(-) (limited to 'src') diff --git a/src/app.c b/src/app.c index ba282440..54f35373 100644 --- a/src/app.c +++ b/src/app.c @@ -129,7 +129,7 @@ struct Impl_App { iTime lastDropTime; /* for detecting drops of multiple items */ int autoReloadTimer; iPeriodic periodic; - int warmupFrames; /* forced refresh just after resuming from background */ + int warmupFrames; /* forced refresh just after resuming from background; FIXME: shouldn't be needed */ /* Preferences: */ iBool commandEcho; /* --echo */ iBool forceSoftwareRender; /* --sw */ diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 9a50b611..0c7ebd54 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c @@ -144,8 +144,38 @@ iDefineTypeConstruction(PersistentDocumentState) /*----------------------------------------------------------------------------------------------*/ -static void animateMedia_DocumentWidget_ (iDocumentWidget *d); -static void updateSideIconBuf_DocumentWidget_ (iDocumentWidget *d); +iDeclareType(DrawBufs) + +enum iDrawBufsFlag { + updateSideBuf_DrawBufsFlag = iBit(1), + updateTimestampBuf_DrawBufsFlag = iBit(2), +}; + +struct Impl_DrawBufs { + int flags; + SDL_Texture * sideIconBuf; + iTextBuf * timestampBuf; +}; + +static void init_DrawBufs(iDrawBufs *d) { + d->flags = 0; + d->sideIconBuf = NULL; + d->timestampBuf = NULL; +} + +static void deinit_DrawBufs(iDrawBufs *d) { + delete_TextBuf(d->timestampBuf); + if (d->sideIconBuf) { + SDL_DestroyTexture(d->sideIconBuf); + } +} + +iDefineTypeConstruction(DrawBufs) + +/*----------------------------------------------------------------------------------------------*/ + +static void animateMedia_DocumentWidget_ (iDocumentWidget *d); +static void updateSideIconBuf_DocumentWidget_ (const iDocumentWidget *d); static const int smoothDuration_DocumentWidget_ = 600; /* milliseconds */ static const int outlineMinWidth_DocumentWdiget_ = 45; /* times gap_UI */ @@ -229,8 +259,7 @@ struct Impl_DocumentWidget { iWidget * playerMenu; iVisBuf * visBuf; iPtrSet * invalidRuns; - SDL_Texture * sideIconBuf; - iTextBuf * timestampBuf; + iDrawBufs * drawBufs; /* dynamic state for drawing */ iTranslation * translation; iWidget * phoneToolbar; }; @@ -291,8 +320,7 @@ void init_DocumentWidget(iDocumentWidget *d) { addChild_Widget(w, iClob(d->scroll = new_ScrollWidget())); d->menu = NULL; /* created when clicking */ d->playerMenu = NULL; - d->sideIconBuf = NULL; - d->timestampBuf = NULL; + d->drawBufs = new_DrawBufs(); d->translation = NULL; addChildFlags_Widget(w, iClob(new_IndicatorWidget()), @@ -311,10 +339,7 @@ void init_DocumentWidget(iDocumentWidget *d) { void deinit_DocumentWidget(iDocumentWidget *d) { delete_Translation(d->translation); - if (d->sideIconBuf) { - SDL_DestroyTexture(d->sideIconBuf); - } - delete_TextBuf(d->timestampBuf); + delete_DrawBufs(d->drawBufs); delete_VisBuf(d->visBuf); delete_PtrSet(d->invalidRuns); iRelease(d->media); @@ -697,7 +722,7 @@ static void updateVisible_DocumentWidget_(iDocumentWidget *d) { } const iRangecc newHeading = currentHeading_DocumentWidget_(d); if (memcmp(&oldHeading, &newHeading, sizeof(oldHeading))) { - updateSideIconBuf_DocumentWidget_(d); + d->drawBufs->flags |= updateSideBuf_DrawBufsFlag; } updateHover_DocumentWidget_(d, mouseCoord_Window(get_Window())); updateSideOpacity_DocumentWidget_(d, iTrue); @@ -779,17 +804,21 @@ static void updateWindowTitle_DocumentWidget_(const iDocumentWidget *d) { } } -static void updateTimestampBuf_DocumentWidget_(iDocumentWidget *d) { - if (d->timestampBuf) { - delete_TextBuf(d->timestampBuf); - d->timestampBuf = NULL; +static void updateTimestampBuf_DocumentWidget_(const iDocumentWidget *d) { + if (!isExposed_Window(get_Window())) { + return; + } + if (d->drawBufs->timestampBuf) { + delete_TextBuf(d->drawBufs->timestampBuf); + d->drawBufs->timestampBuf = NULL; } if (isValid_Time(&d->sourceTime)) { - d->timestampBuf = new_TextBuf( + d->drawBufs->timestampBuf = new_TextBuf( uiLabel_FontId, white_ColorId, cstrCollect_String(format_Time(&d->sourceTime, cstr_Lang("page.timestamp")))); } + d->drawBufs->flags &= ~updateTimestampBuf_DrawBufsFlag; } static void invalidate_DocumentWidget_(iDocumentWidget *d) { @@ -819,7 +848,7 @@ void setSource_DocumentWidget(iDocumentWidget *d, const iString *source) { documentRunsInvalidated_DocumentWidget_(d); updateWindowTitle_DocumentWidget_(d); updateVisible_DocumentWidget_(d); - updateSideIconBuf_DocumentWidget_(d); + d->drawBufs->flags |= updateSideBuf_DrawBufsFlag; invalidate_DocumentWidget_(d); refresh_Widget(as_Widget(d)); } @@ -832,7 +861,7 @@ static void updateTheme_DocumentWidget_(iDocumentWidget *d) { else { setThemeSeed_GmDocument(d->doc, &d->titleUser->chars); } - updateTimestampBuf_DocumentWidget_(d); + d->drawBufs->flags |= updateTimestampBuf_DrawBufsFlag; } static enum iGmDocumentBanner bannerType_DocumentWidget_(const iDocumentWidget *d) { @@ -928,7 +957,7 @@ static void updateDocument_DocumentWidget_(iDocumentWidget *d, const iGmResponse } clear_String(&d->sourceMime); d->sourceTime = response->when; - updateTimestampBuf_DocumentWidget_(d); + d->drawBufs->flags |= updateTimestampBuf_DrawBufsFlag; initBlock_String(&str, &response->body); if (isSuccess_GmStatusCode(statusCode)) { /* Check the MIME type. */ @@ -1075,7 +1104,9 @@ static void cacheRunGlyphs_(void *data, const iGmRun *run) { } static void cacheDocumentGlyphs_DocumentWidget_(const iDocumentWidget *d) { - render_GmDocument(d->doc, (iRangei){ 0, size_GmDocument(d->doc).y }, cacheRunGlyphs_, NULL); + if (isExposed_Window(get_Window())) { + render_GmDocument(d->doc, (iRangei){ 0, size_GmDocument(d->doc).y }, cacheRunGlyphs_, NULL); + } } static iBool updateFromHistory_DocumentWidget_(iDocumentWidget *d) { @@ -1092,14 +1123,14 @@ static iBool updateFromHistory_DocumentWidget_(iDocumentWidget *d) { d->sourceTime = resp->when; d->sourceStatus = success_GmStatusCode; format_String(&d->sourceHeader, cstr_Lang("pageinfo.header.cached")); - updateTimestampBuf_DocumentWidget_(d); + d->drawBufs->flags |= updateTimestampBuf_DrawBufsFlag; set_Block(&d->sourceContent, &resp->body); updateDocument_DocumentWidget_(d, resp, iTrue); init_Anim(&d->scrollY, d->initNormScrollY * size_GmDocument(d->doc).y); init_Anim(&d->altTextOpacity, 0); d->state = ready_RequestState; updateSideOpacity_DocumentWidget_(d, iFalse); - updateSideIconBuf_DocumentWidget_(d); + d->drawBufs->flags |= updateSideBuf_DrawBufsFlag; updateVisible_DocumentWidget_(d); cacheDocumentGlyphs_DocumentWidget_(d); postCommandf_App("document.changed doc:%p url:%s", d, cstr_String(d->mod.url)); @@ -1622,7 +1653,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) d->phoneToolbar = findWidget_App("toolbar"); const iBool keepCenter = equal_Command(cmd, "font.changed"); updateDocumentWidthRetainingScrollPosition_DocumentWidget_(d, keepCenter); - updateSideIconBuf_DocumentWidget_(d); + d->drawBufs->flags |= updateSideBuf_DrawBufsFlag; invalidate_DocumentWidget_(d); dealloc_VisBuf(d->visBuf); updateWindowTitle_DocumentWidget_(d); @@ -1643,7 +1674,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) updateTheme_DocumentWidget_(d); updateVisible_DocumentWidget_(d); updateTrust_DocumentWidget_(d, NULL); - updateSideIconBuf_DocumentWidget_(d); + d->drawBufs->flags |= updateSideBuf_DrawBufsFlag; invalidate_DocumentWidget_(d); refresh_Widget(w); } @@ -1875,7 +1906,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) } iReleasePtr(&d->request); updateVisible_DocumentWidget_(d); - updateSideIconBuf_DocumentWidget_(d); + d->drawBufs->flags |= updateSideBuf_DrawBufsFlag; postCommandf_App("document.changed doc:%p url:%s", d, cstr_String(d->mod.url)); /* Check for a pending goto. */ if (!isEmpty_String(&d->pendingGotoHeading)) { @@ -3258,10 +3289,15 @@ static iBool isSideHeadingVisible_DocumentWidget_(const iDocumentWidget *d) { return sideElementAvailWidth_DocumentWidget_(d) >= lineHeight_Text(banner_FontId) * 4.5f; } -static void updateSideIconBuf_DocumentWidget_(iDocumentWidget *d) { - if (d->sideIconBuf) { - SDL_DestroyTexture(d->sideIconBuf); - d->sideIconBuf = NULL; +static void updateSideIconBuf_DocumentWidget_(const iDocumentWidget *d) { + if (!isExposed_Window(get_Window())) { + return; + } + iDrawBufs *dbuf = d->drawBufs; + dbuf->flags &= ~updateSideBuf_DrawBufsFlag; + if (dbuf->sideIconBuf) { + SDL_DestroyTexture(dbuf->sideIconBuf); + dbuf->sideIconBuf = NULL; } const iGmRun *banner = siteBanner_GmDocument(d->doc); if (!banner) { @@ -3286,13 +3322,13 @@ static void updateSideIconBuf_DocumentWidget_(iDocumentWidget *d) { } } SDL_Renderer *render = renderer_Window(get_Window()); - d->sideIconBuf = SDL_CreateTexture(render, - SDL_PIXELFORMAT_RGBA4444, - SDL_TEXTUREACCESS_STATIC | SDL_TEXTUREACCESS_TARGET, - bufSize.x, bufSize.y); + dbuf->sideIconBuf = SDL_CreateTexture(render, + SDL_PIXELFORMAT_RGBA4444, + SDL_TEXTUREACCESS_STATIC | SDL_TEXTUREACCESS_TARGET, + bufSize.x, bufSize.y); iPaint p; init_Paint(&p); - beginTarget_Paint(&p, d->sideIconBuf); + beginTarget_Paint(&p, dbuf->sideIconBuf); const iColor back = get_Color(tmBannerSideTitle_ColorId); SDL_SetRenderDrawColor(render, back.r, back.g, back.b, 0); /* better blending of the edge */ SDL_RenderClear(render); @@ -3309,7 +3345,7 @@ static void updateSideIconBuf_DocumentWidget_(iDocumentWidget *d) { drawWrapRange_Text(font, pos, avail, tmBannerSideTitle_ColorId, text); } endTarget_Paint(&p); - SDL_SetTextureBlendMode(d->sideIconBuf, SDL_BLENDMODE_BLEND); + SDL_SetTextureBlendMode(dbuf->sideIconBuf, SDL_BLENDMODE_BLEND); } static void drawSideElements_DocumentWidget_(const iDocumentWidget *d) { @@ -3319,12 +3355,13 @@ static void drawSideElements_DocumentWidget_(const iDocumentWidget *d) { const int margin = gap_UI * d->pageMargin; float opacity = value_Anim(&d->sideOpacity); const int avail = left_Rect(docBounds) - left_Rect(bounds) - 2 * margin; - iPaint p; + iDrawBufs * dbuf = d->drawBufs; + iPaint p; init_Paint(&p); setClip_Paint(&p, bounds); /* Side icon and current heading. */ - if (prefs_App()->sideIcon && opacity > 0 && d->sideIconBuf) { - const iInt2 texSize = size_SDLTexture(d->sideIconBuf); + if (prefs_App()->sideIcon && opacity > 0 && dbuf->sideIconBuf) { + const iInt2 texSize = size_SDLTexture(dbuf->sideIconBuf); if (avail > texSize.x) { const int minBannerSize = lineHeight_Text(banner_FontId) * 2; iInt2 pos = addY_I2(add_I2(topLeft_Rect(bounds), init_I2(margin, 0)), @@ -3332,20 +3369,20 @@ static void drawSideElements_DocumentWidget_(const iDocumentWidget *d) { (texSize.y > minBannerSize ? (gap_Text + lineHeight_Text(heading3_FontId)) / 2 : 0)); - SDL_SetTextureAlphaMod(d->sideIconBuf, 255 * opacity); + SDL_SetTextureAlphaMod(dbuf->sideIconBuf, 255 * opacity); SDL_RenderCopy(renderer_Window(get_Window()), - d->sideIconBuf, NULL, + dbuf->sideIconBuf, NULL, &(SDL_Rect){ pos.x, pos.y, texSize.x, texSize.y }); } } /* Reception timestamp. */ - if (d->timestampBuf && d->timestampBuf->size.x <= avail) { + if (dbuf->timestampBuf && dbuf->timestampBuf->size.x <= avail) { draw_TextBuf( - d->timestampBuf, + dbuf->timestampBuf, add_I2( bottomLeft_Rect(bounds), init_I2(margin, - -margin + -d->timestampBuf->size.y + + -margin + -dbuf->timestampBuf->size.y + iMax(0, scrollMax_DocumentWidget_(d) - value_Anim(&d->scrollY)))), tmQuoteIcon_ColorId); } @@ -3378,6 +3415,12 @@ static void draw_DocumentWidget_(const iDocumentWidget *d) { return; } draw_Widget(w); + if (d->drawBufs->flags & updateTimestampBuf_DrawBufsFlag) { + updateTimestampBuf_DocumentWidget_(d); + } + if (d->drawBufs->flags & updateSideBuf_DrawBufsFlag) { + updateSideIconBuf_DocumentWidget_(d); + } allocVisBuffer_DocumentWidget_(d); const iRect ctxWidgetBounds = init_Rect( 0, 0, width_Rect(bounds) - constAs_Widget(d->scroll)->rect.size.x, height_Rect(bounds)); @@ -3617,7 +3660,7 @@ iBool isRequestOngoing_DocumentWidget(const iDocumentWidget *d) { void updateSize_DocumentWidget(iDocumentWidget *d) { updateDocumentWidthRetainingScrollPosition_DocumentWidget_(d, iFalse); resetWideRuns_DocumentWidget_(d); - updateSideIconBuf_DocumentWidget_(d); + d->drawBufs->flags |= updateSideBuf_DrawBufsFlag; updateVisible_DocumentWidget_(d); invalidate_DocumentWidget_(d); } diff --git a/src/ui/text.c b/src/ui/text.c index 674e2a72..6af7d6d1 100644 --- a/src/ui/text.c +++ b/src/ui/text.c @@ -24,6 +24,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "color.h" #include "metrics.h" #include "embedded.h" +#include "window.h" #include "app.h" #define STB_TRUETYPE_IMPLEMENTATION @@ -702,6 +703,7 @@ void cacheTextGlyphs_Font_(iFont *d, const iRangecc text) { iArray * rasters = NULL; SDL_Texture *oldTarget = NULL; iBool isTargetChanged = iFalse; + iAssert(isExposed_Window(get_Window())); /* We'll flush the buffered rasters periodically until everything is cached. */ while (chPos < text.end) { while (chPos < text.end) { @@ -1017,7 +1019,7 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) { int x1 = iMax(xpos, xposExtend); /* Which half of the pixel the glyph falls on? */ const int hoff = enableHalfPixelGlyphs_Text ? (xpos - x1 > 0.5f ? 1 : 0) : 0; - if (!isRasterized_Glyph_(glyph, hoff)) { + if (mode & draw_RunMode && !isRasterized_Glyph_(glyph, hoff)) { /* Need to pause here and make sure all glyphs have been cached in the text. */ cacheTextGlyphs_Font_(d, args->text); glyph = glyph_Font_(d, ch); /* cache may have been reset */ diff --git a/src/ui/window.c b/src/ui/window.c index f92107e3..27740326 100644 --- a/src/ui/window.c +++ b/src/ui/window.c @@ -1769,12 +1769,8 @@ iBool processEvent_Window(iWindow *d, const SDL_Event *ev) { SDL_Event event = *ev; if (event.type == SDL_USEREVENT && isCommand_UserEvent(ev, "window.unfreeze")) { d->isDrawFrozen = iFalse; - /* When the window is shown for the first time, ensure glyphs get - re-cached correctly. */ if (SDL_GetWindowFlags(d->win) & SDL_WINDOW_HIDDEN) { SDL_ShowWindow(d->win); - resetFonts_Text(); - postCommand_App("theme.changed"); } postRefresh_App(); return iTrue; diff --git a/src/ui/window.h b/src/ui/window.h index 7303acb2..6960e03e 100644 --- a/src/ui/window.h +++ b/src/ui/window.h @@ -113,3 +113,8 @@ iWindow * get_Window (void); #if defined (LAGRANGE_CUSTOM_FRAME) SDL_HitTestResult hitTest_Window(const iWindow *d, iInt2 pos); #endif + +iLocalDef iBool isExposed_Window(const iWindow *d) { + iAssert(d); + return d->isExposed; +} -- cgit v1.2.3