Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
typographer_context_stb.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
6
7#include <numeric>
8#include <utility>
9
10#include "flutter/fml/logging.h"
11#include "flutter/fml/trace_event.h"
16#include "typeface_stb.h"
17
18#define DISABLE_COLOR_FONT_SUPPORT 1
19#ifdef DISABLE_COLOR_FONT_SUPPORT
20constexpr auto kColorFontBitsPerPixel = 1;
21#else
22constexpr auto kColorFontBitsPerPixel = 4;
23#endif
24
25namespace impeller {
26
27constexpr size_t kPadding = 1;
28
29std::unique_ptr<TypographerContext> TypographerContextSTB::Make() {
30 return std::make_unique<TypographerContextSTB>();
31}
32
34
36
37std::shared_ptr<GlyphAtlasContext>
39 return std::make_shared<GlyphAtlasContextSTB>();
40}
41
42// Function returns the count of "remaining pairs" not packed into rect of given
43// size.
45 const std::vector<FontGlyphPair>& pairs,
46 const ISize& atlas_size,
47 std::vector<Rect>& glyph_positions,
48 const std::shared_ptr<RectanglePacker>& rect_packer) {
49 if (atlas_size.IsEmpty()) {
50 return false;
51 }
52
53 glyph_positions.clear();
54 glyph_positions.reserve(pairs.size());
55
56 size_t i = 0;
57 for (auto it = pairs.begin(); it != pairs.end(); ++i, ++it) {
58 const auto& pair = *it;
59 const Font& font = pair.scaled_font.font;
60
61 // We downcast to the correct typeface type to access `stb` specific
62 // methods.
63 std::shared_ptr<TypefaceSTB> typeface_stb =
64 std::reinterpret_pointer_cast<TypefaceSTB>(font.GetTypeface());
65 // Conversion factor to scale font size in Points to pixels.
66 // Note this assumes typical DPI.
67 float text_size_pixels =
68 font.GetMetrics().point_size * TypefaceSTB::kPointsToPixels;
69
70 ISize glyph_size;
71 {
72 int x0 = 0, y0 = 0, x1 = 0, y1 = 0;
73 float scale = stbtt_ScaleForMappingEmToPixels(typeface_stb->GetFontInfo(),
74 text_size_pixels);
75 stbtt_GetGlyphBitmapBox(typeface_stb->GetFontInfo(), pair.glyph.index,
76 scale, scale, &x0, &y0, &x1, &y1);
77
78 glyph_size = ISize(x1 - x0, y1 - y0);
79 }
80
81 IPoint16 location_in_atlas;
82 if (!rect_packer->addRect(glyph_size.width + kPadding, //
83 glyph_size.height + kPadding, //
84 &location_in_atlas //
85 )) {
86 return pairs.size() - i;
87 }
88 glyph_positions.emplace_back(Rect::MakeXYWH(location_in_atlas.x(), //
89 location_in_atlas.y(), //
90 glyph_size.width, //
91 glyph_size.height //
92 ));
93 }
94
95 return 0;
96}
97
99 const std::shared_ptr<GlyphAtlas>& atlas,
100 const std::vector<FontGlyphPair>& extra_pairs,
101 std::vector<Rect>& glyph_positions,
102 ISize atlas_size,
103 const std::shared_ptr<RectanglePacker>& rect_packer) {
104 TRACE_EVENT0("impeller", __FUNCTION__);
105 if (!rect_packer || atlas_size.IsEmpty()) {
106 return false;
107 }
108
109 // We assume that all existing glyphs will fit. After all, they fit before.
110 // The glyph_positions only contains the values for the additional glyphs
111 // from extra_pairs.
112 FML_DCHECK(glyph_positions.size() == 0);
113 glyph_positions.reserve(extra_pairs.size());
114 for (size_t i = 0; i < extra_pairs.size(); i++) {
115 const FontGlyphPair& pair = extra_pairs[i];
116 const Font& font = pair.scaled_font.font;
117
118 // We downcast to the correct typeface type to access `stb` specific methods
119 std::shared_ptr<TypefaceSTB> typeface_stb =
120 std::reinterpret_pointer_cast<TypefaceSTB>(font.GetTypeface());
121 // Conversion factor to scale font size in Points to pixels.
122 // Note this assumes typical DPI.
123 float text_size_pixels =
124 font.GetMetrics().point_size * TypefaceSTB::kPointsToPixels;
125
126 ISize glyph_size;
127 {
128 int x0 = 0, y0 = 0, x1 = 0, y1 = 0;
129 float scale_y = stbtt_ScaleForMappingEmToPixels(
130 typeface_stb->GetFontInfo(), text_size_pixels);
131 float scale_x = scale_y;
132 stbtt_GetGlyphBitmapBox(typeface_stb->GetFontInfo(), pair.glyph.index,
133 scale_x, scale_y, &x0, &y0, &x1, &y1);
134
135 glyph_size = ISize(x1 - x0, y1 - y0);
136 }
137
138 IPoint16 location_in_atlas;
139 if (!rect_packer->addRect(glyph_size.width + kPadding, //
140 glyph_size.height + kPadding, //
141 &location_in_atlas //
142 )) {
143 return false;
144 }
145 glyph_positions.emplace_back(Rect::MakeXYWH(location_in_atlas.x(), //
146 location_in_atlas.y(), //
147 glyph_size.width, //
148 glyph_size.height //
149 ));
150 }
151
152 return true;
153}
154
156 const std::vector<FontGlyphPair>& pairs,
157 std::vector<Rect>& glyph_positions,
158 const std::shared_ptr<GlyphAtlasContext>& atlas_context,
160 const ISize& max_texture_size) {
161 static constexpr auto kMinAtlasSize = 8u;
162 static constexpr auto kMinAlphaBitmapSize = 1024u;
163
164 TRACE_EVENT0("impeller", __FUNCTION__);
165
167 ? ISize(kMinAlphaBitmapSize, kMinAlphaBitmapSize)
168 : ISize(kMinAtlasSize, kMinAtlasSize);
169 size_t total_pairs = pairs.size() + 1;
170 do {
171 auto rect_packer = std::shared_ptr<RectanglePacker>(
172 RectanglePacker::Factory(current_size.width, current_size.height));
173
174 auto remaining_pairs = PairsFitInAtlasOfSize(pairs, current_size,
175 glyph_positions, rect_packer);
176 if (remaining_pairs == 0) {
177 atlas_context->UpdateRectPacker(rect_packer);
178 return current_size;
179 } else if (remaining_pairs < std::ceil(total_pairs / 2)) {
180 current_size = ISize::MakeWH(
181 std::max(current_size.width, current_size.height),
183 std::min(current_size.width, current_size.height) + 1));
184 } else {
185 current_size = ISize::MakeWH(
186 Allocation::NextPowerOfTwoSize(current_size.width + 1),
187 Allocation::NextPowerOfTwoSize(current_size.height + 1));
188 }
189 } while (current_size.width <= max_texture_size.width &&
190 current_size.height <= max_texture_size.height);
191 return ISize{0, 0};
192}
193
195 const ScaledFont& scaled_font,
196 const Glyph& glyph,
197 const Rect& location,
198 bool has_color) {
199 const auto& metrics = scaled_font.font.GetMetrics();
200
201 const impeller::Font& font = scaled_font.font;
202 auto typeface = font.GetTypeface();
203 // We downcast to the correct typeface type to access `stb` specific methods
204 std::shared_ptr<TypefaceSTB> typeface_stb =
205 std::reinterpret_pointer_cast<TypefaceSTB>(typeface);
206 // Conversion factor to scale font size in Points to pixels.
207 // Note this assumes typical DPI.
208 float text_size_pixels = metrics.point_size * TypefaceSTB::kPointsToPixels;
209 float scale_y = stbtt_ScaleForMappingEmToPixels(typeface_stb->GetFontInfo(),
210 text_size_pixels);
211 float scale_x = scale_y;
212
213 auto output = bitmap->GetPixelAddress({static_cast<size_t>(location.GetX()),
214 static_cast<size_t>(location.GetY())});
215 // For Alpha and Signed Distance field bitmaps we can use STB to draw the
216 // Glyph in place
217 if (!has_color || DISABLE_COLOR_FONT_SUPPORT) {
218 stbtt_MakeGlyphBitmap(typeface_stb->GetFontInfo(), output,
219 location.GetWidth(), location.GetHeight(),
220 bitmap->GetRowBytes(), scale_x, scale_y, glyph.index);
221 } else {
222 // But for color bitmaps we need to get the glyph pixels and then carry all
223 // channels into the atlas bitmap. This may not be performant but I'm unsure
224 // of any other approach currently.
225 int glyph_bitmap_width = 0;
226 int glyph_bitmap_height = 0;
227 int glyph_bitmap_xoff = 0;
228 int glyph_bitmap_yoff = 0;
229 auto glyph_pixels = stbtt_GetGlyphBitmap(
230 typeface_stb->GetFontInfo(), scale_x, scale_y, glyph.index,
231 &glyph_bitmap_width, &glyph_bitmap_height, &glyph_bitmap_xoff,
232 &glyph_bitmap_yoff);
233
234 uint8_t* write_pos = output;
235 for (auto y = 0; y < glyph_bitmap_height; ++y) {
236 for (auto x = 0; x < glyph_bitmap_width; ++x) {
237 // Color bitmaps write as White (i.e. what is 0 in an alpha bitmap is
238 // 255 in a color bitmap) But not alpha. Alpha still carries
239 // transparency info in the normal way.
240 // There's some issue with color fonts, in that if the pixel color is
241 // nonzero, the alpha is ignored during rendering. That is, partially
242 // (or fully) transparent pixels with nonzero color are rendered as
243 // fully opaque.
244 uint8_t a = glyph_pixels[x + y * glyph_bitmap_width];
245 uint8_t c = 255 - a;
246
247 // Red channel
248 *write_pos = c;
249 write_pos++;
250 // Green channel
251 *write_pos = c;
252 write_pos++;
253 // Blue channel
254 *write_pos = c;
255 write_pos++;
256 // Alpha channel
257 *write_pos = a;
258 write_pos++;
259 }
260 // next row
261 write_pos = output + (y * bitmap->GetRowBytes());
262 }
263 stbtt_FreeBitmap(glyph_pixels, nullptr);
264 }
265}
266
267static bool UpdateAtlasBitmap(const GlyphAtlas& atlas,
268 const std::shared_ptr<BitmapSTB>& bitmap,
269 const std::vector<FontGlyphPair>& new_pairs) {
270 TRACE_EVENT0("impeller", __FUNCTION__);
271 FML_DCHECK(bitmap != nullptr);
272
273 bool has_color = atlas.GetType() == GlyphAtlas::Type::kColorBitmap;
274
275 for (const FontGlyphPair& pair : new_pairs) {
276 auto pos = atlas.FindFontGlyphBounds(pair);
277 if (!pos.has_value()) {
278 continue;
279 }
280 DrawGlyph(bitmap.get(), pair.scaled_font, pair.glyph, pos.value(),
281 has_color);
282 }
283 return true;
284}
285
286static std::shared_ptr<BitmapSTB> CreateAtlasBitmap(const GlyphAtlas& atlas,
287 const ISize& atlas_size) {
288 TRACE_EVENT0("impeller", __FUNCTION__);
289
290 size_t bytes_per_pixel = 1;
291 if (atlas.GetType() == GlyphAtlas::Type::kColorBitmap &&
294 }
295 auto bitmap = std::make_shared<BitmapSTB>(atlas_size.width, atlas_size.height,
297
298 bool has_color = atlas.GetType() == GlyphAtlas::Type::kColorBitmap;
299
300 atlas.IterateGlyphs([&bitmap, has_color](const ScaledFont& scaled_font,
301 const Glyph& glyph,
302 const Rect& location) -> bool {
303 DrawGlyph(bitmap.get(), scaled_font, glyph, location, has_color);
304 return true;
305 });
306
307 return bitmap;
308}
309
310// static bool UpdateGlyphTextureAtlas(std::shared_ptr<SkBitmap> bitmap,
311static bool UpdateGlyphTextureAtlas(std::shared_ptr<BitmapSTB>& bitmap,
312 const std::shared_ptr<Texture>& texture) {
313 TRACE_EVENT0("impeller", __FUNCTION__);
314
315 FML_DCHECK(bitmap != nullptr);
316
317 auto texture_descriptor = texture->GetTextureDescriptor();
318
319 auto mapping = std::make_shared<fml::NonOwnedMapping>(
320 reinterpret_cast<const uint8_t*>(bitmap->GetPixels()), // data
321 texture_descriptor.GetByteSizeOfBaseMipLevel() // size
322 // As the bitmap is static in this module I believe we don't need to
323 // specify a release proc.
324 );
325
326 return texture->SetContents(mapping);
327}
328
329static std::shared_ptr<Texture> UploadGlyphTextureAtlas(
330 const std::shared_ptr<Allocator>& allocator,
331 std::shared_ptr<BitmapSTB>& bitmap,
332 const ISize& atlas_size,
334 TRACE_EVENT0("impeller", __FUNCTION__);
335 if (!allocator) {
336 return nullptr;
337 }
338
339 FML_DCHECK(bitmap != nullptr);
340
341 TextureDescriptor texture_descriptor;
342 texture_descriptor.storage_mode = StorageMode::kHostVisible;
343 texture_descriptor.format = format;
344 texture_descriptor.size = atlas_size;
345
346 if (bitmap->GetRowBytes() * bitmap->GetHeight() !=
347 texture_descriptor.GetByteSizeOfBaseMipLevel()) {
348 return nullptr;
349 }
350
351 auto texture = allocator->CreateTexture(texture_descriptor);
352 if (!texture || !texture->IsValid()) {
353 return nullptr;
354 }
355 texture->SetLabel("GlyphAtlas");
356
357 auto mapping = std::make_shared<fml::NonOwnedMapping>(
358 reinterpret_cast<const uint8_t*>(bitmap->GetPixels()), // data
359 texture_descriptor.GetByteSizeOfBaseMipLevel() // size
360 // As the bitmap is static in this module I believe we don't need to
361 // specify a release proc.
362 );
363
364 if (!texture->SetContents(mapping)) {
365 return nullptr;
366 }
367 return texture;
368}
369
370std::shared_ptr<GlyphAtlas> TypographerContextSTB::CreateGlyphAtlas(
371 Context& context,
373 const std::shared_ptr<GlyphAtlasContext>& atlas_context,
374 const FontGlyphMap& font_glyph_map) const {
375 TRACE_EVENT0("impeller", __FUNCTION__);
376 if (!IsValid()) {
377 return nullptr;
378 }
379 auto& atlas_context_stb = GlyphAtlasContextSTB::Cast(*atlas_context);
380 std::shared_ptr<GlyphAtlas> last_atlas = atlas_context->GetGlyphAtlas();
381
382 if (font_glyph_map.empty()) {
383 return last_atlas;
384 }
385
386 // ---------------------------------------------------------------------------
387 // Step 1: Determine if the atlas type and font glyph pairs are compatible
388 // with the current atlas and reuse if possible.
389 // ---------------------------------------------------------------------------
390 std::vector<FontGlyphPair> new_glyphs;
391 for (const auto& font_value : font_glyph_map) {
392 const ScaledFont& scaled_font = font_value.first;
393 const FontGlyphAtlas* font_glyph_atlas =
394 last_atlas->GetFontGlyphAtlas(scaled_font.font, scaled_font.scale);
395 if (font_glyph_atlas) {
396 for (const Glyph& glyph : font_value.second) {
397 if (!font_glyph_atlas->FindGlyphBounds(glyph)) {
398 new_glyphs.emplace_back(scaled_font, glyph);
399 }
400 }
401 } else {
402 for (const Glyph& glyph : font_value.second) {
403 new_glyphs.emplace_back(scaled_font, glyph);
404 }
405 }
406 }
407 if (last_atlas->GetType() == type && new_glyphs.size() == 0) {
408 return last_atlas;
409 }
410
411 // ---------------------------------------------------------------------------
412 // Step 2: Determine if the additional missing glyphs can be appended to the
413 // existing bitmap without recreating the atlas. This requires that
414 // the type is identical.
415 // ---------------------------------------------------------------------------
416 std::vector<Rect> glyph_positions;
417 if (last_atlas->GetType() == type &&
418 CanAppendToExistingAtlas(last_atlas, new_glyphs, glyph_positions,
419 atlas_context->GetAtlasSize(),
420 atlas_context->GetRectPacker())) {
421 // The old bitmap will be reused and only the additional glyphs will be
422 // added.
423
424 // ---------------------------------------------------------------------------
425 // Step 3a: Record the positions in the glyph atlas of the newly added
426 // glyphs.
427 // ---------------------------------------------------------------------------
428 for (size_t i = 0, count = glyph_positions.size(); i < count; i++) {
429 last_atlas->AddTypefaceGlyphPosition(new_glyphs[i], glyph_positions[i]);
430 }
431
432 // ---------------------------------------------------------------------------
433 // Step 4a: Draw new font-glyph pairs into the existing bitmap.
434 // ---------------------------------------------------------------------------
435 // auto bitmap = atlas_context->GetBitmap();
436 auto bitmap = atlas_context_stb.GetBitmap();
437 if (!UpdateAtlasBitmap(*last_atlas, bitmap, new_glyphs)) {
438 return nullptr;
439 }
440
441 // ---------------------------------------------------------------------------
442 // Step 5a: Update the existing texture with the updated bitmap.
443 // ---------------------------------------------------------------------------
444 if (!UpdateGlyphTextureAtlas(bitmap, last_atlas->GetTexture())) {
445 return nullptr;
446 }
447 return last_atlas;
448 }
449 // A new glyph atlas must be created.
450
451 // ---------------------------------------------------------------------------
452 // Step 3b: Get the optimum size of the texture atlas.
453 // ---------------------------------------------------------------------------
454 std::vector<FontGlyphPair> font_glyph_pairs;
455 font_glyph_pairs.reserve(std::accumulate(
456 font_glyph_map.begin(), font_glyph_map.end(), 0,
457 [](const int a, const auto& b) { return a + b.second.size(); }));
458 for (const auto& font_value : font_glyph_map) {
459 const ScaledFont& scaled_font = font_value.first;
460 for (const Glyph& glyph : font_value.second) {
461 font_glyph_pairs.push_back({scaled_font, glyph});
462 }
463 }
464 auto glyph_atlas = std::make_shared<GlyphAtlas>(type);
465 auto atlas_size = OptimumAtlasSizeForFontGlyphPairs(
466 font_glyph_pairs, //
467 glyph_positions, //
468 atlas_context, //
469 type, //
470 context.GetResourceAllocator()->GetMaxTextureSizeSupported() //
471 );
472
473 atlas_context->UpdateGlyphAtlas(glyph_atlas, atlas_size);
474 if (atlas_size.IsEmpty()) {
475 return nullptr;
476 }
477
478 // ---------------------------------------------------------------------------
479 // Step 4b: Find location of font-glyph pairs in the atlas. We have this from
480 // the last step. So no need to do create another rect packer. But just do a
481 // sanity check of counts. This could also be just an assertion as only a
482 // construction issue would cause such a failure.
483 // ---------------------------------------------------------------------------
484 if (glyph_positions.size() != font_glyph_pairs.size()) {
485 return nullptr;
486 }
487
488 // ---------------------------------------------------------------------------
489 // Step 5b: Record the positions in the glyph atlas.
490 // ---------------------------------------------------------------------------
491 {
492 size_t i = 0;
493 for (auto it = font_glyph_pairs.begin(); it != font_glyph_pairs.end();
494 ++i, ++it) {
495 glyph_atlas->AddTypefaceGlyphPosition(*it, glyph_positions[i]);
496 }
497 }
498
499 // ---------------------------------------------------------------------------
500 // Step 6b: Draw font-glyph pairs in the correct spot in the atlas.
501 // ---------------------------------------------------------------------------
502 auto bitmap = CreateAtlasBitmap(*glyph_atlas, atlas_size);
503 if (!bitmap) {
504 return nullptr;
505 }
506 atlas_context_stb.UpdateBitmap(bitmap);
507
508 // ---------------------------------------------------------------------------
509 // Step 7b: Upload the atlas as a texture.
510 // ---------------------------------------------------------------------------
512 switch (type) {
514 format = context.GetCapabilities()->GetDefaultGlyphAtlasFormat();
515 break;
518 ? context.GetCapabilities()->GetDefaultGlyphAtlasFormat()
520 break;
521 }
523 atlas_size, format);
524 if (!texture) {
525 return nullptr;
526 }
527
528 // ---------------------------------------------------------------------------
529 // Step 8b: Record the texture in the glyph atlas.
530 // ---------------------------------------------------------------------------
531 glyph_atlas->SetTexture(std::move(texture));
532
533 return glyph_atlas;
534}
535
536} // namespace impeller
int count
SkPoint pos
static uint32_t NextPowerOfTwoSize(uint32_t x)
Definition allocation.cc:41
static GlyphAtlasContextSTB & Cast(GlyphAtlasContext &base)
To do anything rendering related with Impeller, you need a context.
Definition context.h:46
virtual const std::shared_ptr< const Capabilities > & GetCapabilities() const =0
Get the capabilities of Impeller context. All optionally supported feature of the platform,...
virtual std::shared_ptr< Allocator > GetResourceAllocator() const =0
Returns the allocator used to create textures and buffers on the device.
An object that can look up glyph locations within the GlyphAtlas for a particular typeface.
std::optional< Rect > FindGlyphBounds(const Glyph &glyph) const
Find the location of a glyph in the atlas.
Describes a typeface along with any modifications to its intrinsic properties.
Definition font.h:22
const Metrics & GetMetrics() const
Definition font.cc:37
A texture containing the bitmap representation of glyphs in different fonts along with the ability to...
Definition glyph_atlas.h:28
Type
Describes how the glyphs are represented in the texture.
Definition glyph_atlas.h:32
static std::unique_ptr< RectanglePacker > Factory(int width, int height)
Return an empty packer with area specified by width and height.
static constexpr float kPointsToPixels
static std::unique_ptr< TypographerContext > Make()
std::shared_ptr< GlyphAtlasContext > CreateGlyphAtlasContext() const override
std::shared_ptr< GlyphAtlas > CreateGlyphAtlas(Context &context, GlyphAtlas::Type type, const std::shared_ptr< GlyphAtlasContext > &atlas_context, const FontGlyphMap &font_glyph_map) const override
The graphics context necessary to render text.
static bool b
struct MyStruct a[10]
uint32_t uint32_t * format
#define FML_DCHECK(condition)
Definition logging.h:103
FlTexture * texture
double y
double x
std::unordered_map< ScaledFont, std::unordered_set< Glyph > > FontGlyphMap
static std::shared_ptr< Texture > UploadGlyphTextureAtlas(const std::shared_ptr< Allocator > &allocator, std::shared_ptr< SkBitmap > bitmap, const ISize &atlas_size, PixelFormat format)
PixelFormat
The Pixel formats supported by Impeller. The naming convention denotes the usage of the component,...
Definition formats.h:100
constexpr auto kPadding
static std::shared_ptr< SkBitmap > CreateAtlasBitmap(const GlyphAtlas &atlas, const ISize &atlas_size)
TSize< int64_t > ISize
Definition size.h:138
static void DrawGlyph(SkCanvas *canvas, const ScaledFont &scaled_font, const Glyph &glyph, const Rect &location, bool has_color)
static ISize OptimumAtlasSizeForFontGlyphPairs(const std::vector< FontGlyphPair > &pairs, std::vector< Rect > &glyph_positions, const std::shared_ptr< GlyphAtlasContext > &atlas_context, GlyphAtlas::Type type, const ISize &max_texture_size)
static bool UpdateGlyphTextureAtlas(std::shared_ptr< SkBitmap > bitmap, const std::shared_ptr< Texture > &texture)
static size_t PairsFitInAtlasOfSize(const std::vector< FontGlyphPair > &pairs, const ISize &atlas_size, std::vector< Rect > &glyph_positions, const std::shared_ptr< RectanglePacker > &rect_packer)
static bool UpdateAtlasBitmap(const GlyphAtlas &atlas, const std::shared_ptr< SkBitmap > &bitmap, const std::vector< FontGlyphPair > &new_pairs)
static bool CanAppendToExistingAtlas(const std::shared_ptr< GlyphAtlas > &atlas, const std::vector< FontGlyphPair > &extra_pairs, std::vector< Rect > &glyph_positions, ISize atlas_size, const std::shared_ptr< RectanglePacker > &rect_packer)
static size_t bytes_per_pixel(skcms_PixelFormat fmt)
Definition skcms.cc:2449
const Scalar scale
A font along with a glyph in that font rendered at a particular scale.
const ScaledFont & scaled_font
The glyph index in the typeface.
Definition glyph.h:20
uint16_t index
Definition glyph.h:26
int16_t y() const
int16_t x() const
A font and a scale. Used as a key that represents a typeface within a glyph atlas.
constexpr Type GetY() const
Returns the Y coordinate of the upper left corner, equivalent to |GetOrigin().y|.
Definition rect.h:304
constexpr Type GetHeight() const
Returns the height of the rectangle, equivalent to |GetSize().height|.
Definition rect.h:314
constexpr Type GetX() const
Returns the X coordinate of the upper left corner, equivalent to |GetOrigin().x|.
Definition rect.h:300
static constexpr TRect MakeXYWH(Type x, Type y, Type width, Type height)
Definition rect.h:136
constexpr Type GetWidth() const
Returns the width of the rectangle, equivalent to |GetSize().width|.
Definition rect.h:308
Type height
Definition size.h:23
Type width
Definition size.h:22
static constexpr TSize MakeWH(Type width, Type height)
Definition size.h:34
constexpr bool IsEmpty() const
Returns true if either of the width or height are 0, negative, or NaN.
Definition size.h:105
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...
constexpr size_t GetByteSizeOfBaseMipLevel() const
#define TRACE_EVENT0(category_group, name)
#define DISABLE_COLOR_FONT_SUPPORT
constexpr auto kColorFontBitsPerPixel