summaryrefslogtreecommitdiff
path: root/src/gmdocument.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gmdocument.c')
-rw-r--r--src/gmdocument.c30
1 files changed, 28 insertions, 2 deletions
diff --git a/src/gmdocument.c b/src/gmdocument.c
index 42bc7515..6c66451c 100644
--- a/src/gmdocument.c
+++ b/src/gmdocument.c
@@ -67,6 +67,21 @@ static int lastVisibleRunBottom_GmDocument_(const iGmDocument *d) {
67 return 0; 67 return 0;
68} 68}
69 69
70iInt2 measurePreformattedBlock_GmDocument_(const iGmDocument *d, const char *start, int font) {
71 const iRangecc content = { start, constEnd_String(&d->source) };
72 iRangecc line = iNullRange;
73 nextSplit_Rangecc(&content, "\n", &line);
74 iAssert(startsWith_Rangecc(&line, "```"));
75 iRangecc preBlock = { line.end + 1, line.end + 1 };
76 while (nextSplit_Rangecc(&content, "\n", &line)) {
77 if (startsWith_Rangecc(&line, "```")) {
78 break;
79 }
80 preBlock.end = line.end;
81 }
82 return measureRange_Text(font, preBlock);
83}
84
70static void doLayout_GmDocument_(iGmDocument *d) { 85static void doLayout_GmDocument_(iGmDocument *d) {
71 if (d->size.x <= 0 || isEmpty_String(&d->source)) { 86 if (d->size.x <= 0 || isEmpty_String(&d->source)) {
72 return; 87 return;
@@ -98,6 +113,7 @@ static void doLayout_GmDocument_(iGmDocument *d) {
98 iRangecc preAltText = iNullRange; 113 iRangecc preAltText = iNullRange;
99 enum iGmLineType prevType = text_GmLineType; 114 enum iGmLineType prevType = text_GmLineType;
100 iBool isFirstText = iTrue; 115 iBool isFirstText = iTrue;
116 int preFont = preformatted_FontId;
101 while (nextSplit_Rangecc(&content, "\n", &line)) { 117 while (nextSplit_Rangecc(&content, "\n", &line)) {
102 iGmRun run; 118 iGmRun run;
103 run.color = white_ColorId; 119 run.color = white_ColorId;
@@ -109,6 +125,12 @@ static void doLayout_GmDocument_(iGmDocument *d) {
109 indent = indents[type]; 125 indent = indents[type];
110 if (type == preformatted_GmLineType) { 126 if (type == preformatted_GmLineType) {
111 isPreformat = iTrue; 127 isPreformat = iTrue;
128 preFont = preformatted_FontId;
129 /* Use a smaller font if the block contents are wide. */
130 if (measurePreformattedBlock_GmDocument_(d, line.start, preFont).x >
131 d->size.x - indents[preformatted_GmLineType]) {
132 preFont = preformattedSmall_FontId;
133 }
112 trimLine_Rangecc_(&line, type); 134 trimLine_Rangecc_(&line, type);
113 preAltText = line; 135 preAltText = line;
114 /* TODO: store and link the alt text to this run */ 136 /* TODO: store and link the alt text to this run */
@@ -118,21 +140,23 @@ static void doLayout_GmDocument_(iGmDocument *d) {
118 run.font = fonts[type]; 140 run.font = fonts[type];
119 } 141 }
120 else { 142 else {
143 /* Preformatted line. */
121 type = preformatted_GmLineType; 144 type = preformatted_GmLineType;
122 if (startsWithSc_Rangecc(&line, "```", &iCaseSensitive)) { 145 if (startsWithSc_Rangecc(&line, "```", &iCaseSensitive)) {
123 isPreformat = iFalse; 146 isPreformat = iFalse;
124 preAltText = iNullRange; 147 preAltText = iNullRange;
125 continue; 148 continue;
126 } 149 }
127 run.font = preformatted_FontId; 150 run.font = preFont;
128 indent = indents[type]; 151 indent = indents[type];
129 } 152 }
130 /* Check the margin. */ 153 /* Empty lines don't produce text runs. */
131 if (isEmpty_Range(&line)) { 154 if (isEmpty_Range(&line)) {
132 pos.y += lineHeight_Text(run.font); 155 pos.y += lineHeight_Text(run.font);
133 prevType = text_GmLineType; 156 prevType = text_GmLineType;
134 continue; 157 continue;
135 } 158 }
159 /* Check the margin vs. previous run. */
136 if (!isPreformat || (prevType != preformatted_GmLineType)) { 160 if (!isPreformat || (prevType != preformatted_GmLineType)) {
137 int required = 161 int required =
138 iMax(topMargin[type], bottomMargin[prevType]) * lineHeight_Text(paragraph_FontId); 162 iMax(topMargin[type], bottomMargin[prevType]) * lineHeight_Text(paragraph_FontId);
@@ -144,6 +168,7 @@ static void doLayout_GmDocument_(iGmDocument *d) {
144 pos.y += required - delta; 168 pos.y += required - delta;
145 } 169 }
146 } 170 }
171 /* List bullet. */
147 if (type == bullet_GmLineType) { 172 if (type == bullet_GmLineType) {
148 run.bounds.pos = addX_I2(pos, indent * gap_UI); 173 run.bounds.pos = addX_I2(pos, indent * gap_UI);
149 run.bounds.size = advance_Text(run.font, bullet); 174 run.bounds.size = advance_Text(run.font, bullet);
@@ -151,6 +176,7 @@ static void doLayout_GmDocument_(iGmDocument *d) {
151 run.text = (iRangecc){ bullet, bullet + strlen(bullet) }; 176 run.text = (iRangecc){ bullet, bullet + strlen(bullet) };
152 pushBack_Array(&d->layout, &run); 177 pushBack_Array(&d->layout, &run);
153 } 178 }
179 /* Special formatting for the first paragraph (e.g., subtitle, introduction, or lede). */
154 if (type == text_GmLineType && isFirstText) { 180 if (type == text_GmLineType && isFirstText) {
155 run.font = firstParagraph_FontId; 181 run.font = firstParagraph_FontId;
156 isFirstText = iFalse; 182 isFirstText = iFalse;