19FT_Library &ftLibrary() {
20 static struct Holder {
21 FT_Library lib =
nullptr;
23 if (FT_Init_FreeType(&lib) != 0)
28 FT_Done_FreeType(lib);
35uint32_t nextCodepoint(
const std::string &text,
size_t &i) {
38 const auto *
s =
reinterpret_cast<const unsigned char *
>(
text.data() + i);
39 const size_t rem =
text.size() - i;
40 unsigned char c0 =
s[0];
45 if ((c0 & 0xE0) == 0xC0 && rem >= 2 && (
s[1] & 0xC0) == 0x80) {
47 return ((c0 & 0x1F) << 6) | (
s[1] & 0x3F);
49 if ((c0 & 0xF0) == 0xE0 && rem >= 3 && (
s[1] & 0xC0) == 0x80 && (
s[2] & 0xC0) == 0x80) {
51 return ((c0 & 0x0F) << 12) | ((
s[1] & 0x3F) << 6) | (
s[2] & 0x3F);
53 if ((c0 & 0xF8) == 0xF0 && rem >= 4 && (
s[1] & 0xC0) == 0x80 && (
s[2] & 0xC0) == 0x80 &&
54 (
s[3] & 0xC0) == 0x80) {
56 return ((c0 & 0x07) << 18) | ((
s[1] & 0x3F) << 12) | ((
s[2] & 0x3F) << 6) | (
s[3] & 0x3F);
65 :
Resource(std::move(uri)), bytes(std::move(fontBytes)), pixelSize(size) {
71 FT_Library lib = ftLibrary();
75 FT_Error err = FT_New_Memory_Face(lib, bytes.data(),
static_cast<FT_Long
>(bytes.size()), 0, &face);
76 if (err != 0 || !face)
77 throw eve::Exception(
"Could not decode font data (FreeType error %d)",
static_cast<int>(err));
79 err = FT_Set_Pixel_Sizes(face, 0,
static_cast<FT_UInt
>(pixelSize));
83 throw eve::Exception(
"Could not set font pixel size (FreeType error %d)",
static_cast<int>(err));
86 glyphCache.resize(
static_cast<size_t>(std::max<FT_Long>(face->num_glyphs, 1)));
97 auto &other =
static_cast<FontData &
>(replacement);
98 std::swap(bytes, other.bytes);
99 std::swap(face, other.face);
100 std::swap(pixelSize, other.pixelSize);
101 std::swap(glyphCache, other.glyphCache);
109 return static_cast<float>(face->size->metrics.ascender) / 64.f;
116 return static_cast<float>(face->size->metrics.descender) / 64.f;
121 return static_cast<float>(pixelSize);
122 return static_cast<float>(face->size->metrics.height) / 64.f;
128 if (!face || !face->family_name)
130 return face->family_name;
134 if (!face || !face->style_name)
136 return face->style_name;
142 return static_cast<int>(face->num_glyphs);
145unsigned int FontData::glyphIndex(
int codepoint)
const {
146 if (!face || codepoint < 0)
148 return FT_Get_Char_Index(face,
static_cast<FT_ULong
>(codepoint));
152 return glyphIndex(codepoint) != 0;
157 while (i < text.size()) {
158 uint32_t cp = nextCodepoint(text, i);
161 if (!
hasGlyph(
static_cast<int>(cp)))
168 if (!face || !FT_HAS_KERNING(face))
170 FT_UInt left = glyphIndex(leftCodepoint);
171 FT_UInt right = glyphIndex(rightCodepoint);
172 if (left == 0 || right == 0)
175 if (FT_Get_Kerning(face, left, right, FT_KERNING_DEFAULT, &delta) != 0)
177 return static_cast<float>(delta.x) / 64.f;
180const FontData::GlyphCache &FontData::ensureGlyph(
int codepoint)
const {
181 static GlyphCache missing;
185 FT_UInt index = glyphIndex(codepoint);
187 if (index >= glyphCache.size()) {
188 glyphCache.resize(index + 1);
191 GlyphCache &slot = glyphCache[index];
195 FT_Error err = FT_Load_Glyph(face, index, FT_LOAD_DEFAULT);
202 slot.advance =
static_cast<int>((face->glyph->advance.x + 32) >> 6);
203 slot.bearingX = face->glyph->bitmap_left;
204 slot.bearingY = face->glyph->bitmap_top;
205 slot.width =
static_cast<int>((face->glyph->metrics.width + 63) >> 6);
206 slot.height =
static_cast<int>((face->glyph->metrics.height + 63) >> 6);
207 slot.empty = (index == 0 && codepoint != 0);
216 while (i < text.size()) {
217 uint32_t cp = nextCodepoint(text, i);
220 int code =
static_cast<int>(cp);
223 width +=
static_cast<float>(ensureGlyph(code).advance);
239 FT_UInt index = glyphIndex(codepoint);
240 FT_Error err = FT_Load_Glyph(face, index, FT_LOAD_RENDER);
241 if (err != 0 || !face->glyph->bitmap.buffer || face->glyph->bitmap.width == 0 ||
242 face->glyph->bitmap.rows == 0) {
244 ensureGlyph(codepoint);
248 const FT_Bitmap &bm = face->glyph->bitmap;
249 const int w =
static_cast<int>(bm.width);
250 const int h =
static_cast<int>(bm.rows);
253 if (index >= glyphCache.size())
254 glyphCache.resize(index + 1);
255 GlyphCache &slot = glyphCache[index];
258 slot.bearingX = face->glyph->bitmap_left;
259 slot.bearingY = face->glyph->bitmap_top;
260 slot.advance =
static_cast<int>((face->glyph->advance.x + 32) >> 6);
265 auto *dst =
static_cast<unsigned char *
>(img->getData());
267 if (bm.pixel_mode == FT_PIXEL_MODE_GRAY) {
268 for (
int y = 0;
y <
h; ++
y) {
269 const unsigned char *src = bm.buffer +
y * bm.pitch;
270 unsigned char *row = dst +
y *
w * 4;
271 for (
int x = 0;
x <
w; ++
x) {
272 unsigned char a = src[
x];
273 row[
x * 4 + 0] = 255;
274 row[
x * 4 + 1] = 255;
275 row[
x * 4 + 2] = 255;
279 }
else if (bm.pixel_mode == FT_PIXEL_MODE_MONO) {
280 for (
int y = 0;
y <
h; ++
y) {
281 const unsigned char *src = bm.buffer +
y * bm.pitch;
282 unsigned char *row = dst +
y *
w * 4;
283 for (
int x = 0;
x <
w; ++
x) {
284 unsigned char byte = src[
x >> 3];
285 unsigned char a = (
byte & (0x80 >> (
x & 7))) ? 255 : 0;
286 row[
x * 4 + 0] = 255;
287 row[
x * 4 + 1] = 255;
288 row[
x * 4 + 2] = 255;
294 std::memset(dst, 0,
static_cast<size_t>(
w) *
static_cast<size_t>(
h) * 4u);
Resource is a game object that is managed by the ResourceManager. It can be loaded from a file or gen...
CPU-side decoded font face (FreeType FT_Face + owned font bytes). Does not upload to GPU — rasterize ...
FontData(std::vector< uint8_t > bytes, int pixelSize, std::string uri="")
从字体字节创建指定像素尺寸的字体面。
float getWidth(std::string text) const
int getGlyphHeight(int codepoint) const
int getGlyphAdvance(int codepoint) const
float getBaseline() const
std::string getFamilyName() const
字体元信息。
bool hasGlyphs(std::string text) const
int getGlyphBearingX(int codepoint) const
image::ImageData * newGlyphImageData(int codepoint)
Rasterize one glyph to RGBA8 ImageData (RGB white, A from FreeType gray). Returns a 0x0 ImageData if ...
int getGlyphBearingY(int codepoint) const
void adopt(eve::Resource &replacement) override
Replace this face with replacement's (cache reload).
float getKerning(int leftCodepoint, int rightCodepoint) const
int getSize() const
字号 / 度量信息。
int getGlyphCount() const
std::string getStyleName() const
float getLineHeight() const
bool hasGlyph(int codepoint) const
字形 / 文本测量。
int getGlyphWidth(int codepoint) const
单字形度量(像素)。
Represents raw pixel data.
WidgetDesc text(std::string content, std::string id)
Static text label.