Skip to content

Commit f2d2351

Browse files
chinmaygardednfield
authored andcommitted
Implement impeller::DisplayListDispatcher::drawTextBlob. (flutter#94)
1 parent 3235eac commit f2d2351

20 files changed

+323
-63
lines changed

impeller/aiks/aiks_unittests.cc

+1-10
Original file line numberDiff line numberDiff line change
@@ -347,19 +347,10 @@ bool RenderTextInCanvas(std::shared_ptr<Context> context,
347347

348348
// Create the Impeller text frame and draw it at the designated baseline.
349349
auto frame = TextFrameFromTextBlob(blob);
350-
TextRenderContextSkia text_context(context);
351-
if (!text_context.IsValid()) {
352-
return false;
353-
}
354-
auto atlas = text_context.CreateGlyphAtlas(frame);
355-
if (!atlas) {
356-
return false;
357-
}
358350

359351
Paint text_paint;
360352
text_paint.color = Color::Yellow();
361-
canvas.DrawTextFrame(std::move(frame), std::move(atlas), text_position,
362-
text_paint);
353+
canvas.DrawTextFrame(std::move(frame), text_position, text_paint);
363354
return true;
364355
}
365356

impeller/aiks/canvas.cc

+5-8
Original file line numberDiff line numberDiff line change
@@ -269,17 +269,14 @@ void Canvas::Save(bool create_subpass) {
269269
xformation_stack_.emplace_back(std::move(entry));
270270
}
271271

272-
void Canvas::DrawTextFrame(TextFrame text_frame,
273-
std::shared_ptr<GlyphAtlas> atlas,
274-
Point position,
275-
Paint paint) {
276-
if (!atlas || !atlas->IsValid()) {
277-
return;
278-
}
272+
void Canvas::DrawTextFrame(TextFrame text_frame, Point position, Paint paint) {
273+
auto lazy_glyph_atlas = GetCurrentPass().GetLazyGlyphAtlas();
274+
275+
lazy_glyph_atlas->AddTextFrame(std::move(text_frame));
279276

280277
auto text_contents = std::make_shared<TextContents>();
281278
text_contents->SetTextFrame(std::move(text_frame));
282-
text_contents->SetGlyphAtlas(std::move(atlas));
279+
text_contents->SetGlyphAtlas(std::move(lazy_glyph_atlas));
283280
text_contents->SetColor(paint.color.Premultiply());
284281

285282
Entity entity;

impeller/aiks/canvas.h

+1-4
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,7 @@ class Canvas {
7878

7979
void DrawPicture(Picture picture);
8080

81-
void DrawTextFrame(TextFrame text_frame,
82-
std::shared_ptr<GlyphAtlas> atlas,
83-
Point position,
84-
Paint paint);
81+
void DrawTextFrame(TextFrame text_frame, Point position, Paint paint);
8582

8683
Picture EndRecordingAsPicture();
8784

impeller/display_list/BUILD.gn

+6-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ impeller_component("display_list") {
1010
"display_list_dispatcher.h",
1111
]
1212

13-
deps = [
13+
public_deps = [
1414
"../aiks",
1515
"//flutter/display_list",
1616
"//flutter/fml",
@@ -21,7 +21,11 @@ impeller_component("display_list") {
2121
impeller_component("display_list_unittests") {
2222
testonly = true
2323

24-
sources = [ "display_list_unittests.cc" ]
24+
sources = [
25+
"display_list_playground.cc",
26+
"display_list_playground.h",
27+
"display_list_unittests.cc",
28+
]
2529

2630
deps = [
2731
":display_list",

impeller/display_list/display_list_dispatcher.cc

+6-2
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,8 @@ void DisplayListDispatcher::clipPath(const SkPath& path,
454454
}
455455

456456
// |flutter::Dispatcher|
457-
void DisplayListDispatcher::drawColor(SkColor color, flutter::DlBlendMode dl_mode) {
457+
void DisplayListDispatcher::drawColor(SkColor color,
458+
flutter::DlBlendMode dl_mode) {
458459
Paint paint;
459460
paint.color = ToColor(color);
460461
if (auto mode = ToBlendMode(dl_mode); mode.has_value()) {
@@ -608,7 +609,10 @@ void DisplayListDispatcher::drawDisplayList(
608609
void DisplayListDispatcher::drawTextBlob(const sk_sp<SkTextBlob> blob,
609610
SkScalar x,
610611
SkScalar y) {
611-
UNIMPLEMENTED;
612+
canvas_.DrawTextFrame(TextFrameFromTextBlob(blob), //
613+
impeller::Point{x, y}, //
614+
paint_ //
615+
);
612616
}
613617

614618
// |flutter::Dispatcher|
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
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/display_list/display_list_playground.h"
6+
7+
#include "flutter/testing/testing.h"
8+
#include "impeller/aiks/aiks_context.h"
9+
#include "impeller/display_list/display_list_dispatcher.h"
10+
#include "third_party/skia/include/core/SkData.h"
11+
12+
namespace impeller {
13+
14+
DisplayListPlayground::DisplayListPlayground() = default;
15+
16+
DisplayListPlayground::~DisplayListPlayground() = default;
17+
18+
bool DisplayListPlayground::OpenPlaygroundHere(
19+
flutter::DisplayListBuilder& builder) {
20+
return OpenPlaygroundHere(builder.Build());
21+
}
22+
23+
bool DisplayListPlayground::OpenPlaygroundHere(
24+
sk_sp<flutter::DisplayList> list) {
25+
if (!Playground::is_enabled()) {
26+
return true;
27+
}
28+
29+
if (!list) {
30+
return false;
31+
}
32+
33+
DisplayListDispatcher dispatcher;
34+
list->Dispatch(dispatcher);
35+
auto picture = dispatcher.EndRecordingAsPicture();
36+
37+
AiksContext context(GetContext());
38+
if (!context.IsValid()) {
39+
return false;
40+
}
41+
return Playground::OpenPlaygroundHere(
42+
[&picture, &context](RenderPass& pass) -> bool {
43+
return context.Render(picture, pass);
44+
});
45+
}
46+
47+
static sk_sp<SkData> OpenFixtureAsSkData(const char* fixture_name) {
48+
auto mapping = flutter::testing::OpenFixtureAsMapping(fixture_name);
49+
if (!mapping) {
50+
return nullptr;
51+
}
52+
return SkData::MakeWithProc(
53+
mapping->GetMapping(), mapping->GetSize(),
54+
[](const void* ptr, void* context) {
55+
delete reinterpret_cast<fml::Mapping*>(context);
56+
},
57+
mapping.release());
58+
}
59+
60+
SkFont DisplayListPlayground::CreateTestFontOfSize(SkScalar scalar) {
61+
static constexpr const char* kTestFontFixture = "Roboto-Regular.ttf";
62+
auto mapping = OpenFixtureAsSkData(kTestFontFixture);
63+
FML_CHECK(mapping);
64+
return SkFont{SkTypeface::MakeFromData(mapping), scalar};
65+
}
66+
67+
SkFont DisplayListPlayground::CreateTestFont() {
68+
return CreateTestFontOfSize(50);
69+
}
70+
71+
} // namespace impeller
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
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+
#pragma once
6+
7+
#include "flutter/display_list/display_list.h"
8+
#include "flutter/display_list/display_list_builder.h"
9+
#include "flutter/fml/macros.h"
10+
#include "impeller/playground/playground.h"
11+
#include "third_party/skia/include/core/SkFont.h"
12+
13+
namespace impeller {
14+
15+
class DisplayListPlayground : public Playground {
16+
public:
17+
DisplayListPlayground();
18+
19+
~DisplayListPlayground();
20+
21+
bool OpenPlaygroundHere(flutter::DisplayListBuilder& builder);
22+
23+
bool OpenPlaygroundHere(sk_sp<flutter::DisplayList> list);
24+
25+
SkFont CreateTestFontOfSize(SkScalar scalar);
26+
27+
SkFont CreateTestFont();
28+
29+
private:
30+
FML_DISALLOW_COPY_AND_ASSIGN(DisplayListPlayground);
31+
};
32+
33+
} // namespace impeller

impeller/display_list/display_list_unittests.cc

+18-1
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,29 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
#include "flutter/display_list/display_list_builder.h"
56
#include "flutter/testing/testing.h"
7+
#include "impeller/display_list/display_list_playground.h"
68

79
namespace impeller {
810
namespace testing {
911

10-
TEST(DisplayListTest, CanCreateDisatcher) {}
12+
using DisplayListTest = DisplayListPlayground;
13+
14+
TEST_F(DisplayListTest, CanDrawRect) {
15+
flutter::DisplayListBuilder builder;
16+
builder.setColor(SK_ColorBLUE);
17+
builder.drawRect(SkRect::MakeXYWH(10, 10, 100, 100));
18+
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
19+
}
20+
21+
TEST_F(DisplayListTest, CanDrawTextBlob) {
22+
flutter::DisplayListBuilder builder;
23+
builder.setColor(SK_ColorBLUE);
24+
builder.drawTextBlob(SkTextBlob::MakeFromString("Hello", CreateTestFont()),
25+
100, 100);
26+
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
27+
}
1128

1229
} // namespace testing
1330
} // namespace impeller

impeller/entity/contents/text_contents.cc

+27-6
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5-
#include "text_contents.h"
5+
#include "impeller/entity/contents/text_contents.h"
66

77
#include "impeller/entity/contents/content_context.h"
88
#include "impeller/entity/entity.h"
@@ -11,8 +11,10 @@
1111
#include "impeller/renderer/sampler_library.h"
1212
#include "impeller/tessellator/tessellator.h"
1313
#include "impeller/typographer/glyph_atlas.h"
14+
#include "impeller/typographer/lazy_glyph_atlas.h"
1415

1516
namespace impeller {
17+
1618
TextContents::TextContents() = default;
1719

1820
TextContents::~TextContents() = default;
@@ -25,6 +27,23 @@ void TextContents::SetGlyphAtlas(std::shared_ptr<GlyphAtlas> atlas) {
2527
atlas_ = std::move(atlas);
2628
}
2729

30+
void TextContents::SetGlyphAtlas(std::shared_ptr<LazyGlyphAtlas> atlas) {
31+
atlas_ = std::move(atlas);
32+
}
33+
34+
std::shared_ptr<GlyphAtlas> TextContents::ResolveAtlas(
35+
std::shared_ptr<Context> context) const {
36+
if (auto lazy_atlas = std::get_if<std::shared_ptr<LazyGlyphAtlas>>(&atlas_)) {
37+
return lazy_atlas->get()->CreateOrGetGlyphAtlas(context);
38+
}
39+
40+
if (auto atlas = std::get_if<std::shared_ptr<GlyphAtlas>>(&atlas_)) {
41+
return *atlas;
42+
}
43+
44+
return nullptr;
45+
}
46+
2847
void TextContents::SetColor(Color color) {
2948
color_ = color;
3049
}
@@ -36,7 +55,9 @@ bool TextContents::Render(const ContentContext& renderer,
3655
return true;
3756
}
3857

39-
if (!atlas_ || !atlas_->IsValid()) {
58+
auto atlas = ResolveAtlas(renderer.GetContext());
59+
60+
if (!atlas || !atlas->IsValid()) {
4061
VALIDATION_LOG << "Cannot render glyphs without prepared atlas.";
4162
return false;
4263
}
@@ -57,15 +78,15 @@ bool TextContents::Render(const ContentContext& renderer,
5778
frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
5879
entity.GetTransformation();
5980
frame_info.atlas_size =
60-
Point{static_cast<Scalar>(atlas_->GetTexture()->GetSize().width),
61-
static_cast<Scalar>(atlas_->GetTexture()->GetSize().height)};
81+
Point{static_cast<Scalar>(atlas->GetTexture()->GetSize().width),
82+
static_cast<Scalar>(atlas->GetTexture()->GetSize().height)};
6283
frame_info.text_color = ToVector(color_);
6384
VS::BindFrameInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frame_info));
6485

6586
// Common fragment uniforms for all glyphs.
6687
FS::BindGlyphAtlasSampler(
6788
cmd, // command
68-
atlas_->GetTexture(), // texture
89+
atlas->GetTexture(), // texture
6990
renderer.GetContext()->GetSamplerLibrary()->GetSampler({}) // sampler
7091
);
7192

@@ -107,7 +128,7 @@ bool TextContents::Render(const ContentContext& renderer,
107128
// Draw each glyph individually. This should probably be batched.
108129
for (const auto& glyph_position : run.GetGlyphPositions()) {
109130
FontGlyphPair font_glyph_pair{font, glyph_position.glyph};
110-
auto atlas_glyph_pos = atlas_->FindFontGlyphPosition(font_glyph_pair);
131+
auto atlas_glyph_pos = atlas->FindFontGlyphPosition(font_glyph_pair);
111132
if (!atlas_glyph_pos.has_value()) {
112133
VALIDATION_LOG << "Could not find glyph position in the atlas.";
113134
return false;

impeller/entity/contents/text_contents.h

+11-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include <functional>
88
#include <memory>
9+
#include <variant>
910
#include <vector>
1011

1112
#include "flutter/fml/macros.h"
@@ -16,6 +17,8 @@
1617
namespace impeller {
1718

1819
class GlyphAtlas;
20+
class LazyGlyphAtlas;
21+
class Context;
1922

2023
class TextContents final : public Contents {
2124
public:
@@ -27,6 +30,8 @@ class TextContents final : public Contents {
2730

2831
void SetGlyphAtlas(std::shared_ptr<GlyphAtlas> atlas);
2932

33+
void SetGlyphAtlas(std::shared_ptr<LazyGlyphAtlas> atlas);
34+
3035
void SetColor(Color color);
3136

3237
// |Contents|
@@ -37,7 +42,12 @@ class TextContents final : public Contents {
3742
private:
3843
TextFrame frame_;
3944
Color color_;
40-
std::shared_ptr<GlyphAtlas> atlas_;
45+
mutable std::variant<std::shared_ptr<GlyphAtlas>,
46+
std::shared_ptr<LazyGlyphAtlas>>
47+
atlas_;
48+
49+
std::shared_ptr<GlyphAtlas> ResolveAtlas(
50+
std::shared_ptr<Context> context) const;
4151

4252
FML_DISALLOW_COPY_AND_ASSIGN(TextContents);
4353
};

impeller/entity/entity_pass.cc

+4
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ size_t EntityPass::GetSubpassesDepth() const {
4444
return max_subpass_depth + 1u;
4545
}
4646

47+
const std::shared_ptr<LazyGlyphAtlas>& EntityPass::GetLazyGlyphAtlas() const {
48+
return lazy_glyph_atlas_;
49+
}
50+
4751
std::optional<Rect> EntityPass::GetEntitiesCoverage() const {
4852
std::optional<Rect> result;
4953
for (const auto& entity : entities_) {

impeller/entity/entity_pass.h

+5
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "impeller/entity/entity.h"
1414
#include "impeller/entity/entity_pass_delegate.h"
1515
#include "impeller/renderer/render_target.h"
16+
#include "impeller/typographer/lazy_glyph_atlas.h"
1617

1718
namespace impeller {
1819

@@ -41,6 +42,8 @@ class EntityPass {
4142

4243
const Subpasses& GetSubpasses() const;
4344

45+
const std::shared_ptr<LazyGlyphAtlas>& GetLazyGlyphAtlas() const;
46+
4447
EntityPass* AddSubpass(std::unique_ptr<EntityPass> pass);
4548

4649
EntityPass* GetSuperpass() const;
@@ -61,6 +64,8 @@ class EntityPass {
6164
size_t stencil_depth_ = 0u;
6265
std::unique_ptr<EntityPassDelegate> delegate_ =
6366
EntityPassDelegate::MakeDefault();
67+
std::shared_ptr<LazyGlyphAtlas> lazy_glyph_atlas_ =
68+
std::make_shared<LazyGlyphAtlas>();
6469

6570
std::optional<Rect> GetSubpassCoverage(const EntityPass& subpass) const;
6671

0 commit comments

Comments
 (0)