summaryrefslogtreecommitdiff
path: root/src/ui
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2021-10-15 12:08:27 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2021-10-15 12:08:27 +0300
commit2f3987f5e54d95658f95c6991b0644bc15eedabf (patch)
treec8b76534a2b5d758c3062603afb3b2665856a548 /src/ui
parentf5938745dcbe567d6e52f79b63151584d2c917d8 (diff)
Text: Fixed a line wrapping issue
When the last safe break position was not in the current attributed run, the calculated wrap advance came out incorrect. This was possible when the first glyph in an attributed run didn't fit.
Diffstat (limited to 'src/ui')
-rw-r--r--src/ui/documentwidget.c6
-rw-r--r--src/ui/text.c79
2 files changed, 50 insertions, 35 deletions
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index 8fefb95c..924dc0c4 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -4522,8 +4522,10 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) {
4522 } 4522 }
4523 } 4523 }
4524 } 4524 }
4525// drawRect_Paint(&d->paint, (iRect){ visPos, run->bounds.size }, green_ColorId); 4525 if (0) {
4526// drawRect_Paint(&d->paint, (iRect){ visPos, run->visBounds.size }, red_ColorId); 4526 drawRect_Paint(&d->paint, (iRect){ visPos, run->bounds.size }, green_ColorId);
4527 drawRect_Paint(&d->paint, (iRect){ visPos, run->visBounds.size }, red_ColorId);
4528 }
4527} 4529}
4528 4530
4529static int drawSideRect_(iPaint *p, iRect rect) { 4531static int drawSideRect_(iPaint *p, iRect rect) {
diff --git a/src/ui/text.c b/src/ui/text.c
index 7afaf583..d22faea1 100644
--- a/src/ui/text.c
+++ b/src/ui/text.c
@@ -214,7 +214,6 @@ static void init_Font(iFont *d, const iFontSpec *fontSpec, const iFontFile *font
214 d->baseline = fontFile->ascent * d->yScale; 214 d->baseline = fontFile->ascent * d->yScale;
215 d->vertOffset = d->height * (1.0f - glyphScale) / 2 * fontSpec->vertOffsetScale[scaleType]; 215 d->vertOffset = d->height * (1.0f - glyphScale) / 2 * fontSpec->vertOffsetScale[scaleType];
216 d->table = NULL; 216 d->table = NULL;
217 // printf("{%s} height:%d baseline:%d\n", cstr_String(&d->fontSpec->id), d->height, d->baseline);
218} 217}
219 218
220static void deinit_Font(iFont *d) { 219static void deinit_Font(iFont *d) {
@@ -934,6 +933,12 @@ static void finishRun_AttributedText_(iAttributedText *d, iAttributedRun *run, i
934 iAssert(endAt >= 0 && endAt <= size_Array(&d->logical)); 933 iAssert(endAt >= 0 && endAt <= size_Array(&d->logical));
935 finishedRun.logical.end = endAt; 934 finishedRun.logical.end = endAt;
936 if (!isEmpty_Range(&finishedRun.logical)) { 935 if (!isEmpty_Range(&finishedRun.logical)) {
936#if 0
937 /* Colorize individual runs to see boundaries. */
938 static int dbg;
939 static const int dbgClr[3] = { red_ColorId, green_ColorId, blue_ColorId };
940 finishedRun.attrib.colorId = dbgClr[dbg++ % 3];
941#endif
937 pushBack_Array(&d->runs, &finishedRun); 942 pushBack_Array(&d->runs, &finishedRun);
938 run->flags.isLineBreak = iFalse; 943 run->flags.isLineBreak = iFalse;
939 run->flags.isArabic = iFalse; 944 run->flags.isArabic = iFalse;
@@ -1120,15 +1125,18 @@ static void prepare_AttributedText_(iAttributedText *d, int overrideBaseDir, iCh
1120 continue; 1125 continue;
1121 } 1126 }
1122 if (ch == 0x20) { 1127 if (ch == 0x20) {
1123 if (run.font->fontSpec->flags & auxiliary_FontSpecFlag) { 1128 if (run.font->fontSpec->flags & auxiliary_FontSpecFlag &&
1129 ~run.font->fontSpec->flags & allowSpacePunct_FontSpecFlag) {
1124 finishRun_AttributedText_(d, &run, pos); 1130 finishRun_AttributedText_(d, &run, pos);
1125 run.font = d->font; /* never use space from the symbols font, it's too wide */ 1131 run.font = d->font; /* auxilitary font space not allowed, could be wrong width */
1126 } 1132 }
1127 continue; 1133 continue;
1128 } 1134 }
1129 iFont *currentFont = attribFont; 1135 iFont *currentFont = attribFont;
1130 if (run.font->fontSpec->flags & arabic_FontSpecFlag && isPunct_Char(ch)) { 1136 if (run.font->fontSpec->flags & auxiliary_FontSpecFlag &&
1131 currentFont = run.font; /* remain as Arabic for whitespace */ 1137 run.font->fontSpec->flags & allowSpacePunct_FontSpecFlag &&
1138 isPunct_Char(ch)) {
1139 currentFont = run.font; /* keep the current font */
1132 } 1140 }
1133 const iGlyph *glyph = glyph_Font_(currentFont, ch); 1141 const iGlyph *glyph = glyph_Font_(currentFont, ch);
1134 if (index_Glyph_(glyph) && glyph->font != run.font) { 1142 if (index_Glyph_(glyph) && glyph->font != run.font) {
@@ -1153,8 +1161,10 @@ static void prepare_AttributedText_(iAttributedText *d, int overrideBaseDir, iCh
1153 printf("[AttributedText] %zu runs:\n", size_Array(&d->runs)); 1161 printf("[AttributedText] %zu runs:\n", size_Array(&d->runs));
1154 iConstForEach(Array, i, &d->runs) { 1162 iConstForEach(Array, i, &d->runs) {
1155 const iAttributedRun *run = i.value; 1163 const iAttributedRun *run = i.value;
1156 printf(" %zu %s log:%d...%d vis:%d...%d {%s}\n", index_ArrayConstIterator(&i), 1164 printf(" %zu %s fnt:%d log:%d...%d vis:%d...%d {%s}\n",
1165 index_ArrayConstIterator(&i),
1157 run->attrib.isRTL ? "<-" : "->", 1166 run->attrib.isRTL ? "<-" : "->",
1167 fontId_Text_(run->font),
1158 run->logical.start, run->logical.end - 1, 1168 run->logical.start, run->logical.end - 1,
1159 logToVis[run->logical.start], logToVis[run->logical.end - 1], 1169 logToVis[run->logical.start], logToVis[run->logical.end - 1],
1160 cstr_Rangecc(sourceRange_AttributedText_(d, run->logical))); 1170 cstr_Rangecc(sourceRange_AttributedText_(d, run->logical)));
@@ -1598,6 +1608,7 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) {
1598 wrap->hitPoint.y < orig.y + yCursor + d->height); 1608 wrap->hitPoint.y < orig.y + yCursor + d->height);
1599 iBool wasCharHit = iFalse; /* on this line */ 1609 iBool wasCharHit = iFalse; /* on this line */
1600 float breakAdvance = -1.0f; 1610 float breakAdvance = -1.0f;
1611 size_t breakRunIndex = iInvalidPos;
1601 iAssert(wrapPosRange.end == textLen); 1612 iAssert(wrapPosRange.end == textLen);
1602 /* Determine ends of wrapRuns and wrapVisRange. */ 1613 /* Determine ends of wrapRuns and wrapVisRange. */
1603 int safeBreakPos = -1; 1614 int safeBreakPos = -1;
@@ -1621,7 +1632,8 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) {
1621 iAssert(run->font == buf->font); 1632 iAssert(run->font == buf->font);
1622 shape_GlyphBuffer_(buf); 1633 shape_GlyphBuffer_(buf);
1623 iChar prevCh = 0; 1634 iChar prevCh = 0;
1624 lastAttrib = run->attrib; 1635 lastAttrib = run->attrib;
1636// printf("checking run %zu...\n", runIndex);
1625 for (unsigned int ir = 0; ir < buf->glyphCount; ir++) { 1637 for (unsigned int ir = 0; ir < buf->glyphCount; ir++) {
1626 const int i = (run->attrib.isRTL ? buf->glyphCount - ir - 1 : ir); 1638 const int i = (run->attrib.isRTL ? buf->glyphCount - ir - 1 : ir);
1627 const hb_glyph_info_t *info = &buf->glyphInfo[i]; 1639 const hb_glyph_info_t *info = &buf->glyphInfo[i];
@@ -1648,24 +1660,27 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) {
1648 iAssert(xAdvance >= 0); 1660 iAssert(xAdvance >= 0);
1649 if (args->wrap->mode == word_WrapTextMode) { 1661 if (args->wrap->mode == word_WrapTextMode) {
1650 /* When word wrapping, only consider certain places breakable. */ 1662 /* When word wrapping, only consider certain places breakable. */
1651 if (!isPunct_Char(ch) && (prevCh == '-' || prevCh == '/')) { 1663 if ((prevCh == '-' || prevCh == '/') && !isPunct_Char(ch)) {
1652 safeBreakPos = logPos; 1664 safeBreakPos = logPos;
1653 breakAdvance = wrapAdvance; 1665 breakAdvance = wrapAdvance;
1654// printf("breakAdv_A:%f\n", breakAdvance); 1666 breakRunIndex = runIndex;
1667// printf("sbp:%d breakAdv_A:%f\n", safeBreakPos, breakAdvance);
1655 // isSoftHyphenBreak = iFalse; 1668 // isSoftHyphenBreak = iFalse;
1656 } 1669 }
1657 else if (isSpace_Char(ch)) { 1670 else if (isSpace_Char(ch)) {
1658 safeBreakPos = logPos; 1671 safeBreakPos = logPos;
1659 breakAdvance = wrapAdvance; 1672 breakAdvance = wrapAdvance;
1660// printf("breakAdv_B:%f sbb:%d\n", breakAdvance, safeBreakPos); 1673 breakRunIndex = runIndex;
1674// printf("sbp:%d breakAdv_B:%f\n", safeBreakPos, breakAdvance);
1661 // isSoftHyphenBreak = iFalse; 1675 // isSoftHyphenBreak = iFalse;
1662 } 1676 }
1663 prevCh = ch; 1677 prevCh = ch;
1664 } 1678 }
1665 else { 1679 else {
1666 safeBreakPos = logPos; 1680 safeBreakPos = logPos;
1667 breakAdvance = wrapAdvance; 1681 breakAdvance = wrapAdvance;
1668 wrapAttrib = run->attrib; 1682 breakRunIndex = runIndex;
1683 wrapAttrib = run->attrib;
1669 } 1684 }
1670 if (isHitPointOnThisLine) { 1685 if (isHitPointOnThisLine) {
1671 if (wrap->hitPoint.x >= orig.x + wrapAdvance && 1686 if (wrap->hitPoint.x >= orig.x + wrapAdvance &&
@@ -1681,7 +1696,9 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) {
1681 if (wrap->maxWidth > 0 && 1696 if (wrap->maxWidth > 0 &&
1682 wrapAdvance + xOffset + glyph->d[0].x + glyph->rect[0].size.x > 1697 wrapAdvance + xOffset + glyph->d[0].x + glyph->rect[0].size.x >
1683 args->wrap->maxWidth) { 1698 args->wrap->maxWidth) {
1684// printf("safeBreakPos:%d\n", safeBreakPos); 1699// printf("out of room at lp:%d! safeBreakPos:%d (idx:%zu) breakAdv:%f\n",
1700// logPos, safeBreakPos,
1701// breakRunIndex, breakAdvance);
1685 if (safeBreakPos >= 0) { 1702 if (safeBreakPos >= 0) {
1686 wrapPosRange.end = safeBreakPos; 1703 wrapPosRange.end = safeBreakPos;
1687 } 1704 }
@@ -1697,6 +1714,7 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) {
1697 } 1714 }
1698 wrapPosRange.end = logPos; 1715 wrapPosRange.end = logPos;
1699 breakAdvance = wrapAdvance; 1716 breakAdvance = wrapAdvance;
1717 breakRunIndex = runIndex;
1700 } 1718 }
1701 wrapResumePos = wrapPosRange.end; 1719 wrapResumePos = wrapPosRange.end;
1702 if (args->wrap->mode != anyCharacter_WrapTextMode) { 1720 if (args->wrap->mode != anyCharacter_WrapTextMode) {
@@ -1704,14 +1722,14 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) {
1704 wrapResumePos++; /* skip space */ 1722 wrapResumePos++; /* skip space */
1705 } 1723 }
1706 } 1724 }
1707 wrapRuns.end = runIndex + 1; /* still includes this run */ 1725 wrapRuns.end = breakRunIndex + 1; /* still includes this run */
1708 wrapResumeRunIndex = runIndex; /* ...but continue from the same one */ 1726 wrapResumeRunIndex = breakRunIndex; /* ...but continue from the same one */
1727// printf("-> wrapAdv:%f (breakAdv:%f)\n", wrapAdvance, breakAdvance);
1709 wrapAdvance = breakAdvance; 1728 wrapAdvance = breakAdvance;
1710// printf("-> wrapAdv:%f (breakAdv)\n", wrapAdvance); 1729// printf("wrapResumePos:%d\n", wrapResumePos);
1711 break; 1730 break;
1712 } 1731 }
1713 wrapAdvance += xAdvance; 1732 wrapAdvance += xAdvance;
1714 printf("lp:%d wrap:%f\n", logPos, wrapAdvance);
1715 /* Additional kerning tweak. It would be better to use HarfBuzz font callbacks, 1733 /* Additional kerning tweak. It would be better to use HarfBuzz font callbacks,
1716 but they don't seem to get called? */ 1734 but they don't seem to get called? */
1717 if (i + 1 < buf->glyphCount) { 1735 if (i + 1 < buf->glyphCount) {
@@ -1720,6 +1738,7 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) {
1720 buf->glyphInfo[i + 1].codepoint); 1738 buf->glyphInfo[i + 1].codepoint);
1721 } 1739 }
1722 } 1740 }
1741// printf("...finished checking run %zu\n", runIndex);
1723 } 1742 }
1724 if (isHitPointOnThisLine && wrap->hitPoint.x >= orig.x + wrapAdvance) { 1743 if (isHitPointOnThisLine && wrap->hitPoint.x >= orig.x + wrapAdvance) {
1725 /* On the right side. */ 1744 /* On the right side. */
@@ -1774,16 +1793,17 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) {
1774 } 1793 }
1775 } 1794 }
1776 } 1795 }
1777 }
1778#if 0 1796#if 0
1779 printf("Run order: "); 1797 printf("Run order: ");
1780 iConstForEach(Array, ro, &runOrder) { 1798 iConstForEach(Array, ro, &runOrder) {
1781 const size_t *idx = ro.value; 1799 const size_t *idx = ro.value;
1782 printf("%zu {%s}\n", *idx, 1800 printf("%zu {%s}\n", *idx,
1783 cstr_Rangecc(sourceRange_AttributedText_(&attrText, ((const iAttributedRun *) at_Array(&attrText.runs, *idx))->logical))); 1801 cstr_Rangecc(sourceRange_AttributedText_(&attrText, ((const iAttributedRun *) at_Array(&attrText.runs, *idx))->logical)));
1784 } 1802 }
1785 printf("\n"); 1803 printf("\n");
1786#endif 1804#endif
1805
1806 }
1787 iAssert(size_Array(&runOrder) == size_Range(&wrapRuns)); 1807 iAssert(size_Array(&runOrder) == size_Range(&wrapRuns));
1788 /* Alignment. */ 1808 /* Alignment. */
1789 int origin = 0; 1809 int origin = 0;
@@ -1791,12 +1811,7 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) {
1791 if (isRightAligned) { 1811 if (isRightAligned) {
1792 if (layoutBound > 0) { 1812 if (layoutBound > 0) {
1793 origin = layoutBound - wrapAdvance; 1813 origin = layoutBound - wrapAdvance;
1794 printf("orig:%d (lbo:%d wrapAdv:%f)\n", origin, layoutBound, wrapAdvance);
1795 } 1814 }
1796 printf("yes; base RTL\n");
1797 }
1798 else {
1799 printf("not base RTL\n");
1800 } 1815 }
1801 /* Make a callback for each wrapped line. */ 1816 /* Make a callback for each wrapped line. */
1802 if (wrap && wrap->wrapFunc && 1817 if (wrap && wrap->wrapFunc &&
@@ -1866,8 +1881,6 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) {
1866 const int bl1 = attrText.baseFont->baseline + attrText.baseFont->vertOffset; 1881 const int bl1 = attrText.baseFont->baseline + attrText.baseFont->vertOffset;
1867 const int bl2 = run->font->baseline + run->font->vertOffset; 1882 const int bl2 = run->font->baseline + run->font->vertOffset;
1868 dst.y += bl1 - bl2; 1883 dst.y += bl1 - bl2;
1869// printf("baseline difference: run %d, base %d\n",
1870// run->font->baseline, attrText.baseFont->baseline);
1871 } 1884 }
1872 if (mode & visualFlag_RunMode) { 1885 if (mode & visualFlag_RunMode) {
1873 if (isEmpty_Rect(bounds)) { 1886 if (isEmpty_Rect(bounds)) {