From d16b2ab18a4a7c0d90ea2518883c066a62714d39 Mon Sep 17 00:00:00 2001 From: Mirek Fidler Date: Sun, 12 Dec 2021 16:36:17 +0100 Subject: [PATCH] Draw: Fixed Color Emoji with FreeType --- uppbox/FontMaps2/TypeReader.cpp | 5 ----- uppsrc/CtrlCore/GtkDrawText.cpp | 25 ++++++++++++++++--------- uppsrc/Draw/Draw.h | 1 + uppsrc/Draw/FontFc.cpp | 28 ++++++++++++++++++++-------- uppsrc/Draw/FontInt.h | 1 + uppsrc/Draw/Fonts.i | 1 + upptst/CJK/main.cpp | 9 +++++---- upptst/ColorEmoji/ColorEmoji.upp | 9 +++++++++ upptst/ColorEmoji/main.cpp | 24 ++++++++++++++++++++++++ 9 files changed, 77 insertions(+), 26 deletions(-) create mode 100644 upptst/ColorEmoji/ColorEmoji.upp create mode 100644 upptst/ColorEmoji/main.cpp diff --git a/uppbox/FontMaps2/TypeReader.cpp b/uppbox/FontMaps2/TypeReader.cpp index 18a18cde2..ca44f5b98 100644 --- a/uppbox/FontMaps2/TypeReader.cpp +++ b/uppbox/FontMaps2/TypeReader.cpp @@ -8,11 +8,6 @@ int FontTypeReader::Error() throw Fail(); return 0; } -int FontTypeReader::Error() -{ - throw Fail(); return 0; -} - int FontTypeReader::Peek8(const char *s) { return s + 1 < data.end() ? (byte)*s : Error(); diff --git a/uppsrc/CtrlCore/GtkDrawText.cpp b/uppsrc/CtrlCore/GtkDrawText.cpp index 643ef076c..568b95b1d 100644 --- a/uppsrc/CtrlCore/GtkDrawText.cpp +++ b/uppsrc/CtrlCore/GtkDrawText.cpp @@ -15,6 +15,8 @@ FT_Face FTFace(Font fnt, String *rpath = NULL); struct FontSysData { cairo_scaled_font_t *scaled_font; + bool colorimg = false; + Sizef colorimg_size; void Init(Font font, int angle); ~FontSysData() { cairo_scaled_font_destroy(scaled_font); } @@ -31,7 +33,10 @@ void FontSysData::Init(Font font, int angle) cairo_matrix_t font_matrix[1], ctm[1]; cairo_matrix_init_identity(ctm); - cairo_matrix_init_scale(font_matrix, font.GetHeight(), font.GetHeight()); + + int fh = font.GetHeight(); + + cairo_matrix_init_scale(font_matrix, fh, fh); if(font.IsItalic() && !(FTFace(font)->style_flags & FT_STYLE_FLAG_ITALIC)) { cairo_matrix_t sheer[1]; @@ -42,6 +47,7 @@ void FontSysData::Init(Font font, int angle) if(angle) cairo_matrix_rotate(font_matrix, -angle * M_2PI / 3600); + cairo_font_options_t *opt = cairo_font_options_create(); scaled_font = cairo_scaled_font_create(font_face, font_matrix, ctm, opt); @@ -66,6 +72,15 @@ void SystemDraw::FlushText() { if(textcache.GetCount() == 0) return; + static LRUCache > cache; + FontDataSysMaker m; + m.font = textfont; + m.angle = textangle; + FontSysData& sf = cache.Get(m); + + cairo_set_scaled_font(cr, sf.scaled_font); + SetColor(textink); + Buffer gs(textcache.GetCount()); for(int i = 0; i < textcache.GetCount(); i++) { cairo_glyph_t& g = gs[i]; @@ -74,14 +89,6 @@ void SystemDraw::FlushText() g.y = textcache[i].y; } - static LRUCache > cache; - FontDataSysMaker m; - m.font = textfont; - m.angle = textangle; - FontSysData& sf = cache.Get(m); - cairo_set_scaled_font(cr, sf.scaled_font); - - SetColor(textink); cairo_show_glyphs(cr, gs, textcache.GetCount()); cache.Shrink(INT_MAX, 128); diff --git a/uppsrc/Draw/Draw.h b/uppsrc/Draw/Draw.h index c9eb0e209..da22eb8ed 100644 --- a/uppsrc/Draw/Draw.h +++ b/uppsrc/Draw/Draw.h @@ -75,6 +75,7 @@ public: SPECIAL = 0x0010, SERIFSTYLE = 0x0020, SCRIPTSTYLE = 0x0040, + COLORIMG = 0x0080, // freetype color bitmap font (emojis) }; static int GetFaceCount(); diff --git a/uppsrc/Draw/FontFc.cpp b/uppsrc/Draw/FontFc.cpp index 2543d500c..788960fd0 100644 --- a/uppsrc/Draw/FontFc.cpp +++ b/uppsrc/Draw/FontFc.cpp @@ -68,12 +68,12 @@ FT_Face CreateFTFace(const FcPattern *pattern, String *rpath) { if (FcPatternGetDouble(pattern, FC_ASPECT, 0, &aspect) != FcResultMatch) aspect = 1.0; - FT_F26Dot6 ysize = (FT_F26Dot6) (dsize * 64.0); - FT_F26Dot6 xsize = (FT_F26Dot6) (dsize * aspect * 64.0); - if(FT_New_Face(sFTlib, (const char *)filename, 0, &face)) return NULL; + FT_F26Dot6 ysize = (FT_F26Dot6) (dsize * 64.0); + FT_F26Dot6 xsize = (FT_F26Dot6) (dsize * aspect * 64.0); + FT_Set_Char_Size(face, xsize, ysize, 0, 0); return face; } @@ -154,6 +154,13 @@ CommonFontInfo GetFontInfoSys(Font font) strcpy(fi.path, ~path); else *fi.path = 0; + + if(font.GetFaceInfo() & Font::COLORIMG) { + fi.colorimg_cy = fi.ascent + fi.descent; + int h = font.GetHeight(); + fi.ascent = h * fi.ascent / fi.colorimg_cy; + fi.descent = h - fi.ascent; + } } return fi; } @@ -177,16 +184,21 @@ GlyphInfo GetGlyphInfoSys(Font font, int chr) LTIMING("GetGlyphInfoSys 2"); int glyph_index = FT_Get_Char_Index(face, chr); if(glyph_index) { -// if(GetGlyphInfoSysXft) -// return (*GetGlyphInfoSysXft)(font, chr); if(FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT|FT_LOAD_NO_BITMAP) == 0 || FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT) == 0) { FT_Glyph_Metrics& m = face->glyph->metrics; int left = FLOOR(m.horiBearingX); int width = TRUNC(CEIL(m.horiBearingX + m.width) - left); gi.width = TRUNC(ROUND(face->glyph->advance.x)); - gi.lspc = TRUNC(left); - gi.rspc = gi.width - width - gi.lspc; + if(font.GetFaceInfo() & Font::COLORIMG) { + gi.lspc = gi.rspc = 0; + int q = GetFontInfo(font).colorimg_cy; + gi.width = font.GetCy() * gi.width / q + max(1, font.GetCy() / 10); // add a little space there... + } + else { + gi.lspc = TRUNC(left); + gi.rspc = gi.width - width - gi.lspc; + } gi.glyphi = glyph_index; } } @@ -233,7 +245,7 @@ Vector GetAllFacesSys() if(FcPatternGetBool(pt, FC_SYMBOL, 0, &bv) == 0 && bv) fi.info |= Font::SPECIAL; if(FcPatternGetBool(pt, FC_COLOR, 0, &bv) == 0 && bv) - fi.info |= Font::SPECIAL; + fi.info |= Font::COLORIMG; if(FcPatternGetBool(pt, FC_SCALABLE, 0, &bv) == 0 && bv) fi.info |= Font::SCALEABLE; String h = ToLower(fi.name); diff --git a/uppsrc/Draw/FontInt.h b/uppsrc/Draw/FontInt.h index 1f1886e93..d4d7c2fb5 100644 --- a/uppsrc/Draw/FontInt.h +++ b/uppsrc/Draw/FontInt.h @@ -25,6 +25,7 @@ struct CommonFontInfo { bool scaleable; bool ttf; int aux; + int colorimg_cy; // FreeType color Emoji original height char path[256]; // optional (linux only) int fonti = 0; // font index in .ttc, .otc diff --git a/uppsrc/Draw/Fonts.i b/uppsrc/Draw/Fonts.i index ccbb43751..1e9dc7f81 100644 --- a/uppsrc/Draw/Fonts.i +++ b/uppsrc/Draw/Fonts.i @@ -1,6 +1,7 @@ // Predefined replacement fonts; if codepoint is not found in these, remaining fonts cmaps from host are loaded #if defined(PLATFORM_POSIX) && !defined(PLATFORM_COCOA) +{ "Noto Color Emoji", { 2,0,6,9,0,0,0,0,0,0 }, { 0xa0000000,0x03a00000,0x00000000,0x00000000,0x00000038,0x00000000,0x00000000,0x00000001 } }, { "Abyssinica SIL", { 2,0,0,0,0,0,0,0,0,0 }, { 0xfe1d0000,0x23400000,0x0080010c,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000 } }, { "Andale Mono", { 2,11,5,9,0,0,0,0,0,4 }, { 0xff17e000,0x07000000,0x0000002c,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000 } }, { "AnjaliOldLipi", { 2,0,6,3,0,0,0,0,0,0 }, { 0xfc100000,0x43000000,0x00000264,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000 } }, diff --git a/upptst/CJK/main.cpp b/upptst/CJK/main.cpp index a555b7499..54529ab84 100644 --- a/upptst/CJK/main.cpp +++ b/upptst/CJK/main.cpp @@ -5,20 +5,21 @@ using namespace Upp; struct MyApp : TopWindow { void Paint(Draw& w) { String text; + text << WString(0x1F970, 1).ToString(); text << WString(0x1F603, 1).ToString(); + text << WString(0x1F923, 1).ToString(); text << " Quick brown fox, 訓民正音 (훈민정음) "; w.DrawRect(GetSize(), White()); int y = 10; int x = 10; - for(int i = 0; i < Font::GetFaceCount(); i++) + for(int i = 0; i < 3/*Font::GetFaceCount()*/; i++) { Font fnt(i, 30); + DLOG(i << " " << fnt << " " << fnt[0x1F970]); if(fnt.IsSpecial()) continue; fnt.Italic(); - String n = AsString(i) + ": " + fnt.GetFaceName() + ": "; - if(fnt.IsSpecial()) - n << " (special)"; + String n; // = AsString(i) + ": " + fnt.GetFaceName() + ": "; w.DrawText(x, y, n, StdFont()); w.DrawText(x + GetTextSize(n, StdFont()).cx, y, text, fnt); y += fnt.GetLineHeight() + 10; diff --git a/upptst/ColorEmoji/ColorEmoji.upp b/upptst/ColorEmoji/ColorEmoji.upp new file mode 100644 index 000000000..5c4f53e15 --- /dev/null +++ b/upptst/ColorEmoji/ColorEmoji.upp @@ -0,0 +1,9 @@ +uses + CtrlLib; + +file + main.cpp; + +mainconfig + "" = "GUI"; + diff --git a/upptst/ColorEmoji/main.cpp b/upptst/ColorEmoji/main.cpp new file mode 100644 index 000000000..c26338844 --- /dev/null +++ b/upptst/ColorEmoji/main.cpp @@ -0,0 +1,24 @@ +#include + +using namespace Upp; + +struct MyApp : TopWindow { + void Paint(Draw& w) { + w.DrawRect(GetSize(), White()); + String text; + text << "Behold: " + << WString(0x1F970, 1).ToString() + << WString(0x1F603, 1).ToString() + << WString(0x1F923, 1).ToString() + << WString(0x1F970, 1).ToString() + << " is not that nice?"; + ; + w.DrawText(500, 200, text, StdFont()); + w.DrawText(500, 250, text, StdFont().Italic()); + w.DrawText(500, 700, 300, text, StdFont()); + } +}; + +GUI_APP_MAIN { + MyApp().Sizeable().Zoomable().Run(); +} \ No newline at end of file