diff options
-rw-r--r-- | src/ui/text.c | 86 |
1 files changed, 65 insertions, 21 deletions
diff --git a/src/ui/text.c b/src/ui/text.c index 6cfb5c51..7e8c7871 100644 --- a/src/ui/text.c +++ b/src/ui/text.c | |||
@@ -742,10 +742,15 @@ static iChar nextChar_(const char **chPos, const char *end) { | |||
742 | 742 | ||
743 | iDeclareType(AttributedRun) | 743 | iDeclareType(AttributedRun) |
744 | 744 | ||
745 | /*enum iAttributedRunFlags { | ||
746 | newline_AttributedRunFlag = iBit(1), | ||
747 | };*/ | ||
748 | |||
745 | struct Impl_AttributedRun { | 749 | struct Impl_AttributedRun { |
746 | iRangecc text; | 750 | iRangecc text; |
747 | iFont *font; | 751 | iFont * font; |
748 | iColor fgColor; | 752 | iColor fgColor; |
753 | int lineBreaks; | ||
749 | }; | 754 | }; |
750 | 755 | ||
751 | iDeclareType(AttributedText) | 756 | iDeclareType(AttributedText) |
@@ -753,7 +758,7 @@ iDeclareTypeConstructionArgs(AttributedText, iRangecc text, iFont *font, iColor | |||
753 | 758 | ||
754 | struct Impl_AttributedText { | 759 | struct Impl_AttributedText { |
755 | iRangecc text; | 760 | iRangecc text; |
756 | iFont *font; | 761 | iFont * font; |
757 | iColor fgColor; | 762 | iColor fgColor; |
758 | iArray runs; | 763 | iArray runs; |
759 | }; | 764 | }; |
@@ -765,27 +770,63 @@ static void prepare_AttributedText_(iAttributedText *d) { | |||
765 | iAssert(isEmpty_Array(&d->runs)); | 770 | iAssert(isEmpty_Array(&d->runs)); |
766 | const char *chPos = d->text.start; | 771 | const char *chPos = d->text.start; |
767 | iAttributedRun run = { .text = d->text, .font = d->font, .fgColor = d->fgColor }; | 772 | iAttributedRun run = { .text = d->text, .font = d->font, .fgColor = d->fgColor }; |
773 | #define finishRun_() { \ | ||
774 | iAttributedRun finishedRun = run; \ | ||
775 | finishedRun.text.end = currentPos; \ | ||
776 | if (!isEmpty_Range(&finishedRun.text)) { \ | ||
777 | pushBack_Array(&d->runs, &finishedRun); \ | ||
778 | run.lineBreaks = 0; \ | ||
779 | } \ | ||
780 | run.text.start = currentPos; \ | ||
781 | } | ||
768 | while (chPos < d->text.end) { | 782 | while (chPos < d->text.end) { |
769 | const char *currentPos = chPos; | 783 | const char *currentPos = chPos; |
784 | if (*chPos == 0x1b) { /* ANSI escape. */ | ||
785 | chPos++; | ||
786 | iRegExpMatch m; | ||
787 | init_RegExpMatch(&m); | ||
788 | if (match_RegExp(text_.ansiEscape, chPos, d->text.end - chPos, &m)) { | ||
789 | finishRun_(); | ||
790 | run.fgColor = ansiForeground_Color(capturedRange_RegExpMatch(&m, 1), | ||
791 | tmParagraph_ColorId); | ||
792 | chPos = end_RegExpMatch(&m); | ||
793 | run.text.start = chPos; | ||
794 | continue; | ||
795 | } | ||
796 | } | ||
770 | const iChar ch = nextChar_(&chPos, d->text.end); | 797 | const iChar ch = nextChar_(&chPos, d->text.end); |
771 | if (ch == '\v') { | 798 | if (ch == '\v') { |
772 | /* TODO: Color escapes. */ | 799 | finishRun_(); |
773 | 800 | /* An internal color escape. */ | |
801 | iChar esc = nextChar_(&chPos, d->text.end); | ||
802 | int colorNum = none_ColorId; /* default color */ | ||
803 | if (esc == '\v') { /* Extended range. */ | ||
804 | esc = nextChar_(&chPos, d->text.end) + asciiExtended_ColorEscape; | ||
805 | colorNum = esc - asciiBase_ColorEscape; | ||
806 | } | ||
807 | else if (esc != 0x24) { /* ASCII Cancel */ | ||
808 | colorNum = esc - asciiBase_ColorEscape; | ||
809 | } | ||
810 | run.text.start = chPos; | ||
811 | run.fgColor = (colorNum >= 0 ? get_Color(colorNum) : d->fgColor); | ||
812 | //prevCh = 0; | ||
813 | continue; | ||
814 | } | ||
815 | if (ch == '\n') { | ||
816 | finishRun_(); | ||
817 | run.text.start = chPos; | ||
818 | run.lineBreaks++; | ||
819 | continue; | ||
774 | } | 820 | } |
775 | if (isSpace_Char(ch) || isVariationSelector_Char(ch) || isDefaultIgnorable_Char(ch) || | 821 | if (isVariationSelector_Char(ch) || isDefaultIgnorable_Char(ch) || |
776 | isFitzpatrickType_Char(ch)) { | 822 | isFitzpatrickType_Char(ch)) { |
777 | continue; | 823 | continue; |
778 | } | 824 | } |
779 | const iGlyph *glyph = glyph_Font_(d->font, ch); | 825 | const iGlyph *glyph = glyph_Font_(d->font, ch); |
780 | /* TODO: Look for ANSI/color escapes. */ | 826 | /* TODO: Look for ANSI/color escapes. */ |
781 | if (glyph->font != run.font) { | 827 | if (index_Glyph_(glyph) && glyph->font != run.font) { |
782 | /* A different font is being used for this glyph. */ | 828 | /* A different font is being used for this glyph. */ |
783 | iAttributedRun finishedRun = run; | 829 | finishRun_(); |
784 | finishedRun.text.end = currentPos; | ||
785 | if (!isEmpty_Range(&finishedRun.text)) { | ||
786 | pushBack_Array(&d->runs, &finishedRun); | ||
787 | } | ||
788 | run.text.start = currentPos; | ||
789 | run.font = glyph->font; | 830 | run.font = glyph->font; |
790 | } | 831 | } |
791 | } | 832 | } |
@@ -818,7 +859,6 @@ struct Impl_RasterGlyph { | |||
818 | 859 | ||
819 | static void cacheGlyphs_Font_(iFont *d, const iArray *glyphIndices) { | 860 | static void cacheGlyphs_Font_(iFont *d, const iArray *glyphIndices) { |
820 | /* TODO: Make this an object so it can be used sequentially without reallocating buffers. */ | 861 | /* TODO: Make this an object so it can be used sequentially without reallocating buffers. */ |
821 | // const char * chPos = text.start; | ||
822 | SDL_Surface *buf = NULL; | 862 | SDL_Surface *buf = NULL; |
823 | const iInt2 bufSize = init_I2(iMin(512, d->height * iMin(2 * size_Array(glyphIndices), 20)), | 863 | const iInt2 bufSize = init_I2(iMin(512, d->height * iMin(2 * size_Array(glyphIndices), 20)), |
824 | d->height * 4 / 3); | 864 | d->height * 4 / 3); |
@@ -827,17 +867,10 @@ static void cacheGlyphs_Font_(iFont *d, const iArray *glyphIndices) { | |||
827 | SDL_Texture *oldTarget = NULL; | 867 | SDL_Texture *oldTarget = NULL; |
828 | iBool isTargetChanged = iFalse; | 868 | iBool isTargetChanged = iFalse; |
829 | iAssert(isExposed_Window(get_Window())); | 869 | iAssert(isExposed_Window(get_Window())); |
830 | // iAttributedText *attrText = new_AttributedText(text, d, (iColor){ 255, 255, 255, 255 }); | ||
831 | /* We'll flush the buffered rasters periodically until everything is cached. */ | 870 | /* We'll flush the buffered rasters periodically until everything is cached. */ |
832 | size_t index = 0; | 871 | size_t index = 0; |
833 | while (index < size_Array(glyphIndices)) { | 872 | while (index < size_Array(glyphIndices)) { |
834 | for (; index < size_Array(glyphIndices); index++) { | 873 | for (; index < size_Array(glyphIndices); index++) { |
835 | // const char *lastPos = chPos; | ||
836 | // const iChar ch = nextChar_(&chPos, text.end); | ||
837 | // if (ch == 0 || isSpace_Char(ch) || isDefaultIgnorable_Char(ch) || | ||
838 | // isFitzpatrickType_Char(ch)) { | ||
839 | // continue; | ||
840 | // } | ||
841 | const uint32_t glyphIndex = constValue_Array(glyphIndices, index, uint32_t); | 874 | const uint32_t glyphIndex = constValue_Array(glyphIndices, index, uint32_t); |
842 | const int lastCacheBottom = text_.cacheBottom; | 875 | const int lastCacheBottom = text_.cacheBottom; |
843 | iGlyph *glyph = glyphByIndex_Font_(d, glyphIndex); | 876 | iGlyph *glyph = glyphByIndex_Font_(d, glyphIndex); |
@@ -929,7 +962,6 @@ static void cacheGlyphs_Font_(iFont *d, const iArray *glyphIndices) { | |||
929 | bufX = 0; | 962 | bufX = 0; |
930 | } | 963 | } |
931 | } | 964 | } |
932 | // delete_AttributedText(attrText); | ||
933 | if (rasters) { | 965 | if (rasters) { |
934 | delete_Array(rasters); | 966 | delete_Array(rasters); |
935 | } | 967 | } |
@@ -952,6 +984,7 @@ static void cacheSingleGlyph_Font_(iFont *d, uint32_t glyphIndex) { | |||
952 | static void cacheTextGlyphs_Font_(iFont *d, const iRangecc text) { | 984 | static void cacheTextGlyphs_Font_(iFont *d, const iRangecc text) { |
953 | iArray glyphIndices; | 985 | iArray glyphIndices; |
954 | init_Array(&glyphIndices, sizeof(uint32_t)); | 986 | init_Array(&glyphIndices, sizeof(uint32_t)); |
987 | /* TODO: Do this with AttributedText */ | ||
955 | for (const char *chPos = text.start; chPos != text.end; ) { | 988 | for (const char *chPos = text.start; chPos != text.end; ) { |
956 | const char *oldPos = chPos; | 989 | const char *oldPos = chPos; |
957 | const iChar ch = nextChar_(&chPos, text.end); | 990 | const iChar ch = nextChar_(&chPos, text.end); |
@@ -1015,6 +1048,10 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) { | |||
1015 | iAttributedText *attrText = new_AttributedText(args->text, d, get_Color(args->color)); | 1048 | iAttributedText *attrText = new_AttributedText(args->text, d, get_Color(args->color)); |
1016 | iConstForEach(Array, i, &attrText->runs) { | 1049 | iConstForEach(Array, i, &attrText->runs) { |
1017 | const iAttributedRun *run = i.value; | 1050 | const iAttributedRun *run = i.value; |
1051 | if (run->lineBreaks) { | ||
1052 | xCursor = 0.0f; | ||
1053 | yCursor += d->height * run->lineBreaks; | ||
1054 | } | ||
1018 | hb_buffer_clear_contents(hbBuf); | 1055 | hb_buffer_clear_contents(hbBuf); |
1019 | hb_buffer_add_utf8(hbBuf, run->text.start, size_Range(&run->text), 0, -1); | 1056 | hb_buffer_add_utf8(hbBuf, run->text.start, size_Range(&run->text), 0, -1); |
1020 | hb_buffer_set_direction(hbBuf, HB_DIRECTION_LTR); /* TODO: FriBidi? */ | 1057 | hb_buffer_set_direction(hbBuf, HB_DIRECTION_LTR); /* TODO: FriBidi? */ |
@@ -1057,6 +1094,13 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) { | |||
1057 | glyph = glyphByIndex_Font_(run->font, glyphId); | 1094 | glyph = glyphByIndex_Font_(run->font, glyphId); |
1058 | iAssert(isRasterized_Glyph_(glyph, hoff)); | 1095 | iAssert(isRasterized_Glyph_(glyph, hoff)); |
1059 | } | 1096 | } |
1097 | if (~mode & permanentColorFlag_RunMode) { | ||
1098 | //const iColor clr = get_Color(colorNum); | ||
1099 | SDL_SetTextureColorMod(text_.cache, run->fgColor.r, run->fgColor.g, run->fgColor.b); | ||
1100 | // if (args->mode & fillBackground_RunMode) { | ||
1101 | // SDL_SetRenderDrawColor(text_.render, clr.r, clr.g, clr.b, 0); | ||
1102 | // } | ||
1103 | } | ||
1060 | SDL_Rect src; | 1104 | SDL_Rect src; |
1061 | memcpy(&src, &glyph->rect[hoff], sizeof(SDL_Rect)); | 1105 | memcpy(&src, &glyph->rect[hoff], sizeof(SDL_Rect)); |
1062 | if (args->mode & fillBackground_RunMode) { | 1106 | if (args->mode & fillBackground_RunMode) { |