Add support for CPAL / COLR tables color emoji
Require freetype 2.10, emoji can be Windows 10 Segoe UI Emoji for example
This commit is contained in:
parent
3601e97d3b
commit
9154aeda58
@ -408,8 +408,11 @@ void FontManager::shape(const std::u32string& text,
|
||||
}
|
||||
}
|
||||
prev_face = cur_face;
|
||||
if (!FT_HAS_COLOR(cur_face))
|
||||
if (!FT_HAS_COLOR(cur_face) ||
|
||||
(FT_HAS_COLOR(cur_face) && cur_face->num_fixed_sizes == 0))
|
||||
{
|
||||
// Handle color emoji with CPAL / COLR tables
|
||||
// (num_fixed_sizes == 0)
|
||||
checkFTError(FT_Set_Pixel_Sizes(cur_face, 0,
|
||||
m_shaping_dpi), "setting DPI");
|
||||
}
|
||||
@ -574,18 +577,55 @@ FT_Face FontManager::loadColorEmoji()
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!FT_HAS_COLOR(face) || face->num_fixed_sizes == 0)
|
||||
if (!FT_HAS_COLOR(face))
|
||||
{
|
||||
Log::error("FontManager", "Bad %s color emoji, ignored.",
|
||||
GUIEngine::getSkin()->getColorEmojiTTF().c_str());
|
||||
checkFTError(FT_Done_Face(face), "removing faces for emoji");
|
||||
return NULL;
|
||||
}
|
||||
if (face->num_fixed_sizes != 0)
|
||||
{
|
||||
// Use the largest size available, it will be scaled to regular face ttf
|
||||
// when loading the glyph, so it can reduce the blurring effect
|
||||
m_shaping_dpi = face->available_sizes[face->num_fixed_sizes - 1].height;
|
||||
checkFTError(FT_Select_Size(face, face->num_fixed_sizes - 1),
|
||||
"setting color emoji size");
|
||||
}
|
||||
|
||||
uint32_t smiley = 0x1f603;
|
||||
uint32_t glyph_index = FT_Get_Char_Index(face, smiley);
|
||||
if (glyph_index == 0)
|
||||
{
|
||||
Log::error("FontManager", "%s doesn't make 0x1f603 smiley, ignored.",
|
||||
GUIEngine::getSkin()->getColorEmojiTTF().c_str());
|
||||
checkFTError(FT_Done_Face(face), "removing faces for emoji");
|
||||
return NULL;
|
||||
}
|
||||
FT_GlyphSlot slot = face->glyph;
|
||||
if (FT_HAS_COLOR(face) && face->num_fixed_sizes != 0)
|
||||
{
|
||||
checkFTError(FT_Load_Glyph(face, glyph_index,
|
||||
FT_LOAD_DEFAULT | FT_LOAD_COLOR), "loading a glyph");
|
||||
}
|
||||
else
|
||||
{
|
||||
checkFTError(FT_Set_Pixel_Sizes(face, 0, 16), "setting DPI");
|
||||
checkFTError(FT_Load_Glyph(face, glyph_index,
|
||||
FT_LOAD_DEFAULT | FT_LOAD_COLOR), "loading a glyph");
|
||||
checkFTError(FT_Render_Glyph(slot,
|
||||
FT_RENDER_MODE_NORMAL), "rendering a glyph to bitmap");
|
||||
}
|
||||
|
||||
FT_Bitmap* bits = &(slot->bitmap);
|
||||
if (!bits || bits->pixel_mode != FT_PIXEL_MODE_BGRA)
|
||||
{
|
||||
Log::error("FontManager", "%s doesn't have color, ignored.",
|
||||
GUIEngine::getSkin()->getColorEmojiTTF().c_str());
|
||||
checkFTError(FT_Done_Face(face), "removing faces for emoji");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
m_has_color_emoji = true;
|
||||
return face;
|
||||
} // loadColorEmoji
|
||||
@ -602,10 +642,11 @@ void FontManager::loadFonts()
|
||||
std::vector<FT_Face> normal_ttf = loadTTF(
|
||||
GUIEngine::getSkin()->getNormalTTF());
|
||||
std::vector<FT_Face> bold_ttf = normal_ttf;
|
||||
FT_Face color_emoji = NULL;
|
||||
if (!ProfileWorld::isNoGraphics())
|
||||
{
|
||||
assert(!normal_ttf.empty());
|
||||
FT_Face color_emoji = loadColorEmoji();
|
||||
color_emoji = loadColorEmoji();
|
||||
if (!normal_ttf.empty() && color_emoji != NULL)
|
||||
{
|
||||
// Put color emoji after 1st default font so can use it before wqy
|
||||
@ -634,6 +675,17 @@ void FontManager::loadFonts()
|
||||
regular->getFaceTTF()->loadTTF(normal_ttf);
|
||||
#endif
|
||||
regular->init();
|
||||
|
||||
#ifndef SERVER_ONLY
|
||||
if (color_emoji && color_emoji->num_fixed_sizes == 0)
|
||||
{
|
||||
// This color emoji has CPAL / COLR tables so it's scalable
|
||||
m_shaping_dpi = regular->getDPI();
|
||||
// Update inverse shaping from m_shaping_dpi
|
||||
regular->setDPI();
|
||||
}
|
||||
#endif
|
||||
|
||||
m_fonts.push_back(regular);
|
||||
m_font_type_map[std::type_index(typeid(RegularFace))] = font_loaded++;
|
||||
|
||||
|
@ -195,7 +195,7 @@ void FontWithFace::insertGlyph(unsigned font_number, unsigned glyph_index)
|
||||
FT_Face cur_face = m_face_ttf->getFace(font_number);
|
||||
FT_GlyphSlot slot = cur_face->glyph;
|
||||
|
||||
if (FT_HAS_COLOR(cur_face))
|
||||
if (FT_HAS_COLOR(cur_face) && cur_face->num_fixed_sizes != 0)
|
||||
{
|
||||
font_manager->checkFTError(FT_Load_Glyph(cur_face, glyph_index,
|
||||
FT_LOAD_DEFAULT | FT_LOAD_COLOR), "loading a glyph");
|
||||
@ -207,8 +207,10 @@ void FontWithFace::insertGlyph(unsigned font_number, unsigned glyph_index)
|
||||
font_manager->checkFTError(FT_Set_Pixel_Sizes(cur_face, 0, getDPI()),
|
||||
"setting DPI");
|
||||
|
||||
unsigned flag = FT_HAS_COLOR(cur_face) ?
|
||||
(FT_LOAD_DEFAULT | FT_LOAD_COLOR) : FT_LOAD_DEFAULT;
|
||||
font_manager->checkFTError(FT_Load_Glyph(cur_face, glyph_index,
|
||||
FT_LOAD_DEFAULT), "loading a glyph");
|
||||
flag), "loading a glyph");
|
||||
|
||||
font_manager->checkFTError(shapeOutline(&(slot->outline)),
|
||||
"shaping outline");
|
||||
|
@ -216,8 +216,6 @@ private:
|
||||
/** Add a character into \ref m_new_char_holder for lazy loading later. */
|
||||
void addLazyLoadChar(wchar_t c) { m_new_char_holder.insert(c); }
|
||||
// ------------------------------------------------------------------------
|
||||
void setDPI();
|
||||
// ------------------------------------------------------------------------
|
||||
/** Override it if sub-class should not do lazy loading characters. */
|
||||
virtual bool supportLazyLoadChar() const { return true; }
|
||||
// ------------------------------------------------------------------------
|
||||
@ -307,6 +305,8 @@ public:
|
||||
float getInverseShaping() const { return m_inverse_shaping; }
|
||||
// ------------------------------------------------------------------------
|
||||
virtual bool useColorGlyphPage() const { return false; }
|
||||
// ------------------------------------------------------------------------
|
||||
void setDPI();
|
||||
}; // FontWithFace
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user