summaryrefslogtreecommitdiff
path: root/src/ui/documentwidget.c
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 /src/ui/documentwidget.c
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
Diffstat (limited to 'src/ui/documentwidget.c')
-rw-r--r--src/ui/documentwidget.c60
1 files changed, 44 insertions, 16 deletions
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();