mirror of
https://github.com/SFML/SFML.git
synced 2024-11-28 22:31:09 +08:00
Simplify 'FontHandles' management
This commit is contained in:
parent
31c4b9472a
commit
230c6a4d57
@ -415,7 +415,7 @@ private:
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// Types
|
// Types
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
class FontHandles;
|
struct FontHandles;
|
||||||
using PageTable = std::unordered_map<unsigned int, Page>; //!< Table mapping a character size to its page (texture)
|
using PageTable = std::unordered_map<unsigned int, Page>; //!< Table mapping a character size to its page (texture)
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
|
@ -91,31 +91,34 @@ std::uint64_t combine(float outlineThickness, bool bold, std::uint32_t index)
|
|||||||
namespace sf
|
namespace sf
|
||||||
{
|
{
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
class Font::FontHandles
|
struct Font::FontHandles
|
||||||
{
|
{
|
||||||
private:
|
FontHandles() = default;
|
||||||
// Default constructible deleter functor
|
|
||||||
struct Deleter
|
|
||||||
{
|
|
||||||
void operator()(FT_Library theLibrary)
|
|
||||||
{
|
|
||||||
FT_Done_FreeType(theLibrary);
|
|
||||||
}
|
|
||||||
void operator()(FT_Face theFace)
|
|
||||||
{
|
|
||||||
FT_Done_Face(theFace);
|
|
||||||
}
|
|
||||||
void operator()(FT_Stroker theStroker)
|
|
||||||
{
|
|
||||||
FT_Stroker_Done(theStroker);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
~FontHandles()
|
||||||
std::unique_ptr<std::remove_pointer_t<FT_Library>, Deleter> library; //< Pointer to the internal library interface
|
{
|
||||||
std::unique_ptr<FT_StreamRec> streamRec; //< Pointer to the stream rec instance
|
// All the function below are safe to call with null pointer arguments.
|
||||||
std::unique_ptr<std::remove_pointer_t<FT_Face>, Deleter> face; //< Pointer to the internal font face
|
// The documentation of FreeType isn't clear on the matter, but the
|
||||||
std::unique_ptr<std::remove_pointer_t<FT_Stroker>, Deleter> stroker; //< Pointer to the stroker
|
// implementation does explictly check for null.
|
||||||
|
|
||||||
|
FT_Stroker_Done(stroker);
|
||||||
|
FT_Done_Face(face);
|
||||||
|
// `streamRec` doesn't need to be explicitly freed.
|
||||||
|
FT_Done_FreeType(library);
|
||||||
|
}
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
FontHandles(const FontHandles&) = delete;
|
||||||
|
FontHandles& operator=(const FontHandles&) = delete;
|
||||||
|
|
||||||
|
FontHandles(FontHandles&&) = delete;
|
||||||
|
FontHandles& operator=(FontHandles&&) = delete;
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
FT_Library library{}; //< Pointer to the internal library interface
|
||||||
|
FT_StreamRec streamRec{}; //< Stream rec object describing an input stream
|
||||||
|
FT_Face face{}; //< Pointer to the internal font face
|
||||||
|
FT_Stroker stroker{}; //< Pointer to the stroker
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -155,36 +158,32 @@ bool Font::loadFromFile(const std::filesystem::path& filename)
|
|||||||
// Cleanup the previous resources
|
// Cleanup the previous resources
|
||||||
cleanup();
|
cleanup();
|
||||||
|
|
||||||
auto fontHandles = std::make_unique<FontHandles>();
|
auto fontHandles = std::make_shared<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
|
||||||
// global manager that would create a lot of issues regarding creation and destruction order.
|
// global manager that would create a lot of issues regarding creation and destruction order.
|
||||||
FT_Library library;
|
if (FT_Init_FreeType(&fontHandles->library) != 0)
|
||||||
if (FT_Init_FreeType(&library) != 0)
|
|
||||||
{
|
{
|
||||||
err() << "Failed to load font (failed to initialize FreeType)\n" << formatDebugPathInfo(filename) << std::endl;
|
err() << "Failed to load font (failed to initialize FreeType)\n" << formatDebugPathInfo(filename) << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
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;
|
||||||
if (FT_New_Face(library, filename.string().c_str(), 0, &face) != 0)
|
if (FT_New_Face(fontHandles->library, filename.string().c_str(), 0, &face) != 0)
|
||||||
{
|
{
|
||||||
err() << "Failed to load font (failed to create the font face)\n" << formatDebugPathInfo(filename) << std::endl;
|
err() << "Failed to load font (failed to create the font face)\n" << formatDebugPathInfo(filename) << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
fontHandles->face.reset(face);
|
fontHandles->face = 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;
|
if (FT_Stroker_New(fontHandles->library, &fontHandles->stroker) != 0)
|
||||||
if (FT_Stroker_New(library, &stroker) != 0)
|
|
||||||
{
|
{
|
||||||
err() << "Failed to load font (failed to create the stroker)\n" << formatDebugPathInfo(filename) << std::endl;
|
err() << "Failed to load font (failed to create the stroker)\n" << formatDebugPathInfo(filename) << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
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)
|
||||||
@ -217,36 +216,36 @@ bool Font::loadFromMemory(const void* data, std::size_t sizeInBytes)
|
|||||||
// Cleanup the previous resources
|
// Cleanup the previous resources
|
||||||
cleanup();
|
cleanup();
|
||||||
|
|
||||||
auto fontHandles = std::make_unique<FontHandles>();
|
auto fontHandles = std::make_shared<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
|
||||||
// global manager that would create a lot of issues regarding creation and destruction order.
|
// global manager that would create a lot of issues regarding creation and destruction order.
|
||||||
FT_Library library;
|
if (FT_Init_FreeType(&fontHandles->library) != 0)
|
||||||
if (FT_Init_FreeType(&library) != 0)
|
|
||||||
{
|
{
|
||||||
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;
|
||||||
}
|
}
|
||||||
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;
|
||||||
if (FT_New_Memory_Face(library, reinterpret_cast<const FT_Byte*>(data), static_cast<FT_Long>(sizeInBytes), 0, &face) != 0)
|
if (FT_New_Memory_Face(fontHandles->library,
|
||||||
|
reinterpret_cast<const FT_Byte*>(data),
|
||||||
|
static_cast<FT_Long>(sizeInBytes),
|
||||||
|
0,
|
||||||
|
&face) != 0)
|
||||||
{
|
{
|
||||||
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;
|
||||||
}
|
}
|
||||||
fontHandles->face.reset(face);
|
fontHandles->face = 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;
|
if (FT_Stroker_New(fontHandles->library, &fontHandles->stroker) != 0)
|
||||||
if (FT_Stroker_New(library, &stroker) != 0)
|
|
||||||
{
|
{
|
||||||
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;
|
||||||
}
|
}
|
||||||
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)
|
||||||
@ -271,18 +270,16 @@ bool Font::loadFromStream(InputStream& stream)
|
|||||||
// Cleanup the previous resources
|
// Cleanup the previous resources
|
||||||
cleanup();
|
cleanup();
|
||||||
|
|
||||||
auto fontHandles = std::make_unique<FontHandles>();
|
auto fontHandles = std::make_shared<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
|
||||||
// global manager that would create a lot of issues regarding creation and destruction order.
|
// global manager that would create a lot of issues regarding creation and destruction order.
|
||||||
FT_Library library;
|
if (FT_Init_FreeType(&fontHandles->library) != 0)
|
||||||
if (FT_Init_FreeType(&library) != 0)
|
|
||||||
{
|
{
|
||||||
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;
|
||||||
}
|
}
|
||||||
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)
|
||||||
@ -292,37 +289,34 @@ 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
|
||||||
fontHandles->streamRec = std::make_unique<FT_StreamRec>();
|
fontHandles->streamRec.base = nullptr;
|
||||||
fontHandles->streamRec->base = nullptr;
|
fontHandles->streamRec.size = static_cast<unsigned long>(stream.getSize());
|
||||||
fontHandles->streamRec->size = static_cast<unsigned long>(stream.getSize());
|
fontHandles->streamRec.pos = 0;
|
||||||
fontHandles->streamRec->pos = 0;
|
fontHandles->streamRec.descriptor.pointer = &stream;
|
||||||
fontHandles->streamRec->descriptor.pointer = &stream;
|
fontHandles->streamRec.read = &read;
|
||||||
fontHandles->streamRec->read = &read;
|
fontHandles->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 = fontHandles->streamRec.get();
|
args.stream = &fontHandles->streamRec;
|
||||||
args.driver = nullptr;
|
args.driver = nullptr;
|
||||||
|
|
||||||
// Load the new font face from the specified stream
|
// Load the new font face from the specified stream
|
||||||
FT_Face face;
|
FT_Face face;
|
||||||
if (FT_Open_Face(library, &args, 0, &face) != 0)
|
if (FT_Open_Face(fontHandles->library, &args, 0, &face) != 0)
|
||||||
{
|
{
|
||||||
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;
|
||||||
}
|
}
|
||||||
fontHandles->face.reset(face);
|
fontHandles->face = 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;
|
if (FT_Stroker_New(fontHandles->library, &fontHandles->stroker) != 0)
|
||||||
if (FT_Stroker_New(library, &stroker) != 0)
|
|
||||||
{
|
{
|
||||||
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;
|
||||||
}
|
}
|
||||||
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)
|
||||||
@ -357,7 +351,7 @@ const Glyph& Font::getGlyph(std::uint32_t codePoint, unsigned int characterSize,
|
|||||||
// 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
|
||||||
std::uint64_t key = combine(outlineThickness,
|
std::uint64_t key = combine(outlineThickness,
|
||||||
bold,
|
bold,
|
||||||
FT_Get_Char_Index(m_fontHandles ? m_fontHandles->face.get() : nullptr, codePoint));
|
FT_Get_Char_Index(m_fontHandles ? m_fontHandles->face : 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())
|
||||||
@ -377,7 +371,7 @@ const Glyph& Font::getGlyph(std::uint32_t codePoint, unsigned int characterSize,
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
bool Font::hasGlyph(std::uint32_t codePoint) const
|
bool Font::hasGlyph(std::uint32_t codePoint) const
|
||||||
{
|
{
|
||||||
return FT_Get_Char_Index(m_fontHandles ? m_fontHandles->face.get() : nullptr, codePoint) != 0;
|
return FT_Get_Char_Index(m_fontHandles ? m_fontHandles->face : nullptr, codePoint) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -388,7 +382,7 @@ float Font::getKerning(std::uint32_t first, std::uint32_t second, unsigned int c
|
|||||||
if (first == 0 || second == 0)
|
if (first == 0 || second == 0)
|
||||||
return 0.f;
|
return 0.f;
|
||||||
|
|
||||||
auto* face = m_fontHandles ? m_fontHandles->face.get() : nullptr;
|
FT_Face face = m_fontHandles ? m_fontHandles->face : nullptr;
|
||||||
|
|
||||||
if (face && setCurrentSize(characterSize))
|
if (face && setCurrentSize(characterSize))
|
||||||
{
|
{
|
||||||
@ -426,7 +420,7 @@ float Font::getKerning(std::uint32_t first, std::uint32_t second, unsigned int c
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
float Font::getLineSpacing(unsigned int characterSize) const
|
float Font::getLineSpacing(unsigned int characterSize) const
|
||||||
{
|
{
|
||||||
auto* face = m_fontHandles ? m_fontHandles->face.get() : nullptr;
|
FT_Face face = m_fontHandles ? m_fontHandles->face : nullptr;
|
||||||
|
|
||||||
if (face && setCurrentSize(characterSize))
|
if (face && setCurrentSize(characterSize))
|
||||||
{
|
{
|
||||||
@ -442,7 +436,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_fontHandles ? m_fontHandles->face.get() : nullptr;
|
FT_Face face = m_fontHandles ? m_fontHandles->face : nullptr;
|
||||||
|
|
||||||
if (face && setCurrentSize(characterSize))
|
if (face && setCurrentSize(characterSize))
|
||||||
{
|
{
|
||||||
@ -463,7 +457,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_fontHandles ? m_fontHandles->face.get() : nullptr;
|
FT_Face face = m_fontHandles ? m_fontHandles->face : nullptr;
|
||||||
|
|
||||||
if (face && setCurrentSize(characterSize))
|
if (face && setCurrentSize(characterSize))
|
||||||
{
|
{
|
||||||
@ -557,7 +551,7 @@ Glyph Font::loadGlyph(std::uint32_t codePoint, unsigned int characterSize, bool
|
|||||||
return glyph;
|
return glyph;
|
||||||
|
|
||||||
// Get our FT_Face
|
// Get our FT_Face
|
||||||
auto* face = m_fontHandles->face.get();
|
FT_Face face = m_fontHandles->face;
|
||||||
if (!face)
|
if (!face)
|
||||||
return glyph;
|
return glyph;
|
||||||
|
|
||||||
@ -590,7 +584,7 @@ Glyph Font::loadGlyph(std::uint32_t codePoint, unsigned int characterSize, bool
|
|||||||
|
|
||||||
if (outlineThickness != 0)
|
if (outlineThickness != 0)
|
||||||
{
|
{
|
||||||
auto* stroker = m_fontHandles->stroker.get();
|
FT_Stroker stroker = m_fontHandles->stroker;
|
||||||
|
|
||||||
FT_Stroker_Set(stroker,
|
FT_Stroker_Set(stroker,
|
||||||
static_cast<FT_Fixed>(outlineThickness * static_cast<float>(1 << 6)),
|
static_cast<FT_Fixed>(outlineThickness * static_cast<float>(1 << 6)),
|
||||||
@ -612,7 +606,7 @@ Glyph Font::loadGlyph(std::uint32_t codePoint, unsigned int characterSize, bool
|
|||||||
if (!outline)
|
if (!outline)
|
||||||
{
|
{
|
||||||
if (bold)
|
if (bold)
|
||||||
FT_Bitmap_Embolden(m_fontHandles->library.get(), &bitmap, weight, weight);
|
FT_Bitmap_Embolden(m_fontHandles->library, &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;
|
||||||
@ -799,7 +793,7 @@ bool Font::setCurrentSize(unsigned int characterSize) const
|
|||||||
// only when necessary to avoid killing performances
|
// only when necessary to avoid killing performances
|
||||||
|
|
||||||
// m_fontHandles and m_fontHandles->face are checked to be non-null before calling this method
|
// m_fontHandles and m_fontHandles->face are checked to be non-null before calling this method
|
||||||
auto* face = m_fontHandles->face.get();
|
FT_Face face = m_fontHandles->face;
|
||||||
FT_UShort currentSize = face->size->metrics.x_ppem;
|
FT_UShort currentSize = face->size->metrics.x_ppem;
|
||||||
|
|
||||||
if (currentSize != characterSize)
|
if (currentSize != characterSize)
|
||||||
|
Loading…
Reference in New Issue
Block a user