summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2021-12-30 09:25:33 +0200
committerJaakko Keränen <jaakko.keranen@iki.fi>2021-12-30 09:25:33 +0200
commit084da73bd33bea50a811f72b15117be967a5f674 (patch)
tree40e060232f9f14419035586a6379a34349375920
parent0e5047069b5782b39620af8a5fd31d57ba9809e5 (diff)
DocumentWidget: Inlining "image/*" responses
Image responses get inlined on gemtext pages. It would make sense to use this mechanism for all media since the MIME type is ultimately what matters in determining the appropriate presentation. The file extensions shouldn't matter. IssueID #373
-rw-r--r--src/app.c1
-rw-r--r--src/history.c9
-rw-r--r--src/history.h1
-rw-r--r--src/media.c11
-rw-r--r--src/media.h3
-rw-r--r--src/ui/documentwidget.c60
6 files changed, 69 insertions, 16 deletions
diff --git a/src/app.c b/src/app.c
index bdc3a733..f10a4768 100644
--- a/src/app.c
+++ b/src/app.c
@@ -2828,6 +2828,7 @@ iBool handleCommand_App(const char *cmd) {
2828 const iBool isHistory = argLabel_Command(cmd, "history") != 0; 2828 const iBool isHistory = argLabel_Command(cmd, "history") != 0;
2829 int redirectCount = argLabel_Command(cmd, "redirect"); 2829 int redirectCount = argLabel_Command(cmd, "redirect");
2830 if (!isHistory) { 2830 if (!isHistory) {
2831 /* TODO: Shouldn't DocumentWidget manage history on its own? */
2831 if (redirectCount) { 2832 if (redirectCount) {
2832 replace_History(history, url); 2833 replace_History(history, url);
2833 } 2834 }
diff --git a/src/history.c b/src/history.c
index 837b38cb..56454009 100644
--- a/src/history.c
+++ b/src/history.c
@@ -310,6 +310,15 @@ void add_History(iHistory *d, const iString *url) {
310 unlock_Mutex(d->mtx); 310 unlock_Mutex(d->mtx);
311} 311}
312 312
313void undo_History(iHistory *d) {
314 lock_Mutex(d->mtx);
315 if (!isEmpty_Array(&d->recent) || d->recentPos != 0) {
316 deinit_RecentUrl(back_Array(&d->recent));
317 popBack_Array(&d->recent);
318 }
319 unlock_Mutex(d->mtx);
320}
321
313iRecentUrl *precedingLocked_History(iHistory *d) { 322iRecentUrl *precedingLocked_History(iHistory *d) {
314 /* NOTE: Manual lock and unlock are required when using this; returning an internal pointer. */ 323 /* NOTE: Manual lock and unlock are required when using this; returning an internal pointer. */
315 iBool ok = iFalse; 324 iBool ok = iFalse;
diff --git a/src/history.h b/src/history.h
index 383c132b..7959187d 100644
--- a/src/history.h
+++ b/src/history.h
@@ -61,6 +61,7 @@ void unlock_History (iHistory *);
61 61
62void clear_History (iHistory *); 62void clear_History (iHistory *);
63void add_History (iHistory *, const iString *url); 63void add_History (iHistory *, const iString *url);
64void undo_History (iHistory *); /* removes the most recent URL */
64void replace_History (iHistory *, const iString *url); 65void replace_History (iHistory *, const iString *url);
65void setCachedResponse_History (iHistory *, const iGmResponse *response); 66void setCachedResponse_History (iHistory *, const iGmResponse *response);
66void setCachedDocument_History (iHistory *, iGmDocument *doc); 67void setCachedDocument_History (iHistory *, iGmDocument *doc);
diff --git a/src/media.c b/src/media.c
index c02090b0..4940c13e 100644
--- a/src/media.c
+++ b/src/media.c
@@ -629,6 +629,17 @@ void deinit_MediaRequest(iMediaRequest *d) {
629 iRelease(d->req); 629 iRelease(d->req);
630} 630}
631 631
632iMediaRequest *newReused_MediaRequest(iDocumentWidget *doc, unsigned int linkId,
633 iGmRequest *request) {
634 iMediaRequest *d = new_Object(&Class_MediaRequest);
635 d->doc = doc;
636 d->linkId = linkId;
637 d->req = request; /* takes ownership */
638 iConnect(GmRequest, d->req, updated, d, updated_MediaRequest_);
639 iConnect(GmRequest, d->req, finished, d, finished_MediaRequest_);
640 return d;
641}
642
632iDefineObjectConstructionArgs(MediaRequest, 643iDefineObjectConstructionArgs(MediaRequest,
633 (iDocumentWidget *doc, unsigned int linkId, const iString *url, 644 (iDocumentWidget *doc, unsigned int linkId, const iString *url,
634 iBool enableFilters), 645 iBool enableFilters),
diff --git a/src/media.h b/src/media.h
index 3b329716..584c77eb 100644
--- a/src/media.h
+++ b/src/media.h
@@ -123,3 +123,6 @@ struct Impl_MediaRequest {
123 123
124iDeclareObjectConstructionArgs(MediaRequest, iDocumentWidget *doc, unsigned int linkId, 124iDeclareObjectConstructionArgs(MediaRequest, iDocumentWidget *doc, unsigned int linkId,
125 const iString *url, iBool enableFilters) 125 const iString *url, iBool enableFilters)
126
127iMediaRequest * newReused_MediaRequest (iDocumentWidget *doc, unsigned int linkId,
128 iGmRequest *request);
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index cbd32066..f9efdd28 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -20,8 +20,8 @@ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 20(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ 21SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
22 22
23/* TODO: This file is a little (!) too large. DocumentWidget could be split into 23/* TODO: Move DocumentView into a source file of its own. Consider cleaning up the network
24 a couple of smaller objects. One for rendering the document, for instance. */ 24 request handling. */
25 25
26#include "documentwidget.h" 26#include "documentwidget.h"
27 27
@@ -297,6 +297,7 @@ struct Impl_DocumentWidget {
297 /* Network request: */ 297 /* Network request: */
298 enum iRequestState state; 298 enum iRequestState state;
299 iGmRequest * request; 299 iGmRequest * request;
300 iGmLinkId requestLinkId; /* ID of the link that initiated the current request */
300 iAtomicInt isRequestUpdated; /* request has new content, need to parse it */ 301 iAtomicInt isRequestUpdated; /* request has new content, need to parse it */
301 int certFlags; 302 int certFlags;
302 iBlock * certFingerprint; 303 iBlock * certFingerprint;
@@ -1079,9 +1080,9 @@ static size_t visibleLinkOrdinal_DocumentView_(const iDocumentView *d, iGmLinkId
1079} 1080}
1080 1081
1081static void documentRunsInvalidated_DocumentWidget_(iDocumentWidget *d) { 1082static void documentRunsInvalidated_DocumentWidget_(iDocumentWidget *d) {
1082 d->foundMark = iNullRange; 1083 d->foundMark = iNullRange;
1083 d->selectMark = iNullRange; 1084 d->selectMark = iNullRange;
1084 d->contextLink = NULL; 1085 d->contextLink = NULL;
1085 documentRunsInvalidated_DocumentView_(&d->view); 1086 documentRunsInvalidated_DocumentView_(&d->view);
1086} 1087}
1087 1088
@@ -2136,6 +2137,7 @@ static void updateBanner_DocumentWidget_(iDocumentWidget *d) {
2136static void documentWasChanged_DocumentWidget_(iDocumentWidget *d) { 2137static void documentWasChanged_DocumentWidget_(iDocumentWidget *d) {
2137 iChangeFlags(d->flags, selecting_DocumentWidgetFlag, iFalse); 2138 iChangeFlags(d->flags, selecting_DocumentWidgetFlag, iFalse);
2138 setFlags_Widget(as_Widget(d), touchDrag_WidgetFlag, iFalse); 2139 setFlags_Widget(as_Widget(d), touchDrag_WidgetFlag, iFalse);
2140 d->requestLinkId = 0;
2139 updateVisitedLinks_GmDocument(d->view.doc); 2141 updateVisitedLinks_GmDocument(d->view.doc);
2140 documentRunsInvalidated_DocumentWidget_(d); 2142 documentRunsInvalidated_DocumentWidget_(d);
2141 updateWindowTitle_DocumentWidget_(d); 2143 updateWindowTitle_DocumentWidget_(d);
@@ -2746,11 +2748,8 @@ static void fetch_DocumentWidget_(iDocumentWidget *d) {
2746 "document.request.started doc:%p url:%s", 2748 "document.request.started doc:%p url:%s",
2747 d, 2749 d,
2748 cstr_String(d->mod.url)); 2750 cstr_String(d->mod.url));
2749 clear_ObjectList(d->media);
2750 d->certFlags = 0;
2751 setLinkNumberMode_DocumentWidget_(d, iFalse); 2751 setLinkNumberMode_DocumentWidget_(d, iFalse);
2752 d->flags &= ~drawDownloadCounter_DocumentWidgetFlag; 2752 d->flags &= ~drawDownloadCounter_DocumentWidgetFlag;
2753 d->flags &= ~fromCache_DocumentWidgetFlag;
2754 d->state = fetching_RequestState; 2753 d->state = fetching_RequestState;
2755 set_Atomic(&d->isRequestUpdated, iFalse); 2754 set_Atomic(&d->isRequestUpdated, iFalse);
2756 d->request = new_GmRequest(certs_App()); 2755 d->request = new_GmRequest(certs_App());
@@ -3043,6 +3042,14 @@ static const char *humanReadableStatusCode_(enum iGmStatusCode code) {
3043 return format_CStr("%d ", code); 3042 return format_CStr("%d ", code);
3044} 3043}
3045 3044
3045static void setUrl_DocumentWidget_(iDocumentWidget *d, const iString *url) {
3046 url = canonicalUrl_String(url);
3047 if (!equal_String(d->mod.url, url)) {
3048 d->flags |= urlChanged_DocumentWidgetFlag;
3049 set_String(d->mod.url, url);
3050 }
3051}
3052
3046static void checkResponse_DocumentWidget_(iDocumentWidget *d) { 3053static void checkResponse_DocumentWidget_(iDocumentWidget *d) {
3047 if (!d->request) { 3054 if (!d->request) {
3048 return; 3055 return;
@@ -3053,8 +3060,35 @@ static void checkResponse_DocumentWidget_(iDocumentWidget *d) {
3053 } 3060 }
3054 iGmResponse *resp = lockResponse_GmRequest(d->request); 3061 iGmResponse *resp = lockResponse_GmRequest(d->request);
3055 if (d->state == fetching_RequestState) { 3062 if (d->state == fetching_RequestState) {
3063 /* Under certain conditions, inline any image response into the current document. */
3064 if (d->requestLinkId &&
3065 isSuccess_GmStatusCode(d->sourceStatus) &&
3066 startsWithCase_String(&d->sourceMime, "text/gemini") &&
3067 isSuccess_GmStatusCode(statusCode) &&
3068 startsWithCase_String(&resp->meta, "image/")) {
3069 /* This request is turned into a new media request in the current document. */
3070 iDisconnect(GmRequest, d->request, updated, d, requestUpdated_DocumentWidget_);
3071 iDisconnect(GmRequest, d->request, finished, d, requestFinished_DocumentWidget_);
3072 iMediaRequest *mr = newReused_MediaRequest(d, d->requestLinkId, d->request);
3073 unlockResponse_GmRequest(d->request);
3074 d->request = NULL; /* ownership moved */
3075 postCommand_Widget(d, "document.request.cancelled doc:%p", d);
3076 pushBack_ObjectList(d->media, mr);
3077 iRelease(mr);
3078 /* Reset the fetch state, returning to the originating page. */
3079 d->state = ready_RequestState;
3080 if (equal_String(&mostRecentUrl_History(d->mod.history)->url, url_GmRequest(mr->req))) {
3081 undo_History(d->mod.history);
3082 }
3083 setUrl_DocumentWidget_(d, url_GmDocument(d->view.doc));
3084 updateFetchProgress_DocumentWidget_(d);
3085 postCommand_Widget(d, "media.updated link:%u request:%p", d->requestLinkId, mr);
3086 return;
3087 }
3088 /* Get ready for the incoming new document. */
3056 d->state = receivedPartialResponse_RequestState; 3089 d->state = receivedPartialResponse_RequestState;
3057 d->flags &= ~fromCache_DocumentWidgetFlag; 3090 d->flags &= ~fromCache_DocumentWidgetFlag;
3091 clear_ObjectList(d->media);
3058 updateTrust_DocumentWidget_(d, resp); 3092 updateTrust_DocumentWidget_(d, resp);
3059 if (isSuccess_GmStatusCode(statusCode)) { 3093 if (isSuccess_GmStatusCode(statusCode)) {
3060 clear_Banner(d->banner); 3094 clear_Banner(d->banner);
@@ -3441,14 +3475,6 @@ static iWidget *swipeParent_DocumentWidget_(iDocumentWidget *d) {
3441 return findChild_Widget(as_Widget(d)->root->widget, "doctabs"); 3475 return findChild_Widget(as_Widget(d)->root->widget, "doctabs");
3442} 3476}
3443 3477
3444static void setUrl_DocumentWidget_(iDocumentWidget *d, const iString *url) {
3445 url = canonicalUrl_String(url);
3446 if (!equal_String(d->mod.url, url)) {
3447 d->flags |= urlChanged_DocumentWidgetFlag;
3448 set_String(d->mod.url, url);
3449 }
3450}
3451
3452static void setupSwipeOverlay_DocumentWidget_(iDocumentWidget *d, iWidget *overlay) { 3478static void setupSwipeOverlay_DocumentWidget_(iDocumentWidget *d, iWidget *overlay) {
3453 iWidget *w = as_Widget(d); 3479 iWidget *w = as_Widget(d);
3454 iWidget *swipeParent = swipeParent_DocumentWidget_(d); 3480 iWidget *swipeParent = swipeParent_DocumentWidget_(d);
@@ -4598,6 +4624,7 @@ static void interactingWithLink_DocumentWidget_(iDocumentWidget *d, iGmLinkId id
4598 clear_String(&d->linePrecedingLink); 4624 clear_String(&d->linePrecedingLink);
4599 return; 4625 return;
4600 } 4626 }
4627 d->requestLinkId = id;
4601 const char *start = range_String(source_GmDocument(d->view.doc)).start; 4628 const char *start = range_String(source_GmDocument(d->view.doc)).start;
4602 /* Find the preceding line. This is offered as a prefill option for a possible input query. */ 4629 /* Find the preceding line. This is offered as a prefill option for a possible input query. */
4603 while (loc.start > start && *loc.start != '\n') { 4630 while (loc.start > start && *loc.start != '\n') {
@@ -5526,6 +5553,7 @@ void init_DocumentWidget(iDocumentWidget *d) {
5526 d->state = blank_RequestState; 5553 d->state = blank_RequestState;
5527 d->titleUser = new_String(); 5554 d->titleUser = new_String();
5528 d->request = NULL; 5555 d->request = NULL;
5556 d->requestLinkId = 0;
5529 d->isRequestUpdated = iFalse; 5557 d->isRequestUpdated = iFalse;
5530 d->media = new_ObjectList(); 5558 d->media = new_ObjectList();
5531 d->banner = new_Banner(); 5559 d->banner = new_Banner();