summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2021-11-03 07:09:16 +0200
committerJaakko Keränen <jaakko.keranen@iki.fi>2021-11-03 07:09:16 +0200
commitf4172885428f9849ff29bd09490db8b167a8d705 (patch)
treec82af9c46bce0f56627e61d180a630e11fb8baee
parent20b5a9bbad524e242b7ade9fdcd06f34721c5f3a (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.c12
-rw-r--r--src/gmdocument.c34
-rw-r--r--src/gmdocument.h22
-rw-r--r--src/history.c11
-rw-r--r--src/history.h1
-rw-r--r--src/ui/documentwidget.c6
6 files changed, 51 insertions, 35 deletions
diff --git a/src/app.c b/src/app.c
index 73771609..63a286f8 100644
--- a/src/app.c
+++ b/src/app.c
@@ -2125,6 +2125,12 @@ void resetFonts_App(void) {
2125 } 2125 }
2126} 2126}
2127 2127
2128static void invalidateCachedDocuments_App_(void) {
2129 iForEach(ObjectList, i, iClob(listDocuments_App(NULL))) {
2130 invalidateCachedLayout_History(history_DocumentWidget(i.object));
2131 }
2132}
2133
2128iBool handleCommand_App(const char *cmd) { 2134iBool 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) {
1166void deinit_GmDocument(iGmDocument *d) { 1165void 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 1723void setWidth_GmDocument(iGmDocument *d, int width, int canvasWidth) {
1726void 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
1731void setWidth_GmDocument(iGmDocument *d, int width, int outsideMargin) { 1729iBool 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
1737void redoLayout_GmDocument(iGmDocument *d) { 1737void redoLayout_GmDocument(iGmDocument *d) {
1738 doLayout_GmDocument_(d); 1738 doLayout_GmDocument_(d);
1739} 1739}
1740 1740
1741void invalidateLayout_GmDocument(iGmDocument *d) {
1742 d->isLayoutInvalidated = iTrue;
1743}
1744
1741static void markLinkRunsVisited_GmDocument_(iGmDocument *d, const iIntSet *linkIds) { 1745static 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
2085void setSource_GmDocument(iGmDocument *d, const iString *source, int width, int outsideMargin, 2089void 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
2130void foldPre_GmDocument(iGmDocument *d, uint16_t preId) { 2134void 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/*
181enum iGmDocumentBanner {
182 none_GmDocumentBanner,
183 siteDomain_GmDocumentBanner,
184 certificateWarning_GmDocumentBanner,
185};*/
186
187enum iGmDocumentUpdate { 178enum 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
192void setThemeSeed_GmDocument (iGmDocument *, const iBlock *seed); 183void setThemeSeed_GmDocument (iGmDocument *, const iBlock *seed);
193void setFormat_GmDocument (iGmDocument *, enum iSourceFormat format); 184void setFormat_GmDocument (iGmDocument *, enum iSourceFormat format);
194//void setBanner_GmDocument (iGmDocument *, enum iGmDocumentBanner type); 185void setWidth_GmDocument (iGmDocument *, int width, int canvasWidth);
195void setWidth_GmDocument (iGmDocument *, int width, int outsideMargin); 186iBool updateWidth_GmDocument (iGmDocument *, int width, int canvasWidth);
196void redoLayout_GmDocument (iGmDocument *); 187void redoLayout_GmDocument (iGmDocument *);
188void invalidateLayout_GmDocument(iGmDocument *); /* will have to be redone later */
197iBool updateOpenURLs_GmDocument(iGmDocument *); 189iBool updateOpenURLs_GmDocument(iGmDocument *);
198void setUrl_GmDocument (iGmDocument *, const iString *url); 190void setUrl_GmDocument (iGmDocument *, const iString *url);
199void setSource_GmDocument (iGmDocument *, const iString *source, int width, int outsideMargin, 191void setSource_GmDocument (iGmDocument *, const iString *source, int width, int canvasWidth,
200 enum iGmDocumentUpdate updateType); 192 enum iGmDocumentUpdate updateType);
201void foldPre_GmDocument (iGmDocument *, uint16_t preId); 193void foldPre_GmDocument (iGmDocument *, uint16_t preId);
202 194
@@ -204,8 +196,6 @@ void updateVisitedLinks_GmDocument (iGmDocument *); /* check all links for
204void invalidatePalette_GmDocument (iGmDocument *); 196void invalidatePalette_GmDocument (iGmDocument *);
205void makePaletteGlobal_GmDocument (const iGmDocument *); /* copies document colors to the global palette */ 197void makePaletteGlobal_GmDocument (const iGmDocument *); /* copies document colors to the global palette */
206 198
207//void reset_GmDocument (iGmDocument *); /* free images */
208
209typedef void (*iGmDocumentRenderFunc)(void *, const iGmRun *); 199typedef void (*iGmDocumentRenderFunc)(void *, const iGmRun *);
210 200
211iMedia * media_GmDocument (iGmDocument *); 201iMedia * 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);
221iInt2 size_GmDocument (const iGmDocument *); 211iInt2 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 *);
226const iArray * headings_GmDocument (const iGmDocument *); /* array of GmHeadings */ 212const iArray * headings_GmDocument (const iGmDocument *); /* array of GmHeadings */
227const iString * source_GmDocument (const iGmDocument *); 213const iString * source_GmDocument (const iGmDocument *);
228size_t memorySize_GmDocument (const iGmDocument *); /* bytes */ 214size_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
443void 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
443size_t pruneLeastImportant_History(iHistory *d) { 454size_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 *);
76size_t pruneLeastImportant_History (iHistory *); 76size_t pruneLeastImportant_History (iHistory *);
77size_t pruneLeastImportantMemory_History (iHistory *); 77size_t pruneLeastImportantMemory_History (iHistory *);
78void invalidateTheme_History (iHistory *); /* theme has changed, cached contents need updating */ 78void invalidateTheme_History (iHistory *); /* theme has changed, cached contents need updating */
79void invalidateCachedLayout_History (iHistory *);
79 80
80iBool atLatest_History (const iHistory *); 81iBool atLatest_History (const iHistory *);
81iBool atOldest_History (const iHistory *); 82iBool 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");