diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-12-10 09:50:15 +0200 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-12-10 09:50:15 +0200 |
commit | 9741611c08d0f481a3f0583419b68b36d8711d1d (patch) | |
tree | de161bbc0bf04b47efa12b6b0e3f9b68b0e3085b | |
parent | 76259953925d42568c9ac80d6bb7732f1a9475be (diff) |
Fixed history with multiple items having the same URL
If there were multiple instances of the same URL in history, only the latest one's content would be used when navigating back/forward.
-rw-r--r-- | res/about/version.gmi | 3 | ||||
-rw-r--r-- | src/history.c | 32 | ||||
-rw-r--r-- | src/history.h | 2 | ||||
-rw-r--r-- | src/ui/documentwidget.c | 30 | ||||
-rw-r--r-- | src/ui/documentwidget.h | 5 |
5 files changed, 46 insertions, 26 deletions
diff --git a/res/about/version.gmi b/res/about/version.gmi index 506e3ae0..625e4ccb 100644 --- a/res/about/version.gmi +++ b/res/about/version.gmi | |||
@@ -10,6 +10,9 @@ | |||
10 | New features: | 10 | New features: |
11 | * Identity toolbar menu can be used to switch between alternate identities. If you have used multiple identities on one site, this makes it more convenient to switch between them. | 11 | * Identity toolbar menu can be used to switch between alternate identities. If you have used multiple identities on one site, this makes it more convenient to switch between them. |
12 | 12 | ||
13 | Fixes: | ||
14 | * Fixed a history caching issue: if there were multiple instances of the same URL in history, only the latest one's content would be used when navigating back/forward. | ||
15 | |||
13 | ## 1.9.2 | 16 | ## 1.9.2 |
14 | * Windows: Use the correct version number for update checks. | 17 | * Windows: Use the correct version number for update checks. |
15 | * Shorter label for "Mark All as Read" in Feeds sidebar actions. | 18 | * Shorter label for "Mark All as Read" in Feeds sidebar actions. |
diff --git a/src/history.c b/src/history.c index d1a731fb..50db33dd 100644 --- a/src/history.c +++ b/src/history.c | |||
@@ -254,18 +254,26 @@ const iString *url_History(const iHistory *d, size_t pos) { | |||
254 | return collectNew_String(); | 254 | return collectNew_String(); |
255 | } | 255 | } |
256 | 256 | ||
257 | iRecentUrl *findUrl_History(iHistory *d, const iString *url) { | 257 | #if 0 |
258 | iRecentUrl *findUrl_History(iHistory *d, const iString *url, int timeDir) { | ||
258 | url = canonicalUrl_String(url); | 259 | url = canonicalUrl_String(url); |
260 | // if (!timeDir) { | ||
261 | // timeDir = -1; | ||
262 | // } | ||
259 | lock_Mutex(d->mtx); | 263 | lock_Mutex(d->mtx); |
260 | iReverseForEach(Array, i, &d->recent) { | 264 | for (size_t i = size_Array(&d->recent) - 1 - d->recentPos; i < size_Array(&d->recent); |
261 | if (cmpStringCase_String(url, &((iRecentUrl *) i.value)->url) == 0) { | 265 | i += timeDir) { |
266 | iRecentUrl *item = at_Array(&d->recent, i); | ||
267 | if (cmpStringCase_String(url, &item->url) == 0) { | ||
262 | unlock_Mutex(d->mtx); | 268 | unlock_Mutex(d->mtx); |
263 | return i.value; | 269 | return item; /* FIXME: Returning an internal pointer; should remain locked. */ |
264 | } | 270 | } |
271 | if (!timeDir) break; | ||
265 | } | 272 | } |
266 | unlock_Mutex(d->mtx); | 273 | unlock_Mutex(d->mtx); |
267 | return NULL; | 274 | return NULL; |
268 | } | 275 | } |
276 | #endif | ||
269 | 277 | ||
270 | void replace_History(iHistory *d, const iString *url) { | 278 | void replace_History(iHistory *d, const iString *url) { |
271 | url = canonicalUrl_String(url); | 279 | url = canonicalUrl_String(url); |
@@ -405,20 +413,18 @@ void setCachedDocument_History(iHistory *d, iGmDocument *doc, iBool openedFromSi | |||
405 | lock_Mutex(d->mtx); | 413 | lock_Mutex(d->mtx); |
406 | iRecentUrl *item = mostRecentUrl_History(d); | 414 | iRecentUrl *item = mostRecentUrl_History(d); |
407 | if (item) { | 415 | if (item) { |
408 | if (equal_String(url_GmDocument(doc), &item->url)) { | ||
409 | item->flags.openedFromSidebar = openedFromSidebar; | ||
410 | if (item->cachedDoc != doc) { | ||
411 | iRelease(item->cachedDoc); | ||
412 | item->cachedDoc = ref_Object(doc); | ||
413 | } | ||
414 | } | ||
415 | #if !defined (NDEBUG) | 416 | #if !defined (NDEBUG) |
416 | else { | 417 | if (!equal_String(url_GmDocument(doc), &item->url)) { |
417 | printf("[History] Not updating cached document; expecting {%s} but document URL is {%s}\n", | 418 | printf("[History] Cache mismatch! Expecting data for item {%s} but document URL is {%s}\n", |
418 | cstr_String(&item->url), | 419 | cstr_String(&item->url), |
419 | cstr_String(url_GmDocument(doc))); | 420 | cstr_String(url_GmDocument(doc))); |
420 | } | 421 | } |
421 | #endif | 422 | #endif |
423 | item->flags.openedFromSidebar = openedFromSidebar; | ||
424 | if (item->cachedDoc != doc) { | ||
425 | iRelease(item->cachedDoc); | ||
426 | item->cachedDoc = ref_Object(doc); | ||
427 | } | ||
422 | } | 428 | } |
423 | unlock_Mutex(d->mtx); | 429 | unlock_Mutex(d->mtx); |
424 | } | 430 | } |
diff --git a/src/history.h b/src/history.h index 3bb3808e..bfb88cf4 100644 --- a/src/history.h +++ b/src/history.h | |||
@@ -71,7 +71,7 @@ iBool goForward_History (iHistory *); | |||
71 | iRecentUrl *precedingLocked_History (iHistory *); /* requires manual lock/unlock! */ | 71 | iRecentUrl *precedingLocked_History (iHistory *); /* requires manual lock/unlock! */ |
72 | iRecentUrl *recentUrl_History (iHistory *, size_t pos); | 72 | iRecentUrl *recentUrl_History (iHistory *, size_t pos); |
73 | iRecentUrl *mostRecentUrl_History (iHistory *); | 73 | iRecentUrl *mostRecentUrl_History (iHistory *); |
74 | iRecentUrl *findUrl_History (iHistory *, const iString *url); | 74 | //iRecentUrl *findUrl_History (iHistory *, const iString *url, int timeDir); |
75 | 75 | ||
76 | void clearCache_History (iHistory *); | 76 | void clearCache_History (iHistory *); |
77 | size_t pruneLeastImportant_History (iHistory *); | 77 | size_t pruneLeastImportant_History (iHistory *); |
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index a9a0e07c..e68af4d8 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -231,6 +231,8 @@ enum iDocumentWidgetFlag { | |||
231 | urlChanged_DocumentWidgetFlag = iBit(13), | 231 | urlChanged_DocumentWidgetFlag = iBit(13), |
232 | openedFromSidebar_DocumentWidgetFlag = iBit(14), | 232 | openedFromSidebar_DocumentWidgetFlag = iBit(14), |
233 | drawDownloadCounter_DocumentWidgetFlag = iBit(15), | 233 | drawDownloadCounter_DocumentWidgetFlag = iBit(15), |
234 | fromCache_DocumentWidgetFlag = iBit(16), /* don't write anything to cache */ | ||
235 | animationPlaceholder_DocumentWidgetFlag = iBit(17), /* avoid slow operations */ | ||
234 | }; | 236 | }; |
235 | 237 | ||
236 | enum iDocumentLinkOrdinalMode { | 238 | enum iDocumentLinkOrdinalMode { |
@@ -1142,9 +1144,11 @@ static void documentWasChanged_DocumentWidget_(iDocumentWidget *d) { | |||
1142 | } | 1144 | } |
1143 | } | 1145 | } |
1144 | showOrHidePinningIndicator_DocumentWidget_(d); | 1146 | showOrHidePinningIndicator_DocumentWidget_(d); |
1145 | setCachedDocument_History(d->mod.history, | 1147 | if (~d->flags & fromCache_DocumentWidgetFlag) { |
1146 | d->doc, /* keeps a ref */ | 1148 | setCachedDocument_History(d->mod.history, |
1147 | (d->flags & openedFromSidebar_DocumentWidgetFlag) != 0); | 1149 | d->doc, /* keeps a ref */ |
1150 | (d->flags & openedFromSidebar_DocumentWidgetFlag) != 0); | ||
1151 | } | ||
1148 | } | 1152 | } |
1149 | 1153 | ||
1150 | void setSource_DocumentWidget(iDocumentWidget *d, const iString *source) { | 1154 | void setSource_DocumentWidget(iDocumentWidget *d, const iString *source) { |
@@ -1743,6 +1747,7 @@ static void updateDocument_DocumentWidget_(iDocumentWidget *d, | |||
1743 | } | 1747 | } |
1744 | 1748 | ||
1745 | static void fetch_DocumentWidget_(iDocumentWidget *d) { | 1749 | static void fetch_DocumentWidget_(iDocumentWidget *d) { |
1750 | iAssert(~d->flags & animationPlaceholder_DocumentWidgetFlag); | ||
1746 | /* Forget the previous request. */ | 1751 | /* Forget the previous request. */ |
1747 | if (d->request) { | 1752 | if (d->request) { |
1748 | iRelease(d->request); | 1753 | iRelease(d->request); |
@@ -1756,6 +1761,7 @@ static void fetch_DocumentWidget_(iDocumentWidget *d) { | |||
1756 | d->certFlags = 0; | 1761 | d->certFlags = 0; |
1757 | setLinkNumberMode_DocumentWidget_(d, iFalse); | 1762 | setLinkNumberMode_DocumentWidget_(d, iFalse); |
1758 | d->flags &= ~drawDownloadCounter_DocumentWidgetFlag; | 1763 | d->flags &= ~drawDownloadCounter_DocumentWidgetFlag; |
1764 | d->flags &= ~fromCache_DocumentWidgetFlag; | ||
1759 | d->state = fetching_RequestState; | 1765 | d->state = fetching_RequestState; |
1760 | set_Atomic(&d->isRequestUpdated, iFalse); | 1766 | set_Atomic(&d->isRequestUpdated, iFalse); |
1761 | d->request = new_GmRequest(certs_App()); | 1767 | d->request = new_GmRequest(certs_App()); |
@@ -1805,7 +1811,8 @@ static void cacheRunGlyphs_(void *data, const iGmRun *run) { | |||
1805 | } | 1811 | } |
1806 | 1812 | ||
1807 | static void cacheDocumentGlyphs_DocumentWidget_(const iDocumentWidget *d) { | 1813 | static void cacheDocumentGlyphs_DocumentWidget_(const iDocumentWidget *d) { |
1808 | if (isFinishedLaunching_App() && isExposed_Window(get_Window())) { | 1814 | if (isFinishedLaunching_App() && isExposed_Window(get_Window()) && |
1815 | ~d->flags & animationPlaceholder_DocumentWidgetFlag) { | ||
1809 | /* Just cache the top of the document, since this is what we usually need. */ | 1816 | /* Just cache the top of the document, since this is what we usually need. */ |
1810 | int maxY = height_Widget(&d->widget) * 2; | 1817 | int maxY = height_Widget(&d->widget) * 2; |
1811 | if (maxY == 0) { | 1818 | if (maxY == 0) { |
@@ -1885,6 +1892,7 @@ static void updateFromCachedResponse_DocumentWidget_(iDocumentWidget *d, float n | |||
1885 | d->doc = new_GmDocument(); | 1892 | d->doc = new_GmDocument(); |
1886 | resetWideRuns_DocumentWidget_(d); | 1893 | resetWideRuns_DocumentWidget_(d); |
1887 | d->state = fetching_RequestState; | 1894 | d->state = fetching_RequestState; |
1895 | d->flags |= fromCache_DocumentWidgetFlag; | ||
1888 | /* Do the fetch. */ { | 1896 | /* Do the fetch. */ { |
1889 | d->initNormScrollY = normScrollY; | 1897 | d->initNormScrollY = normScrollY; |
1890 | /* Use the cached response data. */ | 1898 | /* Use the cached response data. */ |
@@ -1916,7 +1924,8 @@ static void updateFromCachedResponse_DocumentWidget_(iDocumentWidget *d, float n | |||
1916 | } | 1924 | } |
1917 | 1925 | ||
1918 | static iBool updateFromHistory_DocumentWidget_(iDocumentWidget *d) { | 1926 | static iBool updateFromHistory_DocumentWidget_(iDocumentWidget *d) { |
1919 | const iRecentUrl *recent = findUrl_History(d->mod.history, d->mod.url); | 1927 | const iRecentUrl *recent = constMostRecentUrl_History(d->mod.history); |
1928 | iAssert(equalCase_String(&recent->url, d->mod.url)); | ||
1920 | if (recent && recent->cachedResponse) { | 1929 | if (recent && recent->cachedResponse) { |
1921 | iChangeFlags(d->flags, | 1930 | iChangeFlags(d->flags, |
1922 | openedFromSidebar_DocumentWidgetFlag, | 1931 | openedFromSidebar_DocumentWidgetFlag, |
@@ -2677,6 +2686,7 @@ static iBool handleSwipe_DocumentWidget_(iDocumentWidget *d, const char *cmd) { | |||
2677 | iDocumentWidget *swipeIn = findChild_Widget(swipeParent, "swipein"); | 2686 | iDocumentWidget *swipeIn = findChild_Widget(swipeParent, "swipein"); |
2678 | if (!swipeIn) { | 2687 | if (!swipeIn) { |
2679 | swipeIn = new_DocumentWidget(); | 2688 | swipeIn = new_DocumentWidget(); |
2689 | swipeIn->flags |= animationPlaceholder_DocumentWidgetFlag; | ||
2680 | setId_Widget(as_Widget(swipeIn), "swipein"); | 2690 | setId_Widget(as_Widget(swipeIn), "swipein"); |
2681 | setFlags_Widget(as_Widget(swipeIn), | 2691 | setFlags_Widget(as_Widget(swipeIn), |
2682 | disabled_WidgetFlag | refChildrenOffset_WidgetFlag | | 2692 | disabled_WidgetFlag | refChildrenOffset_WidgetFlag | |
@@ -2718,6 +2728,7 @@ static iBool handleSwipe_DocumentWidget_(iDocumentWidget *d, const char *cmd) { | |||
2718 | /* Set up the swipe dummy. */ | 2728 | /* Set up the swipe dummy. */ |
2719 | iWidget *swipeParent = swipeParent_DocumentWidget_(d); | 2729 | iWidget *swipeParent = swipeParent_DocumentWidget_(d); |
2720 | iDocumentWidget *target = new_DocumentWidget(); | 2730 | iDocumentWidget *target = new_DocumentWidget(); |
2731 | target->flags |= animationPlaceholder_DocumentWidgetFlag; | ||
2721 | setId_Widget(as_Widget(target), "swipeout"); | 2732 | setId_Widget(as_Widget(target), "swipeout"); |
2722 | /* "swipeout" takes `d`'s document and goes underneath. */ | 2733 | /* "swipeout" takes `d`'s document and goes underneath. */ |
2723 | target->widget.rect.pos = windowToInner_Widget(swipeParent, localToWindow_Widget(w, w->rect.pos)); | 2734 | target->widget.rect.pos = windowToInner_Widget(swipeParent, localToWindow_Widget(w, w->rect.pos)); |
@@ -2785,6 +2796,7 @@ static iBool handleSwipe_DocumentWidget_(iDocumentWidget *d, const char *cmd) { | |||
2785 | /* What was being shown in the `d` document is now being swapped to | 2796 | /* What was being shown in the `d` document is now being swapped to |
2786 | the outgoing page animation. */ | 2797 | the outgoing page animation. */ |
2787 | iDocumentWidget *target = new_DocumentWidget(); | 2798 | iDocumentWidget *target = new_DocumentWidget(); |
2799 | target->flags |= animationPlaceholder_DocumentWidgetFlag; | ||
2788 | addChildPos_Widget(swipeParent, iClob(target), back_WidgetAddPos); | 2800 | addChildPos_Widget(swipeParent, iClob(target), back_WidgetAddPos); |
2789 | setId_Widget(as_Widget(target), "swipeout"); | 2801 | setId_Widget(as_Widget(target), "swipeout"); |
2790 | swap_DocumentWidget_(target, d->doc, d); | 2802 | swap_DocumentWidget_(target, d->doc, d); |
@@ -2967,7 +2979,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
2967 | timeVerified_GmCertFlag); | 2979 | timeVerified_GmCertFlag); |
2968 | const iBool canTrust = ~d->certFlags & trusted_GmCertFlag && | 2980 | const iBool canTrust = ~d->certFlags & trusted_GmCertFlag && |
2969 | ((d->certFlags & requiredForTrust) == requiredForTrust); | 2981 | ((d->certFlags & requiredForTrust) == requiredForTrust); |
2970 | const iRecentUrl *recent = findUrl_History(d->mod.history, d->mod.url); | 2982 | const iRecentUrl *recent = constMostRecentUrl_History(d->mod.history); |
2971 | const iString *meta = &d->sourceMime; | 2983 | const iString *meta = &d->sourceMime; |
2972 | if (recent && recent->cachedResponse) { | 2984 | if (recent && recent->cachedResponse) { |
2973 | meta = &recent->cachedResponse->meta; | 2985 | meta = &recent->cachedResponse->meta; |
@@ -3178,6 +3190,8 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
3178 | postProcessRequestContent_DocumentWidget_(d, iFalse); | 3190 | postProcessRequestContent_DocumentWidget_(d, iFalse); |
3179 | /* The response may be cached. */ | 3191 | /* The response may be cached. */ |
3180 | if (d->request) { | 3192 | if (d->request) { |
3193 | iAssert(~d->flags & animationPlaceholder_DocumentWidgetFlag); | ||
3194 | iAssert(~d->flags & fromCache_DocumentWidgetFlag); | ||
3181 | if (!equal_Rangecc(urlScheme_String(d->mod.url), "about") && | 3195 | if (!equal_Rangecc(urlScheme_String(d->mod.url), "about") && |
3182 | (startsWithCase_String(meta_GmRequest(d->request), "text/") || | 3196 | (startsWithCase_String(meta_GmRequest(d->request), "text/") || |
3183 | !cmp_String(&d->sourceMime, mimeType_Gempub))) { | 3197 | !cmp_String(&d->sourceMime, mimeType_Gempub))) { |
@@ -5399,12 +5413,12 @@ void deserializeState_DocumentWidget(iDocumentWidget *d, iStream *ins) { | |||
5399 | void setUrlFlags_DocumentWidget(iDocumentWidget *d, const iString *url, int setUrlFlags) { | 5413 | void setUrlFlags_DocumentWidget(iDocumentWidget *d, const iString *url, int setUrlFlags) { |
5400 | iChangeFlags(d->flags, openedFromSidebar_DocumentWidgetFlag, | 5414 | iChangeFlags(d->flags, openedFromSidebar_DocumentWidgetFlag, |
5401 | (setUrlFlags & openedFromSidebar_DocumentWidgetSetUrlFlag) != 0); | 5415 | (setUrlFlags & openedFromSidebar_DocumentWidgetSetUrlFlag) != 0); |
5402 | const iBool isFromCache = (setUrlFlags & useCachedContentIfAvailable_DocumentWidgetSetUrlFlag) != 0; | 5416 | const iBool allowCache = (setUrlFlags & useCachedContentIfAvailable_DocumentWidgetSetUrlFlag) != 0; |
5403 | setLinkNumberMode_DocumentWidget_(d, iFalse); | 5417 | setLinkNumberMode_DocumentWidget_(d, iFalse); |
5404 | setUrl_DocumentWidget_(d, urlFragmentStripped_String(url)); | 5418 | setUrl_DocumentWidget_(d, urlFragmentStripped_String(url)); |
5405 | /* See if there a username in the URL. */ | 5419 | /* See if there a username in the URL. */ |
5406 | parseUser_DocumentWidget_(d); | 5420 | parseUser_DocumentWidget_(d); |
5407 | if (!isFromCache || !updateFromHistory_DocumentWidget_(d)) { | 5421 | if (!allowCache || !updateFromHistory_DocumentWidget_(d)) { |
5408 | fetch_DocumentWidget_(d); | 5422 | fetch_DocumentWidget_(d); |
5409 | } | 5423 | } |
5410 | } | 5424 | } |
diff --git a/src/ui/documentwidget.h b/src/ui/documentwidget.h index 2df3392b..c97fa0ba 100644 --- a/src/ui/documentwidget.h +++ b/src/ui/documentwidget.h | |||
@@ -48,12 +48,9 @@ const iString * bookmarkTitle_DocumentWidget (const iDocumentWidget *); | |||
48 | const iString * feedTitle_DocumentWidget (const iDocumentWidget *); | 48 | const iString * feedTitle_DocumentWidget (const iDocumentWidget *); |
49 | int documentWidth_DocumentWidget (const iDocumentWidget *); | 49 | int documentWidth_DocumentWidget (const iDocumentWidget *); |
50 | 50 | ||
51 | //iBool findCachedContent_DocumentWidget(const iDocumentWidget *, const iString *url, | ||
52 | // iString *mime_out, iBlock *data_out); | ||
53 | |||
54 | enum iDocumentWidgetSetUrlFlags { | 51 | enum iDocumentWidgetSetUrlFlags { |
55 | useCachedContentIfAvailable_DocumentWidgetSetUrlFlag = iBit(1), | 52 | useCachedContentIfAvailable_DocumentWidgetSetUrlFlag = iBit(1), |
56 | openedFromSidebar_DocumentWidgetSetUrlFlag = iBit(2), | 53 | openedFromSidebar_DocumentWidgetSetUrlFlag = iBit(2), |
57 | }; | 54 | }; |
58 | 55 | ||
59 | void setUrl_DocumentWidget (iDocumentWidget *, const iString *url); | 56 | void setUrl_DocumentWidget (iDocumentWidget *, const iString *url); |