diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-07-11 16:22:58 +0300 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-07-11 16:22:58 +0300 |
commit | f7b06f4151a732a3b60f52aed1d51ce8460f1fe7 (patch) | |
tree | dfd81f8c1e8485a325c344a76c93569a5f06c941 | |
parent | 1ffac41ed4c8674b82eabf55582b7cb72f923ffd (diff) |
GmDocument: More efficient line wrapping
`WrapText` iterates over the wrapped line segments and does a callback on each one, without losing any work buffers and text shaping information along the way.
-rw-r--r-- | src/gmdocument.c | 55 |
1 files changed, 28 insertions, 27 deletions
diff --git a/src/gmdocument.c b/src/gmdocument.c index 3ea35ba9..f0c8f2b7 100644 --- a/src/gmdocument.c +++ b/src/gmdocument.c | |||
@@ -394,37 +394,30 @@ static const int colors[max_GmLineType] = { | |||
394 | tmLinkText_ColorId, | 394 | tmLinkText_ColorId, |
395 | }; | 395 | }; |
396 | 396 | ||
397 | static iRangecc typesetOneLine_RunTypesetter_(iRunTypesetter *d, iRangecc runLine) { | 397 | static iBool typesetOneLine_RunTypesetter_(iWrapText *wrap, iRangecc wrapRange, int wrapAdvance) { |
398 | iRunTypesetter *d = wrap->context; | ||
399 | const int fontId = d->run.font; | ||
400 | d->run.text = wrapRange; | ||
398 | if (~d->run.flags & startOfLine_GmRunFlag && d->lineHeightReduction > 0.0f) { | 401 | if (~d->run.flags & startOfLine_GmRunFlag && d->lineHeightReduction > 0.0f) { |
399 | d->pos.y -= d->lineHeightReduction * lineHeight_Text(d->run.font); | 402 | d->pos.y -= d->lineHeightReduction * lineHeight_Text(fontId); |
400 | } | 403 | } |
401 | d->run.bounds.pos = addX_I2(d->pos, d->indent); | 404 | d->run.bounds.pos = addX_I2(d->pos, d->indent); |
402 | const int wrapAvail = d->layoutWidth - d->run.bounds.pos.x - d->rightMargin; | 405 | const iInt2 dims = init_I2(wrapAdvance, lineHeight_Text(fontId)); |
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)); | 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. */ | 407 | d->run.bounds.size.x = iMax(wrap->maxWidth, dims.x); /* Extends to the right edge for selection. */ |
408 | d->run.bounds.size.y = dims.y; | 408 | d->run.bounds.size.y = dims.y; |
409 | d->run.visBounds = d->run.bounds; | 409 | d->run.visBounds = d->run.bounds; |
410 | d->run.visBounds.size.x = dims.x; | 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); | 411 | pushBack_Array(&d->doc->layout, &d->run); |
419 | d->run.flags &= ~startOfLine_GmRunFlag; | 412 | d->run.flags &= ~startOfLine_GmRunFlag; |
420 | runLine.start = contPos; | 413 | // runLine.start = contPos; |
421 | trimStart_Rangecc(&runLine); | 414 | // trimStart_Rangecc(&runLine); |
422 | d->pos.y += lineHeight_Text(d->run.font) * prefs_App()->lineSpacing; | 415 | d->pos.y += lineHeight_Text(fontId) * prefs_App()->lineSpacing; |
423 | if (--d->bigCount == 0) { | 416 | // if (--d->bigCount == 0) { |
424 | d->run.font = d->fonts[text_GmLineType]; | 417 | // d->run.font = d->fonts[text_GmLineType]; |
425 | d->run.color = colors[text_GmLineType]; | 418 | // d->run.color = colors[text_GmLineType]; |
426 | } | 419 | // } |
427 | return runLine; | 420 | return iTrue; /* continue to next wrapped line */ |
428 | } | 421 | } |
429 | 422 | ||
430 | static void doLayout_GmDocument_(iGmDocument *d) { | 423 | static void doLayout_GmDocument_(iGmDocument *d) { |
@@ -811,9 +804,17 @@ static void doLayout_GmDocument_(iGmDocument *d) { | |||
811 | .isPreformat = isPreformat, | 804 | .isPreformat = isPreformat, |
812 | .bigCount = bigCount, | 805 | .bigCount = bigCount, |
813 | .fonts = fonts }; | 806 | .fonts = fonts }; |
814 | while (!isEmpty_Range(&runLine)) { | 807 | // while (!isEmpty_Range(&runLine)) { |
815 | runLine = typesetOneLine_RunTypesetter_(&rts, runLine); | 808 | // runLine = typesetOneLine_RunTypesetter_(&rts, runLine); |
816 | } | 809 | // } |
810 | iWrapText wrapText = { .text = runLine, | ||
811 | .maxWidth = isWordWrapped ? d->size.x - run.bounds.pos.x - | ||
812 | rts.indent - rts.rightMargin | ||
813 | : 0 /* unlimited */, | ||
814 | .mode = word_WrapTextMode, | ||
815 | .wrapFunc = typesetOneLine_RunTypesetter_, | ||
816 | .context = &rts }; | ||
817 | measure_WrapText(&wrapText, run.font); | ||
817 | pos = rts.pos; | 818 | pos = rts.pos; |
818 | /* Flag the end of line, too. */ | 819 | /* Flag the end of line, too. */ |
819 | ((iGmRun *) back_Array(&d->layout))->flags |= endOfLine_GmRunFlag; | 820 | ((iGmRun *) back_Array(&d->layout))->flags |= endOfLine_GmRunFlag; |