summaryrefslogtreecommitdiff
path: root/src/gmdocument.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gmdocument.c')
-rw-r--r--src/gmdocument.c51
1 files changed, 49 insertions, 2 deletions
diff --git a/src/gmdocument.c b/src/gmdocument.c
index cb9e2acb..e23d5836 100644
--- a/src/gmdocument.c
+++ b/src/gmdocument.c
@@ -86,6 +86,8 @@ struct Impl_GmDocument {
86 iPtrArray links; 86 iPtrArray links;
87 iString title; /* the first top-level title */ 87 iString title; /* the first top-level title */
88 iPtrArray images; /* persistent across layouts, references links by ID */ 88 iPtrArray images; /* persistent across layouts, references links by ID */
89 uint32_t themeSeed;
90 iChar siteIcon;
89}; 91};
90 92
91iDefineObjectConstruction(GmDocument) 93iDefineObjectConstruction(GmDocument)
@@ -299,11 +301,12 @@ static void doLayout_GmDocument_(iGmDocument *d) {
299 enum iGmLineType prevType = text_GmLineType; 301 enum iGmLineType prevType = text_GmLineType;
300 iBool isPreformat = iFalse; 302 iBool isPreformat = iFalse;
301 iBool isFirstText = iTrue; 303 iBool isFirstText = iTrue;
304 iBool addSiteBanner = iTrue;
302 int preFont = preformatted_FontId; 305 int preFont = preformatted_FontId;
303 if (d->format == plainText_GmDocumentFormat) { 306 if (d->format == plainText_GmDocumentFormat) {
304 isPreformat = iTrue; 307 isPreformat = iTrue;
305 isFirstText = iFalse; 308 isFirstText = iFalse;
306 } 309 }
307 while (nextSplit_Rangecc(&content, "\n", &line)) { 310 while (nextSplit_Rangecc(&content, "\n", &line)) {
308 iGmRun run; 311 iGmRun run;
309 run.flags = 0; 312 run.flags = 0;
@@ -345,11 +348,26 @@ static void doLayout_GmDocument_(iGmDocument *d) {
345 startsWithSc_Rangecc(&line, "```", &iCaseSensitive)) { 348 startsWithSc_Rangecc(&line, "```", &iCaseSensitive)) {
346 isPreformat = iFalse; 349 isPreformat = iFalse;
347 preAltText = iNullRange; 350 preAltText = iNullRange;
351 addSiteBanner = iFalse; /* overrides the banner */
348 continue; 352 continue;
349 } 353 }
350 run.font = preFont; 354 run.font = preFont;
351 indent = indents[type]; 355 indent = indents[type];
352 } 356 }
357 if (addSiteBanner) {
358 addSiteBanner = iFalse;
359 const iRangecc bannerText = urlHost_String(&d->url);
360 if (!isEmpty_Range(&bannerText)) {
361 iGmRun banner = { .flags = siteBanner_GmRunFlag };
362 banner.bounds = zero_Rect();
363 banner.visBounds = init_Rect(0, 0, d->size.x, lineHeight_Text(banner_FontId) * 2);
364 banner.font = banner_FontId;
365 banner.text = bannerText;
366 banner.color = gray50_ColorId;
367 pushBack_Array(&d->layout, &banner);
368 pos.y += height_Rect(banner.visBounds) + lineHeight_Text(paragraph_FontId);
369 }
370 }
353 /* Empty lines don't produce text runs. */ 371 /* Empty lines don't produce text runs. */
354 if (isEmpty_Range(&line)) { 372 if (isEmpty_Range(&line)) {
355 pos.y += lineHeight_Text(run.font); 373 pos.y += lineHeight_Text(run.font);
@@ -415,7 +433,7 @@ static void doLayout_GmDocument_(iGmDocument *d) {
415 int bigCount = 0; 433 int bigCount = 0;
416 if (type == text_GmLineType && isFirstText) { 434 if (type == text_GmLineType && isFirstText) {
417 run.font = firstParagraph_FontId; 435 run.font = firstParagraph_FontId;
418 run.color = gray88_ColorId; 436 run.color = white_ColorId;
419 bigCount = 15; /* max lines -- what if the whole document is one paragraph? */ 437 bigCount = 15; /* max lines -- what if the whole document is one paragraph? */
420 isFirstText = iFalse; 438 isFirstText = iFalse;
421 } 439 }
@@ -505,6 +523,7 @@ void init_GmDocument(iGmDocument *d) {
505 init_PtrArray(&d->links); 523 init_PtrArray(&d->links);
506 init_String(&d->title); 524 init_String(&d->title);
507 init_PtrArray(&d->images); 525 init_PtrArray(&d->images);
526 setThemeSeed_GmDocument(d, NULL);
508} 527}
509 528
510void deinit_GmDocument(iGmDocument *d) { 529void deinit_GmDocument(iGmDocument *d) {
@@ -527,6 +546,30 @@ void reset_GmDocument(iGmDocument *d) {
527 clear_Array(&d->layout); 546 clear_Array(&d->layout);
528 clear_String(&d->url); 547 clear_String(&d->url);
529 clear_String(&d->localHost); 548 clear_String(&d->localHost);
549 d->themeSeed = 0;
550}
551
552void setThemeSeed_GmDocument(iGmDocument *d, const iBlock *seed) {
553 static const iChar siteIcons[] = {
554 0x25ed, 0x2600, 0x2601, 0x2604, 0x2605, 0x2606, 0x265c, 0x265e, 0x2690,
555 0x2691, 0x2693, 0x2698, 0x2699, 0x26f0, 0x270e, 0x2728, 0x272a, 0x272f,
556 0x2731, 0x2738, 0x273a, 0x273e, 0x2740, 0x2742, 0x2744, 0x2748, 0x274a,
557 0x2751, 0x2756, 0x2766, 0x27bd, 0x27c1, 0x27d0, 0x2b19, 0x1f300, 0x1f303,
558 0x1f306, 0x1f308, 0x1f30a, 0x1f319, 0x1f31f, 0x1f320, 0x1f340, 0x1f4cd, 0x1f4e1,
559 0x1f657, 0x1f659, 0x1f665, 0x1f78b, 0x1f796, 0x1f79c,
560 };
561 d->themeSeed = 0;
562 d->siteIcon = 0;
563 if (seed && !isEmpty_Block(seed)) {
564 d->themeSeed = crc32_Block(seed);
565 d->siteIcon = siteIcons[(d->themeSeed >> 7) % iElemCount(siteIcons)];
566 }
567 /* Special exceptions. */ {
568 const iRangecc host = urlHost_String(&d->url);
569 if (equalCase_Rangecc(&host, "gemini.circumlunar.space")) {
570 d->siteIcon = 0x264a; /* gemini */
571 }
572 }
530} 573}
531 574
532void setFormat_GmDocument(iGmDocument *d, enum iGmDocumentFormat format) { 575void setFormat_GmDocument(iGmDocument *d, enum iGmDocumentFormat format) {
@@ -786,6 +829,10 @@ const iString *title_GmDocument(const iGmDocument *d) {
786 return &d->title; 829 return &d->title;
787} 830}
788 831
832iChar siteIcon_GmDocument(const iGmDocument *d) {
833 return d->siteIcon;
834}
835
789const char *findLoc_GmRun(const iGmRun *d, iInt2 pos) { 836const char *findLoc_GmRun(const iGmRun *d, iInt2 pos) {
790 const int x = pos.x - left_Rect(d->bounds); 837 const int x = pos.x - left_Rect(d->bounds);
791 const char *loc; 838 const char *loc;