| 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 std::vector< std::shared_ptr< TextFrame >> &text_frames) 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 std::vector< std::shared_ptr< TextFrame >> & | text_frames
| ) |  | const
| override virtual

Implements impeller::TypographerContext.

Definition at line 502 of file typographer_context_skia.cc.

507 {
508 TRACE_EVENT0("impeller", __FUNCTION__);
509 if (!IsValid()) {
510 return nullptr;
511 }
512 std::shared_ptr<GlyphAtlas> last_atlas = atlas_context->GetGlyphAtlas();
513 FML_DCHECK(last_atlas->GetType() == type);
514
515 if (text_frames.empty()) {
516 return last_atlas;
517 }
518
519 // ---------------------------------------------------------------------------
520 // Step 1: Determine if the atlas type and font glyph pairs are compatible
521 // with the current atlas and reuse if possible. For each new font and
522 // glyph pair, compute the glyph size at scale.
523 // ---------------------------------------------------------------------------
524 auto [new_glyphs, glyph_sizes] = CollectNewGlyphs(last_atlas, text_frames);
525 if (new_glyphs.size() == 0) {
526 return last_atlas;
527 }
528
529 // ---------------------------------------------------------------------------
530 // Step 2: Determine if the additional missing glyphs can be appended to the
531 // existing bitmap without recreating the atlas.
532 // ---------------------------------------------------------------------------
533 std::vector<Rect> glyph_positions;
534 glyph_positions.reserve(new_glyphs.size());
535 size_t first_missing_index = 0;
536
537 if (last_atlas->GetTexture()) {
538 // Append all glyphs that fit into the current atlas.
539 first_missing_index = AppendToExistingAtlas(
540 last_atlas, new_glyphs, glyph_positions, glyph_sizes,
541 atlas_context->GetAtlasSize(), atlas_context->GetHeightAdjustment(),
542 atlas_context->GetRectPacker());
543
544 // ---------------------------------------------------------------------------
545 // Step 3a: Record the positions in the glyph atlas of the newly added
546 // glyphs.
547 // ---------------------------------------------------------------------------
548 for (size_t i = 0; i < first_missing_index; i++) {
549 last_atlas->AddTypefaceGlyphPositionAndBounds(
550 new_glyphs[i], glyph_positions[i], glyph_sizes[i]);
551 }
552
553 std::shared_ptr<CommandBuffer> cmd_buffer = context.CreateCommandBuffer();
554 std::shared_ptr<BlitPass> blit_pass = cmd_buffer->CreateBlitPass();
555
556 fml::ScopedCleanupClosure closure([&]() {
557 blit_pass->EncodeCommands();
558 if (!context.EnqueueCommandBuffer(std::move(cmd_buffer))) {
559 VALIDATION_LOG << "Failed to submit glyph atlas command buffer";
560 }
561 });
562
563 // ---------------------------------------------------------------------------
564 // Step 4a: Draw new font-glyph pairs into the a host buffer and encode
565 // the uploads into the blit pass.
566 // ---------------------------------------------------------------------------
567 if (!UpdateAtlasBitmap(*last_atlas, blit_pass, data_host_buffer,
568 last_atlas->GetTexture(), new_glyphs, 0,
569 first_missing_index)) {
570 return nullptr;
571 }
572
573 // If all glyphs fit, just return the old atlas.
574 if (first_missing_index == new_glyphs.size()) {
575 return last_atlas;
576 }
577 }
578
579 int64_t height_adjustment = atlas_context->GetAtlasSize().height;
580 const int64_t max_texture_height =
581 context.GetResourceAllocator()->GetMaxTextureSizeSupported().height;
582
583 // IF the current atlas size is as big as it can get, then "GC" and create an
584 // atlas with only the required glyphs. OpenGLES cannot reliably perform the
585 // blit required here, as 1) it requires attaching textures as read and write
586 // framebuffers which has substantially smaller size limits that max textures
587 // and 2) is missing a GLES 2.0 implementation and cap check.
588 bool blit_old_atlas = true;
589 std::shared_ptr<GlyphAtlas> new_atlas = last_atlas;
590 if (atlas_context->GetAtlasSize().height >= max_texture_height ||
591 context.GetBackendType() == Context::BackendType::kOpenGLES) {
592 blit_old_atlas = false;
593 new_atlas = std::make_shared<GlyphAtlas>(
594 type, /*initial_generation=*/last_atlas->GetAtlasGeneration() + 1);
595
596 auto [update_glyphs, update_sizes] =
597 CollectNewGlyphs(new_atlas, text_frames);
598 new_glyphs = std::move(update_glyphs);
599 glyph_sizes = std::move(update_sizes);
600
601 glyph_positions.clear();
602 glyph_positions.reserve(new_glyphs.size());
603 first_missing_index = 0;
604
605 height_adjustment = 0;
606 atlas_context->UpdateRectPacker(nullptr);
607 atlas_context->UpdateGlyphAtlas(new_atlas, {0, 0}, 0);
608 }
609
610 // A new glyph atlas must be created.
611 ISize atlas_size = ComputeNextAtlasSize(atlas_context, //
612 new_glyphs, //
613 glyph_positions, //
614 glyph_sizes, //
615 first_missing_index, //
616 max_texture_height //
617 );
618
619 atlas_context->UpdateGlyphAtlas(new_atlas, atlas_size, height_adjustment);
620 if (atlas_size.IsEmpty()) {
621 return nullptr;
622 }
623 FML_DCHECK(new_glyphs.size() == glyph_positions.size());
624
625 TextureDescriptor descriptor;
626 switch (type) {
627 case GlyphAtlas::Type::kAlphaBitmap:
628 descriptor.format =
629 context.GetCapabilities()->GetDefaultGlyphAtlasFormat();
630 break;
631 case GlyphAtlas::Type::kColorBitmap:
632 descriptor.format = PixelFormat::kR8G8B8A8UNormInt;
633 break;
634 }
635 descriptor.size = atlas_size;
636 descriptor.storage_mode = StorageMode::kDevicePrivate;
637 descriptor.usage = TextureUsage::kShaderRead;
638 std::shared_ptr<Texture> new_texture =
639 context.GetResourceAllocator()->CreateTexture(descriptor);
640 if (!new_texture) {
641 return nullptr;
642 }
643
644 new_texture->SetLabel("GlyphAtlas");
645
646 std::shared_ptr<CommandBuffer> cmd_buffer = context.CreateCommandBuffer();
647 std::shared_ptr<BlitPass> blit_pass = cmd_buffer->CreateBlitPass();
648
649 fml::ScopedCleanupClosure closure([&]() {
650 blit_pass->EncodeCommands();
651 if (!context.EnqueueCommandBuffer(std::move(cmd_buffer))) {
652 VALIDATION_LOG << "Failed to submit glyph atlas command buffer";
653 }
654 });
655
656 // Now append all remaining glyphs. This should never have any missing data...
657 auto old_texture = new_atlas->GetTexture();
658 new_atlas->SetTexture(std::move(new_texture));
659
660 // ---------------------------------------------------------------------------
661 // Step 3a: Record the positions in the glyph atlas of the newly added
662 // glyphs.
663 // ---------------------------------------------------------------------------
664 for (size_t i = first_missing_index; i < glyph_positions.size(); i++) {
665 new_atlas->AddTypefaceGlyphPositionAndBounds(
666 new_glyphs[i], glyph_positions[i], glyph_sizes[i]);
667 }
668
669 // ---------------------------------------------------------------------------
670 // Step 4a: Draw new font-glyph pairs into the a host buffer and encode
671 // the uploads into the blit pass.
672 // ---------------------------------------------------------------------------
673 if (!BulkUpdateAtlasBitmap(*new_atlas, blit_pass, data_host_buffer,
674 new_atlas->GetTexture(), new_glyphs,
675 first_missing_index, new_glyphs.size())) {
676 return nullptr;
677 }
678
679 // Blit the old texture to the top left of the new atlas.
680 if (blit_old_atlas && old_texture) {
681 blit_pass->AddCopy(old_texture, new_atlas->GetTexture(),
682 IRect::MakeSize(new_atlas->GetTexture()->GetSize()),
683 {0, 0});
684 }
685
686 // ---------------------------------------------------------------------------
687 // Step 8b: Record the texture in the glyph atlas.
688 // ---------------------------------------------------------------------------
689
690 return new_atlas;
691 }
type
GLenum type
Definition: blit_command_gles.cc:153
impeller::Context::BackendType::kOpenGLES
@ kOpenGLES
impeller::GlyphAtlas::Type::kAlphaBitmap
@ kAlphaBitmap
impeller::GlyphAtlas::Type::kColorBitmap
@ kColorBitmap
impeller::TypographerContext::IsValid
virtual bool IsValid() const
Definition: typographer_context.cc:17
impeller::UpdateAtlasBitmap
static bool UpdateAtlasBitmap(const GlyphAtlas &atlas, std::shared_ptr< BlitPass > &blit_pass, HostBuffer &data_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:324
impeller::StorageMode::kDevicePrivate
@ kDevicePrivate
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:102
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:166
impeller::PixelFormat::kR8G8B8A8UNormInt
@ kR8G8B8A8UNormInt
impeller::BulkUpdateAtlasBitmap
static bool BulkUpdateAtlasBitmap(const GlyphAtlas &atlas, std::shared_ptr< BlitPass > &blit_pass, HostBuffer &data_host_buffer, const std::shared_ptr< Texture > &texture, const std::vector< FontGlyphPair > &new_pairs, size_t start_index, size_t end_index)
Batch render to a single surface.
Definition: typographer_context_skia.cc:265
impeller::ISize
ISize64 ISize
Definition: size.h:162
impeller::TextureUsage::kShaderRead
@ kShaderRead
impeller::TRect::MakeSize
constexpr static TRect MakeSize(const TSize< U > &size)
Definition: rect.h:150

References impeller::AppendToExistingAtlas(), impeller::BulkUpdateAtlasBitmap(), impeller::ComputeNextAtlasSize(), impeller::Context::CreateCommandBuffer(), impeller::Context::EnqueueCommandBuffer(), impeller::TextureDescriptor::format, impeller::Context::GetBackendType(), impeller::Context::GetCapabilities(), impeller::Context::GetResourceAllocator(), 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::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 85 of file typographer_context_skia.cc.

85 {
86 return std::make_shared<GlyphAtlasContext>(type);
87 }

References type.

## ◆ Make()

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

Definition at line 76 of file typographer_context_skia.cc.

76 {
77 return std::make_shared<TypographerContextSkia>();
78 }

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