diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-11-03 07:09:16 +0200 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-11-03 07:09:16 +0200 |
commit | f4172885428f9849ff29bd09490db8b167a8d705 (patch) | |
tree | c82af9c46bce0f56627e61d180a630e11fb8baee | |
parent | 20b5a9bbad524e242b7ade9fdcd06f34721c5f3a (diff) |
Redo cached document layout if needed
Changing the fonts, zoom level, or window width will cause cached documents to be laid out again if they are restored from memory.
-rw-r--r-- | src/app.c | 12 | ||||
-rw-r--r-- | src/gmdocument.c | 34 | ||||
-rw-r--r-- | src/gmdocument.h | 22 | ||||
-rw-r--r-- | src/history.c | 11 | ||||
-rw-r--r-- | src/history.h | 1 | ||||
-rw-r--r-- | src/ui/documentwidget.c | 6 |
6 files changed, 51 insertions, 35 deletions
@@ -2125,6 +2125,12 @@ void resetFonts_App(void) { | |||
2125 | } | 2125 | } |
2126 | } | 2126 | } |
2127 | 2127 | ||
2128 | static void invalidateCachedDocuments_App_(void) { | ||
2129 | iForEach(ObjectList, i, iClob(listDocuments_App(NULL))) { | ||
2130 | invalidateCachedLayout_History(history_DocumentWidget(i.object)); | ||
2131 | } | ||
2132 | } | ||
2133 | |||
2128 | iBool handleCommand_App(const char *cmd) { | 2134 | iBool handleCommand_App(const char *cmd) { |
2129 | iApp *d = &app_; | 2135 | iApp *d = &app_; |
2130 | const iBool isFrozen = !d->window || d->window->isDrawFrozen; | 2136 | const iBool isFrozen = !d->window || d->window->isDrawFrozen; |
@@ -2289,7 +2295,10 @@ iBool handleCommand_App(const char *cmd) { | |||
2289 | if (!isFrozen) { | 2295 | if (!isFrozen) { |
2290 | setFreezeDraw_MainWindow(get_MainWindow(), iTrue); /* no intermediate draws before docs updated */ | 2296 | setFreezeDraw_MainWindow(get_MainWindow(), iTrue); /* no intermediate draws before docs updated */ |
2291 | } | 2297 | } |
2292 | d->prefs.zoomPercent = arg_Command(cmd); | 2298 | if (arg_Command(cmd) != d->prefs.zoomPercent) { |
2299 | d->prefs.zoomPercent = arg_Command(cmd); | ||
2300 | invalidateCachedDocuments_App_(); | ||
2301 | } | ||
2293 | setDocumentFontSize_Text(text_Window(d->window), (float) d->prefs.zoomPercent / 100.0f); | 2302 | setDocumentFontSize_Text(text_Window(d->window), (float) d->prefs.zoomPercent / 100.0f); |
2294 | if (!isFrozen) { | 2303 | if (!isFrozen) { |
2295 | postCommand_App("font.changed"); | 2304 | postCommand_App("font.changed"); |
@@ -2306,6 +2315,7 @@ iBool handleCommand_App(const char *cmd) { | |||
2306 | delta /= 2; | 2315 | delta /= 2; |
2307 | } | 2316 | } |
2308 | d->prefs.zoomPercent = iClamp(d->prefs.zoomPercent + delta, 50, 200); | 2317 | d->prefs.zoomPercent = iClamp(d->prefs.zoomPercent + delta, 50, 200); |
2318 | invalidateCachedDocuments_App_(); | ||
2309 | setDocumentFontSize_Text(text_Window(d->window), (float) d->prefs.zoomPercent / 100.0f); | 2319 | setDocumentFontSize_Text(text_Window(d->window), (float) d->prefs.zoomPercent / 100.0f); |
2310 | if (!isFrozen) { | 2320 | if (!isFrozen) { |
2311 | postCommand_App("font.changed"); | 2321 | postCommand_App("font.changed"); |
diff --git a/src/gmdocument.c b/src/gmdocument.c index a459b42f..0027bdb3 100644 --- a/src/gmdocument.c +++ b/src/gmdocument.c | |||
@@ -161,10 +161,9 @@ struct Impl_GmDocument { | |||
161 | iInt2 size; | 161 | iInt2 size; |
162 | int outsideMargin; | 162 | int outsideMargin; |
163 | iBool enableCommandLinks; /* `about:command?` only allowed on selected pages */ | 163 | iBool enableCommandLinks; /* `about:command?` only allowed on selected pages */ |
164 | iBool isLayoutInvalidated; | ||
164 | iArray layout; /* contents of source, laid out in document space */ | 165 | iArray layout; /* contents of source, laid out in document space */ |
165 | iPtrArray links; | 166 | iPtrArray links; |
166 | // enum iGmDocumentBanner bannerType; | ||
167 | // iString bannerText; | ||
168 | iString title; /* the first top-level title */ | 167 | iString title; /* the first top-level title */ |
169 | iArray headings; | 168 | iArray headings; |
170 | iArray preMeta; /* metadata about preformatted blocks */ | 169 | iArray preMeta; /* metadata about preformatted blocks */ |
@@ -607,6 +606,7 @@ static void doLayout_GmDocument_(iGmDocument *d) { | |||
607 | // const iBool isDarkBg = isDark_GmDocumentTheme( | 606 | // const iBool isDarkBg = isDark_GmDocumentTheme( |
608 | // isDark_ColorTheme(colorTheme_App()) ? prefs->docThemeDark : prefs->docThemeLight); | 607 | // isDark_ColorTheme(colorTheme_App()) ? prefs->docThemeDark : prefs->docThemeLight); |
609 | initTheme_GmDocument_(d); | 608 | initTheme_GmDocument_(d); |
609 | d->isLayoutInvalidated = iFalse; | ||
610 | /* TODO: Collect these parameters into a GmTheme. */ | 610 | /* TODO: Collect these parameters into a GmTheme. */ |
611 | float indents[max_GmLineType] = { 5, 10, 5, isNarrow ? 5 : 10, 0, 0, 0, 5 }; | 611 | float indents[max_GmLineType] = { 5, 10, 5, isNarrow ? 5 : 10, 0, 0, 0, 5 }; |
612 | if (isExtremelyNarrow) { | 612 | if (isExtremelyNarrow) { |
@@ -1144,13 +1144,12 @@ void init_GmDocument(iGmDocument *d) { | |||
1144 | init_String(&d->source); | 1144 | init_String(&d->source); |
1145 | init_String(&d->url); | 1145 | init_String(&d->url); |
1146 | init_String(&d->localHost); | 1146 | init_String(&d->localHost); |
1147 | // d->bannerType = siteDomain_GmDocumentBanner; | ||
1148 | d->outsideMargin = 0; | 1147 | d->outsideMargin = 0; |
1149 | d->size = zero_I2(); | 1148 | d->size = zero_I2(); |
1150 | d->enableCommandLinks = iFalse; | 1149 | d->enableCommandLinks = iFalse; |
1150 | d->isLayoutInvalidated = iFalse; | ||
1151 | init_Array(&d->layout, sizeof(iGmRun)); | 1151 | init_Array(&d->layout, sizeof(iGmRun)); |
1152 | init_PtrArray(&d->links); | 1152 | init_PtrArray(&d->links); |
1153 | // init_String(&d->bannerText); | ||
1154 | init_String(&d->title); | 1153 | init_String(&d->title); |
1155 | init_Array(&d->headings, sizeof(iGmHeading)); | 1154 | init_Array(&d->headings, sizeof(iGmHeading)); |
1156 | init_Array(&d->preMeta, sizeof(iGmPreMeta)); | 1155 | init_Array(&d->preMeta, sizeof(iGmPreMeta)); |
@@ -1166,7 +1165,6 @@ void init_GmDocument(iGmDocument *d) { | |||
1166 | void deinit_GmDocument(iGmDocument *d) { | 1165 | void deinit_GmDocument(iGmDocument *d) { |
1167 | iReleasePtr(&d->openURLs); | 1166 | iReleasePtr(&d->openURLs); |
1168 | delete_Media(d->media); | 1167 | delete_Media(d->media); |
1169 | // deinit_String(&d->bannerText); | ||
1170 | deinit_String(&d->title); | 1168 | deinit_String(&d->title); |
1171 | clearLinks_GmDocument_(d); | 1169 | clearLinks_GmDocument_(d); |
1172 | deinit_PtrArray(&d->links); | 1170 | deinit_PtrArray(&d->links); |
@@ -1722,22 +1720,28 @@ void setFormat_GmDocument(iGmDocument *d, enum iSourceFormat format) { | |||
1722 | d->format = format; | 1720 | d->format = format; |
1723 | } | 1721 | } |
1724 | 1722 | ||
1725 | #if 0 | 1723 | void setWidth_GmDocument(iGmDocument *d, int width, int canvasWidth) { |
1726 | void setBanner_GmDocument(iGmDocument *d, enum iGmDocumentBanner type) { | 1724 | d->size.x = width; |
1727 | d->bannerType = type; | 1725 | d->outsideMargin = iMax(0, (canvasWidth - width) / 2); /* distance to edge of the canvas */ |
1726 | doLayout_GmDocument_(d); /* TODO: just flag need-layout and do it later */ | ||
1728 | } | 1727 | } |
1729 | #endif | ||
1730 | 1728 | ||
1731 | void setWidth_GmDocument(iGmDocument *d, int width, int outsideMargin) { | 1729 | iBool updateWidth_GmDocument(iGmDocument *d, int width, int canvasWidth) { |
1732 | d->size.x = width; | 1730 | if (d->size.x != width || d->isLayoutInvalidated) { |
1733 | d->outsideMargin = outsideMargin; /* distance to edge of the viewport */ | 1731 | setWidth_GmDocument(d, width, canvasWidth); |
1734 | doLayout_GmDocument_(d); /* TODO: just flag need-layout and do it later */ | 1732 | return iTrue; |
1733 | } | ||
1734 | return iFalse; | ||
1735 | } | 1735 | } |
1736 | 1736 | ||
1737 | void redoLayout_GmDocument(iGmDocument *d) { | 1737 | void redoLayout_GmDocument(iGmDocument *d) { |
1738 | doLayout_GmDocument_(d); | 1738 | doLayout_GmDocument_(d); |
1739 | } | 1739 | } |
1740 | 1740 | ||
1741 | void invalidateLayout_GmDocument(iGmDocument *d) { | ||
1742 | d->isLayoutInvalidated = iTrue; | ||
1743 | } | ||
1744 | |||
1741 | static void markLinkRunsVisited_GmDocument_(iGmDocument *d, const iIntSet *linkIds) { | 1745 | static void markLinkRunsVisited_GmDocument_(iGmDocument *d, const iIntSet *linkIds) { |
1742 | iForEach(Array, r, &d->layout) { | 1746 | iForEach(Array, r, &d->layout) { |
1743 | iGmRun *run = r.value; | 1747 | iGmRun *run = r.value; |
@@ -2082,7 +2086,7 @@ static void convertMarkdownToGemtext_GmDocument_(iGmDocument *d) { | |||
2082 | d->format = gemini_SourceFormat; | 2086 | d->format = gemini_SourceFormat; |
2083 | } | 2087 | } |
2084 | 2088 | ||
2085 | void setSource_GmDocument(iGmDocument *d, const iString *source, int width, int outsideMargin, | 2089 | void setSource_GmDocument(iGmDocument *d, const iString *source, int width, int canvasWidth, |
2086 | enum iGmDocumentUpdate updateType) { | 2090 | enum iGmDocumentUpdate updateType) { |
2087 | /* TODO: This API has been set up to allow partial/progressive updating of the content. | 2091 | /* TODO: This API has been set up to allow partial/progressive updating of the content. |
2088 | Currently the entire source is replaced every time, though. */ | 2092 | Currently the entire source is replaced every time, though. */ |
@@ -2124,7 +2128,7 @@ void setSource_GmDocument(iGmDocument *d, const iString *source, int width, int | |||
2124 | if (isNormalized_GmDocument_(d)) { | 2128 | if (isNormalized_GmDocument_(d)) { |
2125 | normalize_GmDocument(d); | 2129 | normalize_GmDocument(d); |
2126 | } | 2130 | } |
2127 | setWidth_GmDocument(d, width, outsideMargin); /* re-do layout */ | 2131 | setWidth_GmDocument(d, width, canvasWidth); /* re-do layout */ |
2128 | } | 2132 | } |
2129 | 2133 | ||
2130 | void foldPre_GmDocument(iGmDocument *d, uint16_t preId) { | 2134 | void foldPre_GmDocument(iGmDocument *d, uint16_t preId) { |
diff --git a/src/gmdocument.h b/src/gmdocument.h index 444520c6..58fc3db3 100644 --- a/src/gmdocument.h +++ b/src/gmdocument.h | |||
@@ -120,10 +120,8 @@ enum iGmRunFlags { | |||
120 | decoration_GmRunFlag = iBit(1), /* not part of the source */ | 120 | decoration_GmRunFlag = iBit(1), /* not part of the source */ |
121 | startOfLine_GmRunFlag = iBit(2), | 121 | startOfLine_GmRunFlag = iBit(2), |
122 | endOfLine_GmRunFlag = iBit(3), | 122 | endOfLine_GmRunFlag = iBit(3), |
123 | // siteBanner_GmRunFlag = iBit(4), /* area reserved for the site banner */ | ||
124 | quoteBorder_GmRunFlag = iBit(5), | 123 | quoteBorder_GmRunFlag = iBit(5), |
125 | wide_GmRunFlag = iBit(6), /* horizontally scrollable */ | 124 | wide_GmRunFlag = iBit(6), /* horizontally scrollable */ |
126 | // footer_GmRunFlag = iBit(7), | ||
127 | altText_GmRunFlag = iBit(8), | 125 | altText_GmRunFlag = iBit(8), |
128 | }; | 126 | }; |
129 | 127 | ||
@@ -177,13 +175,6 @@ enum iGmDocumentWarning { | |||
177 | missingGlyphs_GmDocumentWarning = iBit(2), | 175 | missingGlyphs_GmDocumentWarning = iBit(2), |
178 | }; | 176 | }; |
179 | 177 | ||
180 | /* | ||
181 | enum iGmDocumentBanner { | ||
182 | none_GmDocumentBanner, | ||
183 | siteDomain_GmDocumentBanner, | ||
184 | certificateWarning_GmDocumentBanner, | ||
185 | };*/ | ||
186 | |||
187 | enum iGmDocumentUpdate { | 178 | enum iGmDocumentUpdate { |
188 | partial_GmDocumentUpdate, /* appending more content */ | 179 | partial_GmDocumentUpdate, /* appending more content */ |
189 | final_GmDocumentUpdate, /* process all lines, including the last one if not terminated */ | 180 | final_GmDocumentUpdate, /* process all lines, including the last one if not terminated */ |
@@ -191,12 +182,13 @@ enum iGmDocumentUpdate { | |||
191 | 182 | ||
192 | void setThemeSeed_GmDocument (iGmDocument *, const iBlock *seed); | 183 | void setThemeSeed_GmDocument (iGmDocument *, const iBlock *seed); |
193 | void setFormat_GmDocument (iGmDocument *, enum iSourceFormat format); | 184 | void setFormat_GmDocument (iGmDocument *, enum iSourceFormat format); |
194 | //void setBanner_GmDocument (iGmDocument *, enum iGmDocumentBanner type); | 185 | void setWidth_GmDocument (iGmDocument *, int width, int canvasWidth); |
195 | void setWidth_GmDocument (iGmDocument *, int width, int outsideMargin); | 186 | iBool updateWidth_GmDocument (iGmDocument *, int width, int canvasWidth); |
196 | void redoLayout_GmDocument (iGmDocument *); | 187 | void redoLayout_GmDocument (iGmDocument *); |
188 | void invalidateLayout_GmDocument(iGmDocument *); /* will have to be redone later */ | ||
197 | iBool updateOpenURLs_GmDocument(iGmDocument *); | 189 | iBool updateOpenURLs_GmDocument(iGmDocument *); |
198 | void setUrl_GmDocument (iGmDocument *, const iString *url); | 190 | void setUrl_GmDocument (iGmDocument *, const iString *url); |
199 | void setSource_GmDocument (iGmDocument *, const iString *source, int width, int outsideMargin, | 191 | void setSource_GmDocument (iGmDocument *, const iString *source, int width, int canvasWidth, |
200 | enum iGmDocumentUpdate updateType); | 192 | enum iGmDocumentUpdate updateType); |
201 | void foldPre_GmDocument (iGmDocument *, uint16_t preId); | 193 | void foldPre_GmDocument (iGmDocument *, uint16_t preId); |
202 | 194 | ||
@@ -204,8 +196,6 @@ void updateVisitedLinks_GmDocument (iGmDocument *); /* check all links for | |||
204 | void invalidatePalette_GmDocument (iGmDocument *); | 196 | void invalidatePalette_GmDocument (iGmDocument *); |
205 | void makePaletteGlobal_GmDocument (const iGmDocument *); /* copies document colors to the global palette */ | 197 | void makePaletteGlobal_GmDocument (const iGmDocument *); /* copies document colors to the global palette */ |
206 | 198 | ||
207 | //void reset_GmDocument (iGmDocument *); /* free images */ | ||
208 | |||
209 | typedef void (*iGmDocumentRenderFunc)(void *, const iGmRun *); | 199 | typedef void (*iGmDocumentRenderFunc)(void *, const iGmRun *); |
210 | 200 | ||
211 | iMedia * media_GmDocument (iGmDocument *); | 201 | iMedia * media_GmDocument (iGmDocument *); |
@@ -219,10 +209,6 @@ const iGmRun * renderProgressive_GmDocument(const iGmDocument *d, const iGmRun | |||
219 | iRangei visRangeY, iGmDocumentRenderFunc render, | 209 | iRangei visRangeY, iGmDocumentRenderFunc render, |
220 | void *context); | 210 | void *context); |
221 | iInt2 size_GmDocument (const iGmDocument *); | 211 | iInt2 size_GmDocument (const iGmDocument *); |
222 | //const iGmRun * siteBanner_GmDocument (const iGmDocument *); | ||
223 | //iBool hasSiteBanner_GmDocument (const iGmDocument *); | ||
224 | //enum iGmDocumentBanner bannerType_GmDocument(const iGmDocument *); | ||
225 | //const iString * bannerText_GmDocument (const iGmDocument *); | ||
226 | const iArray * headings_GmDocument (const iGmDocument *); /* array of GmHeadings */ | 212 | const iArray * headings_GmDocument (const iGmDocument *); /* array of GmHeadings */ |
227 | const iString * source_GmDocument (const iGmDocument *); | 213 | const iString * source_GmDocument (const iGmDocument *); |
228 | size_t memorySize_GmDocument (const iGmDocument *); /* bytes */ | 214 | size_t memorySize_GmDocument (const iGmDocument *); /* bytes */ |
diff --git a/src/history.c b/src/history.c index 208c239d..7185912f 100644 --- a/src/history.c +++ b/src/history.c | |||
@@ -440,6 +440,17 @@ void clearCache_History(iHistory *d) { | |||
440 | unlock_Mutex(d->mtx); | 440 | unlock_Mutex(d->mtx); |
441 | } | 441 | } |
442 | 442 | ||
443 | void invalidateCachedLayout_History(iHistory *d) { | ||
444 | lock_Mutex(d->mtx); | ||
445 | iForEach(Array, i, &d->recent) { | ||
446 | iRecentUrl *url = i.value; | ||
447 | if (url->cachedDoc) { | ||
448 | invalidateLayout_GmDocument(url->cachedDoc); | ||
449 | } | ||
450 | } | ||
451 | unlock_Mutex(d->mtx); | ||
452 | } | ||
453 | |||
443 | size_t pruneLeastImportant_History(iHistory *d) { | 454 | size_t pruneLeastImportant_History(iHistory *d) { |
444 | size_t delta = 0; | 455 | size_t delta = 0; |
445 | size_t chosen = iInvalidPos; | 456 | size_t chosen = iInvalidPos; |
diff --git a/src/history.h b/src/history.h index 7dad72df..d3daae80 100644 --- a/src/history.h +++ b/src/history.h | |||
@@ -76,6 +76,7 @@ void clearCache_History (iHistory *); | |||
76 | size_t pruneLeastImportant_History (iHistory *); | 76 | size_t pruneLeastImportant_History (iHistory *); |
77 | size_t pruneLeastImportantMemory_History (iHistory *); | 77 | size_t pruneLeastImportantMemory_History (iHistory *); |
78 | void invalidateTheme_History (iHistory *); /* theme has changed, cached contents need updating */ | 78 | void invalidateTheme_History (iHistory *); /* theme has changed, cached contents need updating */ |
79 | void invalidateCachedLayout_History (iHistory *); | ||
79 | 80 | ||
80 | iBool atLatest_History (const iHistory *); | 81 | iBool atLatest_History (const iHistory *); |
81 | iBool atOldest_History (const iHistory *); | 82 | iBool atOldest_History (const iHistory *); |
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 79bfea7b..8c24d4a9 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -1702,6 +1702,7 @@ static void updateDocument_DocumentWidget_(iDocumentWidget *d, | |||
1702 | } | 1702 | } |
1703 | if (cachedDoc) { | 1703 | if (cachedDoc) { |
1704 | replaceDocument_DocumentWidget_(d, cachedDoc); | 1704 | replaceDocument_DocumentWidget_(d, cachedDoc); |
1705 | updateWidth_GmDocument(d->doc, documentWidth_DocumentWidget_(d), width_Widget(d)); | ||
1705 | } | 1706 | } |
1706 | else if (setSource) { | 1707 | else if (setSource) { |
1707 | setSource_DocumentWidget(d, &str); | 1708 | setSource_DocumentWidget(d, &str); |
@@ -2498,7 +2499,7 @@ static iBool updateDocumentWidthRetainingScrollPosition_DocumentWidget_(iDocumen | |||
2498 | /* TODO: First *fully* visible run? */ | 2499 | /* TODO: First *fully* visible run? */ |
2499 | voffset = visibleRange_DocumentWidget_(d).start - top_Rect(run->visBounds); | 2500 | voffset = visibleRange_DocumentWidget_(d).start - top_Rect(run->visBounds); |
2500 | } | 2501 | } |
2501 | setWidth_GmDocument(d->doc, newWidth, (width_Widget(d) - newWidth) / 2); | 2502 | setWidth_GmDocument(d->doc, newWidth, width_Widget(d)); |
2502 | setWidth_Banner(d->banner, newWidth); | 2503 | setWidth_Banner(d->banner, newWidth); |
2503 | documentRunsInvalidated_DocumentWidget_(d); | 2504 | documentRunsInvalidated_DocumentWidget_(d); |
2504 | if (runLoc && !keepCenter) { | 2505 | if (runLoc && !keepCenter) { |
@@ -2734,6 +2735,9 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
2734 | } | 2735 | } |
2735 | else if (equal_Command(cmd, "window.resized") || equal_Command(cmd, "font.changed") || | 2736 | else if (equal_Command(cmd, "window.resized") || equal_Command(cmd, "font.changed") || |
2736 | equal_Command(cmd, "keyroot.changed")) { | 2737 | equal_Command(cmd, "keyroot.changed")) { |
2738 | if (equal_Command(cmd, "font.changed")) { | ||
2739 | invalidateCachedLayout_History(d->mod.history); | ||
2740 | } | ||
2737 | /* Alt/Option key may be involved in window size changes. */ | 2741 | /* Alt/Option key may be involved in window size changes. */ |
2738 | setLinkNumberMode_DocumentWidget_(d, iFalse); | 2742 | setLinkNumberMode_DocumentWidget_(d, iFalse); |
2739 | d->phoneToolbar = findWidget_App("toolbar"); | 2743 | d->phoneToolbar = findWidget_App("toolbar"); |