| Flutter Impeller |

typographer_context_skia.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
5 #include "impeller/typographer/backends/skia/typographer_context_skia.h"
6
7 #include <cstddef>
8 #include <memory>
9 #include <numeric>
10 #include <utility>
11 #include <vector>
12
13 #include "flutter/fml/logging.h"
14 #include "flutter/fml/trace_event.h"
15 #include "fml/closure.h"
16
17 #include "impeller/core/allocator.h"
18 #include "impeller/core/buffer_view.h"
19 #include "impeller/core/formats.h"
20 #include "impeller/core/host_buffer.h"
21 #include "impeller/core/platform.h"
22 #include "impeller/core/texture_descriptor.h"
23 #include "impeller/geometry/rect.h"
24 #include "impeller/geometry/size.h"
25 #include "impeller/renderer/command_buffer.h"
26 #include "impeller/renderer/render_pass.h"
27 #include "impeller/renderer/render_target.h"
28 #include "impeller/typographer/backends/skia/typeface_skia.h"
29 #include "impeller/typographer/font_glyph_pair.h"
30 #include "impeller/typographer/glyph.h"
31 #include "impeller/typographer/glyph_atlas.h"
32 #include "impeller/typographer/rectangle_packer.h"
33 #include "impeller/typographer/typographer_context.h"
34 #include "include/core/SkColor.h"
35 #include "include/core/SkImageInfo.h"
36 #include "include/core/SkPaint.h"
37 #include "include/core/SkSize.h"
38
39 #include "third_party/skia/include/core/SkBitmap.h"
40 #include "third_party/skia/include/core/SkBlendMode.h"
41 #include "third_party/skia/include/core/SkCanvas.h"
42 #include "third_party/skia/include/core/SkFont.h"
43 #include "third_party/skia/include/core/SkSurface.h"
44
45 namespace impeller {
46
47 // TODO(bdero): We might be able to remove this per-glyph padding if we fix
48 // the underlying causes of the overlap.
49 // https://github.com/flutter/flutter/issues/114563
50 constexpr auto kPadding = 2;
51
52 namespace {
53 SkPaint::Cap ToSkiaCap(Cap cap) {
54 switch (cap) {
55 case Cap::kButt:
56 return SkPaint::Cap::kButt_Cap;
57 case Cap::kRound:
58 return SkPaint::Cap::kRound_Cap;
59 case Cap::kSquare:
60 return SkPaint::Cap::kSquare_Cap;
61 }
62 FML_UNREACHABLE();
63 }
64
65 SkPaint::Join ToSkiaJoin(Join join) {
66 switch (join) {
67 case Join::kMiter:
68 return SkPaint::Join::kMiter_Join;
69 case Join::kRound:
70 return SkPaint::Join::kRound_Join;
71 case Join::kBevel:
72 return SkPaint::Join::kBevel_Join;
73 }
74 FML_UNREACHABLE();
75 }
76 } // namespace
77
78 std::shared_ptr<TypographerContext> TypographerContextSkia::Make() {
79 return std::make_shared<TypographerContextSkia>();
80 }
81
82 TypographerContextSkia::TypographerContextSkia() = default;
83
84 TypographerContextSkia::~TypographerContextSkia() = default;
85
86 std::shared_ptr<GlyphAtlasContext>
87 TypographerContextSkia::CreateGlyphAtlasContext(GlyphAtlas::Type type) const {
88 return std::make_shared<GlyphAtlasContext>(type);
89 }
90
91 static SkImageInfo GetImageInfo(const GlyphAtlas& atlas, Size size) {
92 switch (atlas.GetType()) {
93 case GlyphAtlas::Type::kAlphaBitmap:
94 return SkImageInfo::MakeA8(SkISize{static_cast<int32_t>(size.width),
95 static_cast<int32_t>(size.height)});
96 case GlyphAtlas::Type::kColorBitmap:
97 return SkImageInfo::MakeN32Premul(size.width, size.height);
98 }
99 FML_UNREACHABLE();
100 }
101
102 /// Append as many glyphs to the texture as will fit, and return the first index
103 /// of [extra_pairs] that did not fit.
104 static size_t AppendToExistingAtlas(
105 const std::shared_ptr<GlyphAtlas>& atlas,
106 const std::vector<FontGlyphPair>& extra_pairs,
107 std::vector<Rect>& glyph_positions,
108 const std::vector<Rect>& glyph_sizes,
109 ISize atlas_size,
110 int64_t height_adjustment,
111 const std::shared_ptr<RectanglePacker>& rect_packer) {
112 TRACE_EVENT0("impeller", __FUNCTION__);
113 if (!rect_packer || atlas_size.IsEmpty()) {
114 return 0;
115 }
116
117 for (size_t i = 0; i < extra_pairs.size(); i++) {
118 ISize glyph_size = ISize::Ceil(glyph_sizes[i].GetSize());
119 IPoint16 location_in_atlas;
120 if (!rect_packer->AddRect(glyph_size.width + kPadding, //
121 glyph_size.height + kPadding, //
122 &location_in_atlas //
123 )) {
124 return i;
125 }
126 // Position the glyph in the center of the 1px padding.
127 glyph_positions.push_back(Rect::MakeXYWH(
128 location_in_atlas.x() + 1, //
129 location_in_atlas.y() + height_adjustment + 1, //
130 glyph_size.width, //
131 glyph_size.height //
132 ));
133 }
134
135 return extra_pairs.size();
136 }
137
138 static size_t PairsFitInAtlasOfSize(
139 const std::vector<FontGlyphPair>& pairs,
140 const ISize& atlas_size,
141 std::vector<Rect>& glyph_positions,
142 const std::vector<Rect>& glyph_sizes,
143 int64_t height_adjustment,
144 const std::shared_ptr<RectanglePacker>& rect_packer,
145 size_t start_index) {
146 FML_DCHECK(!atlas_size.IsEmpty());
147
148 for (size_t i = start_index; i < pairs.size(); i++) {
149 ISize glyph_size = ISize::Ceil(glyph_sizes[i].GetSize());
150 IPoint16 location_in_atlas;
151 if (!rect_packer->AddRect(glyph_size.width + kPadding, //
152 glyph_size.height + kPadding, //
153 &location_in_atlas //
154 )) {
155 return i;
156 }
157 glyph_positions.push_back(Rect::MakeXYWH(
158 location_in_atlas.x() + 1, //
159 location_in_atlas.y() + height_adjustment + 1, //
160 glyph_size.width, //
161 glyph_size.height //
162 ));
163 }
164
165 return pairs.size();
166 }
167
168 static ISize ComputeNextAtlasSize(
169 const std::shared_ptr<GlyphAtlasContext>& atlas_context,
170 const std::vector<FontGlyphPair>& extra_pairs,
171 std::vector<Rect>& glyph_positions,
172 const std::vector<Rect>& glyph_sizes,
173 size_t glyph_index_start,
174 int64_t max_texture_height) {
175 // Because we can't grow the skyline packer horizontally, pick a reasonable
176 // large width for all atlases.
177 static constexpr int64_t kAtlasWidth = 4096;
178 static constexpr int64_t kMinAtlasHeight = 1024;
179
180 ISize current_size = ISize(kAtlasWidth, kMinAtlasHeight);
181 if (atlas_context->GetAtlasSize().height > current_size.height) {
182 current_size.height = atlas_context->GetAtlasSize().height * 2;
183 }
184
185 auto height_adjustment = atlas_context->GetAtlasSize().height;
186 while (current_size.height <= max_texture_height) {
187 std::shared_ptr<RectanglePacker> rect_packer;
188 if (atlas_context->GetRectPacker() || glyph_index_start) {
189 rect_packer = RectanglePacker::Factory(
190 kAtlasWidth,
191 current_size.height - atlas_context->GetAtlasSize().height);
192 } else {
193 rect_packer = RectanglePacker::Factory(kAtlasWidth, current_size.height);
194 }
195 glyph_positions.erase(glyph_positions.begin() + glyph_index_start,
196 glyph_positions.end());
197 atlas_context->UpdateRectPacker(rect_packer);
198 auto next_index = PairsFitInAtlasOfSize(
199 extra_pairs, current_size, glyph_positions, glyph_sizes,
200 height_adjustment, rect_packer, glyph_index_start);
201 if (next_index == extra_pairs.size()) {
202 return current_size;
203 }
204 current_size = ISize(current_size.width, current_size.height * 2);
205 }
206 return {};
207 }
208
209 static void DrawGlyph(SkCanvas* canvas,
210 const ScaledFont& scaled_font,
211 const SubpixelGlyph& glyph,
212 const Rect& scaled_bounds,
213 const GlyphProperties& prop,
214 bool has_color) {
215 const auto& metrics = scaled_font.font.GetMetrics();
216 SkPoint position = SkPoint::Make(1, 1);
217 SkGlyphID glyph_id = glyph.glyph.index;
218
219 SkFont sk_font(
220 TypefaceSkia::Cast(*scaled_font.font.GetTypeface()).GetSkiaTypeface(),
221 metrics.point_size, metrics.scaleX, metrics.skewX);
222 sk_font.setEdging(SkFont::Edging::kAntiAlias);
223 sk_font.setHinting(SkFontHinting::kSlight);
224 sk_font.setEmbolden(metrics.embolden);
225 sk_font.setSubpixel(true);
226 sk_font.setSize(sk_font.getSize() * scaled_font.scale);
227
228 auto glyph_color =
229 has_color ? glyph.properties.color.ToARGB() : SK_ColorBLACK;
230
231 SkPaint glyph_paint;
232 glyph_paint.setColor(glyph_color);
233 glyph_paint.setBlendMode(SkBlendMode::kSrc);
234 if (prop.stroke) {
235 glyph_paint.setStroke(true);
236 glyph_paint.setStrokeWidth(prop.stroke_width * scaled_font.scale);
237 glyph_paint.setStrokeCap(ToSkiaCap(glyph.properties.stroke_cap));
238 glyph_paint.setStrokeJoin(ToSkiaJoin(glyph.properties.stroke_join));
239 glyph_paint.setStrokeMiter(prop.stroke_miter * scaled_font.scale);
240 }
241 canvas->translate(glyph.subpixel_offset.x, glyph.subpixel_offset.y);
242 canvas->drawGlyphs(1u, // count
243 &glyph_id, // glyphs
244 &position, // positions
245 SkPoint::Make(-scaled_bounds.GetLeft(),
246 -scaled_bounds.GetTop()), // origin
247 sk_font, // font
248 glyph_paint // paint
249 );
250 }
251
252 static bool UpdateAtlasBitmap(const GlyphAtlas& atlas,
253 std::shared_ptr<BlitPass>& blit_pass,
254 HostBuffer& host_buffer,
255 const std::shared_ptr<Texture>& texture,
256 const std::vector<FontGlyphPair>& new_pairs,
257 size_t start_index,
258 size_t end_index) {
259 TRACE_EVENT0("impeller", __FUNCTION__);
260
261 bool has_color = atlas.GetType() == GlyphAtlas::Type::kColorBitmap;
262
263 for (size_t i = start_index; i < end_index; i++) {
264 const FontGlyphPair& pair = new_pairs[i];
265 auto data = atlas.FindFontGlyphBounds(pair);
266 if (!data.has_value()) {
267 continue;
268 }
269 auto [pos, bounds] = data.value();
270 Size size = pos.GetSize();
271 if (size.IsEmpty()) {
272 continue;
273 }
274 // The uploaded bitmap is expanded by 1px of padding
275 // on each side.
276 size.width += 2;
277 size.height += 2;
278
279 SkBitmap bitmap;
280 bitmap.setInfo(GetImageInfo(atlas, size));
281 if (!bitmap.tryAllocPixels()) {
282 return false;
283 }
284
285 auto surface = SkSurfaces::WrapPixels(bitmap.pixmap());
286 if (!surface) {
287 return false;
288 }
289 auto canvas = surface->getCanvas();
290 if (!canvas) {
291 return false;
292 }
293
294 DrawGlyph(canvas, pair.scaled_font, pair.glyph, bounds,
295 pair.glyph.properties, has_color);
296
297 // Writing to a malloc'd buffer and then copying to the staging buffers
298 // benchmarks as substantially faster on a number of Android devices.
299 BufferView buffer_view = host_buffer.Emplace(
300 bitmap.getAddr(0, 0),
301 size.Area() * BytesPerPixelForPixelFormat(
302 atlas.GetTexture()->GetTextureDescriptor().format),
303 DefaultUniformAlignment());
304
305 // convert_to_read is set to false so that the texture remains in a transfer
306 // dst layout until we finish writing to it below. This only has an impact
307 // on Vulkan where we are responsible for managing image layouts.
308 if (!blit_pass->AddCopy(std::move(buffer_view), //
309 texture, //
310 IRect::MakeXYWH(pos.GetLeft() - 1, pos.GetTop() - 1,
311 size.width, size.height), //
312 /*label=*/"", //
313 /*slice=*/0, //
314 /*convert_to_read=*/false //
315 )) {
316 return false;
317 }
318 }
319 return blit_pass->ConvertTextureToShaderRead(texture);
320 }
321
322 static Rect ComputeGlyphSize(const SkFont& font,
323 const SubpixelGlyph& glyph,
324 Scalar scale) {
325 SkRect scaled_bounds;
326 SkPaint glyph_paint;
327 if (glyph.properties.stroke) {
328 glyph_paint.setStroke(true);
329 glyph_paint.setStrokeWidth(glyph.properties.stroke_width * scale);
330 glyph_paint.setStrokeCap(ToSkiaCap(glyph.properties.stroke_cap));
331 glyph_paint.setStrokeJoin(ToSkiaJoin(glyph.properties.stroke_join));
332 glyph_paint.setStrokeMiter(glyph.properties.stroke_miter * scale);
333 }
334 font.getBounds(&glyph.glyph.index, 1, &scaled_bounds, &glyph_paint);
335
336 // Expand the bounds of glyphs at subpixel offsets by 2 in the x direction.
337 Scalar adjustment = 0.0;
338 if (glyph.subpixel_offset != Point(0, 0)) {
339 adjustment = 1.0;
340 }
341 return Rect::MakeLTRB(scaled_bounds.fLeft - adjustment, scaled_bounds.fTop,
342 scaled_bounds.fRight + adjustment,
343 scaled_bounds.fBottom);
344 };
345
346 std::shared_ptr<GlyphAtlas> TypographerContextSkia::CreateGlyphAtlas(
347 Context& context,
348 GlyphAtlas::Type type,
349 HostBuffer& host_buffer,
350 const std::shared_ptr<GlyphAtlasContext>& atlas_context,
351 const FontGlyphMap& font_glyph_map) const {
352 TRACE_EVENT0("impeller", __FUNCTION__);
353 if (!IsValid()) {
354 return nullptr;
355 }
356 std::shared_ptr<GlyphAtlas> last_atlas = atlas_context->GetGlyphAtlas();
357 FML_DCHECK(last_atlas->GetType() == type);
358
359 if (font_glyph_map.empty()) {
360 return last_atlas;
361 }
362
363 // ---------------------------------------------------------------------------
364 // Step 1: Determine if the atlas type and font glyph pairs are compatible
365 // with the current atlas and reuse if possible. For each new font and
366 // glyph pair, compute the glyph size at scale.
367 // ---------------------------------------------------------------------------
368 std::vector<Rect> glyph_sizes;
369 std::vector<FontGlyphPair> new_glyphs;
370 for (const auto& font_value : font_glyph_map) {
371 const ScaledFont& scaled_font = font_value.first;
372 const FontGlyphAtlas* font_glyph_atlas =
373 last_atlas->GetFontGlyphAtlas(scaled_font.font, scaled_font.scale);
374
375 auto metrics = scaled_font.font.GetMetrics();
376
377 SkFont sk_font(
378 TypefaceSkia::Cast(*scaled_font.font.GetTypeface()).GetSkiaTypeface(),
379 metrics.point_size, metrics.scaleX, metrics.skewX);
380 sk_font.setEdging(SkFont::Edging::kAntiAlias);
381 sk_font.setHinting(SkFontHinting::kSlight);
382 sk_font.setEmbolden(metrics.embolden);
383 // Rather than computing the bounds at the requested point size and scaling
384 // up the bounds, we scale up the font size and request the bounds. This
385 // seems to give more accurate bounds information.
386 sk_font.setSize(sk_font.getSize() * scaled_font.scale);
387 sk_font.setSubpixel(true);
388
389 if (font_glyph_atlas) {
390 for (const SubpixelGlyph& glyph : font_value.second) {
391 if (!font_glyph_atlas->FindGlyphBounds(glyph)) {
392 new_glyphs.emplace_back(scaled_font, glyph);
393 glyph_sizes.push_back(
394 ComputeGlyphSize(sk_font, glyph, scaled_font.scale));
395 }
396 }
397 } else {
398 for (const SubpixelGlyph& glyph : font_value.second) {
399 new_glyphs.emplace_back(scaled_font, glyph);
400 glyph_sizes.push_back(
401 ComputeGlyphSize(sk_font, glyph, scaled_font.scale));
402 }
403 }
404 }
405 if (new_glyphs.size() == 0) {
406 return last_atlas;
407 }
408
409 // ---------------------------------------------------------------------------
410 // Step 2: Determine if the additional missing glyphs can be appended to the
411 // existing bitmap without recreating the atlas.
412 // ---------------------------------------------------------------------------
413 std::vector<Rect> glyph_positions;
414 glyph_positions.reserve(new_glyphs.size());
415 size_t first_missing_index = 0;
416
417 if (last_atlas->GetTexture()) {
418 // Append all glyphs that fit into the current atlas.
419 first_missing_index = AppendToExistingAtlas(
420 last_atlas, new_glyphs, glyph_positions, glyph_sizes,
421 atlas_context->GetAtlasSize(), atlas_context->GetHeightAdjustment(),
422 atlas_context->GetRectPacker());
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; i < first_missing_index; i++) {
429 last_atlas->AddTypefaceGlyphPositionAndBounds(
430 new_glyphs[i], glyph_positions[i], glyph_sizes[i]);
431 }
432
433 std::shared_ptr<CommandBuffer> cmd_buffer = context.CreateCommandBuffer();
434 std::shared_ptr<BlitPass> blit_pass = cmd_buffer->CreateBlitPass();
435
436 fml::ScopedCleanupClosure closure([&]() {
437 blit_pass->EncodeCommands(context.GetResourceAllocator());
438 context.GetCommandQueue()->Submit({std::move(cmd_buffer)});
439 });
440
441 // ---------------------------------------------------------------------------
442 // Step 4a: Draw new font-glyph pairs into the a host buffer and encode
443 // the uploads into the blit pass.
444 // ---------------------------------------------------------------------------
445 if (!UpdateAtlasBitmap(*last_atlas, blit_pass, host_buffer,
446 last_atlas->GetTexture(), new_glyphs, 0,
447 first_missing_index)) {
448 return nullptr;
449 }
450
451 // If all glyphs fit, just return the old atlas.
452 if (first_missing_index == new_glyphs.size()) {
453 return last_atlas;
454 }
455 }
456
457 int64_t height_adjustment = atlas_context->GetAtlasSize().height;
458 const int64_t max_texture_height =
459 context.GetResourceAllocator()->GetMaxTextureSizeSupported().height;
460
461 // IF the current atlas size is as big as it can get, then "GC" and create an
462 // atlas with only the required glyphs. OpenGLES cannot reliably perform the
463 // blit required here, as 1) it requires attaching textures as read and write
464 // framebuffers which has substantially smaller size limits that max textures
465 // and 2) is missing a GLES 2.0 implementation and cap check.
466 bool blit_old_atlas = true;
467 std::shared_ptr<GlyphAtlas> new_atlas = last_atlas;
468 if (atlas_context->GetAtlasSize().height >= max_texture_height ||
469 context.GetBackendType() == Context::BackendType::kOpenGLES) {
470 blit_old_atlas = false;
471 first_missing_index = 0;
472 glyph_positions.clear();
473 height_adjustment = 0;
474 new_atlas = std::make_shared<GlyphAtlas>(type);
475 atlas_context->UpdateRectPacker(nullptr);
476 atlas_context->UpdateGlyphAtlas(new_atlas, {0, 0}, 0);
477 }
478
479 // A new glyph atlas must be created.
480 ISize atlas_size = ComputeNextAtlasSize(atlas_context, //
481 new_glyphs, //
482 glyph_positions, //
483 glyph_sizes, //
484 first_missing_index, //
485 max_texture_height //
486 );
487
488 atlas_context->UpdateGlyphAtlas(new_atlas, atlas_size, height_adjustment);
489 if (atlas_size.IsEmpty()) {
490 return nullptr;
491 }
492 FML_DCHECK(new_glyphs.size() == glyph_positions.size());
493
494 TextureDescriptor descriptor;
495 switch (type) {
496 case GlyphAtlas::Type::kAlphaBitmap:
497 descriptor.format =
498 context.GetCapabilities()->GetDefaultGlyphAtlasFormat();
499 break;
500 case GlyphAtlas::Type::kColorBitmap:
501 descriptor.format = PixelFormat::kR8G8B8A8UNormInt;
502 break;
503 }
504 descriptor.size = atlas_size;
505 descriptor.storage_mode = StorageMode::kDevicePrivate;
506 descriptor.usage = TextureUsage::kShaderRead;
507 std::shared_ptr<Texture> new_texture =
508 context.GetResourceAllocator()->CreateTexture(descriptor);
509 if (!new_texture) {
510 return nullptr;
511 }
512
513 new_texture->SetLabel("GlyphAtlas");
514
515 std::shared_ptr<CommandBuffer> cmd_buffer = context.CreateCommandBuffer();
516 std::shared_ptr<BlitPass> blit_pass = cmd_buffer->CreateBlitPass();
517
518 // The R8/A8 textures used for certain glyphs is not supported as color
519 // attachments in most graphics drivers. For other textures, most framebuffer
520 // attachments have a much smaller size limit than the max texture size.
521 {
522 TRACE_EVENT0("flutter", "ClearGlyphAtlas");
523 size_t byte_size =
524 new_texture->GetTextureDescriptor().GetByteSizeOfBaseMipLevel();
525 BufferView buffer_view =
526 host_buffer.Emplace(nullptr, byte_size, DefaultUniformAlignment());
527
528 ::memset(buffer_view.buffer->OnGetContents() + buffer_view.range.offset, 0,
529 byte_size);
530 buffer_view.buffer->Flush();
531 blit_pass->AddCopy(buffer_view, new_texture);
532 }
533
534 fml::ScopedCleanupClosure closure([&]() {
535 blit_pass->EncodeCommands(context.GetResourceAllocator());
536 context.GetCommandQueue()->Submit({std::move(cmd_buffer)});
537 });
538
539 // Blit the old texture to the top left of the new atlas.
540 if (new_atlas->GetTexture() && blit_old_atlas) {
541 blit_pass->AddCopy(new_atlas->GetTexture(), new_texture,
542 IRect::MakeSize(new_atlas->GetTexture()->GetSize()),
543 {0, 0});
544 }
545
546 // Now append all remaining glyphs. This should never have any missing data...
547 new_atlas->SetTexture(std::move(new_texture));
548
549 // ---------------------------------------------------------------------------
550 // Step 3a: Record the positions in the glyph atlas of the newly added
551 // glyphs.
552 // ---------------------------------------------------------------------------
553 for (size_t i = first_missing_index; i < glyph_positions.size(); i++) {
554 new_atlas->AddTypefaceGlyphPositionAndBounds(
555 new_glyphs[i], glyph_positions[i], glyph_sizes[i]);
556 }
557
558 // ---------------------------------------------------------------------------
559 // Step 4a: Draw new font-glyph pairs into the a host buffer and encode
560 // the uploads into the blit pass.
561 // ---------------------------------------------------------------------------
562 if (!UpdateAtlasBitmap(*new_atlas, blit_pass, host_buffer,
563 new_atlas->GetTexture(), new_glyphs,
564 first_missing_index, new_glyphs.size())) {
565 return nullptr;
566 }
567 // ---------------------------------------------------------------------------
568 // Step 8b: Record the texture in the glyph atlas.
569 // ---------------------------------------------------------------------------
570
571 return new_atlas;
572 }
573
574 } // namespace impeller
impeller::ISize
ISize64 ISize
Definition: size.h:140
impeller::GlyphAtlas::Type::kColorBitmap
@ kColorBitmap
host_buffer.h
impeller::Cap::kRound
@ kRound
impeller::Cap::kSquare
@ kSquare
impeller::HostBuffer::Emplace
BufferView Emplace(const BufferType &buffer, size_t alignment=0)
Emplace non-uniform data (like contiguous vertices) onto the host buffer.
Definition: host_buffer.h:95
impeller::TPoint::y
Type y
Definition: point.h:31
impeller::Scalar
float Scalar
Definition: scalar.h:18
impeller::DefaultUniformAlignment
constexpr size_t DefaultUniformAlignment()
Definition: platform.h:14
impeller::GlyphAtlas::Type::kAlphaBitmap
@ kAlphaBitmap
impeller::GlyphProperties
Definition: font_glyph_pair.h:19
impeller::UpdateAtlasBitmap
static bool UpdateAtlasBitmap(const GlyphAtlas &atlas, std::shared_ptr< BlitPass > &blit_pass, HostBuffer &host_buffer, const std::shared_ptr< Texture > &texture, const std::vector< FontGlyphPair > &new_pairs, size_t start_index, size_t end_index)
Definition: typographer_context_skia.cc:252
impeller::TRect< Scalar >::MakeXYWH
constexpr static TRect MakeXYWH(Type x, Type y, Type width, Type height)
Definition: rect.h:136
impeller::FontGlyphAtlas
An object that can look up glyph locations within the GlyphAtlas for a particular typeface.
Definition: glyph_atlas.h:200
impeller::Context::GetCapabilities
virtual const std::shared_ptr< const Capabilities > & GetCapabilities() const =0
Get the capabilities of Impeller context. All optionally supported feature of the platform,...
impeller::HostBuffer
Definition: host_buffer.h:28
data
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63
impeller::SubpixelGlyph::subpixel_offset
Point subpixel_offset
Definition: font_glyph_pair.h:42
impeller::TextureDescriptor::format
PixelFormat format
Definition: texture_descriptor.h:41
impeller::ScaledFont::font
Font font
Definition: font_glyph_pair.h:33
impeller::PixelFormat::kR8G8B8A8UNormInt
@ kR8G8B8A8UNormInt
texture_descriptor.h
impeller::SubpixelGlyph
A glyph and its subpixel position.
Definition: font_glyph_pair.h:40
formats.h
impeller::TSize::Ceil
constexpr TSize Ceil() const
Definition: size.h:96
impeller::Color::ToARGB
constexpr uint32_t ToARGB() const
Convert to ARGB 32 bit color.
Definition: color.h:261
impeller::IPoint16::x
int16_t x() const
Definition: rectangle_packer.h:16
typographer_context.h
buffer_view
BufferView buffer_view
Definition: blit_command_gles.cc:127
impeller::GlyphProperties::stroke_miter
Scalar stroke_miter
Definition: font_glyph_pair.h:24
impeller::Cap::kButt
@ kButt
impeller::TextureDescriptor::usage
TextureUsageMask usage
Definition: texture_descriptor.h:44
impeller::GlyphProperties::color
Color color
Definition: font_glyph_pair.h:20
impeller::IPoint16::y
int16_t y() const
Definition: rectangle_packer.h:17
impeller::Join::kMiter
@ kMiter
typographer_context_skia.h
impeller::Context::GetBackendType
virtual BackendType GetBackendType() const =0
Get the graphics backend of an Impeller context.
impeller::Font::GetTypeface
const std::shared_ptr< Typeface > & GetTypeface() const
The typeface whose intrinsic properties this font modifies.
Definition: font.cc:27
impeller::TypefaceSkia::GetSkiaTypeface
const sk_sp< SkTypeface > & GetSkiaTypeface() const
Definition: typeface_skia.cc:31
impeller::TSize< Scalar >
impeller::ComputeNextAtlasSize
static ISize ComputeNextAtlasSize(const std::shared_ptr< GlyphAtlasContext > &atlas_context, const std::vector< FontGlyphPair > &extra_pairs, std::vector< Rect > &glyph_positions, const std::vector< Rect > &glyph_sizes, size_t glyph_index_start, int64_t max_texture_height)
Definition: typographer_context_skia.cc:168
impeller::FontGlyphPair::glyph
const SubpixelGlyph & glyph
Definition: font_glyph_pair.h:64
render_pass.h
impeller::TRect::GetLeft
constexpr auto GetLeft() const
Definition: rect.h:341
impeller::BytesPerPixelForPixelFormat
constexpr size_t BytesPerPixelForPixelFormat(PixelFormat format)
Definition: formats.h:460
glyph.h
impeller::Context::BackendType::kOpenGLES
@ kOpenGLES
rectangle_packer.h
impeller::FontGlyphPair::scaled_font
const ScaledFont & scaled_font
Definition: font_glyph_pair.h:63
impeller::GlyphAtlas::GetType
Type GetType() const
Describes how the glyphs are represented in the texture.
Definition: glyph_atlas.cc:54
impeller::StorageMode::kDevicePrivate
@ kDevicePrivate
impeller::GlyphAtlas::GetTexture
const std::shared_ptr< Texture > & GetTexture() const
Get the texture for the glyph atlas.
Definition: glyph_atlas.cc:58
impeller::TypographerContextSkia::TypographerContextSkia
TypographerContextSkia()
impeller::GlyphAtlas::Type
Type
Describes how the glyphs are represented in the texture.
Definition: glyph_atlas.h:31
impeller::FontGlyphMap
std::unordered_map< ScaledFont, std::unordered_set< SubpixelGlyph > > FontGlyphMap
Definition: font_glyph_pair.h:54
font_glyph_pair.h
type
GLenum type
Definition: blit_command_gles.cc:126
impeller::SubpixelGlyph::glyph
Glyph glyph
Definition: font_glyph_pair.h:41
impeller::RectanglePacker::Factory
static std::shared_ptr< RectanglePacker > Factory(int width, int height)
Return an empty packer with area specified by width and height.
Definition: rectangle_packer.cc:174
impeller::SubpixelGlyph::properties
GlyphProperties properties
Definition: font_glyph_pair.h:43
impeller::GlyphProperties::stroke_join
Join stroke_join
Definition: font_glyph_pair.h:23
impeller::Glyph::index
uint16_t index
Definition: glyph.h:22
impeller::GlyphProperties::stroke
bool stroke
Definition: font_glyph_pair.h:25
impeller::Context::CreateCommandBuffer
virtual std::shared_ptr< CommandBuffer > CreateCommandBuffer() const =0
Create a new command buffer. Command buffers can be used to encode graphics, blit,...
impeller::Context::GetCommandQueue
virtual std::shared_ptr< CommandQueue > GetCommandQueue() const =0
Return the graphics queue for submitting command buffers.
impeller::Join::kRound
@ kRound
impeller::FontGlyphPair
A font along with a glyph in that font rendered at a particular scale and subpixel position.
Definition: font_glyph_pair.h:60
impeller::Font::GetMetrics
const Metrics & GetMetrics() const
Definition: font.cc:45
platform.h
impeller::kPadding
constexpr auto kPadding
Definition: typographer_context_skia.cc:50
impeller::TSize::width
Type width
Definition: size.h:22
impeller::TPoint::x
Type x
Definition: point.h:30
impeller::GlyphProperties::stroke_width
Scalar stroke_width
Definition: font_glyph_pair.h:21
impeller::TextureDescriptor::size
ISize size
Definition: texture_descriptor.h:42
impeller::ScaledFont::scale
Scalar scale
Definition: font_glyph_pair.h:34
impeller::Join::kBevel
@ kBevel
command_buffer.h
typeface_skia.h
allocator.h
impeller::BufferView
Definition: buffer_view.h:15
impeller::GlyphAtlas
A texture containing the bitmap representation of glyphs in different fonts along with the ability to...
Definition: glyph_atlas.h:27
impeller::FontGlyphAtlas::FindGlyphBounds
std::optional< std::pair< Rect, Rect > > FindGlyphBounds(const SubpixelGlyph &glyph) const
Find the location of a glyph in the atlas.
Definition: glyph_atlas.cc:119
impeller::TypographerContextSkia::CreateGlyphAtlasContext
std::shared_ptr< GlyphAtlasContext > CreateGlyphAtlasContext(GlyphAtlas::Type type) const override
Definition: typographer_context_skia.cc:87
impeller::GlyphProperties::stroke_cap
Cap stroke_cap
Definition: font_glyph_pair.h:22
impeller::Join
Join
Definition: path.h:24
impeller::TSize::Area
constexpr Type Area() const
Definition: size.h:102
impeller::Context
To do anything rendering related with Impeller, you need a context.
Definition: context.h:45
impeller::TRect::MakeSize
constexpr static TRect MakeSize(const TSize< U > &size)
Definition: rect.h:146
buffer_view.h
impeller::TypographerContextSkia::~TypographerContextSkia
~TypographerContextSkia() override
rect.h
impeller::GlyphAtlas::FindFontGlyphBounds
std::optional< std::pair< Rect, Rect > > FindFontGlyphBounds(const FontGlyphPair &pair) const
Find the location of a specific font-glyph pair in the atlas.
Definition: glyph_atlas.cc:73
impeller::TPoint
Definition: point.h:27
impeller::BackendCast< TypefaceSkia, Typeface >::Cast
static TypefaceSkia & Cast(Typeface &base)
Definition: backend_cast.h:13
impeller::IPoint16
Definition: rectangle_packer.h:15
impeller::TextureUsage::kShaderRead
@ kShaderRead
scale
const Scalar scale
Definition: stroke_path_geometry.cc:308
impeller::DrawGlyph
static void DrawGlyph(SkCanvas *canvas, const ScaledFont &scaled_font, const SubpixelGlyph &glyph, const Rect &scaled_bounds, const GlyphProperties &prop, bool has_color)
Definition: typographer_context_skia.cc:209
impeller::TypographerContextSkia::CreateGlyphAtlas
std::shared_ptr< GlyphAtlas > CreateGlyphAtlas(Context &context, GlyphAtlas::Type type, HostBuffer &host_buffer, const std::shared_ptr< GlyphAtlasContext > &atlas_context, const FontGlyphMap &font_glyph_map) const override
Definition: typographer_context_skia.cc:346
impeller::ComputeGlyphSize
static Rect ComputeGlyphSize(const SkFont &font, const SubpixelGlyph &glyph, Scalar scale)
Definition: typographer_context_skia.cc:322
impeller::TextureDescriptor::storage_mode
StorageMode storage_mode
Definition: texture_descriptor.h:39
impeller::TSize::height
Type height
Definition: size.h:23
impeller::TRect< Scalar >::MakeLTRB
constexpr static TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
Definition: rect.h:129
glyph_atlas.h
impeller::TextureDescriptor
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...
Definition: texture_descriptor.h:38
impeller::TSize::IsEmpty
constexpr bool IsEmpty() const
Returns true if either of the width or height are 0, negative, or NaN.
Definition: size.h:105
render_target.h
impeller::AppendToExistingAtlas
static size_t AppendToExistingAtlas(const std::shared_ptr< GlyphAtlas > &atlas, const std::vector< FontGlyphPair > &extra_pairs, std::vector< Rect > &glyph_positions, const std::vector< Rect > &glyph_sizes, ISize atlas_size, int64_t height_adjustment, const std::shared_ptr< RectanglePacker > &rect_packer)
Definition: typographer_context_skia.cc:104
impeller
Definition: aiks_blend_unittests.cc:18
impeller::Context::GetResourceAllocator
virtual std::shared_ptr< Allocator > GetResourceAllocator() const =0
Returns the allocator used to create textures and buffers on the device.
impeller::TRect::GetTop
constexpr auto GetTop() const
Definition: rect.h:343
impeller::PairsFitInAtlasOfSize
static size_t PairsFitInAtlasOfSize(const std::vector< FontGlyphPair > &pairs, const ISize &atlas_size, std::vector< Rect > &glyph_positions, const std::vector< Rect > &glyph_sizes, int64_t height_adjustment, const std::shared_ptr< RectanglePacker > &rect_packer, size_t start_index)
Definition: typographer_context_skia.cc:138
impeller::TypographerContextSkia::Make
static std::shared_ptr< TypographerContext > Make()
Definition: typographer_context_skia.cc:78
impeller::TRect< Scalar >
impeller::GetImageInfo
static SkImageInfo GetImageInfo(const GlyphAtlas &atlas, Size size)
Definition: typographer_context_skia.cc:91
impeller::ScaledFont
A font and a scale. Used as a key that represents a typeface within a glyph atlas.
Definition: font_glyph_pair.h:32
size.h
impeller::TypographerContext::IsValid
virtual bool IsValid() const
Definition: typographer_context.cc:17
impeller::Cap
Cap
Definition: path.h:18