summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2021-07-11 15:29:01 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2021-07-11 15:29:01 +0300
commit1ffac41ed4c8674b82eabf55582b7cb72f923ffd (patch)
treeef41f72360fe131089729416a3585bef548ac7bf
parent6748fe343a388dd24dfe45cfbda75cf85de8ebcf (diff)
GmDocument: Refactoring line typesetter
The goal is to switch to `WrapText` so the entire paragraph can be processed in one go without having to re-initialize the HarfBuzz buffers after every wrap.
-rw-r--r--src/gmdocument.c112
1 files changed, 73 insertions, 39 deletions
diff --git a/src/gmdocument.c b/src/gmdocument.c
index 3d91fb34..3ea35ba9 100644
--- a/src/gmdocument.c
+++ b/src/gmdocument.c
@@ -367,6 +367,66 @@ static void updateOpenURLs_GmDocument_(iGmDocument *d) {
367 d->openURLs = listOpenURLs_App(); 367 d->openURLs = listOpenURLs_App();
368} 368}
369 369
370iDeclareType(RunTypesetter)
371
372struct Impl_RunTypesetter {
373 iGmDocument *doc;
374 iGmRun run;
375 iInt2 pos;
376 float lineHeightReduction;
377 int indent;
378 int layoutWidth;
379 int rightMargin;
380 iBool isWordWrapped;
381 iBool isPreformat;
382 int bigCount;
383 const int *fonts;
384};
385
386static const int colors[max_GmLineType] = {
387 tmParagraph_ColorId,
388 tmParagraph_ColorId,
389 tmPreformatted_ColorId,
390 tmQuote_ColorId,
391 tmHeading1_ColorId,
392 tmHeading2_ColorId,
393 tmHeading3_ColorId,
394 tmLinkText_ColorId,
395};
396
397static iRangecc typesetOneLine_RunTypesetter_(iRunTypesetter *d, iRangecc runLine) {
398 if (~d->run.flags & startOfLine_GmRunFlag && d->lineHeightReduction > 0.0f) {
399 d->pos.y -= d->lineHeightReduction * lineHeight_Text(d->run.font);
400 }
401 d->run.bounds.pos = addX_I2(d->pos, d->indent);
402 const int wrapAvail = d->layoutWidth - d->run.bounds.pos.x - d->rightMargin;
403 const int avail = d->isWordWrapped ? wrapAvail : 0;
404 const char *contPos;
405 const iInt2 dims = tryAdvance_Text(d->run.font, runLine, avail, &contPos);
406 iChangeFlags(d->run.flags, wide_GmRunFlag, (d->isPreformat && dims.x > d->layoutWidth));
407 d->run.bounds.size.x = iMax(wrapAvail, dims.x); /* Extends to the right edge for selection. */
408 d->run.bounds.size.y = dims.y;
409 d->run.visBounds = d->run.bounds;
410 d->run.visBounds.size.x = dims.x;
411 if (contPos > runLine.start) {
412 d->run.text = (iRangecc){ runLine.start, contPos };
413 }
414 else {
415 d->run.text = runLine;
416 contPos = runLine.end;
417 }
418 pushBack_Array(&d->doc->layout, &d->run);
419 d->run.flags &= ~startOfLine_GmRunFlag;
420 runLine.start = contPos;
421 trimStart_Rangecc(&runLine);
422 d->pos.y += lineHeight_Text(d->run.font) * prefs_App()->lineSpacing;
423 if (--d->bigCount == 0) {
424 d->run.font = d->fonts[text_GmLineType];
425 d->run.color = colors[text_GmLineType];
426 }
427 return runLine;
428}
429
370static void doLayout_GmDocument_(iGmDocument *d) { 430static void doLayout_GmDocument_(iGmDocument *d) {
371 const iPrefs *prefs = prefs_App(); 431 const iPrefs *prefs = prefs_App();
372 const iBool isMono = isForcedMonospace_GmDocument_(d); 432 const iBool isMono = isForcedMonospace_GmDocument_(d);
@@ -390,16 +450,6 @@ static void doLayout_GmDocument_(iGmDocument *d) {
390 ? bold_FontId 450 ? bold_FontId
391 : paragraph_FontId, 451 : paragraph_FontId,
392 }; 452 };
393 static const int colors[max_GmLineType] = {
394 tmParagraph_ColorId,
395 tmParagraph_ColorId,
396 tmPreformatted_ColorId,
397 tmQuote_ColorId,
398 tmHeading1_ColorId,
399 tmHeading2_ColorId,
400 tmHeading3_ColorId,
401 tmLinkText_ColorId,
402 };
403 float indents[max_GmLineType] = { 453 float indents[max_GmLineType] = {
404 5, 10, 5, isNarrow ? 5 : 10, 0, 0, 0, 5 454 5, 10, 5, isNarrow ? 5 : 10, 0, 0, 0, 5
405 }; 455 };
@@ -750,37 +800,21 @@ static void doLayout_GmDocument_(iGmDocument *d) {
750 } 800 }
751 } 801 }
752 iAssert(!isEmpty_Range(&runLine)); /* must have something at this point */ 802 iAssert(!isEmpty_Range(&runLine)); /* must have something at this point */
803 iRunTypesetter rts = { .doc = d,
804 .run = run,
805 .pos = pos,
806 .lineHeightReduction = lineHeightReduction,
807 .indent = indent * gap_Text,
808 .layoutWidth = d->size.x,
809 .rightMargin = rightMargin * gap_Text,
810 .isWordWrapped = isWordWrapped,
811 .isPreformat = isPreformat,
812 .bigCount = bigCount,
813 .fonts = fonts };
753 while (!isEmpty_Range(&runLine)) { 814 while (!isEmpty_Range(&runLine)) {
754 if (~run.flags & startOfLine_GmRunFlag && lineHeightReduction > 0.0f) { 815 runLine = typesetOneLine_RunTypesetter_(&rts, runLine);
755 pos.y -= lineHeightReduction * lineHeight_Text(run.font);
756 }
757 run.bounds.pos = addX_I2(pos, indent * gap_Text);
758 const int wrapAvail = d->size.x - run.bounds.pos.x - rightMargin * gap_Text;
759 const int avail = isWordWrapped ? wrapAvail : 0;
760 const char *contPos;
761 const iInt2 dims = tryAdvance_Text(run.font, runLine, avail, &contPos);
762 iChangeFlags(run.flags, wide_GmRunFlag, (isPreformat && dims.x > d->size.x));
763 run.bounds.size.x = iMax(wrapAvail, dims.x); /* Extends to the right edge for selection. */
764 run.bounds.size.y = dims.y;
765 run.visBounds = run.bounds;
766 run.visBounds.size.x = dims.x;
767 if (contPos > runLine.start) {
768 run.text = (iRangecc){ runLine.start, contPos };
769 }
770 else {
771 run.text = runLine;
772 contPos = runLine.end;
773 }
774 pushBack_Array(&d->layout, &run);
775 run.flags &= ~startOfLine_GmRunFlag;
776 runLine.start = contPos;
777 trimStart_Rangecc(&runLine);
778 pos.y += lineHeight_Text(run.font) * prefs->lineSpacing;
779 if (--bigCount == 0) {
780 run.font = fonts[text_GmLineType];
781 run.color = colors[text_GmLineType];
782 }
783 } 816 }
817 pos = rts.pos;
784 /* Flag the end of line, too. */ 818 /* Flag the end of line, too. */
785 ((iGmRun *) back_Array(&d->layout))->flags |= endOfLine_GmRunFlag; 819 ((iGmRun *) back_Array(&d->layout))->flags |= endOfLine_GmRunFlag;
786 /* Image or audio content. */ 820 /* Image or audio content. */