| Flutter Impeller |

Public Member Functions | Static Public Member Functions | List of all members
impeller::TypographerContextSkia Class Reference

`#include <typographer_context_skia.h>`

Inheritance diagram for impeller::TypographerContextSkia:

## Public Member Functions
| TypographerContextSkia ()
| ~TypographerContextSkia () override
std::shared_ptr< GlyphAtlasContext > | CreateGlyphAtlasContext (GlyphAtlas::Type type) const override
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
Public Member Functions inherited from impeller::TypographerContext
virtual | ~TypographerContext ()
virtual bool | IsValid () const

## Static Public Member Functions
static std::shared_ptr< TypographerContext > | Make ()

## Additional Inherited Members
Protected Member Functions inherited from impeller::TypographerContext
| TypographerContext ()
| Create a new context to render text that talks to an underlying graphics context. More...

## Detailed Description

Definition at line 12 of file typographer_context_skia.h.

## Constructor & Destructor Documentation

## ◆ TypographerContextSkia()

impeller::TypographerContextSkia::TypographerContextSkia | ( |  | ) |
| default

## ◆ ~TypographerContextSkia()

impeller::TypographerContextSkia::~TypographerContextSkia | ( |  | ) |
| override default

## Member Function Documentation

## ◆ CreateGlyphAtlas()

std::shared_ptr< GlyphAtlas > impeller::TypographerContextSkia::CreateGlyphAtlas | ( | Context & | context,
|  | GlyphAtlas::Type | type,
|  | HostBuffer & | host_buffer,
|  | const std::shared_ptr< GlyphAtlasContext > & | atlas_context,
|  | const FontGlyphMap & | font_glyph_map
| ) |  | const
| override virtual

Implements impeller::TypographerContext.

Definition at line 346 of file typographer_context_skia.cc.

351 {
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 }

References impeller::AppendToExistingAtlas(), buffer_view, impeller::BackendCast< TypefaceSkia, Typeface >::Cast(), impeller::ComputeGlyphSize(), impeller::ComputeNextAtlasSize(), impeller::Context::CreateCommandBuffer(), impeller::DefaultUniformAlignment(), impeller::HostBuffer::Emplace(), impeller::FontGlyphAtlas::FindGlyphBounds(), impeller::ScaledFont::font, impeller::TextureDescriptor::format, impeller::Context::GetBackendType(), impeller::Context::GetCapabilities(), impeller::Context::GetCommandQueue(), impeller::Font::GetMetrics(), impeller::Context::GetResourceAllocator(), impeller::TypefaceSkia::GetSkiaTypeface(), impeller::Font::GetTypeface(), impeller::TSize< T >::IsEmpty(), impeller::TypographerContext::IsValid(), impeller::GlyphAtlas::kAlphaBitmap, impeller::GlyphAtlas::kColorBitmap, impeller::kDevicePrivate, impeller::Context::kOpenGLES, impeller::kR8G8B8A8UNormInt, impeller::kShaderRead, impeller::TRect< T >::MakeSize(), impeller::ScaledFont::scale, impeller::TextureDescriptor::size, impeller::TextureDescriptor::storage_mode, type, impeller::UpdateAtlasBitmap(), and impeller::TextureDescriptor::usage.

## ◆ CreateGlyphAtlasContext()

std::shared_ptr< GlyphAtlasContext > impeller::TypographerContextSkia::CreateGlyphAtlasContext | ( | GlyphAtlas::Type | type | ) | const
| override virtual

Implements impeller::TypographerContext.

Definition at line 87 of file typographer_context_skia.cc.

87 {
88 return std::make_shared<GlyphAtlasContext>(type);
89 }

References type.

## ◆ Make()

std::shared_ptr< TypographerContext > impeller::TypographerContextSkia::Make | ( |  | ) |
| static

Definition at line 78 of file typographer_context_skia.cc.

78 {
79 return std::make_shared<TypographerContextSkia>();
80 }

Referenced by impeller::DlPlayground::OpenPlaygroundHere(), and impeller::testing::TEST_P().

The documentation for this class was generated from the following files:

- impeller/typographer/backends/skia/typographer_context_skia.h
- impeller/typographer/backends/skia/typographer_context_skia.cc

impeller::ISize
ISize64 ISize
Definition: size.h:140
impeller::GlyphAtlas::Type::kColorBitmap
@ kColorBitmap
impeller::DefaultUniformAlignment
constexpr size_t DefaultUniformAlignment()
Definition: platform.h:14
impeller::GlyphAtlas::Type::kAlphaBitmap
@ kAlphaBitmap
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::PixelFormat::kR8G8B8A8UNormInt
@ kR8G8B8A8UNormInt
buffer_view
BufferView buffer_view
Definition: blit_command_gles.cc:127
impeller::TypefaceSkia::GetSkiaTypeface
const sk_sp< SkTypeface > & GetSkiaTypeface() const
Definition: typeface_skia.cc:31
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::Context::BackendType::kOpenGLES
@ kOpenGLES
impeller::StorageMode::kDevicePrivate
@ kDevicePrivate
type
GLenum type
Definition: blit_command_gles.cc:126
impeller::TRect::MakeSize
constexpr static TRect MakeSize(const TSize< U > &size)
Definition: rect.h:146
impeller::BackendCast< TypefaceSkia, Typeface >::Cast
static TypefaceSkia & Cast(Typeface &base)
Definition: backend_cast.h:13
impeller::TextureUsage::kShaderRead
@ kShaderRead
impeller::ComputeGlyphSize
static Rect ComputeGlyphSize(const SkFont &font, const SubpixelGlyph &glyph, Scalar scale)
Definition: typographer_context_skia.cc:322
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::TypographerContext::IsValid
virtual bool IsValid() const
Definition: typographer_context.cc:17