From f2d23512b7a06e4941c5af6b3b8ebebb62e3a157 Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Tue, 22 Mar 2022 09:39:28 -0700 Subject: [PATCH] Implement impeller::DisplayListDispatcher::drawTextBlob. (#94) --- impeller/aiks/aiks_unittests.cc | 11 +-- impeller/aiks/canvas.cc | 13 ++-- impeller/aiks/canvas.h | 5 +- impeller/display_list/BUILD.gn | 8 ++- .../display_list/display_list_dispatcher.cc | 8 ++- .../display_list/display_list_playground.cc | 71 +++++++++++++++++++ .../display_list/display_list_playground.h | 33 +++++++++ .../display_list/display_list_unittests.cc | 19 ++++- impeller/entity/contents/text_contents.cc | 33 +++++++-- impeller/entity/contents/text_contents.h | 12 +++- impeller/entity/entity_pass.cc | 4 ++ impeller/entity/entity_pass.h | 5 ++ impeller/typographer/BUILD.gn | 2 + .../backends/skia/text_render_context_skia.cc | 21 +++--- .../backends/skia/text_render_context_skia.h | 2 +- impeller/typographer/lazy_glyph_atlas.cc | 49 +++++++++++++ impeller/typographer/lazy_glyph_atlas.h | 32 +++++++++ impeller/typographer/text_render_context.cc | 21 ++++++ impeller/typographer/text_render_context.h | 29 ++++---- impeller/typographer/typographer_unittests.cc | 8 +-- 20 files changed, 323 insertions(+), 63 deletions(-) create mode 100644 impeller/display_list/display_list_playground.cc create mode 100644 impeller/display_list/display_list_playground.h create mode 100644 impeller/typographer/lazy_glyph_atlas.cc create mode 100644 impeller/typographer/lazy_glyph_atlas.h diff --git a/impeller/aiks/aiks_unittests.cc b/impeller/aiks/aiks_unittests.cc index 738abc6651056..5ea7fb9f5507b 100644 --- a/impeller/aiks/aiks_unittests.cc +++ b/impeller/aiks/aiks_unittests.cc @@ -347,19 +347,10 @@ bool RenderTextInCanvas(std::shared_ptr context, // Create the Impeller text frame and draw it at the designated baseline. auto frame = TextFrameFromTextBlob(blob); - TextRenderContextSkia text_context(context); - if (!text_context.IsValid()) { - return false; - } - auto atlas = text_context.CreateGlyphAtlas(frame); - if (!atlas) { - return false; - } Paint text_paint; text_paint.color = Color::Yellow(); - canvas.DrawTextFrame(std::move(frame), std::move(atlas), text_position, - text_paint); + canvas.DrawTextFrame(std::move(frame), text_position, text_paint); return true; } diff --git a/impeller/aiks/canvas.cc b/impeller/aiks/canvas.cc index b77beb800b949..d9464e8f4ef6b 100644 --- a/impeller/aiks/canvas.cc +++ b/impeller/aiks/canvas.cc @@ -269,17 +269,14 @@ void Canvas::Save(bool create_subpass) { xformation_stack_.emplace_back(std::move(entry)); } -void Canvas::DrawTextFrame(TextFrame text_frame, - std::shared_ptr atlas, - Point position, - Paint paint) { - if (!atlas || !atlas->IsValid()) { - return; - } +void Canvas::DrawTextFrame(TextFrame text_frame, Point position, Paint paint) { + auto lazy_glyph_atlas = GetCurrentPass().GetLazyGlyphAtlas(); + + lazy_glyph_atlas->AddTextFrame(std::move(text_frame)); auto text_contents = std::make_shared(); text_contents->SetTextFrame(std::move(text_frame)); - text_contents->SetGlyphAtlas(std::move(atlas)); + text_contents->SetGlyphAtlas(std::move(lazy_glyph_atlas)); text_contents->SetColor(paint.color.Premultiply()); Entity entity; diff --git a/impeller/aiks/canvas.h b/impeller/aiks/canvas.h index c407915953abf..06ebb0f88fa1b 100644 --- a/impeller/aiks/canvas.h +++ b/impeller/aiks/canvas.h @@ -78,10 +78,7 @@ class Canvas { void DrawPicture(Picture picture); - void DrawTextFrame(TextFrame text_frame, - std::shared_ptr atlas, - Point position, - Paint paint); + void DrawTextFrame(TextFrame text_frame, Point position, Paint paint); Picture EndRecordingAsPicture(); diff --git a/impeller/display_list/BUILD.gn b/impeller/display_list/BUILD.gn index ca5a54bc253b0..e3f51afb3554a 100644 --- a/impeller/display_list/BUILD.gn +++ b/impeller/display_list/BUILD.gn @@ -10,7 +10,7 @@ impeller_component("display_list") { "display_list_dispatcher.h", ] - deps = [ + public_deps = [ "../aiks", "//flutter/display_list", "//flutter/fml", @@ -21,7 +21,11 @@ impeller_component("display_list") { impeller_component("display_list_unittests") { testonly = true - sources = [ "display_list_unittests.cc" ] + sources = [ + "display_list_playground.cc", + "display_list_playground.h", + "display_list_unittests.cc", + ] deps = [ ":display_list", diff --git a/impeller/display_list/display_list_dispatcher.cc b/impeller/display_list/display_list_dispatcher.cc index 5d1bf440d703b..b1e23010cda72 100644 --- a/impeller/display_list/display_list_dispatcher.cc +++ b/impeller/display_list/display_list_dispatcher.cc @@ -454,7 +454,8 @@ void DisplayListDispatcher::clipPath(const SkPath& path, } // |flutter::Dispatcher| -void DisplayListDispatcher::drawColor(SkColor color, flutter::DlBlendMode dl_mode) { +void DisplayListDispatcher::drawColor(SkColor color, + flutter::DlBlendMode dl_mode) { Paint paint; paint.color = ToColor(color); if (auto mode = ToBlendMode(dl_mode); mode.has_value()) { @@ -608,7 +609,10 @@ void DisplayListDispatcher::drawDisplayList( void DisplayListDispatcher::drawTextBlob(const sk_sp blob, SkScalar x, SkScalar y) { - UNIMPLEMENTED; + canvas_.DrawTextFrame(TextFrameFromTextBlob(blob), // + impeller::Point{x, y}, // + paint_ // + ); } // |flutter::Dispatcher| diff --git a/impeller/display_list/display_list_playground.cc b/impeller/display_list/display_list_playground.cc new file mode 100644 index 0000000000000..4bbcb07fe410e --- /dev/null +++ b/impeller/display_list/display_list_playground.cc @@ -0,0 +1,71 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "impeller/display_list/display_list_playground.h" + +#include "flutter/testing/testing.h" +#include "impeller/aiks/aiks_context.h" +#include "impeller/display_list/display_list_dispatcher.h" +#include "third_party/skia/include/core/SkData.h" + +namespace impeller { + +DisplayListPlayground::DisplayListPlayground() = default; + +DisplayListPlayground::~DisplayListPlayground() = default; + +bool DisplayListPlayground::OpenPlaygroundHere( + flutter::DisplayListBuilder& builder) { + return OpenPlaygroundHere(builder.Build()); +} + +bool DisplayListPlayground::OpenPlaygroundHere( + sk_sp list) { + if (!Playground::is_enabled()) { + return true; + } + + if (!list) { + return false; + } + + DisplayListDispatcher dispatcher; + list->Dispatch(dispatcher); + auto picture = dispatcher.EndRecordingAsPicture(); + + AiksContext context(GetContext()); + if (!context.IsValid()) { + return false; + } + return Playground::OpenPlaygroundHere( + [&picture, &context](RenderPass& pass) -> bool { + return context.Render(picture, pass); + }); +} + +static sk_sp OpenFixtureAsSkData(const char* fixture_name) { + auto mapping = flutter::testing::OpenFixtureAsMapping(fixture_name); + if (!mapping) { + return nullptr; + } + return SkData::MakeWithProc( + mapping->GetMapping(), mapping->GetSize(), + [](const void* ptr, void* context) { + delete reinterpret_cast(context); + }, + mapping.release()); +} + +SkFont DisplayListPlayground::CreateTestFontOfSize(SkScalar scalar) { + static constexpr const char* kTestFontFixture = "Roboto-Regular.ttf"; + auto mapping = OpenFixtureAsSkData(kTestFontFixture); + FML_CHECK(mapping); + return SkFont{SkTypeface::MakeFromData(mapping), scalar}; +} + +SkFont DisplayListPlayground::CreateTestFont() { + return CreateTestFontOfSize(50); +} + +} // namespace impeller diff --git a/impeller/display_list/display_list_playground.h b/impeller/display_list/display_list_playground.h new file mode 100644 index 0000000000000..f0028a50acf2b --- /dev/null +++ b/impeller/display_list/display_list_playground.h @@ -0,0 +1,33 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include "flutter/display_list/display_list.h" +#include "flutter/display_list/display_list_builder.h" +#include "flutter/fml/macros.h" +#include "impeller/playground/playground.h" +#include "third_party/skia/include/core/SkFont.h" + +namespace impeller { + +class DisplayListPlayground : public Playground { + public: + DisplayListPlayground(); + + ~DisplayListPlayground(); + + bool OpenPlaygroundHere(flutter::DisplayListBuilder& builder); + + bool OpenPlaygroundHere(sk_sp list); + + SkFont CreateTestFontOfSize(SkScalar scalar); + + SkFont CreateTestFont(); + + private: + FML_DISALLOW_COPY_AND_ASSIGN(DisplayListPlayground); +}; + +} // namespace impeller diff --git a/impeller/display_list/display_list_unittests.cc b/impeller/display_list/display_list_unittests.cc index 4a1ad3f52f11c..6fef7b37f5c89 100644 --- a/impeller/display_list/display_list_unittests.cc +++ b/impeller/display_list/display_list_unittests.cc @@ -2,12 +2,29 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "flutter/display_list/display_list_builder.h" #include "flutter/testing/testing.h" +#include "impeller/display_list/display_list_playground.h" namespace impeller { namespace testing { -TEST(DisplayListTest, CanCreateDisatcher) {} +using DisplayListTest = DisplayListPlayground; + +TEST_F(DisplayListTest, CanDrawRect) { + flutter::DisplayListBuilder builder; + builder.setColor(SK_ColorBLUE); + builder.drawRect(SkRect::MakeXYWH(10, 10, 100, 100)); + ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); +} + +TEST_F(DisplayListTest, CanDrawTextBlob) { + flutter::DisplayListBuilder builder; + builder.setColor(SK_ColorBLUE); + builder.drawTextBlob(SkTextBlob::MakeFromString("Hello", CreateTestFont()), + 100, 100); + ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); +} } // namespace testing } // namespace impeller diff --git a/impeller/entity/contents/text_contents.cc b/impeller/entity/contents/text_contents.cc index c58855039f31d..8b4e698183025 100644 --- a/impeller/entity/contents/text_contents.cc +++ b/impeller/entity/contents/text_contents.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "text_contents.h" +#include "impeller/entity/contents/text_contents.h" #include "impeller/entity/contents/content_context.h" #include "impeller/entity/entity.h" @@ -11,8 +11,10 @@ #include "impeller/renderer/sampler_library.h" #include "impeller/tessellator/tessellator.h" #include "impeller/typographer/glyph_atlas.h" +#include "impeller/typographer/lazy_glyph_atlas.h" namespace impeller { + TextContents::TextContents() = default; TextContents::~TextContents() = default; @@ -25,6 +27,23 @@ void TextContents::SetGlyphAtlas(std::shared_ptr atlas) { atlas_ = std::move(atlas); } +void TextContents::SetGlyphAtlas(std::shared_ptr atlas) { + atlas_ = std::move(atlas); +} + +std::shared_ptr TextContents::ResolveAtlas( + std::shared_ptr context) const { + if (auto lazy_atlas = std::get_if>(&atlas_)) { + return lazy_atlas->get()->CreateOrGetGlyphAtlas(context); + } + + if (auto atlas = std::get_if>(&atlas_)) { + return *atlas; + } + + return nullptr; +} + void TextContents::SetColor(Color color) { color_ = color; } @@ -36,7 +55,9 @@ bool TextContents::Render(const ContentContext& renderer, return true; } - if (!atlas_ || !atlas_->IsValid()) { + auto atlas = ResolveAtlas(renderer.GetContext()); + + if (!atlas || !atlas->IsValid()) { VALIDATION_LOG << "Cannot render glyphs without prepared atlas."; return false; } @@ -57,15 +78,15 @@ bool TextContents::Render(const ContentContext& renderer, frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * entity.GetTransformation(); frame_info.atlas_size = - Point{static_cast(atlas_->GetTexture()->GetSize().width), - static_cast(atlas_->GetTexture()->GetSize().height)}; + Point{static_cast(atlas->GetTexture()->GetSize().width), + static_cast(atlas->GetTexture()->GetSize().height)}; frame_info.text_color = ToVector(color_); VS::BindFrameInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frame_info)); // Common fragment uniforms for all glyphs. FS::BindGlyphAtlasSampler( cmd, // command - atlas_->GetTexture(), // texture + atlas->GetTexture(), // texture renderer.GetContext()->GetSamplerLibrary()->GetSampler({}) // sampler ); @@ -107,7 +128,7 @@ bool TextContents::Render(const ContentContext& renderer, // Draw each glyph individually. This should probably be batched. for (const auto& glyph_position : run.GetGlyphPositions()) { FontGlyphPair font_glyph_pair{font, glyph_position.glyph}; - auto atlas_glyph_pos = atlas_->FindFontGlyphPosition(font_glyph_pair); + auto atlas_glyph_pos = atlas->FindFontGlyphPosition(font_glyph_pair); if (!atlas_glyph_pos.has_value()) { VALIDATION_LOG << "Could not find glyph position in the atlas."; return false; diff --git a/impeller/entity/contents/text_contents.h b/impeller/entity/contents/text_contents.h index 370bdd1973d2e..238de9a43e77e 100644 --- a/impeller/entity/contents/text_contents.h +++ b/impeller/entity/contents/text_contents.h @@ -6,6 +6,7 @@ #include #include +#include #include #include "flutter/fml/macros.h" @@ -16,6 +17,8 @@ namespace impeller { class GlyphAtlas; +class LazyGlyphAtlas; +class Context; class TextContents final : public Contents { public: @@ -27,6 +30,8 @@ class TextContents final : public Contents { void SetGlyphAtlas(std::shared_ptr atlas); + void SetGlyphAtlas(std::shared_ptr atlas); + void SetColor(Color color); // |Contents| @@ -37,7 +42,12 @@ class TextContents final : public Contents { private: TextFrame frame_; Color color_; - std::shared_ptr atlas_; + mutable std::variant, + std::shared_ptr> + atlas_; + + std::shared_ptr ResolveAtlas( + std::shared_ptr context) const; FML_DISALLOW_COPY_AND_ASSIGN(TextContents); }; diff --git a/impeller/entity/entity_pass.cc b/impeller/entity/entity_pass.cc index 6840c2b30e896..914da3ebedcd7 100644 --- a/impeller/entity/entity_pass.cc +++ b/impeller/entity/entity_pass.cc @@ -44,6 +44,10 @@ size_t EntityPass::GetSubpassesDepth() const { return max_subpass_depth + 1u; } +const std::shared_ptr& EntityPass::GetLazyGlyphAtlas() const { + return lazy_glyph_atlas_; +} + std::optional EntityPass::GetEntitiesCoverage() const { std::optional result; for (const auto& entity : entities_) { diff --git a/impeller/entity/entity_pass.h b/impeller/entity/entity_pass.h index e2305f92fcd28..f4dc5cf424d61 100644 --- a/impeller/entity/entity_pass.h +++ b/impeller/entity/entity_pass.h @@ -13,6 +13,7 @@ #include "impeller/entity/entity.h" #include "impeller/entity/entity_pass_delegate.h" #include "impeller/renderer/render_target.h" +#include "impeller/typographer/lazy_glyph_atlas.h" namespace impeller { @@ -41,6 +42,8 @@ class EntityPass { const Subpasses& GetSubpasses() const; + const std::shared_ptr& GetLazyGlyphAtlas() const; + EntityPass* AddSubpass(std::unique_ptr pass); EntityPass* GetSuperpass() const; @@ -61,6 +64,8 @@ class EntityPass { size_t stencil_depth_ = 0u; std::unique_ptr delegate_ = EntityPassDelegate::MakeDefault(); + std::shared_ptr lazy_glyph_atlas_ = + std::make_shared(); std::optional GetSubpassCoverage(const EntityPass& subpass) const; diff --git a/impeller/typographer/BUILD.gn b/impeller/typographer/BUILD.gn index 1c10a77a8deaf..2c0a21fa90c7f 100644 --- a/impeller/typographer/BUILD.gn +++ b/impeller/typographer/BUILD.gn @@ -20,6 +20,8 @@ impeller_component("typographer") { "glyph.h", "glyph_atlas.cc", "glyph_atlas.h", + "lazy_glyph_atlas.cc", + "lazy_glyph_atlas.h", "text_frame.cc", "text_frame.h", "text_render_context.cc", diff --git a/impeller/typographer/backends/skia/text_render_context_skia.cc b/impeller/typographer/backends/skia/text_render_context_skia.cc index ca7b93bdad01e..3c67bea2612b2 100644 --- a/impeller/typographer/backends/skia/text_render_context_skia.cc +++ b/impeller/typographer/backends/skia/text_render_context_skia.cc @@ -25,22 +25,24 @@ TextRenderContextSkia::TextRenderContextSkia(std::shared_ptr context) TextRenderContextSkia::~TextRenderContextSkia() = default; static FontGlyphPair::Set CollectUniqueFontGlyphPairsSet( - const std::vector& runs) { + TextRenderContext::FrameIterator frame_iterator) { FontGlyphPair::Set set; - for (const auto& run : runs) { - auto font = run.GetFont(); - for (const auto& glyph_position : run.GetGlyphPositions()) { - set.insert({font, glyph_position.glyph}); + while (auto frame = frame_iterator()) { + for (const auto& run : frame->GetRuns()) { + auto font = run.GetFont(); + for (const auto& glyph_position : run.GetGlyphPositions()) { + set.insert({font, glyph_position.glyph}); + } } } return set; } static FontGlyphPair::Vector CollectUniqueFontGlyphPairs( - const std::vector& runs) { + TextRenderContext::FrameIterator frame_iterator) { TRACE_EVENT0("impeller", __FUNCTION__); FontGlyphPair::Vector vector; - auto set = CollectUniqueFontGlyphPairsSet(runs); + auto set = CollectUniqueFontGlyphPairsSet(frame_iterator); vector.reserve(set.size()); for (const auto& item : set) { vector.emplace_back(std::move(item)); @@ -202,7 +204,7 @@ static std::shared_ptr UploadGlyphTextureAtlas( } std::shared_ptr TextRenderContextSkia::CreateGlyphAtlas( - const TextFrame& frame) const { + FrameIterator frame_iterator) const { TRACE_EVENT0("impeller", __FUNCTION__); if (!IsValid()) { return nullptr; @@ -213,7 +215,8 @@ std::shared_ptr TextRenderContextSkia::CreateGlyphAtlas( // --------------------------------------------------------------------------- // Step 1: Collect unique font-glyph pairs in the frame. // --------------------------------------------------------------------------- - auto font_glyph_pairs = CollectUniqueFontGlyphPairs(frame.GetRuns()); + + auto font_glyph_pairs = CollectUniqueFontGlyphPairs(frame_iterator); if (font_glyph_pairs.empty()) { return glyph_atlas; } diff --git a/impeller/typographer/backends/skia/text_render_context_skia.h b/impeller/typographer/backends/skia/text_render_context_skia.h index 936b64bfde448..26dfb19a80788 100644 --- a/impeller/typographer/backends/skia/text_render_context_skia.h +++ b/impeller/typographer/backends/skia/text_render_context_skia.h @@ -17,7 +17,7 @@ class TextRenderContextSkia : public TextRenderContext { // |TextRenderContext| std::shared_ptr CreateGlyphAtlas( - const TextFrame& frame) const override; + FrameIterator iterator) const override; private: FML_DISALLOW_COPY_AND_ASSIGN(TextRenderContextSkia); diff --git a/impeller/typographer/lazy_glyph_atlas.cc b/impeller/typographer/lazy_glyph_atlas.cc new file mode 100644 index 0000000000000..e2b2631b926e3 --- /dev/null +++ b/impeller/typographer/lazy_glyph_atlas.cc @@ -0,0 +1,49 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "impeller/typographer/lazy_glyph_atlas.h" + +#include "impeller/base/validation.h" +#include "impeller/typographer/text_render_context.h" + +namespace impeller { + +LazyGlyphAtlas::LazyGlyphAtlas() = default; + +LazyGlyphAtlas::~LazyGlyphAtlas() = default; + +void LazyGlyphAtlas::AddTextFrame(TextFrame frame) { + FML_DCHECK(!atlas_); + frames_.emplace_back(std::move(frame)); +} + +std::shared_ptr LazyGlyphAtlas::CreateOrGetGlyphAtlas( + std::shared_ptr context) const { + if (atlas_) { + return atlas_; + } + + auto text_context = TextRenderContext::Create(std::move(context)); + if (!text_context || !text_context->IsValid()) { + return nullptr; + } + size_t i = 0; + TextRenderContext::FrameIterator iterator = [&]() -> const TextFrame* { + if (i >= frames_.size()) { + return nullptr; + } + const auto& result = frames_[i]; + i++; + return &result; + }; + auto atlas = text_context->CreateGlyphAtlas(iterator); + if (!atlas || !atlas->IsValid()) { + VALIDATION_LOG << "Could not create valid atlas."; + return nullptr; + } + atlas_ = std::move(atlas); + return atlas_; +} + +} // namespace impeller diff --git a/impeller/typographer/lazy_glyph_atlas.h b/impeller/typographer/lazy_glyph_atlas.h new file mode 100644 index 0000000000000..8d36e05cc4d03 --- /dev/null +++ b/impeller/typographer/lazy_glyph_atlas.h @@ -0,0 +1,32 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include "flutter/fml/macros.h" +#include "impeller/renderer/context.h" +#include "impeller/typographer/glyph_atlas.h" +#include "impeller/typographer/text_frame.h" + +namespace impeller { + +class LazyGlyphAtlas { + public: + LazyGlyphAtlas(); + + ~LazyGlyphAtlas(); + + void AddTextFrame(TextFrame frame); + + std::shared_ptr CreateOrGetGlyphAtlas( + std::shared_ptr context) const; + + private: + std::vector frames_; + mutable std::shared_ptr atlas_; + + FML_DISALLOW_COPY_AND_ASSIGN(LazyGlyphAtlas); +}; + +} // namespace impeller diff --git a/impeller/typographer/text_render_context.cc b/impeller/typographer/text_render_context.cc index 98b74047670f9..beecdaae51699 100644 --- a/impeller/typographer/text_render_context.cc +++ b/impeller/typographer/text_render_context.cc @@ -4,8 +4,16 @@ #include "impeller/typographer/text_render_context.h" +#include "impeller/typographer/backends/skia/text_render_context_skia.h" + namespace impeller { +std::unique_ptr TextRenderContext::Create( + std::shared_ptr context) { + // There is only one backend today. + return std::make_unique(std::move(context)); +} + TextRenderContext::TextRenderContext(std::shared_ptr context) : context_(std::move(context)) { if (!context_ || !context_->IsValid()) { @@ -24,4 +32,17 @@ const std::shared_ptr& TextRenderContext::GetContext() const { return context_; } +std::shared_ptr TextRenderContext::CreateGlyphAtlas( + const TextFrame& frame) const { + size_t count = 0; + FrameIterator iterator = [&]() -> const TextFrame* { + count++; + if (count == 1) { + return &frame; + } + return nullptr; + }; + return CreateGlyphAtlas(iterator); +} + } // namespace impeller diff --git a/impeller/typographer/text_render_context.h b/impeller/typographer/text_render_context.h index 8d5ac6fa133ab..c725c03c5b128 100644 --- a/impeller/typographer/text_render_context.h +++ b/impeller/typographer/text_render_context.h @@ -4,6 +4,7 @@ #pragma once +#include #include #include "flutter/fml/macros.h" @@ -19,18 +20,11 @@ namespace impeller { /// This is necessary to create and reference resources related to /// rendering text on the GPU. /// -/// It is caller responsibility to create as few of these and keep -/// these around for as long possible. /// class TextRenderContext { public: - //---------------------------------------------------------------------------- - /// @brief Create a new context to render text that talks to an - /// underlying graphics context. - /// - /// @param[in] context The graphics context - /// - TextRenderContext(std::shared_ptr context); + static std::unique_ptr Create( + std::shared_ptr context); virtual ~TextRenderContext(); @@ -43,15 +37,20 @@ class TextRenderContext { /// const std::shared_ptr& GetContext() const; + using FrameIterator = std::function; + virtual std::shared_ptr CreateGlyphAtlas( + FrameIterator iterator) const = 0; + + std::shared_ptr CreateGlyphAtlas(const TextFrame& frame) const; + + protected: //---------------------------------------------------------------------------- - /// @brief Create a new glyph atlas for the specified text frame. - /// - /// @param[in] frame The text frame + /// @brief Create a new context to render text that talks to an + /// underlying graphics context. /// - /// @return A valid glyph atlas or null. + /// @param[in] context The graphics context /// - virtual std::shared_ptr CreateGlyphAtlas( - const TextFrame& frame) const = 0; + TextRenderContext(std::shared_ptr context); private: std::shared_ptr context_; diff --git a/impeller/typographer/typographer_unittests.cc b/impeller/typographer/typographer_unittests.cc index 1f59d633bc7dd..0cb41841aec25 100644 --- a/impeller/typographer/typographer_unittests.cc +++ b/impeller/typographer/typographer_unittests.cc @@ -27,13 +27,13 @@ TEST_F(TypographerTest, CanConvertTextBlob) { } TEST_F(TypographerTest, CanCreateRenderContext) { - auto context = std::make_shared(GetContext()); - ASSERT_TRUE(context->IsValid()); + auto context = TextRenderContext::Create(GetContext()); + ASSERT_TRUE(context && context->IsValid()); } TEST_F(TypographerTest, CanCreateGlyphAtlas) { - auto context = std::make_shared(GetContext()); - ASSERT_TRUE(context->IsValid()); + auto context = TextRenderContext::Create(GetContext()); + ASSERT_TRUE(context && context->IsValid()); SkFont sk_font; auto blob = SkTextBlob::MakeFromString("hello", sk_font); ASSERT_TRUE(blob);