Draw: Fixed Color Emoji with FreeType

This commit is contained in:
Mirek Fidler 2021-12-12 16:36:17 +01:00
parent 7edfc57742
commit d16b2ab18a
9 changed files with 77 additions and 26 deletions

View file

@ -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();

View file

@ -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<FontSysData, Tuple2<Font, int> > 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<cairo_glyph_t> 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<FontSysData, Tuple2<Font, int> > 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);

View file

@ -75,6 +75,7 @@ public:
SPECIAL = 0x0010,
SERIFSTYLE = 0x0020,
SCRIPTSTYLE = 0x0040,
COLORIMG = 0x0080, // freetype color bitmap font (emojis)
};
static int GetFaceCount();

View file

@ -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));
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<FaceInfo> 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);

View file

@ -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

View file

@ -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 } },

View file

@ -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;

View file

@ -0,0 +1,9 @@
uses
CtrlLib;
file
main.cpp;
mainconfig
"" = "GUI";

View file

@ -0,0 +1,24 @@
#include <CtrlLib/CtrlLib.h>
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();
}