summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2022-01-07 07:47:47 +0200
committerJaakko Keränen <jaakko.keranen@iki.fi>2022-01-07 07:47:47 +0200
commited7b61cf6b4e0e0b23a4a450a8155ce56c93674b (patch)
tree8eb7c8d1699fa282d4cdb9a748406c29de7dd273 /src
parent5a82a64ea145a99482817952b14cb8befd62369c (diff)
Text: CJK word wrapping
Improve mixed-language word wrapping, and position U+3001 and U+3002 near the baseline. IssueID #380
Diffstat (limited to 'src')
-rw-r--r--src/ui/text.c50
-rw-r--r--src/ui/util.c8
2 files changed, 40 insertions, 18 deletions
diff --git a/src/ui/text.c b/src/ui/text.c
index c0661ee8..618f3d79 100644
--- a/src/ui/text.c
+++ b/src/ui/text.c
@@ -657,17 +657,27 @@ enum iScript {
657 arabic_Script, 657 arabic_Script,
658 bengali_Script, 658 bengali_Script,
659 devanagari_Script, 659 devanagari_Script,
660 han_Script,
661 hiragana_Script,
662 katakana_Script,
660 oriya_Script, 663 oriya_Script,
661 tamil_Script, 664 tamil_Script,
662 max_Script 665 max_Script
663}; 666};
664 667
668iLocalDef iBool isCJK_Script_(enum iScript d) {
669 return d == han_Script || d == hiragana_Script || d == katakana_Script;
670}
671
665#if defined (LAGRANGE_ENABLE_HARFBUZZ) 672#if defined (LAGRANGE_ENABLE_HARFBUZZ)
666static const hb_script_t hbScripts_[max_Script] = { 673static const hb_script_t hbScripts_[max_Script] = {
667 0, 674 0,
668 HB_SCRIPT_ARABIC, 675 HB_SCRIPT_ARABIC,
669 HB_SCRIPT_BENGALI, 676 HB_SCRIPT_BENGALI,
670 HB_SCRIPT_DEVANAGARI, 677 HB_SCRIPT_DEVANAGARI,
678 HB_SCRIPT_HAN,
679 HB_SCRIPT_HIRAGANA,
680 HB_SCRIPT_KATAKANA,
671 HB_SCRIPT_ORIYA, 681 HB_SCRIPT_ORIYA,
672 HB_SCRIPT_TAMIL, 682 HB_SCRIPT_TAMIL,
673}; 683};
@@ -1006,7 +1016,6 @@ static void prepare_AttributedText_(iAttributedText *d, int overrideBaseDir, iCh
1006#endif 1016#endif
1007 } 1017 }
1008 /* Detect the script. */ 1018 /* Detect the script. */
1009 // printf("Char %08x %lc => %s\n", ch, (int) ch, script_Char(ch));
1010#if defined (LAGRANGE_ENABLE_FRIBIDI) 1019#if defined (LAGRANGE_ENABLE_FRIBIDI)
1011 if (fribidi_get_bidi_type(ch) == FRIBIDI_TYPE_AL) { 1020 if (fribidi_get_bidi_type(ch) == FRIBIDI_TYPE_AL) {
1012 run.flags.script = arabic_Script; 1021 run.flags.script = arabic_Script;
@@ -1015,12 +1024,22 @@ static void prepare_AttributedText_(iAttributedText *d, int overrideBaseDir, iCh
1015#endif 1024#endif
1016 { 1025 {
1017 const char *scr = script_Char(ch); 1026 const char *scr = script_Char(ch);
1027// printf("Char %08x %lc => %s\n", ch, (int) ch, scr);
1018 if (!iCmpStr(scr, "Bengali")) { 1028 if (!iCmpStr(scr, "Bengali")) {
1019 run.flags.script = bengali_Script; 1029 run.flags.script = bengali_Script;
1020 } 1030 }
1021 else if (!iCmpStr(scr, "Devanagari")) { 1031 else if (!iCmpStr(scr, "Devanagari")) {
1022 run.flags.script = devanagari_Script; 1032 run.flags.script = devanagari_Script;
1023 } 1033 }
1034 else if (!iCmpStr(scr, "Han")) {
1035 run.flags.script = han_Script;
1036 }
1037 else if (!iCmpStr(scr, "Hiragana")) {
1038 run.flags.script = hiragana_Script;
1039 }
1040 else if (!iCmpStr(scr, "Katakana")) {
1041 run.flags.script = katakana_Script;
1042 }
1024 else if (!iCmpStr(scr, "Oriya")) { 1043 else if (!iCmpStr(scr, "Oriya")) {
1025 run.flags.script = oriya_Script; 1044 run.flags.script = oriya_Script;
1026 } 1045 }
@@ -1538,8 +1557,11 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) {
1538 const float xOffset = run->font->xScale * buf->glyphPos[i].x_offset; 1557 const float xOffset = run->font->xScale * buf->glyphPos[i].x_offset;
1539 const float xAdvance = run->font->xScale * buf->glyphPos[i].x_advance; 1558 const float xAdvance = run->font->xScale * buf->glyphPos[i].x_advance;
1540 const iChar ch = logicalText[logPos]; 1559 const iChar ch = logicalText[logPos];
1560 const enum iWrapTextMode wrapMode = isCJK_Script_(run->flags.script)
1561 ? anyCharacter_WrapTextMode
1562 : args->wrap->mode;
1541 iAssert(xAdvance >= 0); 1563 iAssert(xAdvance >= 0);
1542 if (args->wrap->mode == word_WrapTextMode) { 1564 if (wrapMode == word_WrapTextMode) {
1543 /* When word wrapping, only consider certain places breakable. */ 1565 /* When word wrapping, only consider certain places breakable. */
1544 if ((prevCh == '-' || prevCh == '/') && !isPunct_Char(ch)) { 1566 if ((prevCh == '-' || prevCh == '/') && !isPunct_Char(ch)) {
1545 safeBreakPos = logPos; 1567 safeBreakPos = logPos;
@@ -1584,7 +1606,7 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) {
1584 wrapPosRange.end = safeBreakPos; 1606 wrapPosRange.end = safeBreakPos;
1585 } 1607 }
1586 else { 1608 else {
1587 if (args->wrap->mode == word_WrapTextMode && run->logical.start > wrapPosRange.start) { 1609 if (wrapMode == word_WrapTextMode && run->logical.start > wrapPosRange.start) {
1588 /* Don't have a word break position, so the whole run needs 1610 /* Don't have a word break position, so the whole run needs
1589 to be cut. */ 1611 to be cut. */
1590 wrapPosRange.end = run->logical.start; 1612 wrapPosRange.end = run->logical.start;
@@ -1598,7 +1620,7 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) {
1598 breakRunIndex = runIndex; 1620 breakRunIndex = runIndex;
1599 } 1621 }
1600 wrapResumePos = wrapPosRange.end; 1622 wrapResumePos = wrapPosRange.end;
1601 if (args->wrap->mode != anyCharacter_WrapTextMode) { 1623 if (wrapMode != anyCharacter_WrapTextMode) {
1602 while (wrapResumePos < textLen && isSpace_Char(logicalText[wrapResumePos])) { 1624 while (wrapResumePos < textLen && isSpace_Char(logicalText[wrapResumePos])) {
1603 wrapResumePos++; /* skip space */ 1625 wrapResumePos++; /* skip space */
1604 } 1626 }
@@ -1737,12 +1759,13 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) {
1737 /* Already handled this part of the run. */ 1759 /* Already handled this part of the run. */
1738 continue; 1760 continue;
1739 } 1761 }
1740 const float xOffset = run->font->xScale * buf->glyphPos[i].x_offset; 1762 const float xOffset = run->font->xScale * buf->glyphPos[i].x_offset;
1741 const float yOffset = run->font->yScale * buf->glyphPos[i].y_offset; 1763 float yOffset = run->font->yScale * buf->glyphPos[i].y_offset;
1742 const float xAdvance = run->font->xScale * buf->glyphPos[i].x_advance; 1764 const float xAdvance = run->font->xScale * buf->glyphPos[i].x_advance;
1743 const float yAdvance = run->font->yScale * buf->glyphPos[i].y_advance; 1765 const float yAdvance = run->font->yScale * buf->glyphPos[i].y_advance;
1744 const iGlyph *glyph = glyphByIndex_Font_(run->font, glyphId); 1766 const iGlyph *glyph = glyphByIndex_Font_(run->font, glyphId);
1745 if (logicalText[logPos] == '\t') { 1767 const iChar ch = logicalText[logPos];
1768 if (ch == '\t') {
1746#if 0 1769#if 0
1747 if (mode & draw_RunMode) { 1770 if (mode & draw_RunMode) {
1748 /* Tab indicator. */ 1771 /* Tab indicator. */
@@ -1761,6 +1784,13 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) {
1761 } 1784 }
1762 const float xf = xCursor + xOffset; 1785 const float xf = xCursor + xOffset;
1763 const int hoff = enableHalfPixelGlyphs_Text ? (xf - ((int) xf) > 0.5f ? 1 : 0) : 0; 1786 const int hoff = enableHalfPixelGlyphs_Text ? (xf - ((int) xf) > 0.5f ? 1 : 0) : 0;
1787 if (ch == 0x3001 || ch == 0x3002) {
1788 /* Vertical misalignment?? */
1789 if (yOffset == 0.0f) {
1790 /* Move down to baseline. Why doesn't HarfBuzz do this? */
1791 yOffset = glyph->d[hoff].y + glyph->rect[hoff].size.y + glyph->d[hoff].y / 4;
1792 }
1793 }
1764 /* Output position for the glyph. */ 1794 /* Output position for the glyph. */
1765 SDL_Rect dst = { orig.x + xCursor + xOffset + glyph->d[hoff].x, 1795 SDL_Rect dst = { orig.x + xCursor + xOffset + glyph->d[hoff].x,
1766 orig.y + yCursor - yOffset + glyph->font->baseline + glyph->d[hoff].y, 1796 orig.y + yCursor - yOffset + glyph->font->baseline + glyph->d[hoff].y,
diff --git a/src/ui/util.c b/src/ui/util.c
index a5f48e62..77d9a63a 100644
--- a/src/ui/util.c
+++ b/src/ui/util.c
@@ -3438,14 +3438,6 @@ iWidget *makeTranslation_Widget(iWidget *parent) {
3438 languages[prefs_App()->langFrom].command); 3438 languages[prefs_App()->langFrom].command);
3439 updateDropdownSelection_LabelWidget(findChild_Widget(dlg, "xlt.to"), 3439 updateDropdownSelection_LabelWidget(findChild_Widget(dlg, "xlt.to"),
3440 languages[prefs_App()->langTo].command); 3440 languages[prefs_App()->langTo].command);
3441// updateText_LabelWidget(
3442// findChild_Widget(dlg, "xlt.from"),
3443// text_LabelWidget(child_Widget(findChild_Widget(findChild_Widget(dlg, "xlt.from"), "menu"),
3444// prefs_App()->langFrom)));
3445// updateText_LabelWidget(
3446// findChild_Widget(dlg, "xlt.to"),
3447// text_LabelWidget(child_Widget(findChild_Widget(findChild_Widget(dlg, "xlt.to"), "menu"),
3448// prefs_App()->langTo)));
3449 setCommandHandler_Widget(dlg, translationHandler_); 3441 setCommandHandler_Widget(dlg, translationHandler_);
3450 setupSheetTransition_Mobile(dlg, iTrue); 3442 setupSheetTransition_Mobile(dlg, iTrue);
3451 return dlg; 3443 return dlg;