Fix null pointer dereference in Font

This commit is contained in:
kimci86 2021-12-22 21:51:16 +01:00 committed by Vittorio Romeo
parent d0c63f46fc
commit 53594dfbe7
2 changed files with 48 additions and 43 deletions

View File

@ -401,7 +401,7 @@ private:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Member data // Member data
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
std::shared_ptr<FontHandles> m_font; //!< Shared information about the internal font instance std::shared_ptr<FontHandles> m_fontHandles; //!< Shared information about the internal font instance
bool m_isSmooth; //!< Status of the smooth filter bool m_isSmooth; //!< Status of the smooth filter
Info m_info; //!< Information about the font Info m_info; //!< Information about the font
mutable PageTable m_pages; //!< Table containing the glyphs pages by character size mutable PageTable m_pages; //!< Table containing the glyphs pages by character size

View File

@ -106,7 +106,7 @@ public:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
Font::Font() : Font::Font() :
m_font (), m_fontHandles(),
m_isSmooth (true), m_isSmooth (true),
m_info () m_info ()
{ {
@ -116,7 +116,7 @@ m_info ()
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
Font::Font(const Font& copy) : Font::Font(const Font& copy) :
m_font (copy.m_font), m_fontHandles(copy.m_fontHandles),
m_isSmooth (copy.m_isSmooth), m_isSmooth (copy.m_isSmooth),
m_info (copy.m_info), m_info (copy.m_info),
m_pages (copy.m_pages), m_pages (copy.m_pages),
@ -141,7 +141,7 @@ bool Font::loadFromFile(const std::string& filename)
// Cleanup the previous resources // Cleanup the previous resources
cleanup(); cleanup();
auto font = std::make_unique<FontHandles>(); auto fontHandles = std::make_unique<FontHandles>();
// Initialize FreeType // Initialize FreeType
// Note: we initialize FreeType for every font instance in order to avoid having a single // Note: we initialize FreeType for every font instance in order to avoid having a single
@ -152,7 +152,7 @@ bool Font::loadFromFile(const std::string& filename)
err() << "Failed to load font \"" << filename << "\" (failed to initialize FreeType)" << std::endl; err() << "Failed to load font \"" << filename << "\" (failed to initialize FreeType)" << std::endl;
return false; return false;
} }
font->library.reset(library); fontHandles->library.reset(library);
// Load the new font face from the specified file // Load the new font face from the specified file
FT_Face face; FT_Face face;
@ -161,7 +161,7 @@ bool Font::loadFromFile(const std::string& filename)
err() << "Failed to load font \"" << filename << "\" (failed to create the font face)" << std::endl; err() << "Failed to load font \"" << filename << "\" (failed to create the font face)" << std::endl;
return false; return false;
} }
font->face.reset(face); fontHandles->face.reset(face);
// Load the stroker that will be used to outline the font // Load the stroker that will be used to outline the font
FT_Stroker stroker; FT_Stroker stroker;
@ -170,7 +170,7 @@ bool Font::loadFromFile(const std::string& filename)
err() << "Failed to load font \"" << filename << "\" (failed to create the stroker)" << std::endl; err() << "Failed to load font \"" << filename << "\" (failed to create the stroker)" << std::endl;
return false; return false;
} }
font->stroker.reset(stroker); fontHandles->stroker.reset(stroker);
// Select the unicode character map // Select the unicode character map
if (FT_Select_Charmap(face, FT_ENCODING_UNICODE) != 0) if (FT_Select_Charmap(face, FT_ENCODING_UNICODE) != 0)
@ -180,7 +180,7 @@ bool Font::loadFromFile(const std::string& filename)
} }
// Store the loaded font handles // Store the loaded font handles
m_font = std::move(font); m_fontHandles = std::move(fontHandles);
// Store the font information // Store the font information
m_info.family = face->family_name ? face->family_name : std::string(); m_info.family = face->family_name ? face->family_name : std::string();
@ -202,7 +202,7 @@ bool Font::loadFromMemory(const void* data, std::size_t sizeInBytes)
// Cleanup the previous resources // Cleanup the previous resources
cleanup(); cleanup();
auto font = std::make_unique<FontHandles>(); auto fontHandles = std::make_unique<FontHandles>();
// Initialize FreeType // Initialize FreeType
// Note: we initialize FreeType for every font instance in order to avoid having a single // Note: we initialize FreeType for every font instance in order to avoid having a single
@ -213,7 +213,7 @@ bool Font::loadFromMemory(const void* data, std::size_t sizeInBytes)
err() << "Failed to load font from memory (failed to initialize FreeType)" << std::endl; err() << "Failed to load font from memory (failed to initialize FreeType)" << std::endl;
return false; return false;
} }
font->library.reset(library); fontHandles->library.reset(library);
// Load the new font face from the specified file // Load the new font face from the specified file
FT_Face face; FT_Face face;
@ -222,7 +222,7 @@ bool Font::loadFromMemory(const void* data, std::size_t sizeInBytes)
err() << "Failed to load font from memory (failed to create the font face)" << std::endl; err() << "Failed to load font from memory (failed to create the font face)" << std::endl;
return false; return false;
} }
font->face.reset(face); fontHandles->face.reset(face);
// Load the stroker that will be used to outline the font // Load the stroker that will be used to outline the font
FT_Stroker stroker; FT_Stroker stroker;
@ -231,7 +231,7 @@ bool Font::loadFromMemory(const void* data, std::size_t sizeInBytes)
err() << "Failed to load font from memory (failed to create the stroker)" << std::endl; err() << "Failed to load font from memory (failed to create the stroker)" << std::endl;
return false; return false;
} }
font->stroker.reset(stroker); fontHandles->stroker.reset(stroker);
// Select the Unicode character map // Select the Unicode character map
if (FT_Select_Charmap(face, FT_ENCODING_UNICODE) != 0) if (FT_Select_Charmap(face, FT_ENCODING_UNICODE) != 0)
@ -241,7 +241,7 @@ bool Font::loadFromMemory(const void* data, std::size_t sizeInBytes)
} }
// Store the loaded font handles // Store the loaded font handles
m_font = std::move(font); m_fontHandles = std::move(fontHandles);
// Store the font information // Store the font information
m_info.family = face->family_name ? face->family_name : std::string(); m_info.family = face->family_name ? face->family_name : std::string();
@ -256,7 +256,7 @@ bool Font::loadFromStream(InputStream& stream)
// Cleanup the previous resources // Cleanup the previous resources
cleanup(); cleanup();
auto font = std::make_unique<FontHandles>(); auto fontHandles = std::make_unique<FontHandles>();
// Initialize FreeType // Initialize FreeType
// Note: we initialize FreeType for every font instance in order to avoid having a single // Note: we initialize FreeType for every font instance in order to avoid having a single
@ -267,7 +267,7 @@ bool Font::loadFromStream(InputStream& stream)
err() << "Failed to load font from stream (failed to initialize FreeType)" << std::endl; err() << "Failed to load font from stream (failed to initialize FreeType)" << std::endl;
return false; return false;
} }
font->library.reset(library); fontHandles->library.reset(library);
// Make sure that the stream's reading position is at the beginning // Make sure that the stream's reading position is at the beginning
if (stream.seek(0) == -1) if (stream.seek(0) == -1)
@ -277,19 +277,19 @@ bool Font::loadFromStream(InputStream& stream)
} }
// Prepare a wrapper for our stream, that we'll pass to FreeType callbacks // Prepare a wrapper for our stream, that we'll pass to FreeType callbacks
font->streamRec = std::make_unique<FT_StreamRec>(); fontHandles->streamRec = std::make_unique<FT_StreamRec>();
std::memset(font->streamRec.get(), 0, sizeof(*font->streamRec)); std::memset(fontHandles->streamRec.get(), 0, sizeof(*fontHandles->streamRec));
font->streamRec->base = nullptr; fontHandles->streamRec->base = nullptr;
font->streamRec->size = static_cast<unsigned long>(stream.getSize()); fontHandles->streamRec->size = static_cast<unsigned long>(stream.getSize());
font->streamRec->pos = 0; fontHandles->streamRec->pos = 0;
font->streamRec->descriptor.pointer = &stream; fontHandles->streamRec->descriptor.pointer = &stream;
font->streamRec->read = &read; fontHandles->streamRec->read = &read;
font->streamRec->close = &close; fontHandles->streamRec->close = &close;
// Setup the FreeType callbacks that will read our stream // Setup the FreeType callbacks that will read our stream
FT_Open_Args args; FT_Open_Args args;
args.flags = FT_OPEN_STREAM; args.flags = FT_OPEN_STREAM;
args.stream = font->streamRec.get(); args.stream = fontHandles->streamRec.get();
args.driver = nullptr; args.driver = nullptr;
// Load the new font face from the specified stream // Load the new font face from the specified stream
@ -299,7 +299,7 @@ bool Font::loadFromStream(InputStream& stream)
err() << "Failed to load font from stream (failed to create the font face)" << std::endl; err() << "Failed to load font from stream (failed to create the font face)" << std::endl;
return false; return false;
} }
font->face.reset(face); fontHandles->face.reset(face);
// Load the stroker that will be used to outline the font // Load the stroker that will be used to outline the font
FT_Stroker stroker; FT_Stroker stroker;
@ -308,7 +308,7 @@ bool Font::loadFromStream(InputStream& stream)
err() << "Failed to load font from stream (failed to create the stroker)" << std::endl; err() << "Failed to load font from stream (failed to create the stroker)" << std::endl;
return false; return false;
} }
font->stroker.reset(stroker); fontHandles->stroker.reset(stroker);
// Select the Unicode character map // Select the Unicode character map
if (FT_Select_Charmap(face, FT_ENCODING_UNICODE) != 0) if (FT_Select_Charmap(face, FT_ENCODING_UNICODE) != 0)
@ -318,7 +318,7 @@ bool Font::loadFromStream(InputStream& stream)
} }
// Store the loaded font handles // Store the loaded font handles
m_font = std::move(font); m_fontHandles = std::move(fontHandles);
// Store the font information // Store the font information
m_info.family = face->family_name ? face->family_name : std::string(); m_info.family = face->family_name ? face->family_name : std::string();
@ -341,7 +341,7 @@ const Glyph& Font::getGlyph(Uint32 codePoint, unsigned int characterSize, bool b
GlyphTable& glyphs = m_pages[characterSize].glyphs; GlyphTable& glyphs = m_pages[characterSize].glyphs;
// Build the key by combining the glyph index (based on code point), bold flag, and outline thickness // Build the key by combining the glyph index (based on code point), bold flag, and outline thickness
Uint64 key = combine(outlineThickness, bold, FT_Get_Char_Index(m_font->face.get(), codePoint)); Uint64 key = combine(outlineThickness, bold, FT_Get_Char_Index(m_fontHandles ? m_fontHandles->face.get() : nullptr, codePoint));
// Search the glyph into the cache // Search the glyph into the cache
if (auto it = glyphs.find(key); it != glyphs.end()) if (auto it = glyphs.find(key); it != glyphs.end())
@ -361,7 +361,7 @@ const Glyph& Font::getGlyph(Uint32 codePoint, unsigned int characterSize, bool b
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool Font::hasGlyph(Uint32 codePoint) const bool Font::hasGlyph(Uint32 codePoint) const
{ {
return FT_Get_Char_Index(m_font->face.get(), codePoint) != 0; return FT_Get_Char_Index(m_fontHandles ? m_fontHandles->face.get() : nullptr, codePoint) != 0;
} }
@ -372,7 +372,7 @@ float Font::getKerning(Uint32 first, Uint32 second, unsigned int characterSize,
if (first == 0 || second == 0) if (first == 0 || second == 0)
return 0.f; return 0.f;
auto face = m_font->face.get(); auto face = m_fontHandles ? m_fontHandles->face.get() : nullptr;
if (face && setCurrentSize(characterSize)) if (face && setCurrentSize(characterSize))
{ {
@ -409,7 +409,7 @@ float Font::getKerning(Uint32 first, Uint32 second, unsigned int characterSize,
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
float Font::getLineSpacing(unsigned int characterSize) const float Font::getLineSpacing(unsigned int characterSize) const
{ {
auto face = m_font->face.get(); auto face = m_fontHandles ? m_fontHandles->face.get() : nullptr;
if (face && setCurrentSize(characterSize)) if (face && setCurrentSize(characterSize))
{ {
@ -425,7 +425,7 @@ float Font::getLineSpacing(unsigned int characterSize) const
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
float Font::getUnderlinePosition(unsigned int characterSize) const float Font::getUnderlinePosition(unsigned int characterSize) const
{ {
auto face = m_font->face.get(); auto face = m_fontHandles ? m_fontHandles->face.get() : nullptr;
if (face && setCurrentSize(characterSize)) if (face && setCurrentSize(characterSize))
{ {
@ -445,7 +445,7 @@ float Font::getUnderlinePosition(unsigned int characterSize) const
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
float Font::getUnderlineThickness(unsigned int characterSize) const float Font::getUnderlineThickness(unsigned int characterSize) const
{ {
auto face = m_font->face.get(); auto face = m_fontHandles ? m_fontHandles->face.get() : nullptr;
if (face && setCurrentSize(characterSize)) if (face && setCurrentSize(characterSize))
{ {
@ -494,7 +494,7 @@ Font& Font::operator =(const Font& right)
{ {
Font temp(right); Font temp(right);
std::swap(m_font, temp.m_font); std::swap(m_fontHandles, temp.m_fontHandles);
std::swap(m_isSmooth, temp.m_isSmooth); std::swap(m_isSmooth, temp.m_isSmooth);
std::swap(m_info, temp.m_info); std::swap(m_info, temp.m_info);
std::swap(m_pages, temp.m_pages); std::swap(m_pages, temp.m_pages);
@ -512,7 +512,7 @@ Font& Font::operator =(const Font& right)
void Font::cleanup() void Font::cleanup()
{ {
// Drop ownership of shared FreeType pointers // Drop ownership of shared FreeType pointers
m_font.reset(); m_fontHandles.reset();
// Reset members // Reset members
m_pages.clear(); m_pages.clear();
@ -526,8 +526,12 @@ Glyph Font::loadGlyph(Uint32 codePoint, unsigned int characterSize, bool bold, f
// The glyph to return // The glyph to return
Glyph glyph; Glyph glyph;
// First, get our FT_Face // Stop if no font is loaded
auto face = m_font->face.get(); if (!m_fontHandles)
return glyph;
// Get our FT_Face
auto face = m_fontHandles->face.get();
if (!face) if (!face)
return glyph; return glyph;
@ -560,7 +564,7 @@ Glyph Font::loadGlyph(Uint32 codePoint, unsigned int characterSize, bool bold, f
if (outlineThickness != 0) if (outlineThickness != 0)
{ {
auto stroker = m_font->stroker.get(); auto stroker = m_fontHandles->stroker.get();
FT_Stroker_Set(stroker, static_cast<FT_Fixed>(outlineThickness * static_cast<float>(1 << 6)), FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0); FT_Stroker_Set(stroker, static_cast<FT_Fixed>(outlineThickness * static_cast<float>(1 << 6)), FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0);
FT_Glyph_Stroke(&glyphDesc, stroker, true); FT_Glyph_Stroke(&glyphDesc, stroker, true);
@ -578,7 +582,7 @@ Glyph Font::loadGlyph(Uint32 codePoint, unsigned int characterSize, bool bold, f
if (!outline) if (!outline)
{ {
if (bold) if (bold)
FT_Bitmap_Embolden(m_font->library.get(), &bitmap, weight, weight); FT_Bitmap_Embolden(m_fontHandles->library.get(), &bitmap, weight, weight);
if (outlineThickness != 0) if (outlineThickness != 0)
err() << "Failed to outline glyph (no fallback available)" << std::endl; err() << "Failed to outline glyph (no fallback available)" << std::endl;
@ -764,7 +768,8 @@ bool Font::setCurrentSize(unsigned int characterSize) const
// FT_Set_Pixel_Sizes is an expensive function, so we must call it // FT_Set_Pixel_Sizes is an expensive function, so we must call it
// only when necessary to avoid killing performances // only when necessary to avoid killing performances
auto face = m_font->face.get(); // m_fontHandles and m_fontHandles->face are checked to be non-null before calling this method
auto face = m_fontHandles->face.get();
FT_UShort currentSize = face->size->metrics.x_ppem; FT_UShort currentSize = face->size->metrics.x_ppem;
if (currentSize != characterSize) if (currentSize != characterSize)