summaryrefslogtreecommitdiff
path: root/src/ui/text.c
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2021-07-03 14:13:37 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2021-07-03 14:13:37 +0300
commitbd1504bbefc8954557044691bddd463c0d0e1911 (patch)
tree7989d18610acdb2e593ec8cc523cbaa871a69fcb /src/ui/text.c
parent1828df7b3260907a18096c438814f90e048da908 (diff)
Text: Use FriBidi for visual order
Todo: This seems a little late in the game. The reordering should be done for each paragraph of text.
Diffstat (limited to 'src/ui/text.c')
-rw-r--r--src/ui/text.c65
1 files changed, 60 insertions, 5 deletions
diff --git a/src/ui/text.c b/src/ui/text.c
index 786e11ff..175b25a1 100644
--- a/src/ui/text.c
+++ b/src/ui/text.c
@@ -142,11 +142,13 @@ struct Impl_Font {
142 142
143static iFont *font_Text_(enum iFontId id); 143static iFont *font_Text_(enum iFontId id);
144 144
145#if 0
145static hb_position_t hbGlyphHKernForNunito_(hb_font_t *font, void *fontData, 146static hb_position_t hbGlyphHKernForNunito_(hb_font_t *font, void *fontData,
146 hb_codepoint_t firstGlyph, hb_codepoint_t secondGlyph, 147 hb_codepoint_t firstGlyph, hb_codepoint_t secondGlyph,
147 void *userData) { 148 void *userData) {
148 return 100; 149 return 100;
149} 150}
151#endif
150 152
151static void init_Font(iFont *d, const iBlock *data, int height, float scale, 153static void init_Font(iFont *d, const iBlock *data, int height, float scale,
152 enum iFontSize sizeId, iBool isMonospaced) { 154 enum iFontSize sizeId, iBool isMonospaced) {
@@ -161,6 +163,9 @@ static void init_Font(iFont *d, const iBlock *data, int height, float scale,
161 data == &fontNunitoExtraLight_Embedded) { 163 data == &fontNunitoExtraLight_Embedded) {
162 d->family = nunito_TextFont; 164 d->family = nunito_TextFont;
163 } 165 }
166 else if (data == &fontNotoSansArabicUIRegular_Embedded) {
167 d->family = notoSansArabic_TextFont;
168 }
164 d->isMonospaced = isMonospaced; 169 d->isMonospaced = isMonospaced;
165 d->height = height; 170 d->height = height;
166 iZap(d->font); 171 iZap(d->font);
@@ -851,7 +856,12 @@ static void prepare_AttributedText_(iAttributedText *d) {
851 run.text.end = currentPos; 856 run.text.end = currentPos;
852 break; 857 break;
853 } 858 }
854 const iGlyph *glyph = glyph_Font_(d->font, ch); 859 iFont *currentFont = d->font;
860 if (run.font->family == notoSansArabic_TextFont && ch == 0x20) {
861 currentFont = run.font; /* remain as Arabic for whitespace */
862 /* TODO: FriBidi should be applied before this loop, but how to map the positions? */
863 }
864 const iGlyph *glyph = glyph_Font_(currentFont, ch);
855 if (index_Glyph_(glyph) && glyph->font != run.font) { 865 if (index_Glyph_(glyph) && glyph->font != run.font) {
856 /* A different font is being used for this character. */ 866 /* A different font is being used for this character. */
857 finishRun_AttributedText_(d, &run, currentPos); 867 finishRun_AttributedText_(d, &run, currentPos);
@@ -1160,18 +1170,61 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) {
1160 hb_buffer_clear_contents(hbBuf); 1170 hb_buffer_clear_contents(hbBuf);
1161 /* Cluster values are used to determine offset inside the UTF-8 source string. */ 1171 /* Cluster values are used to determine offset inside the UTF-8 source string. */
1162 //hb_buffer_set_cluster_level(hbBuf, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS); 1172 //hb_buffer_set_cluster_level(hbBuf, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
1173#if 0 && defined (LAGRANGE_ENABLE_FRIBIDI)
1174 /* Reorder to visual order. */ {
1175 iArray u32;
1176 iArray logToRun;
1177 init_Array(&u32, sizeof(uint32_t));
1178 init_Array(&logToRun, sizeof(FriBidiStrIndex));
1179 for (const char *pos = runText.start; pos < runText.end; ) {
1180 iChar ucp = 0;
1181 const int len = decodeBytes_MultibyteChar(pos, runText.end, &ucp);
1182 if (len > 0) {
1183 pushBack_Array(&u32, &ucp);
1184 pushBack_Array(&logToRun, &(int){ pos - runText.start });
1185 pos += len;
1186 }
1187 else break;
1188 }
1189 iArray vis32;
1190 init_Array(&vis32, sizeof(uint32_t));
1191 resize_Array(&vis32, size_Array(&u32));
1192 iArray visToLog;
1193 init_Array(&visToLog, sizeof(FriBidiStrIndex));
1194 resize_Array(&visToLog, size_Array(&u32));
1195 FriBidiParType baseDir = (FriBidiParType) FRIBIDI_TYPE_ON;
1196 fribidi_log2vis(constData_Array(&u32),
1197 size_Array(&u32),
1198 &baseDir,
1199 data_Array(&vis32),
1200 NULL,
1201 data_Array(&visToLog),
1202 NULL);
1203 const FriBidiStrIndex *visToLogIndex = constData_Array(&visToLog);
1204 const FriBidiStrIndex *logToRunIndex = constData_Array(&logToRun);
1205 iConstForEach(Array, v, &vis32) {
1206 hb_buffer_add(hbBuf,
1207 *(const hb_codepoint_t *) v.value,
1208 logToRunIndex[visToLogIndex[index_ArrayConstIterator(&v)]]);
1209 }
1210 deinit_Array(&visToLog);
1211 deinit_Array(&vis32);
1212 deinit_Array(&logToRun);
1213 deinit_Array(&u32);
1214 }
1215#else /* !defined (LAGRANGE_ENABLE_FRIBIDI) */
1163 for (const char *pos = runText.start; pos < runText.end; ) { 1216 for (const char *pos = runText.start; pos < runText.end; ) {
1164 iChar ucp = 0; 1217 iChar ucp = 0;
1165 const int len = decodeBytes_MultibyteChar(pos, runText.end, &ucp); 1218 const int len = decodeBytes_MultibyteChar(pos, runText.end, &ucp);
1166// if (ucp == 0xad) ucp = '-';
1167 if (len > 0) { 1219 if (len > 0) {
1168 hb_buffer_add(hbBuf, ucp, pos - runText.start); 1220 hb_buffer_add(hbBuf, ucp, pos - runText.start);
1169 pos += len; 1221 pos += len;
1170 } 1222 }
1171 else break; 1223 else break;
1172 } 1224 }
1225#endif
1173 hb_buffer_set_content_type(hbBuf, HB_BUFFER_CONTENT_TYPE_UNICODE); 1226 hb_buffer_set_content_type(hbBuf, HB_BUFFER_CONTENT_TYPE_UNICODE);
1174 hb_buffer_set_direction(hbBuf, HB_DIRECTION_LTR); /* TODO: FriBidi? */ 1227 hb_buffer_set_direction(hbBuf, HB_DIRECTION_LTR);
1175 /* hb_buffer_set_script(hbBuf, HB_SCRIPT_LATIN); */ /* will be autodetected */ 1228 /* hb_buffer_set_script(hbBuf, HB_SCRIPT_LATIN); */ /* will be autodetected */
1176 //hb_buffer_set_language(hbBuf, hb_language_from_string("en", -1)); /* TODO: language from document/UI, if known */ 1229 //hb_buffer_set_language(hbBuf, hb_language_from_string("en", -1)); /* TODO: language from document/UI, if known */
1177 hb_shape(run->font->hbFont, hbBuf, NULL, 0); /* TODO: Specify features, too? */ 1230 hb_shape(run->font->hbFont, hbBuf, NULL, 0); /* TODO: Specify features, too? */
@@ -1264,6 +1317,8 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) {
1264 const hb_glyph_info_t *info = &glyphInfo[i]; 1317 const hb_glyph_info_t *info = &glyphInfo[i];
1265 const hb_codepoint_t glyphId = info->codepoint; 1318 const hb_codepoint_t glyphId = info->codepoint;
1266 const char *textPos = runText.start + info->cluster; 1319 const char *textPos = runText.start + info->cluster;
1320 iAssert(textPos >= runText.start);
1321 iAssert(textPos < runText.end);
1267 const float xOffset = run->font->xScale * glyphPos[i].x_offset; 1322 const float xOffset = run->font->xScale * glyphPos[i].x_offset;
1268 const float yOffset = run->font->yScale * glyphPos[i].y_offset; 1323 const float yOffset = run->font->yScale * glyphPos[i].y_offset;
1269 const float xAdvance = run->font->xScale * glyphPos[i].x_advance; 1324 const float xAdvance = run->font->xScale * glyphPos[i].x_advance;
@@ -1405,8 +1460,8 @@ iInt2 tryAdvance_Text(int fontId, iRangecc text, int width, const char **endPos)
1405 iWrapText wrap = { .mode = word_WrapTextMode, 1460 iWrapText wrap = { .mode = word_WrapTextMode,
1406 .text = text, .maxWidth = width, 1461 .text = text, .maxWidth = width,
1407 .wrapFunc = cbAdvanceOneLine_, .context = endPos }; 1462 .wrapFunc = cbAdvanceOneLine_, .context = endPos };
1408 //const int x = advance_WrapText(&wrap, fontId).x; 1463 /* The return value is expected to be the horizontal/vertical bounds, while WrapText
1409 //return init_I2(x, lineHeight_Text(fontId)); 1464 returns the actual advanced cursor position. */
1410 return addY_I2(advance_WrapText(&wrap, fontId), lineHeight_Text(fontId)); 1465 return addY_I2(advance_WrapText(&wrap, fontId), lineHeight_Text(fontId));
1411 1466
1412#if 0 1467#if 0