diff options
Diffstat (limited to 'src/ui')
-rw-r--r-- | src/ui/documentwidget.c | 42 | ||||
-rw-r--r-- | src/ui/documentwidget.h | 1 | ||||
-rw-r--r-- | src/ui/text.c | 8 |
3 files changed, 40 insertions, 11 deletions
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 7450ba12..dd119e3e 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -5,6 +5,7 @@ | |||
5 | #include "paint.h" | 5 | #include "paint.h" |
6 | #include "command.h" | 6 | #include "command.h" |
7 | #include "util.h" | 7 | #include "util.h" |
8 | #include "history.h" | ||
8 | #include "app.h" | 9 | #include "app.h" |
9 | #include "../gmdocument.h" | 10 | #include "../gmdocument.h" |
10 | #include "../gmrequest.h" | 11 | #include "../gmrequest.h" |
@@ -91,6 +92,7 @@ struct Impl_DocumentWidget { | |||
91 | iPtrArray visibleLinks; | 92 | iPtrArray visibleLinks; |
92 | const iGmRun *hoverLink; | 93 | const iGmRun *hoverLink; |
93 | iClick click; | 94 | iClick click; |
95 | int initialScrollY; | ||
94 | iScrollWidget *scroll; | 96 | iScrollWidget *scroll; |
95 | iWidget *menu; | 97 | iWidget *menu; |
96 | SDL_Cursor *arrowCursor; | 98 | SDL_Cursor *arrowCursor; |
@@ -242,6 +244,12 @@ static void updateVisible_DocumentWidget_(iDocumentWidget *d) { | |||
242 | clear_PtrArray(&d->visibleLinks); | 244 | clear_PtrArray(&d->visibleLinks); |
243 | render_GmDocument(d->doc, visRange, addVisibleLink_DocumentWidget_, d); | 245 | render_GmDocument(d->doc, visRange, addVisibleLink_DocumentWidget_, d); |
244 | updateHover_DocumentWidget_(d, mouseCoord_Window(get_Window())); | 246 | updateHover_DocumentWidget_(d, mouseCoord_Window(get_Window())); |
247 | /* Remember scroll positions of recently visited pages. */ { | ||
248 | iHistoryItem *it = item_History(history_App()); | ||
249 | if (it) { | ||
250 | it->scrollY = d->scrollY / gap_UI; | ||
251 | } | ||
252 | } | ||
245 | } | 253 | } |
246 | 254 | ||
247 | static void updateWindowTitle_DocumentWidget_(const iDocumentWidget *d) { | 255 | static void updateWindowTitle_DocumentWidget_(const iDocumentWidget *d) { |
@@ -300,9 +308,14 @@ static void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode | |||
300 | break; | 308 | break; |
301 | } | 309 | } |
302 | setSource_DocumentWidget_(d, src); | 310 | setSource_DocumentWidget_(d, src); |
311 | d->scrollY = 0; | ||
312 | d->state = ready_DocumentState; | ||
303 | } | 313 | } |
304 | 314 | ||
305 | static void updateSource_DocumentWidget_(iDocumentWidget *d) { | 315 | static void updateSource_DocumentWidget_(iDocumentWidget *d) { |
316 | if (d->state == ready_DocumentState) { | ||
317 | return; | ||
318 | } | ||
306 | /* TODO: Do this in the background. However, that requires a text metrics calculator | 319 | /* TODO: Do this in the background. However, that requires a text metrics calculator |
307 | that does not try to cache the glyph bitmaps. */ | 320 | that does not try to cache the glyph bitmaps. */ |
308 | const enum iGmStatusCode statusCode = status_GmRequest(d->request); | 321 | const enum iGmStatusCode statusCode = status_GmRequest(d->request); |
@@ -384,6 +397,10 @@ void setUrl_DocumentWidget(iDocumentWidget *d, const iString *url) { | |||
384 | } | 397 | } |
385 | } | 398 | } |
386 | 399 | ||
400 | void setInitialScroll_DocumentWidget (iDocumentWidget *d, int scrollY) { | ||
401 | d->initialScrollY = scrollY; | ||
402 | } | ||
403 | |||
387 | iBool isRequestOngoing_DocumentWidget(const iDocumentWidget *d) { | 404 | iBool isRequestOngoing_DocumentWidget(const iDocumentWidget *d) { |
388 | return d->state == fetching_DocumentState || d->state == receivedPartialResponse_DocumentState; | 405 | return d->state == fetching_DocumentState || d->state == receivedPartialResponse_DocumentState; |
389 | } | 406 | } |
@@ -437,11 +454,14 @@ static void checkResponse_DocumentWidget_(iDocumentWidget *d) { | |||
437 | return; | 454 | return; |
438 | } | 455 | } |
439 | enum iGmStatusCode statusCode = status_GmRequest(d->request); | 456 | enum iGmStatusCode statusCode = status_GmRequest(d->request); |
457 | if (statusCode == none_GmStatusCode) { | ||
458 | return; | ||
459 | } | ||
440 | if (d->state == fetching_DocumentState) { | 460 | if (d->state == fetching_DocumentState) { |
441 | d->state = receivedPartialResponse_DocumentState; | 461 | d->state = receivedPartialResponse_DocumentState; |
442 | updateTrust_DocumentWidget_(d); | 462 | updateTrust_DocumentWidget_(d); |
443 | switch (statusCode / 10) { | 463 | switch (category_GmStatusCode(statusCode)) { |
444 | case 1: /* input required */ { | 464 | case categoryInput_GmStatusCode: { |
445 | iUrl parts; | 465 | iUrl parts; |
446 | init_Url(&parts, d->url); | 466 | init_Url(&parts, d->url); |
447 | printf("%s\n", cstr_String(meta_GmRequest(d->request))); | 467 | printf("%s\n", cstr_String(meta_GmRequest(d->request))); |
@@ -460,16 +480,17 @@ static void checkResponse_DocumentWidget_(iDocumentWidget *d) { | |||
460 | statusCode == sensitiveInput_GmStatusCode); | 480 | statusCode == sensitiveInput_GmStatusCode); |
461 | break; | 481 | break; |
462 | } | 482 | } |
463 | case 2: /* success */ | 483 | case categorySuccess_GmStatusCode: |
464 | d->scrollY = 0; | 484 | d->scrollY = d->initialScrollY; |
465 | reset_GmDocument(d->doc); /* new content incoming */ | 485 | reset_GmDocument(d->doc); /* new content incoming */ |
466 | updateSource_DocumentWidget_(d); | 486 | updateSource_DocumentWidget_(d); |
467 | break; | 487 | break; |
468 | case 3: /* redirect */ | 488 | case categoryRedirect_GmStatusCode: |
469 | if (isEmpty_String(meta_GmRequest(d->request))) { | 489 | if (isEmpty_String(meta_GmRequest(d->request))) { |
470 | showErrorPage_DocumentWidget_(d, invalidRedirect_GmStatusCode); | 490 | showErrorPage_DocumentWidget_(d, invalidRedirect_GmStatusCode); |
471 | } | 491 | } |
472 | else { | 492 | else { |
493 | /* TODO: only accept redirects that use gemini protocol */ | ||
473 | postCommandf_App( | 494 | postCommandf_App( |
474 | "open redirect:1 url:%s", | 495 | "open redirect:1 url:%s", |
475 | cstr_String(absoluteUrl_String(d->url, meta_GmRequest(d->request)))); | 496 | cstr_String(absoluteUrl_String(d->url, meta_GmRequest(d->request)))); |
@@ -480,18 +501,20 @@ static void checkResponse_DocumentWidget_(iDocumentWidget *d) { | |||
480 | if (isDefined_GmError(statusCode)) { | 501 | if (isDefined_GmError(statusCode)) { |
481 | showErrorPage_DocumentWidget_(d, statusCode); | 502 | showErrorPage_DocumentWidget_(d, statusCode); |
482 | } | 503 | } |
483 | else if (statusCode / 10 == 4) { | 504 | else if (category_GmStatusCode(statusCode) == |
505 | categoryTemporaryFailure_GmStatusCode) { | ||
484 | showErrorPage_DocumentWidget_(d, temporaryFailure_GmStatusCode); | 506 | showErrorPage_DocumentWidget_(d, temporaryFailure_GmStatusCode); |
485 | } | 507 | } |
486 | else if (statusCode / 10 == 5) { | 508 | else if (category_GmStatusCode(statusCode) == |
509 | categoryPermanentFailure_GmStatusCode) { | ||
487 | showErrorPage_DocumentWidget_(d, permanentFailure_GmStatusCode); | 510 | showErrorPage_DocumentWidget_(d, permanentFailure_GmStatusCode); |
488 | } | 511 | } |
489 | break; | 512 | break; |
490 | } | 513 | } |
491 | } | 514 | } |
492 | else if (d->state == receivedPartialResponse_DocumentState) { | 515 | else if (d->state == receivedPartialResponse_DocumentState) { |
493 | switch (statusCode) { | 516 | switch (category_GmStatusCode(statusCode)) { |
494 | case success_GmStatusCode: | 517 | case categorySuccess_GmStatusCode: |
495 | /* More content available. */ | 518 | /* More content available. */ |
496 | updateSource_DocumentWidget_(d); | 519 | updateSource_DocumentWidget_(d); |
497 | break; | 520 | break; |
@@ -649,7 +672,6 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
649 | } | 672 | } |
650 | else if (isCommand_Widget(w, ev, "document.request.finished") && | 673 | else if (isCommand_Widget(w, ev, "document.request.finished") && |
651 | pointerLabel_Command(command_UserEvent(ev), "request") == d->request) { | 674 | pointerLabel_Command(command_UserEvent(ev), "request") == d->request) { |
652 | iAssert(d->state == receivedPartialResponse_DocumentState); /* must already have been updated at least once */ | ||
653 | checkResponse_DocumentWidget_(d); | 675 | checkResponse_DocumentWidget_(d); |
654 | d->state = ready_DocumentState; | 676 | d->state = ready_DocumentState; |
655 | iReleasePtr(&d->request); | 677 | iReleasePtr(&d->request); |
diff --git a/src/ui/documentwidget.h b/src/ui/documentwidget.h index dfd342af..6b0ea607 100644 --- a/src/ui/documentwidget.h +++ b/src/ui/documentwidget.h | |||
@@ -6,4 +6,5 @@ iDeclareWidgetClass(DocumentWidget) | |||
6 | iDeclareObjectConstruction(DocumentWidget) | 6 | iDeclareObjectConstruction(DocumentWidget) |
7 | 7 | ||
8 | void setUrl_DocumentWidget (iDocumentWidget *, const iString *url); | 8 | void setUrl_DocumentWidget (iDocumentWidget *, const iString *url); |
9 | void setInitialScroll_DocumentWidget (iDocumentWidget *, int scrollY); /* set after content received */ | ||
9 | iBool isRequestOngoing_DocumentWidget (const iDocumentWidget *); | 10 | iBool isRequestOngoing_DocumentWidget (const iDocumentWidget *); |
diff --git a/src/ui/text.c b/src/ui/text.c index 50b3bbab..f562e642 100644 --- a/src/ui/text.c +++ b/src/ui/text.c | |||
@@ -356,6 +356,7 @@ static iRect run_Font_(iFont *d, enum iRunMode mode, iRangecc text, size_t maxLe | |||
356 | iChar prevCh = 0; | 356 | iChar prevCh = 0; |
357 | for (const char *chPos = text.start; chPos != text.end; ) { | 357 | for (const char *chPos = text.start; chPos != text.end; ) { |
358 | iAssert(chPos < text.end); | 358 | iAssert(chPos < text.end); |
359 | const char *currentPos = chPos; | ||
359 | if (*chPos == 0x1b) { | 360 | if (*chPos == 0x1b) { |
360 | /* ANSI escape. */ | 361 | /* ANSI escape. */ |
361 | chPos++; | 362 | chPos++; |
@@ -394,7 +395,12 @@ static iRect run_Font_(iFont *d, enum iRunMode mode, iRangecc text, size_t maxLe | |||
394 | int x2 = x1 + glyph->rect[hoff].size.x; | 395 | int x2 = x1 + glyph->rect[hoff].size.x; |
395 | /* Out of the allotted space? */ | 396 | /* Out of the allotted space? */ |
396 | if (xposLimit > 0 && x2 > xposLimit) { | 397 | if (xposLimit > 0 && x2 > xposLimit) { |
397 | *continueFrom_out = lastWordEnd; | 398 | if (lastWordEnd != text.start) { |
399 | *continueFrom_out = lastWordEnd; | ||
400 | } | ||
401 | else { | ||
402 | *continueFrom_out = currentPos; /* forced break */ | ||
403 | } | ||
398 | break; | 404 | break; |
399 | } | 405 | } |
400 | const SDL_Rect dst = { x1 + glyph->d[hoff].x, | 406 | const SDL_Rect dst = { x1 + glyph->d[hoff].x, |