summaryrefslogtreecommitdiff
path: root/src/ui/documentwidget.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/documentwidget.c')
-rw-r--r--src/ui/documentwidget.c295
1 files changed, 148 insertions, 147 deletions
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index 963bae8f..17111ed0 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -27,6 +27,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
27 27
28#include "app.h" 28#include "app.h"
29#include "audio/player.h" 29#include "audio/player.h"
30#include "banner.h"
30#include "bookmarks.h" 31#include "bookmarks.h"
31#include "command.h" 32#include "command.h"
32#include "defs.h" 33#include "defs.h"
@@ -280,6 +281,7 @@ struct Impl_DocumentWidget {
280 iTime sourceTime; 281 iTime sourceTime;
281 iGempub * sourceGempub; /* NULL unless the page is Gempub content */ 282 iGempub * sourceGempub; /* NULL unless the page is Gempub content */
282 iGmDocument * doc; 283 iGmDocument * doc;
284 iBanner * banner;
283 285
284 /* Rendering: */ 286 /* Rendering: */
285 int pageMargin; 287 int pageMargin;
@@ -339,6 +341,7 @@ void init_DocumentWidget(iDocumentWidget *d) {
339 d->isRequestUpdated = iFalse; 341 d->isRequestUpdated = iFalse;
340 d->media = new_ObjectList(); 342 d->media = new_ObjectList();
341 d->doc = new_GmDocument(); 343 d->doc = new_GmDocument();
344 d->banner = new_Banner();
342 d->redirectCount = 0; 345 d->redirectCount = 0;
343 d->ordinalBase = 0; 346 d->ordinalBase = 0;
344 d->initNormScrollY = 0; 347 d->initNormScrollY = 0;
@@ -429,6 +432,7 @@ void deinit_DocumentWidget(iDocumentWidget *d) {
429 deinit_Block(&d->sourceContent); 432 deinit_Block(&d->sourceContent);
430 deinit_String(&d->sourceMime); 433 deinit_String(&d->sourceMime);
431 deinit_String(&d->sourceHeader); 434 deinit_String(&d->sourceHeader);
435 delete_Banner(d->banner);
432 iRelease(d->doc); 436 iRelease(d->doc);
433 if (d->mediaTimer) { 437 if (d->mediaTimer) {
434 SDL_RemoveTimer(d->mediaTimer); 438 SDL_RemoveTimer(d->mediaTimer);
@@ -512,35 +516,67 @@ static int documentWidth_DocumentWidget_(const iDocumentWidget *d) {
512 prefs->lineWidth * prefs->zoomPercent / 100); 516 prefs->lineWidth * prefs->zoomPercent / 100);
513} 517}
514 518
519static int documentTopPad_DocumentWidget_(const iDocumentWidget *d) {
520 /* Amount of space between banner and top of the document. */
521 return isEmpty_Banner(d->banner) ? 0 : lineHeight_Text(paragraph_FontId);
522}
523
524static int pageHeight_DocumentWidget_(const iDocumentWidget *d) {
525 return height_Banner(d->banner) + documentTopPad_DocumentWidget_(d) + size_GmDocument(d->doc).y;
526}
527
515static iRect documentBounds_DocumentWidget_(const iDocumentWidget *d) { 528static iRect documentBounds_DocumentWidget_(const iDocumentWidget *d) {
516 const iRect bounds = bounds_Widget(constAs_Widget(d)); 529 const iRect bounds = bounds_Widget(constAs_Widget(d));
517 const int margin = gap_UI * d->pageMargin; 530 const int margin = gap_UI * d->pageMargin;
518 iRect rect; 531 iRect rect;
519 rect.size.x = documentWidth_DocumentWidget_(d); 532 rect.size.x = documentWidth_DocumentWidget_(d);
520 rect.pos.x = mid_Rect(bounds).x - rect.size.x / 2; 533 rect.pos.x = mid_Rect(bounds).x - rect.size.x / 2;
521 rect.pos.y = top_Rect(bounds); 534 rect.pos.y = top_Rect(bounds) + margin;
522 rect.size.y = height_Rect(bounds) - margin; 535 rect.size.y = height_Rect(bounds) - margin;
523 const iGmRun *banner = siteBanner_GmDocument(d->doc); 536 iBool wasCentered = iFalse;
524 if (!banner) {
525 rect.pos.y += margin;
526 rect.size.y -= margin;
527 }
528 if (d->flags & centerVertically_DocumentWidgetFlag) { 537 if (d->flags & centerVertically_DocumentWidgetFlag) {
529 const iInt2 docSize = addY_I2(size_GmDocument(d->doc), 538 const iInt2 docSize = addY_I2(size_GmDocument(d->doc),
530 iMax(height_Widget(d->footerButtons), height_Widget(d->phoneToolbar))); 539 iMax(height_Widget(d->footerButtons), height_Widget(d->phoneToolbar)));
531 if (docSize.y < rect.size.y) { 540 if (docSize.y < rect.size.y) {
532 /* Center vertically if short. There is one empty paragraph line's worth of margin 541 /* Center vertically if short. There is one empty paragraph line's worth of margin
533 between the banner and the page contents. */ 542 between the banner and the page contents. */
534 const int bannerHeight = banner ? height_Rect(banner->visBounds) : 0; 543// const int bannerHeight = 0; //banner ? height_Rect(banner->visBounds) : 0;
535 int offset = iMax(0, (rect.size.y + margin - docSize.y - bannerHeight - 544#if 0
536 lineHeight_Text(paragraph_FontId)) / 2); 545 int offset = iMax(0, (rect.size.y + margin - size_GmDocument(d->doc).y
537 rect.pos.y += offset; 546 //- lineHeight_Text(paragraph_FontId)
547 ) / 2 - height_Banner(d->banner)
548 //-
549 //documentTopPad_DocumentWidget_(d)
550 );
551#endif
552 int offset = iMax(0, height_Rect(bounds) / 2
553// - (isEmpty_Banner(d->banner) ? lineHeight_Text(paragraph_FontId) / 2 : 0)
554 - documentTopPad_DocumentWidget_(d)
555// + lineHeight_Text(paragraph_FontId) / 2
556// - isEmpty_Banner(d->banner) ?
557 - height_Banner(d->banner)
558 - size_GmDocument(d->doc).y / 2
559 );
560 //(//documentTopPad_DocumentWidget_(d) +
561 //size_GmDocument(d->doc).y) / 2);
562 rect.pos.y = top_Rect(bounds) + offset;
538 rect.size.y = docSize.y; 563 rect.size.y = docSize.y;
564 wasCentered = iTrue;
539 } 565 }
540 } 566 }
567 if (!wasCentered && !isEmpty_Banner(d->banner)) {
568 /* The banner overtakes the top banner. */
569 rect.pos.y -= margin;
570 rect.size.y -= margin;
571 }
541 return rect; 572 return rect;
542} 573}
543 574
575static int viewPos_DocumentWidget_(const iDocumentWidget *d) {
576 return height_Banner(d->banner) + documentTopPad_DocumentWidget_(d) - pos_SmoothScroll(&d->scrollY);
577}
578
579#if 0
544static iRect siteBannerRect_DocumentWidget_(const iDocumentWidget *d) { 580static iRect siteBannerRect_DocumentWidget_(const iDocumentWidget *d) {
545 const iGmRun *banner = siteBanner_GmDocument(d->doc); 581 const iGmRun *banner = siteBanner_GmDocument(d->doc);
546 if (!banner) { 582 if (!banner) {
@@ -550,17 +586,23 @@ static iRect siteBannerRect_DocumentWidget_(const iDocumentWidget *d) {
550 const iInt2 origin = addY_I2(topLeft_Rect(docBounds), -pos_SmoothScroll(&d->scrollY)); 586 const iInt2 origin = addY_I2(topLeft_Rect(docBounds), -pos_SmoothScroll(&d->scrollY));
551 return moved_Rect(banner->visBounds, origin); 587 return moved_Rect(banner->visBounds, origin);
552} 588}
589#endif
553 590
554static iInt2 documentPos_DocumentWidget_(const iDocumentWidget *d, iInt2 pos) { 591static iInt2 documentPos_DocumentWidget_(const iDocumentWidget *d, iInt2 pos) {
555 return addY_I2(sub_I2(pos, topLeft_Rect(documentBounds_DocumentWidget_(d))), 592 return addY_I2(sub_I2(pos, topLeft_Rect(documentBounds_DocumentWidget_(d))),
556 pos_SmoothScroll(&d->scrollY)); 593 -viewPos_DocumentWidget_(d));
557} 594}
558 595
559static iRangei visibleRange_DocumentWidget_(const iDocumentWidget *d) { 596static iRangei visibleRange_DocumentWidget_(const iDocumentWidget *d) {
560 const int margin = !hasSiteBanner_GmDocument(d->doc) ? gap_UI * d->pageMargin : 0; 597// const int margin = -documentTopPad_DocumentWidget_(d) +
561 return (iRangei){ pos_SmoothScroll(&d->scrollY) - margin, 598// d->pageMargin * gap_UI;
562 pos_SmoothScroll(&d->scrollY) + height_Rect(bounds_Widget(constAs_Widget(d))) - 599 //const int top = -viewPos_DocumentWidget_(d) - margin;
563 margin }; 600 int top = pos_SmoothScroll(&d->scrollY) - height_Banner(d->banner) - documentTopPad_DocumentWidget_(d);
601 if (isEmpty_Banner(d->banner)) {
602 /* Top padding is not collapsed. */
603 top -= d->pageMargin * gap_UI;
604 }
605 return (iRangei){ top, top + height_Rect(bounds_Widget(constAs_Widget(d))) };
564} 606}
565 607
566static void addVisible_DocumentWidget_(void *context, const iGmRun *run) { 608static void addVisible_DocumentWidget_(void *context, const iGmRun *run) {
@@ -598,7 +640,7 @@ static const iGmRun *lastVisibleLink_DocumentWidget_(const iDocumentWidget *d) {
598} 640}
599 641
600static float normScrollPos_DocumentWidget_(const iDocumentWidget *d) { 642static float normScrollPos_DocumentWidget_(const iDocumentWidget *d) {
601 const int docSize = size_GmDocument(d->doc).y; 643 const int docSize = pageHeight_DocumentWidget_(d); // size_GmDocument(d->doc).y;
602 if (docSize) { 644 if (docSize) {
603 return pos_SmoothScroll(&d->scrollY) / (float) docSize; 645 return pos_SmoothScroll(&d->scrollY) / (float) docSize;
604 } 646 }
@@ -607,15 +649,9 @@ static float normScrollPos_DocumentWidget_(const iDocumentWidget *d) {
607 649
608static int scrollMax_DocumentWidget_(const iDocumentWidget *d) { 650static int scrollMax_DocumentWidget_(const iDocumentWidget *d) {
609 const iWidget *w = constAs_Widget(d); 651 const iWidget *w = constAs_Widget(d);
610 int sm = size_GmDocument(d->doc).y - height_Rect(bounds_Widget(w)) + 652 int sm = pageHeight_DocumentWidget_(d) - height_Rect(bounds_Widget(w)) +
611 (hasSiteBanner_GmDocument(d->doc) ? 1 : 2) * d->pageMargin * gap_UI + 653 (isEmpty_Banner(d->banner) ? 2 : 1) * d->pageMargin * gap_UI + /* top and bottom margins */
612 iMax(height_Widget(d->phoneToolbar), height_Widget(d->footerButtons)); 654 iMax(height_Widget(d->phoneToolbar), height_Widget(d->footerButtons));
613// sm += height_Widget(d->phoneToolbar);
614// if (d->phoneToolbar) {
615// sm += size_Root(w->root).y -
616// top_Rect(boundsWithoutVisualOffset_Widget(d->phoneToolbar));
617// sm += height_Widget(d->phoneToolbar);
618// }
619 return sm; 655 return sm;
620} 656}
621 657
@@ -699,7 +735,8 @@ static void updateHover_DocumentWidget_(iDocumentWidget *d, iInt2 mouse) {
699 const iGmRun * oldHoverLink = d->hoverLink; 735 const iGmRun * oldHoverLink = d->hoverLink;
700 d->hoverPre = NULL; 736 d->hoverPre = NULL;
701 d->hoverLink = NULL; 737 d->hoverLink = NULL;
702 const iInt2 hoverPos = addY_I2(sub_I2(mouse, topLeft_Rect(docBounds)), pos_SmoothScroll(&d->scrollY)); 738 const iInt2 hoverPos = addY_I2(sub_I2(mouse, topLeft_Rect(docBounds)),
739 -viewPos_DocumentWidget_(d));
703 if (isHoverAllowed_DocumentWidget_(d)) { 740 if (isHoverAllowed_DocumentWidget_(d)) {
704 iConstForEach(PtrArray, i, &d->visibleLinks) { 741 iConstForEach(PtrArray, i, &d->visibleLinks) {
705 const iGmRun *run = i.ptr; 742 const iGmRun *run = i.ptr;
@@ -757,8 +794,9 @@ static void updateHover_DocumentWidget_(iDocumentWidget *d, iInt2 mouse) {
757 794
758static void updateSideOpacity_DocumentWidget_(iDocumentWidget *d, iBool isAnimated) { 795static void updateSideOpacity_DocumentWidget_(iDocumentWidget *d, iBool isAnimated) {
759 float opacity = 0.0f; 796 float opacity = 0.0f;
760 const iGmRun *banner = siteBanner_GmDocument(d->doc); 797// const iGmRun *banner = siteBanner_GmDocument(d->doc);
761 if (banner && bottom_Rect(banner->visBounds) < pos_SmoothScroll(&d->scrollY)) { 798 if (!isEmpty_Banner(d->banner) && height_Banner(d->banner) < pos_SmoothScroll(&d->scrollY)) {
799// if (banner && bottom_Rect(banner->visBounds) < pos_SmoothScroll(&d->scrollY)) {
762 opacity = 1.0f; 800 opacity = 1.0f;
763 } 801 }
764 setValue_Anim(&d->sideOpacity, opacity, isAnimated ? (opacity < 0.5f ? 100 : 200) : 0); 802 setValue_Anim(&d->sideOpacity, opacity, isAnimated ? (opacity < 0.5f ? 100 : 200) : 0);
@@ -862,6 +900,7 @@ static void updateVisible_DocumentWidget_(iDocumentWidget *d) {
862 prefs_App()->centerShortDocs || startsWithCase_String(d->mod.url, "about:") || 900 prefs_App()->centerShortDocs || startsWithCase_String(d->mod.url, "about:") ||
863 !isSuccess_GmStatusCode(d->sourceStatus)); 901 !isSuccess_GmStatusCode(d->sourceStatus));
864 const iRangei visRange = visibleRange_DocumentWidget_(d); 902 const iRangei visRange = visibleRange_DocumentWidget_(d);
903// printf("visRange: %d...%d\n", visRange.start, visRange.end);
865 const iRect bounds = bounds_Widget(as_Widget(d)); 904 const iRect bounds = bounds_Widget(as_Widget(d));
866 const int scrollMax = updateScrollMax_DocumentWidget_(d); 905 const int scrollMax = updateScrollMax_DocumentWidget_(d);
867 /* Reposition the footer buttons as appropriate. */ 906 /* Reposition the footer buttons as appropriate. */
@@ -880,13 +919,13 @@ static void updateVisible_DocumentWidget_(iDocumentWidget *d) {
880 } 919 }
881 else { 920 else {
882 d->footerButtons->animOffsetRef = &d->scrollY.pos; 921 d->footerButtons->animOffsetRef = &d->scrollY.pos;
883 d->footerButtons->rect.pos.y = size_GmDocument(d->doc).y + 2 * gap_UI * d->pageMargin; 922 d->footerButtons->rect.pos.y = pageHeight_DocumentWidget_(d) + 2 * gap_UI * d->pageMargin;
884// + height_Widget(d->phoneToolbar); 923// + height_Widget(d->phoneToolbar);
885 } 924 }
886 } 925 }
887 setRange_ScrollWidget(d->scroll, (iRangei){ 0, scrollMax }); 926 setRange_ScrollWidget(d->scroll, (iRangei){ 0, scrollMax });
888 const int docSize = size_GmDocument(d->doc).y + iMax(height_Widget(d->phoneToolbar), 927 const int docSize = pageHeight_DocumentWidget_(d) + iMax(height_Widget(d->phoneToolbar),
889 height_Widget(d->footerButtons)); 928 height_Widget(d->footerButtons));
890 setThumb_ScrollWidget(d->scroll, 929 setThumb_ScrollWidget(d->scroll,
891 pos_SmoothScroll(&d->scrollY), 930 pos_SmoothScroll(&d->scrollY),
892 docSize > 0 ? height_Rect(bounds) * size_Range(&visRange) / docSize : 0); 931 docSize > 0 ? height_Rect(bounds) * size_Range(&visRange) / docSize : 0);
@@ -906,6 +945,11 @@ static void updateVisible_DocumentWidget_(iDocumentWidget *d) {
906 updateHover_DocumentWidget_(d, mouseCoord_Window(get_Window(), 0)); 945 updateHover_DocumentWidget_(d, mouseCoord_Window(get_Window(), 0));
907 updateSideOpacity_DocumentWidget_(d, iTrue); 946 updateSideOpacity_DocumentWidget_(d, iTrue);
908 animateMedia_DocumentWidget_(d); 947 animateMedia_DocumentWidget_(d);
948 setPos_Banner(d->banner, addY_I2(topLeft_Rect(documentBounds_DocumentWidget_(d)),
949 -pos_SmoothScroll(&d->scrollY)));
950 /*init_I2(documentBounds_DocumentWidget_(d).pos.x,
951 viewPos_DocumentWidget_(d) -
952 documentTopPad_DocumentWidget_(d)));*/
909 /* Remember scroll positions of recently visited pages. */ { 953 /* Remember scroll positions of recently visited pages. */ {
910 iRecentUrl *recent = mostRecentUrl_History(d->mod.history); 954 iRecentUrl *recent = mostRecentUrl_History(d->mod.history);
911 if (recent && docSize && d->state == ready_RequestState) { 955 if (recent && docSize && d->state == ready_RequestState) {
@@ -1015,18 +1059,18 @@ static void invalidate_DocumentWidget_(iDocumentWidget *d) {
1015 clear_PtrSet(d->invalidRuns); 1059 clear_PtrSet(d->invalidRuns);
1016} 1060}
1017 1061
1018static iRangecc bannerText_DocumentWidget_(const iDocumentWidget *d) { 1062static iRangecc siteText_DocumentWidget_(const iDocumentWidget *d) {
1019 return isEmpty_String(d->titleUser) ? range_String(bannerText_GmDocument(d->doc)) 1063 return isEmpty_String(d->titleUser) ? urlHost_String(d->mod.url)
1020 : range_String(d->titleUser); 1064 : range_String(d->titleUser);
1021} 1065}
1022 1066
1023static void documentRunsInvalidated_DocumentWidget_(iDocumentWidget *d) { 1067static void documentRunsInvalidated_DocumentWidget_(iDocumentWidget *d) {
1024 d->foundMark = iNullRange; 1068 d->foundMark = iNullRange;
1025 d->selectMark = iNullRange; 1069 d->selectMark = iNullRange;
1026 d->hoverPre = NULL; 1070 d->hoverPre = NULL;
1027 d->hoverAltPre = NULL; 1071 d->hoverAltPre = NULL;
1028 d->hoverLink = NULL; 1072 d->hoverLink = NULL;
1029 d->contextLink = NULL; 1073 d->contextLink = NULL;
1030 iZap(d->visibleRuns); 1074 iZap(d->visibleRuns);
1031 iZap(d->renderRuns); 1075 iZap(d->renderRuns);
1032} 1076}
@@ -1087,6 +1131,7 @@ void setSource_DocumentWidget(iDocumentWidget *d, const iString *source) {
1087 outsideMargin, 1131 outsideMargin,
1088 isFinished_GmRequest(d->request) ? final_GmDocumentUpdate 1132 isFinished_GmRequest(d->request) ? final_GmDocumentUpdate
1089 : partial_GmDocumentUpdate); 1133 : partial_GmDocumentUpdate);
1134 setWidth_Banner(d->banner, docWidth);
1090 documentWasChanged_DocumentWidget_(d); 1135 documentWasChanged_DocumentWidget_(d);
1091} 1136}
1092 1137
@@ -1097,6 +1142,11 @@ static void replaceDocument_DocumentWidget_(iDocumentWidget *d, iGmDocument *new
1097 documentWasChanged_DocumentWidget_(d); 1142 documentWasChanged_DocumentWidget_(d);
1098} 1143}
1099 1144
1145static void updateBanner_DocumentWidget_(iDocumentWidget *d) {
1146 clear_Banner(d->banner);
1147 setSite_Banner(d->banner, siteText_DocumentWidget_(d), siteIcon_GmDocument(d->doc));
1148}
1149
1100static void updateTheme_DocumentWidget_(iDocumentWidget *d) { 1150static void updateTheme_DocumentWidget_(iDocumentWidget *d) {
1101 if (equalCase_Rangecc(urlScheme_String(d->mod.url), "file")) { 1151 if (equalCase_Rangecc(urlScheme_String(d->mod.url), "file")) {
1102 iBlock empty; 1152 iBlock empty;
@@ -1112,8 +1162,10 @@ static void updateTheme_DocumentWidget_(iDocumentWidget *d) {
1112 setThemeSeed_GmDocument(d->doc, &d->titleUser->chars); 1162 setThemeSeed_GmDocument(d->doc, &d->titleUser->chars);
1113 } 1163 }
1114 d->drawBufs->flags |= updateTimestampBuf_DrawBufsFlag; 1164 d->drawBufs->flags |= updateTimestampBuf_DrawBufsFlag;
1165 updateBanner_DocumentWidget_(d);
1115} 1166}
1116 1167
1168#if 0
1117static enum iGmDocumentBanner bannerType_DocumentWidget_(const iDocumentWidget *d) { 1169static enum iGmDocumentBanner bannerType_DocumentWidget_(const iDocumentWidget *d) {
1118 if (d->certFlags & available_GmCertFlag) { 1170 if (d->certFlags & available_GmCertFlag) {
1119 const int req = domainVerified_GmCertFlag | timeVerified_GmCertFlag | trusted_GmCertFlag; 1171 const int req = domainVerified_GmCertFlag | timeVerified_GmCertFlag | trusted_GmCertFlag;
@@ -1123,6 +1175,7 @@ static enum iGmDocumentBanner bannerType_DocumentWidget_(const iDocumentWidget *
1123 } 1175 }
1124 return siteDomain_GmDocumentBanner; 1176 return siteDomain_GmDocumentBanner;
1125} 1177}
1178#endif
1126 1179
1127static void makeFooterButtons_DocumentWidget_(iDocumentWidget *d, const iMenuItem *items, size_t count) { 1180static void makeFooterButtons_DocumentWidget_(iDocumentWidget *d, const iMenuItem *items, size_t count) {
1128 iWidget *w = as_Widget(d); 1181 iWidget *w = as_Widget(d);
@@ -1160,6 +1213,8 @@ static void makeFooterButtons_DocumentWidget_(iDocumentWidget *d, const iMenuIte
1160 1213
1161static void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode code, 1214static void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode code,
1162 const iString *meta) { 1215 const iString *meta) {
1216 /* TODO: No such thing as an "error page". It should be an empty page with an error banner. */
1217#if 0
1163 iString *src = collectNewCStr_String("# "); 1218 iString *src = collectNewCStr_String("# ");
1164 const iGmError *msg = get_GmError(code); 1219 const iGmError *msg = get_GmError(code);
1165 appendChar_String(src, msg->icon ? msg->icon : 0x2327); /* X in a box */ 1220 appendChar_String(src, msg->icon ? msg->icon : 0x2327); /* X in a box */
@@ -1242,14 +1297,16 @@ static void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode
1242 /* Make a new document for the error page.*/ { 1297 /* Make a new document for the error page.*/ {
1243 iGmDocument *errorDoc = new_GmDocument(); 1298 iGmDocument *errorDoc = new_GmDocument();
1244 setUrl_GmDocument(errorDoc, d->mod.url); 1299 setUrl_GmDocument(errorDoc, d->mod.url);
1245 setBanner_GmDocument(errorDoc, useBanner ? bannerType_DocumentWidget_(d) : none_GmDocumentBanner); 1300// setBanner_GmDocument(errorDoc, useBanner ? bannerType_DocumentWidget_(d) : none_GmDocumentBanner);
1301
1246 setFormat_GmDocument(errorDoc, gemini_SourceFormat); 1302 setFormat_GmDocument(errorDoc, gemini_SourceFormat);
1247 replaceDocument_DocumentWidget_(d, errorDoc); 1303 replaceDocument_DocumentWidget_(d, errorDoc);
1248 iRelease(errorDoc); 1304 iRelease(errorDoc);
1249 } 1305 }
1250 translate_Lang(src); 1306 translate_Lang(src);
1307#endif
1251 d->state = ready_RequestState; 1308 d->state = ready_RequestState;
1252 setSource_DocumentWidget(d, src); 1309// setSource_DocumentWidget(d, src);
1253 updateTheme_DocumentWidget_(d); 1310 updateTheme_DocumentWidget_(d);
1254 reset_SmoothScroll(&d->scrollY); 1311 reset_SmoothScroll(&d->scrollY);
1255 init_Anim(&d->sideOpacity, 0); 1312 init_Anim(&d->sideOpacity, 0);
@@ -1729,7 +1786,7 @@ static void updateTrust_DocumentWidget_(iDocumentWidget *d, const iGmResponse *r
1729 else { 1786 else {
1730 updateTextCStr_LabelWidget(lock, green_ColorEscape closedLock_Icon); 1787 updateTextCStr_LabelWidget(lock, green_ColorEscape closedLock_Icon);
1731 } 1788 }
1732 setBanner_GmDocument(d->doc, bannerType_DocumentWidget_(d)); 1789// setBanner_GmDocument(d->doc, bannerType_DocumentWidget_(d));
1733} 1790}
1734 1791
1735static void parseUser_DocumentWidget_(iDocumentWidget *d) { 1792static void parseUser_DocumentWidget_(iDocumentWidget *d) {
@@ -1778,12 +1835,13 @@ static void updateFromCachedResponse_DocumentWidget_(iDocumentWidget *d, float n
1778 updateDocument_DocumentWidget_(d, resp, cachedDoc, iTrue); 1835 updateDocument_DocumentWidget_(d, resp, cachedDoc, iTrue);
1779// setCachedDocument_History(d->mod.history, d->doc, 1836// setCachedDocument_History(d->mod.history, d->doc,
1780// (d->flags & openedFromSidebar_DocumentWidgetFlag) != 0); 1837// (d->flags & openedFromSidebar_DocumentWidgetFlag) != 0);
1838 updateBanner_DocumentWidget_(d);
1781 } 1839 }
1782 d->state = ready_RequestState; 1840 d->state = ready_RequestState;
1783 postProcessRequestContent_DocumentWidget_(d, iTrue); 1841 postProcessRequestContent_DocumentWidget_(d, iTrue);
1784 init_Anim(&d->altTextOpacity, 0); 1842 init_Anim(&d->altTextOpacity, 0);
1785 reset_SmoothScroll(&d->scrollY); 1843 reset_SmoothScroll(&d->scrollY);
1786 init_Anim(&d->scrollY.pos, d->initNormScrollY * size_GmDocument(d->doc).y); 1844 init_Anim(&d->scrollY.pos, d->initNormScrollY * pageHeight_DocumentWidget_(d));
1787 updateSideOpacity_DocumentWidget_(d, iFalse); 1845 updateSideOpacity_DocumentWidget_(d, iFalse);
1788 updateVisible_DocumentWidget_(d); 1846 updateVisible_DocumentWidget_(d);
1789 moveSpan_SmoothScroll(&d->scrollY, 0, 0); /* clamp position to new max */ 1847 moveSpan_SmoothScroll(&d->scrollY, 0, 0); /* clamp position to new max */
@@ -1870,8 +1928,11 @@ static void smoothScroll_DocumentWidget_(iDocumentWidget *d, int offset, int dur
1870} 1928}
1871 1929
1872static void scrollTo_DocumentWidget_(iDocumentWidget *d, int documentY, iBool centered) { 1930static void scrollTo_DocumentWidget_(iDocumentWidget *d, int documentY, iBool centered) {
1873 if (!hasSiteBanner_GmDocument(d->doc)) { 1931 if (!isEmpty_Banner(d->banner)) {
1874 documentY += d->pageMargin * gap_UI; 1932 documentY += height_Banner(d->banner) + documentTopPad_DocumentWidget_(d);
1933 }
1934 else {
1935 documentY += documentTopPad_DocumentWidget_(d) + d->pageMargin * gap_UI;
1875 } 1936 }
1876 init_Anim(&d->scrollY.pos, 1937 init_Anim(&d->scrollY.pos,
1877 documentY - (centered ? documentBounds_DocumentWidget_(d).size.y / 2 1938 documentY - (centered ? documentBounds_DocumentWidget_(d).size.y / 2
@@ -2403,6 +2464,7 @@ static iBool updateDocumentWidthRetainingScrollPosition_DocumentWidget_(iDocumen
2403 voffset = visibleRange_DocumentWidget_(d).start - top_Rect(run->visBounds); 2464 voffset = visibleRange_DocumentWidget_(d).start - top_Rect(run->visBounds);
2404 } 2465 }
2405 setWidth_GmDocument(d->doc, newWidth, (width_Widget(d) - newWidth) / 2); 2466 setWidth_GmDocument(d->doc, newWidth, (width_Widget(d) - newWidth) / 2);
2467 setWidth_Banner(d->banner, newWidth);
2406 documentRunsInvalidated_DocumentWidget_(d); 2468 documentRunsInvalidated_DocumentWidget_(d);
2407 if (runLoc && !keepCenter) { 2469 if (runLoc && !keepCenter) {
2408 run = findRunAtLoc_GmDocument(d->doc, runLoc); 2470 run = findRunAtLoc_GmDocument(d->doc, runLoc);
@@ -2504,7 +2566,8 @@ static iBool handleSwipe_DocumentWidget_(iDocumentWidget *d, const char *cmd) {
2504 if (recent->cachedDoc) { 2566 if (recent->cachedDoc) {
2505 iChangeRef(swipeIn->doc, recent->cachedDoc); 2567 iChangeRef(swipeIn->doc, recent->cachedDoc);
2506 updateScrollMax_DocumentWidget_(d); 2568 updateScrollMax_DocumentWidget_(d);
2507 setValue_Anim(&swipeIn->scrollY.pos, size_GmDocument(swipeIn->doc).y * recent->normScrollY, 0); 2569 setValue_Anim(&swipeIn->scrollY.pos,
2570 pageHeight_DocumentWidget_(d) * recent->normScrollY, 0);
2508 updateVisible_DocumentWidget_(swipeIn); 2571 updateVisible_DocumentWidget_(swipeIn);
2509 swipeIn->drawBufs->flags |= updateTimestampBuf_DrawBufsFlag | updateSideBuf_DrawBufsFlag; 2572 swipeIn->drawBufs->flags |= updateTimestampBuf_DrawBufsFlag | updateSideBuf_DrawBufsFlag;
2510 } 2573 }
@@ -2935,7 +2998,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)
2935 updateFetchProgress_DocumentWidget_(d); 2998 updateFetchProgress_DocumentWidget_(d);
2936 checkResponse_DocumentWidget_(d); 2999 checkResponse_DocumentWidget_(d);
2937 if (category_GmStatusCode(status_GmRequest(d->request)) == categorySuccess_GmStatusCode) { 3000 if (category_GmStatusCode(status_GmRequest(d->request)) == categorySuccess_GmStatusCode) {
2938 init_Anim(&d->scrollY.pos, d->initNormScrollY * size_GmDocument(d->doc).y); /* TODO: unless user already scrolled! */ 3001 init_Anim(&d->scrollY.pos, d->initNormScrollY * pageHeight_DocumentWidget_(d)); /* TODO: unless user already scrolled! */
2939 } 3002 }
2940 iChangeFlags(d->flags, 3003 iChangeFlags(d->flags,
2941 urlChanged_DocumentWidgetFlag | drawDownloadCounter_DocumentWidgetFlag, 3004 urlChanged_DocumentWidgetFlag | drawDownloadCounter_DocumentWidgetFlag,
@@ -3352,7 +3415,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)
3352 3415
3353static iRect runRect_DocumentWidget_(const iDocumentWidget *d, const iGmRun *run) { 3416static iRect runRect_DocumentWidget_(const iDocumentWidget *d, const iGmRun *run) {
3354 const iRect docBounds = documentBounds_DocumentWidget_(d); 3417 const iRect docBounds = documentBounds_DocumentWidget_(d);
3355 return moved_Rect(run->bounds, addY_I2(topLeft_Rect(docBounds), -pos_SmoothScroll(&d->scrollY))); 3418 return moved_Rect(run->bounds, addY_I2(topLeft_Rect(docBounds), viewPos_DocumentWidget_(d)));
3356} 3419}
3357 3420
3358static void setGrabbedPlayer_DocumentWidget_(iDocumentWidget *d, const iGmRun *run) { 3421static void setGrabbedPlayer_DocumentWidget_(iDocumentWidget *d, const iGmRun *run) {
@@ -3660,9 +3723,11 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
3660 if (isVisible_Widget(d->menu)) { 3723 if (isVisible_Widget(d->menu)) {
3661 setCursor_Window(get_Window(), SDL_SYSTEM_CURSOR_ARROW); 3724 setCursor_Window(get_Window(), SDL_SYSTEM_CURSOR_ARROW);
3662 } 3725 }
3726#if 0
3663 else if (contains_Rect(siteBannerRect_DocumentWidget_(d), mpos)) { 3727 else if (contains_Rect(siteBannerRect_DocumentWidget_(d), mpos)) {
3664 setCursor_Window(get_Window(), SDL_SYSTEM_CURSOR_HAND); 3728 setCursor_Window(get_Window(), SDL_SYSTEM_CURSOR_HAND);
3665 } 3729 }
3730#endif
3666 else { 3731 else {
3667 if (value_Anim(&d->altTextOpacity) < 0.833f) { 3732 if (value_Anim(&d->altTextOpacity) < 0.833f) {
3668 setValue_Anim(&d->altTextOpacity, 0, 0); /* keep it hidden while moving */ 3733 setValue_Anim(&d->altTextOpacity, 0, 0); /* keep it hidden while moving */
@@ -4126,6 +4191,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
4126 d->selectMark = iNullRange; 4191 d->selectMark = iNullRange;
4127 refresh_Widget(w); 4192 refresh_Widget(w);
4128 } 4193 }
4194#if 0
4129 /* Clicking on the top/side banner navigates to site root. */ 4195 /* Clicking on the top/side banner navigates to site root. */
4130 const iRect banRect = siteBannerRect_DocumentWidget_(d); 4196 const iRect banRect = siteBannerRect_DocumentWidget_(d);
4131 if (contains_Rect(banRect, pos_Click(&d->click))) { 4197 if (contains_Rect(banRect, pos_Click(&d->click))) {
@@ -4139,6 +4205,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
4139 postCommand_Widget(d, "navigate.root"); 4205 postCommand_Widget(d, "navigate.root");
4140 } 4206 }
4141 } 4207 }
4208#endif
4142 } 4209 }
4143 return iTrue; 4210 return iTrue;
4144 case aborted_ClickResult: 4211 case aborted_ClickResult:
@@ -4200,7 +4267,7 @@ static void fillRange_DrawContext_(iDrawContext *d, const iGmRun *run, enum iCol
4200 } 4267 }
4201 if (~run->flags & decoration_GmRunFlag) { 4268 if (~run->flags & decoration_GmRunFlag) {
4202 const iInt2 visPos = 4269 const iInt2 visPos =
4203 add_I2(run->bounds.pos, addY_I2(d->viewPos, -pos_SmoothScroll(&d->widget->scrollY))); 4270 add_I2(run->bounds.pos, addY_I2(d->viewPos, viewPos_DocumentWidget_(d->widget)));
4204 const iRect rangeRect = { addX_I2(visPos, x), init_I2(w, height_Rect(run->bounds)) }; 4271 const iRect rangeRect = { addX_I2(visPos, x), init_I2(w, height_Rect(run->bounds)) };
4205 if (rangeRect.size.x) { 4272 if (rangeRect.size.x) {
4206 fillRect_Paint(&d->paint, rangeRect, color); 4273 fillRect_Paint(&d->paint, rangeRect, color);
@@ -4220,7 +4287,7 @@ static void fillRange_DrawContext_(iDrawContext *d, const iGmRun *run, enum iCol
4220 (contains_Range(&url, mark.end) || url.end == mark.end)) { 4287 (contains_Range(&url, mark.end) || url.end == mark.end)) {
4221 fillRect_Paint( 4288 fillRect_Paint(
4222 &d->paint, 4289 &d->paint,
4223 moved_Rect(run->visBounds, addY_I2(d->viewPos, -pos_SmoothScroll(&d->widget->scrollY))), 4290 moved_Rect(run->visBounds, addY_I2(d->viewPos, viewPos_DocumentWidget_(d->widget))),
4224 color); 4291 color);
4225 } 4292 }
4226 } 4293 }
@@ -4234,96 +4301,6 @@ static void drawMark_DrawContext_(void *context, const iGmRun *run) {
4234 } 4301 }
4235} 4302}
4236 4303
4237static void drawBannerRun_DrawContext_(iDrawContext *d, const iGmRun *run, iInt2 visPos) {
4238 const iGmDocument *doc = d->widget->doc;
4239 const iChar icon = siteIcon_GmDocument(doc);
4240 iString str;
4241 init_String(&str);
4242 iInt2 bpos = add_I2(visPos, init_I2(0, lineHeight_Text(banner_FontId) / 2));
4243 if (icon) {
4244 appendChar_String(&str, icon);
4245 const iRect iconRect = visualBounds_Text(run->font, range_String(&str));
4246 drawRange_Text(
4247 run->font,
4248 addY_I2(bpos, -mid_Rect(iconRect).y + lineHeight_Text(run->font) / 2),
4249 tmBannerIcon_ColorId,
4250 range_String(&str));
4251 bpos.x += right_Rect(iconRect) + 3 * gap_Text;
4252 }
4253 drawRange_Text(run->font,
4254 bpos,
4255 tmBannerTitle_ColorId,
4256 bannerText_DocumentWidget_(d->widget));
4257 if (bannerType_GmDocument(doc) == certificateWarning_GmDocumentBanner) {
4258 const int domainHeight = lineHeight_Text(banner_FontId) * 2;
4259 iRect rect = { add_I2(visPos, init_I2(0, domainHeight)),
4260 addY_I2(run->visBounds.size, -domainHeight - lineHeight_Text(uiContent_FontId)) };
4261 format_String(&str, "${heading.certwarn}");
4262 const int certFlags = d->widget->certFlags;
4263 if (certFlags & timeVerified_GmCertFlag && certFlags & domainVerified_GmCertFlag) {
4264 iUrl parts;
4265 init_Url(&parts, d->widget->mod.url);
4266 const iTime oldUntil =
4267 domainValidUntil_GmCerts(certs_App(), parts.host, port_Url(&parts));
4268 iDate exp;
4269 init_Date(&exp, &oldUntil);
4270 iTime now;
4271 initCurrent_Time(&now);
4272 const int days = secondsSince_Time(&oldUntil, &now) / 3600 / 24;
4273 appendCStr_String(&str, "\n");
4274 if (days <= 30) {
4275 appendCStr_String(&str,
4276 format_CStr(cstrCount_Lang("dlg.certwarn.mayberenewed.n", days),
4277 cstrCollect_String(format_Date(&exp, "%Y-%m-%d")),
4278 days));
4279 }
4280 else {
4281 appendCStr_String(&str, cstr_Lang("dlg.certwarn.different"));
4282 }
4283 }
4284 else if (certFlags & domainVerified_GmCertFlag) {
4285 appendCStr_String(&str, "\n");
4286 appendFormat_String(&str, cstr_Lang("dlg.certwarn.expired"),
4287 cstrCollect_String(format_Date(&d->widget->certExpiry, "%Y-%m-%d")));
4288 }
4289 else if (certFlags & timeVerified_GmCertFlag) {
4290 appendCStr_String(&str, "\n");
4291 appendFormat_String(&str, cstr_Lang("dlg.certwarn.domain"),
4292 cstr_String(d->widget->certSubject));
4293 }
4294 else {
4295 appendCStr_String(&str, "\n");
4296 appendCStr_String(&str, cstr_Lang("dlg.certwarn.domain.expired"));
4297 }
4298 const iInt2 dims = measureWrapRange_Text(
4299 uiContent_FontId, width_Rect(rect) - 16 * gap_UI, range_String(&str)).bounds.size;
4300 const int warnHeight = run->visBounds.size.y - domainHeight;
4301 const int yOff = (lineHeight_Text(uiLabelLarge_FontId) -
4302 lineHeight_Text(uiContent_FontId)) / 2;
4303 const iRect bgRect =
4304 init_Rect(0, visPos.y + domainHeight, d->widgetBounds.size.x, warnHeight);
4305 fillRect_Paint(&d->paint, bgRect, orange_ColorId);
4306 if (!isDark_ColorTheme(colorTheme_App())) {
4307 drawHLine_Paint(&d->paint,
4308 topLeft_Rect(bgRect), width_Rect(bgRect), tmBannerTitle_ColorId);
4309 drawHLine_Paint(&d->paint,
4310 bottomLeft_Rect(bgRect), width_Rect(bgRect), tmBannerTitle_ColorId);
4311 }
4312 const int fg = black_ColorId;
4313 adjustEdges_Rect(&rect, warnHeight / 2 - dims.y / 2 - yOff, 0, 0, 0);
4314 bpos = topLeft_Rect(rect);
4315 draw_Text(uiLabelLarge_FontId, bpos, fg, "\u26a0");
4316 adjustEdges_Rect(&rect, 0, -8 * gap_UI, 0, 8 * gap_UI);
4317 translate_Lang(&str);
4318 drawWrapRange_Text(uiContent_FontId,
4319 addY_I2(topLeft_Rect(rect), yOff),
4320 width_Rect(rect),
4321 fg,
4322 range_String(&str));
4323 }
4324 deinit_String(&str);
4325}
4326
4327static void drawRun_DrawContext_(void *context, const iGmRun *run) { 4304static void drawRun_DrawContext_(void *context, const iGmRun *run) {
4328 iDrawContext *d = context; 4305 iDrawContext *d = context;
4329 const iInt2 origin = d->viewPos; 4306 const iInt2 origin = d->viewPos;
@@ -4430,6 +4407,7 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) {
4430 run->color, 4407 run->color,
4431 run->text); 4408 run->text);
4432 } 4409 }
4410#if 0
4433 else if (run->flags & siteBanner_GmRunFlag) { 4411 else if (run->flags & siteBanner_GmRunFlag) {
4434 /* Banner background. */ 4412 /* Banner background. */
4435 iRect bannerBack = initCorners_Rect(topLeft_Rect(d->widgetBounds), 4413 iRect bannerBack = initCorners_Rect(topLeft_Rect(d->widgetBounds),
@@ -4438,6 +4416,7 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) {
4438 fillRect_Paint(&d->paint, bannerBack, tmBannerBackground_ColorId); 4416 fillRect_Paint(&d->paint, bannerBack, tmBannerBackground_ColorId);
4439 drawBannerRun_DrawContext_(d, run, visPos); 4417 drawBannerRun_DrawContext_(d, run, visPos);
4440 } 4418 }
4419#endif
4441 else { 4420 else {
4442 if (d->showLinkNumbers && run->linkId && run->flags & decoration_GmRunFlag) { 4421 if (d->showLinkNumbers && run->linkId && run->flags & decoration_GmRunFlag) {
4443 const size_t ord = visibleLinkOrdinal_DocumentWidget_(d->widget, run->linkId); 4422 const size_t ord = visibleLinkOrdinal_DocumentWidget_(d->widget, run->linkId);
@@ -4663,8 +4642,8 @@ static void updateSideIconBuf_DocumentWidget_(const iDocumentWidget *d) {
4663 SDL_DestroyTexture(dbuf->sideIconBuf); 4642 SDL_DestroyTexture(dbuf->sideIconBuf);
4664 dbuf->sideIconBuf = NULL; 4643 dbuf->sideIconBuf = NULL;
4665 } 4644 }
4666 const iGmRun *banner = siteBanner_GmDocument(d->doc); 4645// const iGmRun *banner = siteBanner_GmDocument(d->doc);
4667 if (!banner) { 4646 if (isEmpty_Banner(d->banner)) {
4668 return; 4647 return;
4669 } 4648 }
4670 const int margin = gap_UI * d->pageMargin; 4649 const int margin = gap_UI * d->pageMargin;
@@ -4747,7 +4726,7 @@ static void drawSideElements_DocumentWidget_(const iDocumentWidget *d) {
4747 bottomLeft_Rect(bounds), 4726 bottomLeft_Rect(bounds),
4748 init_I2(margin, 4727 init_I2(margin,
4749 -margin + -dbuf->timestampBuf->size.y + 4728 -margin + -dbuf->timestampBuf->size.y +
4750 iMax(0, d->scrollY.max - pos_SmoothScroll(&d->scrollY)))), 4729 iMax(0, d->scrollY.max + viewPos_DocumentWidget_(d)))),
4751 tmQuoteIcon_ColorId); 4730 tmQuoteIcon_ColorId);
4752 } 4731 }
4753 unsetClip_Paint(&p); 4732 unsetClip_Paint(&p);
@@ -4988,7 +4967,7 @@ static void draw_DocumentWidget_(const iDocumentWidget *d) {
4988 }; 4967 };
4989 init_Paint(&ctx.paint); 4968 init_Paint(&ctx.paint);
4990 render_DocumentWidget_(d, &ctx, iFalse /* just the mandatory parts */); 4969 render_DocumentWidget_(d, &ctx, iFalse /* just the mandatory parts */);
4991 int yTop = docBounds.pos.y - pos_SmoothScroll(&d->scrollY); 4970 int yTop = docBounds.pos.y + viewPos_DocumentWidget_(d);
4992 const iBool isDocEmpty = size_GmDocument(d->doc).y == 0; 4971 const iBool isDocEmpty = size_GmDocument(d->doc).y == 0;
4993 const iBool isTouchSelecting = (flags_Widget(w) & touchDrag_WidgetFlag) != 0; 4972 const iBool isTouchSelecting = (flags_Widget(w) & touchDrag_WidgetFlag) != 0;
4994 if (!isDocEmpty) { 4973 if (!isDocEmpty) {
@@ -5025,12 +5004,22 @@ static void draw_DocumentWidget_(const iDocumentWidget *d) {
5025 } 5004 }
5026 } 5005 }
5027 drawMedia_DocumentWidget_(d, &ctx.paint); 5006 drawMedia_DocumentWidget_(d, &ctx.paint);
5028 /* Fill the top and bottom, in case the document is short. */ 5007 /* Fill the top and bottom, in case the document is short. */
5029 if (yTop > top_Rect(bounds)) { 5008 if (yTop > top_Rect(bounds)) {
5030 fillRect_Paint(&ctx.paint, 5009 fillRect_Paint(&ctx.paint,
5031 (iRect){ bounds.pos, init_I2(bounds.size.x, yTop - top_Rect(bounds)) }, 5010 (iRect){ bounds.pos, init_I2(bounds.size.x, yTop - top_Rect(bounds)) },
5032 hasSiteBanner_GmDocument(d->doc) ? tmBannerBackground_ColorId 5011 !isEmpty_Banner(d->banner) ? tmBannerBackground_ColorId
5033 : tmBackground_ColorId); 5012 : tmBackground_ColorId);
5013 }
5014 /* Banner. */ {
5015 /* Fill the part between the banner and the top of the document. */
5016 fillRect_Paint(&ctx.paint,
5017 (iRect){ init_I2(left_Rect(bounds),
5018 top_Rect(docBounds) + viewPos_DocumentWidget_(d) -
5019 documentTopPad_DocumentWidget_(d)),
5020 init_I2(bounds.size.x, documentTopPad_DocumentWidget_(d)) },
5021 tmBackground_ColorId);
5022 draw_Banner(d->banner);
5034 } 5023 }
5035 const int yBottom = yTop + size_GmDocument(d->doc).y + 1; 5024 const int yBottom = yTop + size_GmDocument(d->doc).y + 1;
5036 if (yBottom < bottom_Rect(bounds)) { 5025 if (yBottom < bottom_Rect(bounds)) {
@@ -5073,7 +5062,7 @@ static void draw_DocumentWidget_(const iDocumentWidget *d) {
5073 const int altFont = uiLabel_FontId; 5062 const int altFont = uiLabel_FontId;
5074 const int wrap = docBounds.size.x - 2 * margin; 5063 const int wrap = docBounds.size.x - 2 * margin;
5075 iInt2 pos = addY_I2(add_I2(docBounds.pos, meta->pixelRect.pos), 5064 iInt2 pos = addY_I2(add_I2(docBounds.pos, meta->pixelRect.pos),
5076 -pos_SmoothScroll(&d->scrollY)); 5065 viewPos_DocumentWidget_(d));
5077 const iInt2 textSize = measureWrapRange_Text(altFont, wrap, meta->altText).bounds.size; 5066 const iInt2 textSize = measureWrapRange_Text(altFont, wrap, meta->altText).bounds.size;
5078 pos.y -= textSize.y + gap_UI; 5067 pos.y -= textSize.y + gap_UI;
5079 pos.y = iMax(pos.y, top_Rect(bounds)); 5068 pos.y = iMax(pos.y, top_Rect(bounds));
@@ -5276,11 +5265,23 @@ void updateSize_DocumentWidget(iDocumentWidget *d) {
5276 resetWideRuns_DocumentWidget_(d); 5265 resetWideRuns_DocumentWidget_(d);
5277 d->drawBufs->flags |= updateSideBuf_DrawBufsFlag; 5266 d->drawBufs->flags |= updateSideBuf_DrawBufsFlag;
5278 updateVisible_DocumentWidget_(d); 5267 updateVisible_DocumentWidget_(d);
5268 setWidth_Banner(d->banner, documentWidth_DocumentWidget(d));
5279 invalidate_DocumentWidget_(d); 5269 invalidate_DocumentWidget_(d);
5280 arrange_Widget(d->footerButtons); 5270 arrange_Widget(d->footerButtons);
5281} 5271}
5282 5272
5273#if 0
5274static void sizeChanged_DocumentWidget_(iDocumentWidget *d) {
5275 if (current_Root()) {
5276 /* TODO: This gets called more than once during a single arrange.
5277 It could be done via some sort of callback instead. */
5278 updateVisible_DocumentWidget_(d);
5279 }
5280}
5281#endif
5282
5283iBeginDefineSubclass(DocumentWidget, Widget) 5283iBeginDefineSubclass(DocumentWidget, Widget)
5284 .processEvent = (iAny *) processEvent_DocumentWidget_, 5284 .processEvent = (iAny *) processEvent_DocumentWidget_,
5285 .draw = (iAny *) draw_DocumentWidget_, 5285 .draw = (iAny *) draw_DocumentWidget_,
5286// .sizeChanged = (iAny *) sizeChanged_DocumentWidget_,
5286iEndDefineSubclass(DocumentWidget) 5287iEndDefineSubclass(DocumentWidget)