summaryrefslogtreecommitdiff
path: root/src/ui/text.c
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2021-11-21 20:44:25 +0200
committerJaakko Keränen <jaakko.keranen@iki.fi>2021-11-21 20:44:25 +0200
commite72764f55b49643160e387fb942ac113d66620cf (patch)
tree1eeefa631beb473fe85b6417d0f65d8a04cabfe2 /src/ui/text.c
parent18212214dda6f18bdc6bb21307668472b5726602 (diff)
Apply ANSI SGR background colors
The background color of the current text run can be changed via ANSI SGR control sequences. Improved the ANSI escape sequence regex to detect more than just SGR sequences, so they can be properly filtered out.
Diffstat (limited to 'src/ui/text.c')
-rw-r--r--src/ui/text.c234
1 files changed, 93 insertions, 141 deletions
diff --git a/src/ui/text.c b/src/ui/text.c
index 91633f27..91ff137a 100644
--- a/src/ui/text.c
+++ b/src/ui/text.c
@@ -263,7 +263,7 @@ struct Impl_Text {
263 iRegExp * ansiEscape; 263 iRegExp * ansiEscape;
264 int ansiFlags; 264 int ansiFlags;
265 int baseFontId; /* base attributes (for restoring via escapes) */ 265 int baseFontId; /* base attributes (for restoring via escapes) */
266 int baseColorId; 266 int baseFgColorId;
267 iBool missingGlyphs; /* true if a glyph couldn't be found */ 267 iBool missingGlyphs; /* true if a glyph couldn't be found */
268}; 268};
269 269
@@ -390,35 +390,14 @@ static void deinitCache_Text_(iText *d) {
390 SDL_DestroyTexture(d->cache); 390 SDL_DestroyTexture(d->cache);
391} 391}
392 392
393#if 0
394void loadUserFonts_Text(void) {
395 if (userFont_) {
396 delete_Block(userFont_);
397 userFont_ = NULL;
398 }
399 /* Load the system font. */
400 const iPrefs *prefs = prefs_App();
401 if (!isEmpty_String(&prefs->symbolFontPath)) {
402 iFile *f = new_File(&prefs->symbolFontPath);
403 if (open_File(f, readOnly_FileMode)) {
404 userFont_ = readAll_File(f);
405 }
406 else {
407 fprintf(stderr, "[Text] failed to open: %s\n", cstr_String(&prefs->symbolFontPath));
408 }
409 iRelease(f);
410 }
411}
412#endif
413
414void init_Text(iText *d, SDL_Renderer *render) { 393void init_Text(iText *d, SDL_Renderer *render) {
415 iText *oldActive = activeText_; 394 iText *oldActive = activeText_;
416 activeText_ = d; 395 activeText_ = d;
417 init_Array(&d->fonts, sizeof(iFont)); 396 init_Array(&d->fonts, sizeof(iFont));
418 d->contentFontSize = contentScale_Text_; 397 d->contentFontSize = contentScale_Text_;
419 d->ansiEscape = new_RegExp("[[()]([0-9;AB]*?)m", 0); 398 d->ansiEscape = new_RegExp("[[()][?]?([0-9;AB]*?)([ABCDEFGHJKSTfhilmn])", 0);
420 d->baseFontId = -1; 399 d->baseFontId = -1;
421 d->baseColorId = -1; 400 d->baseFgColorId = -1;
422 d->render = render; 401 d->render = render;
423 /* A grayscale palette for rasterized glyphs. */ { 402 /* A grayscale palette for rasterized glyphs. */ {
424 SDL_Color colors[256]; 403 SDL_Color colors[256];
@@ -459,9 +438,10 @@ void setOpacity_Text(float opacity) {
459 SDL_SetTextureAlphaMod(activeText_->cache, iClamp(opacity, 0.0f, 1.0f) * 255 + 0.5f); 438 SDL_SetTextureAlphaMod(activeText_->cache, iClamp(opacity, 0.0f, 1.0f) * 255 + 0.5f);
460} 439}
461 440
462void setBaseAttributes_Text(int fontId, int colorId) { 441void setBaseAttributes_Text(int fontId, int fgColorId) {
463 activeText_->baseFontId = fontId; 442 iText *d = activeText_;
464 activeText_->baseColorId = colorId; 443 d->baseFontId = fontId;
444 d->baseFgColorId = fgColorId;
465} 445}
466 446
467void setAnsiFlags_Text(int ansiFlags) { 447void setAnsiFlags_Text(int ansiFlags) {
@@ -574,16 +554,6 @@ iLocalDef iFont *characterFont_Font_(iFont *d, iChar ch, uint32_t *glyphIndex) {
574 return overrideFont; 554 return overrideFont;
575 } 555 }
576 } 556 }
577#if 0
578 /* TODO: Put arrows in Smol Emoji. */
579 /* Manual exceptions. */ {
580 if (ch >= 0x2190 && ch <= 0x2193 /* arrows */) {
581 d = font_Text_(iosevka_FontId + d->sizeId);
582 *glyphIndex = glyphIndex_Font_(d, ch);
583 return d;
584 }
585 }
586#endif
587 /* The font's own version of the glyph. */ 557 /* The font's own version of the glyph. */
588 if ((*glyphIndex = glyphIndex_Font_(d, ch)) != 0) { 558 if ((*glyphIndex = glyphIndex_Font_(d, ch)) != 0) {
589 return d; 559 return d;
@@ -609,69 +579,6 @@ iLocalDef iFont *characterFont_Font_(iFont *d, iChar ch, uint32_t *glyphIndex) {
609 } 579 }
610 } 580 }
611 } 581 }
612#if 0
613 const int fallbacks[] = {
614 notoEmoji_FontId,
615 symbols2_FontId,
616 symbols_FontId
617 };
618 /* First fallback is Smol Emoji. */
619 if (ch != 0x20) {
620 iForIndices(i, fallbacks) {
621 iFont *fallback = font_Text_(fallbacks[i] + d->sizeId);
622 if (fallback != d && (*glyphIndex = glyphIndex_Font_(fallback, ch)) != 0) {
623 return fallback;
624 }
625 }
626 }
627 /* Try Simplified Chinese. */
628 if (ch >= 0x2e80) {
629 iFont *sc = font_Text_(chineseSimplified_FontId + d->sizeId);
630 if (sc != d && (*glyphIndex = glyphIndex_Font_(sc, ch)) != 0) {
631 return sc;
632 }
633 }
634 /* Could be Korean. */
635 if (ch >= 0x3000) {
636 iFont *korean = font_Text_(korean_FontId + d->sizeId);
637 if (korean != d && (*glyphIndex = glyphIndex_Font_(korean, ch)) != 0) {
638 return korean;
639 }
640 }
641 /* Japanese perhaps? */
642 if (ch > 0x3040) {
643 iFont *japanese = font_Text_(japanese_FontId + d->sizeId);
644 if (japanese != d && (*glyphIndex = glyphIndex_Font_(japanese, ch)) != 0) {
645 return japanese;
646 }
647 }
648 /* Maybe Arabic. */
649 if (ch >= 0x600) {
650 iFont *arabic = font_Text_(arabic_FontId + d->sizeId);
651 if (arabic != d && (*glyphIndex = glyphIndex_Font_(arabic, ch)) != 0) {
652 return arabic;
653 }
654 }
655#if defined (iPlatformApple)
656 /* White up arrow is used for the Shift key on macOS. Symbola's glyph is not a great
657 match to the other text, so use the UI font instead. */
658 if ((ch == 0x2318 || ch == 0x21e7) && d == font_Text_(regular_FontId)) {
659 *glyphIndex = glyphIndex_Font_(d = font_Text_(defaultContentRegular_FontId), ch);
660 return d;
661 }
662#endif
663 /* User's symbols font. */ {
664 iFont *sys = font_Text_(userSymbols_FontId + d->sizeId);
665 if (sys != d && (*glyphIndex = glyphIndex_Font_(sys, ch)) != 0) {
666 return sys;
667 }
668 }
669 /* Final fallback. */
670 iFont *font = font_Text_(iosevka_FontId + d->sizeId);
671 if (d != font) {
672 *glyphIndex = glyphIndex_Font_(font, ch);
673 }
674#endif // 0
675 if (!*glyphIndex) { 582 if (!*glyphIndex) {
676 activeText_->missingGlyphs = iTrue; 583 activeText_->missingGlyphs = iTrue;
677 fprintf(stderr, "failed to find %08x (%lc)\n", ch, (int)ch); fflush(stderr); 584 fprintf(stderr, "failed to find %08x (%lc)\n", ch, (int)ch); fflush(stderr);
@@ -680,7 +587,9 @@ iLocalDef iFont *characterFont_Font_(iFont *d, iChar ch, uint32_t *glyphIndex) {
680} 587}
681 588
682static iGlyph *glyphByIndex_Font_(iFont *d, uint32_t glyphIndex) { 589static iGlyph *glyphByIndex_Font_(iFont *d, uint32_t glyphIndex) {
683 iAssert(d->table); 590 if (!d->table) {
591 d->table = new_GlyphTable();
592 }
684 iGlyph* glyph = NULL; 593 iGlyph* glyph = NULL;
685 void * node = value_Hash(&d->table->glyphs, glyphIndex); 594 void * node = value_Hash(&d->table->glyphs, glyphIndex);
686 if (node) { 595 if (node) {
@@ -739,6 +648,7 @@ struct Impl_AttributedRun {
739 iTextAttrib attrib; 648 iTextAttrib attrib;
740 iFont *font; 649 iFont *font;
741 iColor fgColor_; /* any RGB color; A > 0 */ 650 iColor fgColor_; /* any RGB color; A > 0 */
651 iColor bgColor_; /* any RGB color; A > 0 */
742 struct { 652 struct {
743 uint8_t isLineBreak : 1; 653 uint8_t isLineBreak : 1;
744// uint8_t isRTL : 1; 654// uint8_t isRTL : 1;
@@ -750,29 +660,45 @@ static iColor fgColor_AttributedRun_(const iAttributedRun *d) {
750 if (d->fgColor_.a) { 660 if (d->fgColor_.a) {
751 return d->fgColor_; 661 return d->fgColor_;
752 } 662 }
753 if (d->attrib.colorId == none_ColorId) { 663 if (d->attrib.fgColorId == none_ColorId) {
754 return (iColor){ 255, 255, 255, 255 }; 664 return (iColor){ 255, 255, 255, 255 };
755 } 665 }
756 return get_Color(d->attrib.colorId); 666 return get_Color(d->attrib.fgColorId);
667}
668
669static iColor bgColor_AttributedRun_(const iAttributedRun *d) {
670 if (d->bgColor_.a) {
671 return d->bgColor_;
672 }
673 return (iColor){ 255, 255, 255, 0 };
674 if (d->attrib.bgColorId == none_ColorId) {
675 return (iColor){ 255, 255, 255, 0 };
676 }
677 return get_Color(d->attrib.bgColorId);
757} 678}
758 679
759static void setFgColor_AttributedRun_(iAttributedRun *d, int colorId) { 680static void setFgColor_AttributedRun_(iAttributedRun *d, int colorId) {
760 d->attrib.colorId = colorId; 681 d->attrib.fgColorId = colorId;
761 d->fgColor_.a = 0; 682 d->fgColor_.a = 0;
762} 683}
763 684
685static void setBgColor_AttributedRun_(iAttributedRun *d, int colorId) {
686 d->attrib.bgColorId = colorId;
687 d->bgColor_.a = 0;
688}
689
764iDeclareType(AttributedText) 690iDeclareType(AttributedText)
765iDeclareTypeConstructionArgs(AttributedText, iRangecc text, size_t maxLen, iFont *font, 691iDeclareTypeConstructionArgs(AttributedText, iRangecc text, size_t maxLen, iFont *font,
766 int colorId, int baseDir, iFont *baseFont, int baseColorId, 692 int colorId, int baseDir, iFont *baseFont, int baseFgColorId,
767 iChar overrideChar) 693 iChar overrideChar)
768 694
769struct Impl_AttributedText { 695struct Impl_AttributedText {
770 iRangecc source; /* original source text */ 696 iRangecc source; /* original source text */
771 size_t maxLen; 697 size_t maxLen;
772 iFont * font; 698 iFont * font;
773 int colorId; 699 int fgColorId;
774 iFont * baseFont; 700 iFont * baseFont;
775 int baseColorId; 701 int baseFgColorId;
776 iBool isBaseRTL; 702 iBool isBaseRTL;
777 iArray runs; 703 iArray runs;
778 iArray logical; /* UTF-32 text in logical order (mixed directions; matches source) */ 704 iArray logical; /* UTF-32 text in logical order (mixed directions; matches source) */
@@ -785,9 +711,9 @@ struct Impl_AttributedText {
785 711
786iDefineTypeConstructionArgs(AttributedText, 712iDefineTypeConstructionArgs(AttributedText,
787 (iRangecc text, size_t maxLen, iFont *font, int colorId, 713 (iRangecc text, size_t maxLen, iFont *font, int colorId,
788 int baseDir, iFont *baseFont, int baseColorId, 714 int baseDir, iFont *baseFont, int baseFgColorId,
789 iChar overrideChar), 715 iChar overrideChar),
790 text, maxLen, font, colorId, baseDir, baseFont, baseColorId, 716 text, maxLen, font, colorId, baseDir, baseFont, baseFgColorId,
791 overrideChar) 717 overrideChar)
792 718
793static const char *sourcePtr_AttributedText_(const iAttributedText *d, int logicalPos) { 719static const char *sourcePtr_AttributedText_(const iAttributedText *d, int logicalPos) {
@@ -897,7 +823,8 @@ static void prepare_AttributedText_(iAttributedText *d, int overrideBaseDir, iCh
897 } 823 }
898 iAttributedRun run = { 824 iAttributedRun run = {
899 .logical = { 0, length }, 825 .logical = { 0, length },
900 .attrib = { .colorId = d->colorId, .isBaseRTL = d->isBaseRTL }, 826 .attrib = { .fgColorId = d->fgColorId, .bgColorId = none_ColorId,
827 .isBaseRTL = d->isBaseRTL },
901 .font = d->font, 828 .font = d->font,
902 }; 829 };
903 const int *logToSource = constData_Array(&d->logicalToSourceOffset); 830 const int *logToSource = constData_Array(&d->logicalToSourceOffset);
@@ -935,12 +862,13 @@ static void prepare_AttributedText_(iAttributedText *d, int overrideBaseDir, iCh
935 if (match_RegExp(activeText_->ansiEscape, srcPos, d->source.end - srcPos, &m)) { 862 if (match_RegExp(activeText_->ansiEscape, srcPos, d->source.end - srcPos, &m)) {
936 finishRun_AttributedText_(d, &run, pos - 1); 863 finishRun_AttributedText_(d, &run, pos - 1);
937 const int ansi = activeText_->ansiFlags; 864 const int ansi = activeText_->ansiFlags;
938 if (ansi) { 865 if (ansi && capturedRange_RegExpMatch(&m, 2).start[0] ==
866 'm' /* Select Graphic Rendition */) {
939 const iRangecc sequence = capturedRange_RegExpMatch(&m, 1); 867 const iRangecc sequence = capturedRange_RegExpMatch(&m, 1);
940 /* Note: This styling is hardcoded to match `typesetOneLine_RunTypesetter_()`. */ 868 /* Note: This styling is hardcoded to match `typesetOneLine_RunTypesetter_()`. */
941 if (ansi & allowFontStyle_AnsiFlag && equal_Rangecc(sequence, "1")) { 869 if (ansi & allowFontStyle_AnsiFlag && equal_Rangecc(sequence, "1")) {
942 run.attrib.bold = iTrue; 870 run.attrib.bold = iTrue;
943 if (d->baseColorId == tmParagraph_ColorId) { 871 if (d->baseFgColorId == tmParagraph_ColorId) {
944 setFgColor_AttributedRun_(&run, tmFirstParagraph_ColorId); 872 setFgColor_AttributedRun_(&run, tmFirstParagraph_ColorId);
945 } 873 }
946 attribFont = font_Text_(fontWithStyle_Text(fontId_Text_(d->baseFont), 874 attribFont = font_Text_(fontWithStyle_Text(fontId_Text_(d->baseFont),
@@ -962,10 +890,13 @@ static void prepare_AttributedText_(iAttributedText *d, int overrideBaseDir, iCh
962 run.attrib.italic = iFalse; 890 run.attrib.italic = iFalse;
963 run.attrib.monospace = iFalse; 891 run.attrib.monospace = iFalse;
964 attribFont = run.font = d->baseFont; 892 attribFont = run.font = d->baseFont;
965 setFgColor_AttributedRun_(&run, d->baseColorId); 893 setFgColor_AttributedRun_(&run, d->baseFgColorId);
894 setBgColor_AttributedRun_(&run, none_ColorId);
966 } 895 }
967 else if (ansi & allowFg_AnsiFlag) { 896 else {
968 run.fgColor_ = ansiForeground_Color(sequence, tmParagraph_ColorId); 897 ansiColors_Color(sequence, d->baseFgColorId, none_ColorId,
898 ansi & allowFg_AnsiFlag ? &run.fgColor_ : NULL,
899 ansi & allowBg_AnsiFlag ? &run.bgColor_ : NULL);
969 } 900 }
970 } 901 }
971 pos += length_Rangecc(capturedRange_RegExpMatch(&m, 0)); 902 pos += length_Rangecc(capturedRange_RegExpMatch(&m, 0));
@@ -988,7 +919,7 @@ static void prepare_AttributedText_(iAttributedText *d, int overrideBaseDir, iCh
988 colorNum = esc - asciiBase_ColorEscape; 919 colorNum = esc - asciiBase_ColorEscape;
989 } 920 }
990 run.logical.start = pos + 1; 921 run.logical.start = pos + 1;
991 setFgColor_AttributedRun_(&run, colorNum >= 0 ? colorNum : d->colorId); 922 setFgColor_AttributedRun_(&run, colorNum >= 0 ? colorNum : d->fgColorId);
992 continue; 923 continue;
993 } 924 }
994 if (ch == '\n') { 925 if (ch == '\n') {
@@ -1051,14 +982,15 @@ static void prepare_AttributedText_(iAttributedText *d, int overrideBaseDir, iCh
1051} 982}
1052 983
1053void init_AttributedText(iAttributedText *d, iRangecc text, size_t maxLen, iFont *font, int colorId, 984void init_AttributedText(iAttributedText *d, iRangecc text, size_t maxLen, iFont *font, int colorId,
1054 int baseDir, iFont *baseFont, int baseColorId, iChar overrideChar) { 985 int baseDir, iFont *baseFont, int baseFgColorId,
1055 d->source = text; 986 iChar overrideChar) {
1056 d->maxLen = maxLen ? maxLen : iInvalidSize; 987 d->source = text;
1057 d->font = font; 988 d->maxLen = maxLen ? maxLen : iInvalidSize;
1058 d->colorId = colorId; 989 d->font = font;
1059 d->baseFont = baseFont; 990 d->fgColorId = colorId;
1060 d->baseColorId = baseColorId; 991 d->baseFont = baseFont;
1061 d->isBaseRTL = iFalse; 992 d->baseFgColorId = baseFgColorId;
993 d->isBaseRTL = iFalse;
1062 init_Array(&d->runs, sizeof(iAttributedRun)); 994 init_Array(&d->runs, sizeof(iAttributedRun));
1063 init_Array(&d->logical, sizeof(iChar)); 995 init_Array(&d->logical, sizeof(iChar));
1064 init_Array(&d->visual, sizeof(iChar)); 996 init_Array(&d->visual, sizeof(iChar));
@@ -1412,7 +1344,7 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) {
1412 init_AttributedText(&attrText, args->text, args->maxLen, d, args->color, 1344 init_AttributedText(&attrText, args->text, args->maxLen, d, args->color,
1413 args->baseDir, 1345 args->baseDir,
1414 activeText_->baseFontId >= 0 ? font_Text_(activeText_->baseFontId) : d, 1346 activeText_->baseFontId >= 0 ? font_Text_(activeText_->baseFontId) : d,
1415 activeText_->baseColorId, 1347 activeText_->baseFgColorId,
1416 wrap ? wrap->overrideChar : 0); 1348 wrap ? wrap->overrideChar : 0);
1417 if (wrap) { 1349 if (wrap) {
1418 wrap->baseDir = attrText.isBaseRTL ? -1 : +1; 1350 wrap->baseDir = attrText.isBaseRTL ? -1 : +1;
@@ -1464,7 +1396,9 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) {
1464 iRangei wrapPosRange = { 0, textLen }; 1396 iRangei wrapPosRange = { 0, textLen };
1465 int wrapResumePos = textLen; /* logical position where next line resumes */ 1397 int wrapResumePos = textLen; /* logical position where next line resumes */
1466 size_t wrapResumeRunIndex = runCount; /* index of run where next line resumes */ 1398 size_t wrapResumeRunIndex = runCount; /* index of run where next line resumes */
1467 iTextAttrib attrib = { .colorId = args->color, .isBaseRTL = attrText.isBaseRTL }; 1399 iTextAttrib attrib = { .fgColorId = args->color,
1400 .bgColorId = none_ColorId,
1401 .isBaseRTL = attrText.isBaseRTL };
1468 iTextAttrib wrapAttrib = attrib; 1402 iTextAttrib wrapAttrib = attrib;
1469 iTextAttrib lastAttrib = attrib; 1403 iTextAttrib lastAttrib = attrib;
1470 const int layoutBound = (wrap ? wrap->maxWidth : 0); 1404 const int layoutBound = (wrap ? wrap->maxWidth : 0);
@@ -1712,6 +1646,12 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) {
1712 yCursor += d->height; 1646 yCursor += d->height;
1713 continue; 1647 continue;
1714 } 1648 }
1649 const iColor fgClr = fgColor_AttributedRun_(run);
1650 const iColor bgClr = bgColor_AttributedRun_(run);
1651 iBool isBgFilled = iFalse;
1652 if (~mode & permanentColorFlag_RunMode) {
1653 isBgFilled = (bgClr.a != 0) || (mode & fillBackground_RunMode);
1654 }
1715 iGlyphBuffer *buf = at_Array(&buffers, runIndex); 1655 iGlyphBuffer *buf = at_Array(&buffers, runIndex);
1716 shape_GlyphBuffer_(buf); 1656 shape_GlyphBuffer_(buf);
1717 iAssert(run->font == buf->font); 1657 iAssert(run->font == buf->font);
@@ -1772,34 +1712,46 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) {
1772 bounds.size.x = iMax(bounds.size.x, dst.x + dst.w - orig.x); 1712 bounds.size.x = iMax(bounds.size.x, dst.x + dst.w - orig.x);
1773 bounds.size.y = iMax(bounds.size.y, yCursor + glyph->font->height); 1713 bounds.size.y = iMax(bounds.size.y, yCursor + glyph->font->height);
1774 } 1714 }
1775 if (mode & draw_RunMode && logicalText[logPos] > 0x20) { 1715 const iBool isSpace = (logicalText[logPos] == 0x20);
1716 if (mode & draw_RunMode && (isBgFilled || !isSpace)) {
1776 /* Draw the glyph. */ 1717 /* Draw the glyph. */
1777 if (!isRasterized_Glyph_(glyph, hoff)) { 1718 if (!isSpace && !isRasterized_Glyph_(glyph, hoff)) {
1778 cacheSingleGlyph_Font_(run->font, glyphId); /* may cause cache reset */ 1719 cacheSingleGlyph_Font_(run->font, glyphId); /* may cause cache reset */
1779 glyph = glyphByIndex_Font_(run->font, glyphId); 1720 glyph = glyphByIndex_Font_(run->font, glyphId);
1780 iAssert(isRasterized_Glyph_(glyph, hoff)); 1721 iAssert(isRasterized_Glyph_(glyph, hoff));
1781 } 1722 }
1782 if (~mode & permanentColorFlag_RunMode) { 1723 if (~mode & permanentColorFlag_RunMode) {
1783 const iColor clr = fgColor_AttributedRun_(run); 1724 SDL_SetTextureColorMod(activeText_->cache, fgClr.r, fgClr.g, fgClr.b);
1784 SDL_SetTextureColorMod(activeText_->cache, clr.r, clr.g, clr.b);
1785 if (args->mode & fillBackground_RunMode) {
1786 SDL_SetRenderDrawColor(activeText_->render, clr.r, clr.g, clr.b, 0);
1787 }
1788 } 1725 }
1789 SDL_Rect src;
1790 memcpy(&src, &glyph->rect[hoff], sizeof(SDL_Rect));
1791 dst.x += origin_Paint.x; 1726 dst.x += origin_Paint.x;
1792 dst.y += origin_Paint.y; 1727 dst.y += origin_Paint.y;
1793 if (args->mode & fillBackground_RunMode) { 1728 if (isBgFilled) {
1794 /* Alpha blending looks much better if the RGB components don't change in
1795 the partially transparent pixels. */
1796 /* TODO: Backgrounds of all glyphs should be cleared before drawing anything else. */ 1729 /* TODO: Backgrounds of all glyphs should be cleared before drawing anything else. */
1797 SDL_RenderFillRect(activeText_->render, &dst); 1730 if (bgClr.a) {
1731 SDL_SetRenderDrawColor(activeText_->render, bgClr.r, bgClr.g, bgClr.b, 255);
1732 const SDL_Rect bgRect = {
1733 origin_Paint.x + orig.x + xCursor,
1734 origin_Paint.y + orig.y + yCursor,
1735 xAdvance,
1736 d->height,
1737 };
1738 SDL_RenderFillRect(activeText_->render, &bgRect);
1739 }
1740 else if (args->mode & fillBackground_RunMode) {
1741 /* Alpha blending looks much better if the RGB components don't change
1742 in the partially transparent pixels. */
1743 SDL_SetRenderDrawColor(activeText_->render, fgClr.r, fgClr.g, fgClr.b, 0);
1744 SDL_RenderFillRect(activeText_->render, &dst);
1745 }
1746 }
1747 if (!isSpace) {
1748 SDL_Rect src;
1749 memcpy(&src, &glyph->rect[hoff], sizeof(SDL_Rect));
1750 SDL_RenderCopy(activeText_->render, activeText_->cache, &src, &dst);
1798 } 1751 }
1799 SDL_RenderCopy(activeText_->render, activeText_->cache, &src, &dst);
1800#if 0 1752#if 0
1801 /* Show spaces and direction. */ 1753 /* Show spaces and direction. */
1802 if (logicalText[logPos] == 0x20) { 1754 if (isSpace) {
1803 const iColor debug = get_Color(run->flags.isRTL ? yellow_ColorId : red_ColorId); 1755 const iColor debug = get_Color(run->flags.isRTL ? yellow_ColorId : red_ColorId);
1804 SDL_SetRenderDrawColor(text_.render, debug.r, debug.g, debug.b, 255); 1756 SDL_SetRenderDrawColor(text_.render, debug.r, debug.g, debug.b, 255);
1805 dst.w = xAdvance; 1757 dst.w = xAdvance;