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;
|
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,
|
checkFTError(FT_Set_Pixel_Sizes(cur_face, 0,
|
||||||
m_shaping_dpi), "setting DPI");
|
m_shaping_dpi), "setting DPI");
|
||||||
}
|
}
|
||||||
@ -574,18 +577,55 @@ FT_Face FontManager::loadColorEmoji()
|
|||||||
return NULL;
|
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.",
|
Log::error("FontManager", "Bad %s color emoji, ignored.",
|
||||||
GUIEngine::getSkin()->getColorEmojiTTF().c_str());
|
GUIEngine::getSkin()->getColorEmojiTTF().c_str());
|
||||||
checkFTError(FT_Done_Face(face), "removing faces for emoji");
|
checkFTError(FT_Done_Face(face), "removing faces for emoji");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
// Use the largest size available, it will be scaled to regular face ttf
|
if (face->num_fixed_sizes != 0)
|
||||||
// when loading the glyph, so it can reduce the blurring effect
|
{
|
||||||
m_shaping_dpi = face->available_sizes[face->num_fixed_sizes - 1].height;
|
// Use the largest size available, it will be scaled to regular face ttf
|
||||||
checkFTError(FT_Select_Size(face, face->num_fixed_sizes - 1),
|
// when loading the glyph, so it can reduce the blurring effect
|
||||||
"setting color emoji size");
|
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;
|
m_has_color_emoji = true;
|
||||||
return face;
|
return face;
|
||||||
} // loadColorEmoji
|
} // loadColorEmoji
|
||||||
@ -602,10 +642,11 @@ void FontManager::loadFonts()
|
|||||||
std::vector<FT_Face> normal_ttf = loadTTF(
|
std::vector<FT_Face> normal_ttf = loadTTF(
|
||||||
GUIEngine::getSkin()->getNormalTTF());
|
GUIEngine::getSkin()->getNormalTTF());
|
||||||
std::vector<FT_Face> bold_ttf = normal_ttf;
|
std::vector<FT_Face> bold_ttf = normal_ttf;
|
||||||
|
FT_Face color_emoji = NULL;
|
||||||
if (!ProfileWorld::isNoGraphics())
|
if (!ProfileWorld::isNoGraphics())
|
||||||
{
|
{
|
||||||
assert(!normal_ttf.empty());
|
assert(!normal_ttf.empty());
|
||||||
FT_Face color_emoji = loadColorEmoji();
|
color_emoji = loadColorEmoji();
|
||||||
if (!normal_ttf.empty() && color_emoji != NULL)
|
if (!normal_ttf.empty() && color_emoji != NULL)
|
||||||
{
|
{
|
||||||
// Put color emoji after 1st default font so can use it before wqy
|
// 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);
|
regular->getFaceTTF()->loadTTF(normal_ttf);
|
||||||
#endif
|
#endif
|
||||||
regular->init();
|
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_fonts.push_back(regular);
|
||||||
m_font_type_map[std::type_index(typeid(RegularFace))] = font_loaded++;
|
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_Face cur_face = m_face_ttf->getFace(font_number);
|
||||||
FT_GlyphSlot slot = cur_face->glyph;
|
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,
|
font_manager->checkFTError(FT_Load_Glyph(cur_face, glyph_index,
|
||||||
FT_LOAD_DEFAULT | FT_LOAD_COLOR), "loading a glyph");
|
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()),
|
font_manager->checkFTError(FT_Set_Pixel_Sizes(cur_face, 0, getDPI()),
|
||||||
"setting DPI");
|
"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,
|
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)),
|
font_manager->checkFTError(shapeOutline(&(slot->outline)),
|
||||||
"shaping outline");
|
"shaping outline");
|
||||||
|
@ -216,8 +216,6 @@ private:
|
|||||||
/** Add a character into \ref m_new_char_holder for lazy loading later. */
|
/** 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 addLazyLoadChar(wchar_t c) { m_new_char_holder.insert(c); }
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
void setDPI();
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
/** Override it if sub-class should not do lazy loading characters. */
|
/** Override it if sub-class should not do lazy loading characters. */
|
||||||
virtual bool supportLazyLoadChar() const { return true; }
|
virtual bool supportLazyLoadChar() const { return true; }
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
@ -307,6 +305,8 @@ public:
|
|||||||
float getInverseShaping() const { return m_inverse_shaping; }
|
float getInverseShaping() const { return m_inverse_shaping; }
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
virtual bool useColorGlyphPage() const { return false; }
|
virtual bool useColorGlyphPage() const { return false; }
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
void setDPI();
|
||||||
}; // FontWithFace
|
}; // FontWithFace
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user