summaryrefslogtreecommitdiff
path: root/src/gmdocument.c
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2021-10-06 12:16:43 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2021-10-06 12:16:43 +0300
commit61a3dc017067be43472dadb7909094aa04d1fe9d (patch)
tree18b87895489844b4e516f79cd1588038f1d49494 /src/gmdocument.c
parentf6a54d5375aab9c41af3f7c8a5e8fcbd1e0c9287 (diff)
Revised runtime font management
The built-in fonts are loaded via FontPack, and the font table is now constructed dynamically based on available fonts. A full set of variants (style, size) are prepared for each font, but some of the data gets allocated lazily when needed. GmRun needed a larger allocation for fonts, so now all the fields are combined into a single bit field. TODO: Glyph scaling, vertical offsets, and symbol lookup are still not fully working.
Diffstat (limited to 'src/gmdocument.c')
-rw-r--r--src/gmdocument.c103
1 files changed, 53 insertions, 50 deletions
diff --git a/src/gmdocument.c b/src/gmdocument.c
index 2f4c7972..ce9fdec8 100644
--- a/src/gmdocument.c
+++ b/src/gmdocument.c
@@ -355,7 +355,7 @@ static enum iGmDocumentTheme currentTheme_(void) {
355} 355}
356 356
357static void alignDecoration_GmRun_(iGmRun *run, iBool isCentered) { 357static void alignDecoration_GmRun_(iGmRun *run, iBool isCentered) {
358 const iRect visBounds = visualBounds_Text(run->textParams.font, run->text); 358 const iRect visBounds = visualBounds_Text(run->font, run->text);
359 const int visWidth = width_Rect(visBounds); 359 const int visWidth = width_Rect(visBounds);
360 int xAdjust = 0; 360 int xAdjust = 0;
361 if (!isCentered) { 361 if (!isCentered) {
@@ -438,7 +438,7 @@ static iBool typesetOneLine_RunTypesetter_(iWrapText *wrap, iRangecc wrapRange,
438 trimEnd_Rangecc(&wrapRange); 438 trimEnd_Rangecc(&wrapRange);
439// printf("typeset: {%s}\n", cstr_Rangecc(wrapRange)); 439// printf("typeset: {%s}\n", cstr_Rangecc(wrapRange));
440 iRunTypesetter *d = wrap->context; 440 iRunTypesetter *d = wrap->context;
441 const int fontId = d->run.textParams.font; 441 const int fontId = d->run.font;
442 d->run.text = wrapRange; 442 d->run.text = wrapRange;
443 if (~d->run.flags & startOfLine_GmRunFlag && d->lineHeightReduction > 0.0f) { 443 if (~d->run.flags & startOfLine_GmRunFlag && d->lineHeightReduction > 0.0f) {
444 d->pos.y -= d->lineHeightReduction * lineHeight_Text(fontId); 444 d->pos.y -= d->lineHeightReduction * lineHeight_Text(fontId);
@@ -450,7 +450,7 @@ static iBool typesetOneLine_RunTypesetter_(iWrapText *wrap, iRangecc wrapRange,
450 d->run.bounds.size.y = dims.y; 450 d->run.bounds.size.y = dims.y;
451 d->run.visBounds = d->run.bounds; 451 d->run.visBounds = d->run.bounds;
452 d->run.visBounds.size.x = dims.x; 452 d->run.visBounds.size.x = dims.x;
453 d->run.textParams.isRTL = isBaseRTL; 453 d->run.isRTL = isBaseRTL;
454 pushBack_Array(&d->layout, &d->run); 454 pushBack_Array(&d->layout, &d->run);
455 d->run.flags &= ~startOfLine_GmRunFlag; 455 d->run.flags &= ~startOfLine_GmRunFlag;
456 d->pos.y += lineHeight_Text(fontId) * prefs_App()->lineSpacing; 456 d->pos.y += lineHeight_Text(fontId) * prefs_App()->lineSpacing;
@@ -543,7 +543,7 @@ static void doLayout_GmDocument_(iGmDocument *d) {
543 if (*line.end == '\r') { 543 if (*line.end == '\r') {
544 line.end--; /* trim CR always */ 544 line.end--; /* trim CR always */
545 } 545 }
546 iGmRun run = { .textParams = { .color = white_ColorId } }; 546 iGmRun run = { .color = white_ColorId };
547 enum iGmLineType type; 547 enum iGmLineType type;
548 float indent = 0.0f; 548 float indent = 0.0f;
549 /* Detect the type of the line. */ 549 /* Detect the type of the line. */
@@ -581,14 +581,16 @@ static void doLayout_GmDocument_(iGmDocument *d) {
581 continue; 581 continue;
582 } 582 }
583 else if (type == link_GmLineType) { 583 else if (type == link_GmLineType) {
584 line = addLink_GmDocument_(d, line, &run.linkId); 584 iGmLinkId linkId;
585 line = addLink_GmDocument_(d, line, &linkId);
586 run.linkId = linkId;
585 if (!run.linkId) { 587 if (!run.linkId) {
586 /* Invalid formatting. */ 588 /* Invalid formatting. */
587 type = text_GmLineType; 589 type = text_GmLineType;
588 } 590 }
589 } 591 }
590 trimLine_Rangecc(&line, type, isNormalized); 592 trimLine_Rangecc(&line, type, isNormalized);
591 run.textParams.font = fonts[type]; 593 run.font = fonts[type];
592 /* Remember headings for the document outline. */ 594 /* Remember headings for the document outline. */
593 if (type == heading1_GmLineType || type == heading2_GmLineType || type == heading3_GmLineType) { 595 if (type == heading1_GmLineType || type == heading2_GmLineType || type == heading3_GmLineType) {
594 pushBack_Array( 596 pushBack_Array(
@@ -609,7 +611,7 @@ static void doLayout_GmDocument_(iGmDocument *d) {
609 continue; 611 continue;
610 } 612 }
611 run.preId = preId; 613 run.preId = preId;
612 run.textParams.font = (d->format == plainText_SourceFormat ? regularMonospace_FontId : preFont); 614 run.font = (d->format == plainText_SourceFormat ? regularMonospace_FontId : preFont);
613 indent = indents[type]; 615 indent = indents[type];
614 } 616 }
615 if (addSiteBanner) { 617 if (addSiteBanner) {
@@ -624,9 +626,9 @@ static void doLayout_GmDocument_(iGmDocument *d) {
624 banner.visBounds.size.y += iMaxi(6000 * lineHeight_Text(uiLabel_FontId) / 626 banner.visBounds.size.y += iMaxi(6000 * lineHeight_Text(uiLabel_FontId) /
625 d->size.x, lineHeight_Text(uiLabel_FontId) * 5); 627 d->size.x, lineHeight_Text(uiLabel_FontId) * 5);
626 } 628 }
627 banner.text = bannerText; 629 banner.text = bannerText;
628 banner.textParams.font = banner_FontId; 630 banner.font = banner_FontId;
629 banner.textParams.color = tmBannerTitle_ColorId; 631 banner.color = tmBannerTitle_ColorId;
630 pushBack_Array(&d->layout, &banner); 632 pushBack_Array(&d->layout, &banner);
631 pos.y += height_Rect(banner.visBounds) + 633 pos.y += height_Rect(banner.visBounds) +
632 1.5f * lineHeight_Text(paragraph_FontId) * prefs->lineSpacing; 634 1.5f * lineHeight_Text(paragraph_FontId) * prefs->lineSpacing;
@@ -637,13 +639,13 @@ static void doLayout_GmDocument_(iGmDocument *d) {
637 if (type == quote_GmLineType && !prefs->quoteIcon) { 639 if (type == quote_GmLineType && !prefs->quoteIcon) {
638 /* For quote indicators we still need to produce a run. */ 640 /* For quote indicators we still need to produce a run. */
639 run.visBounds.pos = addX_I2(pos, indents[type] * gap_Text); 641 run.visBounds.pos = addX_I2(pos, indents[type] * gap_Text);
640 run.visBounds.size = init_I2(gap_Text, lineHeight_Text(run.textParams.font)); 642 run.visBounds.size = init_I2(gap_Text, lineHeight_Text(run.font));
641 run.bounds = zero_Rect(); /* just visual */ 643 run.bounds = zero_Rect(); /* just visual */
642 run.flags = quoteBorder_GmRunFlag | decoration_GmRunFlag;
643 run.text = iNullRange; 644 run.text = iNullRange;
645 run.flags = quoteBorder_GmRunFlag | decoration_GmRunFlag;
644 pushBack_Array(&d->layout, &run); 646 pushBack_Array(&d->layout, &run);
645 } 647 }
646 pos.y += lineHeight_Text(run.textParams.font) * prefs->lineSpacing; 648 pos.y += lineHeight_Text(run.font) * prefs->lineSpacing;
647 prevType = type; 649 prevType = type;
648 if (type != quote_GmLineType) { 650 if (type != quote_GmLineType) {
649 addQuoteIcon = prefs->quoteIcon; 651 addQuoteIcon = prefs->quoteIcon;
@@ -687,14 +689,14 @@ static void doLayout_GmDocument_(iGmDocument *d) {
687 const iGmPreMeta *meta = constAt_Array(&d->preMeta, preId - 1); 689 const iGmPreMeta *meta = constAt_Array(&d->preMeta, preId - 1);
688 if (meta->flags & folded_GmPreMetaFlag) { 690 if (meta->flags & folded_GmPreMetaFlag) {
689 const iBool isBlank = isEmpty_Range(&meta->altText); 691 const iBool isBlank = isEmpty_Range(&meta->altText);
690 iGmRun altText = { 692 iGmRun altText = { .font = paragraph_FontId,
691 .textParams = { .font = paragraph_FontId, .color = tmQuote_ColorId }, 693 .color = tmQuote_ColorId,
692 .flags = (isBlank ? decoration_GmRunFlag : 0) | altText_GmRunFlag 694 .flags = (isBlank ? decoration_GmRunFlag : 0) | altText_GmRunFlag
693 }; 695 };
694 const iInt2 margin = preRunMargin_GmDocument(d, 0); 696 const iInt2 margin = preRunMargin_GmDocument(d, 0);
695 altText.text = isBlank ? range_Lang(range_CStr("doc.pre.nocaption")) 697 altText.text = isBlank ? range_Lang(range_CStr("doc.pre.nocaption"))
696 : meta->altText; 698 : meta->altText;
697 iInt2 size = measureWrapRange_Text(altText.textParams.font, d->size.x - 2 * margin.x, 699 iInt2 size = measureWrapRange_Text(altText.font, d->size.x - 2 * margin.x,
698 altText.text).bounds.size; 700 altText.text).bounds.size;
699 altText.bounds = altText.visBounds = init_Rect(pos.x, pos.y, d->size.x, 701 altText.bounds = altText.visBounds = init_Rect(pos.x, pos.y, d->size.x,
700 size.y + 2 * margin.y); 702 size.y + 2 * margin.y);
@@ -713,19 +715,20 @@ static void doLayout_GmDocument_(iGmDocument *d) {
713 setRange_String(&d->title, line); 715 setRange_String(&d->title, line);
714 } 716 }
715 /* List bullet. */ 717 /* List bullet. */
716 run.textParams.color = colors[type]; 718 run.color = colors[type];
717 if (type == bullet_GmLineType) { 719 if (type == bullet_GmLineType) {
718 /* TODO: Literata bullet is broken? */ 720 /* TODO: Literata bullet is broken? */
719 iGmRun bulRun = run; 721 iGmRun bulRun = run;
720 if (prefs->font == literata_TextFont) { 722 if (prefs->font == literata_TextFont) {
721 /* Something wrong this the glyph in Literata, looks cropped. */ 723 /* Something wrong this the glyph in Literata, looks cropped. */
722 bulRun.textParams.font = defaultContentRegular_FontId; 724 bulRun.font = FONT_ID(default_FontId, regular_FontStyle,
725 contentRegular_FontSize);
723 } 726 }
724 bulRun.textParams.color = tmQuote_ColorId; 727 bulRun.color = tmQuote_ColorId;
725 bulRun.visBounds.pos = addX_I2(pos, (indents[text_GmLineType] - 0.55f) * gap_Text); 728 bulRun.visBounds.pos = addX_I2(pos, (indents[text_GmLineType] - 0.55f) * gap_Text);
726 bulRun.visBounds.size = 729 bulRun.visBounds.size =
727 init_I2((indents[bullet_GmLineType] - indents[text_GmLineType]) * gap_Text, 730 init_I2((indents[bullet_GmLineType] - indents[text_GmLineType]) * gap_Text,
728 lineHeight_Text(bulRun.textParams.font)); 731 lineHeight_Text(bulRun.font));
729 // bulRun.visBounds.pos.x -= 4 * gap_Text - width_Rect(bulRun.visBounds) / 2; 732 // bulRun.visBounds.pos.x -= 4 * gap_Text - width_Rect(bulRun.visBounds) / 2;
730 bulRun.bounds = zero_Rect(); /* just visual */ 733 bulRun.bounds = zero_Rect(); /* just visual */
731 bulRun.text = range_CStr(bullet); 734 bulRun.text = range_CStr(bullet);
@@ -737,11 +740,11 @@ static void doLayout_GmDocument_(iGmDocument *d) {
737 if (type == quote_GmLineType && addQuoteIcon) { 740 if (type == quote_GmLineType && addQuoteIcon) {
738 addQuoteIcon = iFalse; 741 addQuoteIcon = iFalse;
739 iGmRun quoteRun = run; 742 iGmRun quoteRun = run;
740 quoteRun.textParams.font = heading1_FontId; 743 quoteRun.font = heading1_FontId;
741 quoteRun.text = range_CStr(quote); 744 quoteRun.text = range_CStr(quote);
742 quoteRun.textParams.color = tmQuoteIcon_ColorId; 745 quoteRun.color = tmQuoteIcon_ColorId;
743 iRect vis = visualBounds_Text(quoteRun.textParams.font, quoteRun.text); 746 iRect vis = visualBounds_Text(quoteRun.font, quoteRun.text);
744 quoteRun.visBounds.size = measure_Text(quoteRun.textParams.font, quote).bounds.size; 747 quoteRun.visBounds.size = measure_Text(quoteRun.font, quote).bounds.size;
745 quoteRun.visBounds.pos = 748 quoteRun.visBounds.pos =
746 add_I2(pos, 749 add_I2(pos,
747 init_I2((indents[quote_GmLineType] - 5) * gap_Text, 750 init_I2((indents[quote_GmLineType] - 5) * gap_Text,
@@ -757,7 +760,7 @@ static void doLayout_GmDocument_(iGmDocument *d) {
757 if (type == link_GmLineType) { 760 if (type == link_GmLineType) {
758 iGmRun icon = run; 761 iGmRun icon = run;
759 icon.visBounds.pos = pos; 762 icon.visBounds.pos = pos;
760 icon.visBounds.size = init_I2(indent * gap_Text, lineHeight_Text(run.textParams.font)); 763 icon.visBounds.size = init_I2(indent * gap_Text, lineHeight_Text(run.font));
761 icon.bounds = zero_Rect(); /* just visual */ 764 icon.bounds = zero_Rect(); /* just visual */
762 const iGmLink *link = constAt_PtrArray(&d->links, run.linkId - 1); 765 const iGmLink *link = constAt_PtrArray(&d->links, run.linkId - 1);
763 const enum iGmLinkScheme scheme = scheme_GmLinkFlag(link->flags); 766 const enum iGmLinkScheme scheme = scheme_GmLinkFlag(link->flags);
@@ -775,23 +778,23 @@ static void doLayout_GmDocument_(iGmDocument *d) {
775 } 778 }
776 /* TODO: List bullets needs the same centering logic. */ 779 /* TODO: List bullets needs the same centering logic. */
777 /* Special exception for the tiny bullet operator. */ 780 /* Special exception for the tiny bullet operator. */
778 icon.textParams.font = equal_Rangecc(link->labelIcon, "\u2219") ? regularMonospace_FontId 781 icon.font = equal_Rangecc(link->labelIcon, "\u2219") ? regularMonospace_FontId
779 : regular_FontId; 782 : paragraph_FontId;
780 alignDecoration_GmRun_(&icon, iFalse); 783 alignDecoration_GmRun_(&icon, iFalse);
781 icon.textParams.color = linkColor_GmDocument(d, run.linkId, icon_GmLinkPart); 784 icon.color = linkColor_GmDocument(d, run.linkId, icon_GmLinkPart);
782 icon.flags |= decoration_GmRunFlag; 785 icon.flags |= decoration_GmRunFlag;
783 pushBack_Array(&d->layout, &icon); 786 pushBack_Array(&d->layout, &icon);
784 } 787 }
785 run.textParams.color = colors[type]; 788 run.color = colors[type];
786 if (d->format == plainText_SourceFormat) { 789 if (d->format == plainText_SourceFormat) {
787 run.textParams.color = colors[text_GmLineType]; 790 run.color = colors[text_GmLineType];
788 } 791 }
789 /* Special formatting for the first paragraph (e.g., subtitle, introduction, or lede). */ 792 /* Special formatting for the first paragraph (e.g., subtitle, introduction, or lede). */
790// int bigCount = 0; 793// int bigCount = 0;
791 iBool isLedeParagraph = iFalse; 794 iBool isLedeParagraph = iFalse;
792 if (type == text_GmLineType && isFirstText) { 795 if (type == text_GmLineType && isFirstText) {
793 if (!isMono) run.textParams.font = firstParagraph_FontId; 796 if (!isMono) run.font = firstParagraph_FontId;
794 run.textParams.color = tmFirstParagraph_ColorId; 797 run.color = tmFirstParagraph_ColorId;
795// bigCount = 15; /* max lines -- what if the whole document is one paragraph? */ 798// bigCount = 15; /* max lines -- what if the whole document is one paragraph? */
796 isLedeParagraph = iTrue; 799 isLedeParagraph = iTrue;
797 isFirstText = iFalse; 800 isFirstText = iFalse;
@@ -838,7 +841,7 @@ static void doLayout_GmDocument_(iGmDocument *d) {
838 } 841 }
839 /* Visited links are never bold. */ 842 /* Visited links are never bold. */
840 if (run.linkId && linkFlags_GmDocument(d, run.linkId) & visited_GmLinkFlag) { 843 if (run.linkId && linkFlags_GmDocument(d, run.linkId) & visited_GmLinkFlag) {
841 rts.run.textParams.font = paragraph_FontId; 844 rts.run.font = paragraph_FontId;
842 } 845 }
843 } 846 }
844 if (!prefs->quoteIcon && type == quote_GmLineType) { 847 if (!prefs->quoteIcon && type == quote_GmLineType) {
@@ -854,7 +857,7 @@ static void doLayout_GmDocument_(iGmDocument *d) {
854 .mode = word_WrapTextMode, 857 .mode = word_WrapTextMode,
855 .wrapFunc = typesetOneLine_RunTypesetter_, 858 .wrapFunc = typesetOneLine_RunTypesetter_,
856 .context = &rts }; 859 .context = &rts };
857 measure_WrapText(&wrapText, rts.run.textParams.font); 860 measure_WrapText(&wrapText, rts.run.font);
858 if (!isLedeParagraph || size_Array(&rts.layout) <= maxLedeLines_) { 861 if (!isLedeParagraph || size_Array(&rts.layout) <= maxLedeLines_) {
859 if (wrapText.baseDir < 0) { 862 if (wrapText.baseDir < 0) {
860 /* Right-aligned paragraphs need margins and decorations to be flipped. */ 863 /* Right-aligned paragraphs need margins and decorations to be flipped. */
@@ -880,8 +883,8 @@ static void doLayout_GmDocument_(iGmDocument *d) {
880 } 883 }
881 clear_RunTypesetter_(&rts); 884 clear_RunTypesetter_(&rts);
882 rts.pos = pos; 885 rts.pos = pos;
883 rts.run.textParams.font = rts.fonts[text_GmLineType]; 886 rts.run.font = rts.fonts[text_GmLineType];
884 rts.run.textParams.color = colors[text_GmLineType]; 887 rts.run.color = colors[text_GmLineType];
885 isLedeParagraph = iFalse; 888 isLedeParagraph = iFalse;
886 } 889 }
887 pos = rts.pos; 890 pos = rts.pos;
@@ -922,11 +925,11 @@ static void doLayout_GmDocument_(iGmDocument *d) {
922 run.visBounds.pos.x = run.bounds.size.x / 2 - width_Rect(run.visBounds) / 2; 925 run.visBounds.pos.x = run.bounds.size.x / 2 - width_Rect(run.visBounds) / 2;
923 run.bounds.size.y = run.visBounds.size.y; 926 run.bounds.size.y = run.visBounds.size.y;
924 } 927 }
925 run.text = iNullRange; 928 run.text = iNullRange;
926 run.textParams.font = 0; 929 run.font = 0;
927 run.textParams.color = 0; 930 run.color = 0;
928 run.mediaType = image_GmRunMediaType; 931 run.mediaType = image_GmRunMediaType;
929 run.mediaId = imageId; 932 run.mediaId = imageId;
930 pushBack_Array(&d->layout, &run); 933 pushBack_Array(&d->layout, &run);
931 pos.y += run.bounds.size.y + margin; 934 pos.y += run.bounds.size.y + margin;
932 } 935 }
@@ -941,9 +944,9 @@ static void doLayout_GmDocument_(iGmDocument *d) {
941 run.bounds.size.y = lineHeight_Text(uiContent_FontId) + 3 * gap_UI; 944 run.bounds.size.y = lineHeight_Text(uiContent_FontId) + 3 * gap_UI;
942 run.visBounds = run.bounds; 945 run.visBounds = run.bounds;
943 run.text = iNullRange; 946 run.text = iNullRange;
944 run.textParams.color = 0; 947 run.color = 0;
945 run.mediaType = audio_GmRunMediaType; 948 run.mediaType = audio_GmRunMediaType;
946 run.mediaId = audioId; 949 run.mediaId = audioId;
947 pushBack_Array(&d->layout, &run); 950 pushBack_Array(&d->layout, &run);
948 pos.y += run.bounds.size.y + margin; 951 pos.y += run.bounds.size.y + margin;
949 } 952 }
@@ -958,7 +961,7 @@ static void doLayout_GmDocument_(iGmDocument *d) {
958 run.bounds.size.y = 2 * lineHeight_Text(uiContent_FontId) + 4 * gap_UI; 961 run.bounds.size.y = 2 * lineHeight_Text(uiContent_FontId) + 4 * gap_UI;
959 run.visBounds = run.bounds; 962 run.visBounds = run.bounds;
960 run.text = iNullRange; 963 run.text = iNullRange;
961 run.textParams.color = 0; 964 run.color = 0;
962 run.mediaType = download_GmRunMediaType; 965 run.mediaType = download_GmRunMediaType;
963 run.mediaId = downloadId; 966 run.mediaId = downloadId;
964 pushBack_Array(&d->layout, &run); 967 pushBack_Array(&d->layout, &run);
@@ -1572,11 +1575,11 @@ static void markLinkRunsVisited_GmDocument_(iGmDocument *d, const iIntSet *linkI
1572 iForEach(Array, r, &d->layout) { 1575 iForEach(Array, r, &d->layout) {
1573 iGmRun *run = r.value; 1576 iGmRun *run = r.value;
1574 if (run->linkId && !run->mediaId && contains_IntSet(linkIds, run->linkId)) { 1577 if (run->linkId && !run->mediaId && contains_IntSet(linkIds, run->linkId)) {
1575 if (run->textParams.font == bold_FontId) { 1578 if (run->font == bold_FontId) {
1576 run->textParams.font = paragraph_FontId; 1579 run->font = paragraph_FontId;
1577 } 1580 }
1578 else if (run->flags & decoration_GmRunFlag) { 1581 else if (run->flags & decoration_GmRunFlag) {
1579 run->textParams.color = linkColor_GmDocument(d, run->linkId, icon_GmLinkPart); 1582 run->color = linkColor_GmDocument(d, run->linkId, icon_GmLinkPart);
1580 } 1583 }
1581 } 1584 }
1582 } 1585 }
@@ -2072,7 +2075,7 @@ iRangecc findLoc_GmRun(const iGmRun *d, iInt2 pos) {
2072 return (iRangecc){ d->text.start, d->text.start }; 2075 return (iRangecc){ d->text.start, d->text.start };
2073 } 2076 }
2074 iRangecc loc; 2077 iRangecc loc;
2075 tryAdvanceNoWrap_Text(d->textParams.font, d->text, x, &loc.start); 2078 tryAdvanceNoWrap_Text(d->font, d->text, x, &loc.start);
2076 loc.end = loc.start; 2079 loc.end = loc.start;
2077 if (!contains_Range(&d->text, loc.start)) { 2080 if (!contains_Range(&d->text, loc.start)) {
2078 return iNullRange; /* it's some other text */ 2081 return iNullRange; /* it's some other text */