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:
Benau 2019-09-21 16:08:12 +08:00
parent 3601e97d3b
commit 9154aeda58
3 changed files with 66 additions and 12 deletions

View File

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

View File

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

View File

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