Skip to content

Commit 0dae5ad

Browse files
chinmaygardednfield
authored andcommitted
Add //impeller/typographer. (flutter#36)
Renders shaped text frames. Has the ability to plug into to different text shapers and render glyphs using different techniques. For now, the Aiks layer expects a prepared glyph atlas. But this will be changed so that render pass will be responsible for preparing these and setting these on the content renderer after pass consolidation.
1 parent 451f93e commit 0dae5ad

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+1778
-23
lines changed

impeller/BUILD.gn

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ group("impeller") {
2121
"geometry",
2222
"image",
2323
"renderer",
24+
"typographer",
2425
]
2526

2627
if (is_host) {
@@ -43,5 +44,6 @@ executable("impeller_unittests") {
4344
"image:image_unittests",
4445
"playground",
4546
"renderer:renderer_unittests",
47+
"typographer:typographer_unittests",
4648
]
4749
}

impeller/aiks/aiks_unittests.cc

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
#include "impeller/aiks/image.h"
99
#include "impeller/geometry/geometry_unittests.h"
1010
#include "impeller/geometry/path_builder.h"
11+
#include "impeller/typographer/backends/skia/text_frame_skia.h"
12+
#include "impeller/typographer/backends/skia/text_render_context_skia.h"
13+
#include "third_party/skia/include/core/SkData.h"
1114

1215
namespace impeller {
1316
namespace testing {
@@ -283,5 +286,114 @@ TEST_F(AiksTest, CanRenderDifferencePaths) {
283286
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
284287
}
285288

289+
static sk_sp<SkData> OpenFixtureAsSkData(const char* fixture_name) {
290+
auto mapping = flutter::testing::OpenFixtureAsMapping(fixture_name);
291+
if (!mapping) {
292+
return nullptr;
293+
}
294+
return SkData::MakeWithProc(
295+
mapping->GetMapping(), mapping->GetSize(),
296+
[](const void* ptr, void* context) {
297+
delete reinterpret_cast<fml::Mapping*>(context);
298+
},
299+
mapping.release());
300+
}
301+
302+
TEST_F(AiksTest, CanRenderTextFrame) {
303+
Canvas canvas;
304+
305+
Scalar baseline = 200.0;
306+
Point text_position = {100, baseline};
307+
308+
// Draw the baseline.
309+
canvas.DrawRect({50, baseline, 900, 10},
310+
Paint{.color = Color::Aqua().WithAlpha(0.25)});
311+
312+
// Mark the point at which the text is drawn.
313+
canvas.DrawCircle(text_position, 5.0,
314+
Paint{.color = Color::Red().WithAlpha(0.25)});
315+
316+
// Construct the text blob.
317+
auto mapping = OpenFixtureAsSkData("Roboto-Regular.ttf");
318+
ASSERT_TRUE(mapping);
319+
SkFont sk_font(SkTypeface::MakeFromData(mapping), 50.0);
320+
auto blob = SkTextBlob::MakeFromString(
321+
"the quick brown fox jumped over the lazy dog!.?", sk_font);
322+
ASSERT_TRUE(blob);
323+
324+
// Create the Impeller text frame and draw it at the designated baseline.
325+
auto frame = TextFrameFromTextBlob(blob);
326+
TextRenderContextSkia text_context(GetContext());
327+
ASSERT_TRUE(text_context.IsValid());
328+
auto atlas = text_context.CreateGlyphAtlas(frame);
329+
ASSERT_NE(atlas, nullptr);
330+
canvas.DrawTextFrame(std::move(frame), std::move(atlas), text_position);
331+
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
332+
}
333+
334+
TEST_F(AiksTest, CanRenderItalicizedText) {
335+
Canvas canvas;
336+
337+
Scalar baseline = 200.0;
338+
Point text_position = {100, baseline};
339+
340+
// Draw the baseline.
341+
canvas.DrawRect({50, baseline, 900, 10},
342+
Paint{.color = Color::Aqua().WithAlpha(0.25)});
343+
344+
// Mark the point at which the text is drawn.
345+
canvas.DrawCircle(text_position, 5.0,
346+
Paint{.color = Color::Red().WithAlpha(0.25)});
347+
348+
// Construct the text blob.
349+
auto mapping = OpenFixtureAsSkData("HomemadeApple.ttf");
350+
ASSERT_TRUE(mapping);
351+
SkFont sk_font(SkTypeface::MakeFromData(mapping), 50.0);
352+
auto blob = SkTextBlob::MakeFromString(
353+
"the quick brown fox jumped over the lazy dog!.?", sk_font);
354+
ASSERT_TRUE(blob);
355+
356+
// Create the Impeller text frame and draw it at the designated baseline.
357+
auto frame = TextFrameFromTextBlob(blob);
358+
TextRenderContextSkia text_context(GetContext());
359+
ASSERT_TRUE(text_context.IsValid());
360+
auto atlas = text_context.CreateGlyphAtlas(frame);
361+
ASSERT_NE(atlas, nullptr);
362+
canvas.DrawTextFrame(std::move(frame), std::move(atlas), text_position);
363+
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
364+
}
365+
366+
TEST_F(AiksTest, CanRenderEmojiTextFrame) {
367+
Canvas canvas;
368+
369+
Scalar baseline = 200.0;
370+
Point text_position = {100, baseline};
371+
372+
// Draw the baseline.
373+
canvas.DrawRect({50, baseline, 900, 10},
374+
Paint{.color = Color::Aqua().WithAlpha(0.25)});
375+
376+
// Mark the point at which the text is drawn.
377+
canvas.DrawCircle(text_position, 5.0,
378+
Paint{.color = Color::Red().WithAlpha(0.25)});
379+
380+
// Construct the text blob.
381+
auto mapping = OpenFixtureAsSkData("NotoColorEmoji.ttf");
382+
ASSERT_TRUE(mapping);
383+
SkFont sk_font(SkTypeface::MakeFromData(mapping), 50.0);
384+
auto blob = SkTextBlob::MakeFromString(
385+
"😀 😃 😄 😁 😆 😅 😂 🤣 🥲 ☺️ 😊", sk_font);
386+
ASSERT_TRUE(blob);
387+
388+
// Create the Impeller text frame and draw it at the designated baseline.
389+
auto frame = TextFrameFromTextBlob(blob);
390+
TextRenderContextSkia text_context(GetContext());
391+
ASSERT_TRUE(text_context.IsValid());
392+
auto atlas = text_context.CreateGlyphAtlas(frame);
393+
ASSERT_NE(atlas, nullptr);
394+
canvas.DrawTextFrame(std::move(frame), std::move(atlas), text_position);
395+
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
396+
}
397+
286398
} // namespace testing
287399
} // namespace impeller

impeller/aiks/canvas.cc

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,4 +252,25 @@ void Canvas::Save(bool create_subpass) {
252252
xformation_stack_.emplace_back(std::move(entry));
253253
}
254254

255+
void Canvas::DrawTextFrame(TextFrame text_frame,
256+
std::shared_ptr<GlyphAtlas> atlas,
257+
Point position) {
258+
if (!atlas || !atlas->IsValid()) {
259+
return;
260+
}
261+
262+
auto text_contents = std::make_shared<TextContents>();
263+
text_contents->SetTextFrame(std::move(text_frame));
264+
text_contents->SetGlyphAtlas(std::move(atlas));
265+
266+
Entity entity;
267+
entity.SetTransformation(GetCurrentTransformation() *
268+
Matrix::MakeTranslation(position));
269+
entity.SetPath({});
270+
entity.SetStencilDepth(GetStencilDepth());
271+
entity.SetContents(std::move(text_contents));
272+
273+
GetCurrentPass().AddEntity(std::move(entity));
274+
}
275+
255276
} // namespace impeller

impeller/aiks/canvas.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "impeller/geometry/path.h"
1919
#include "impeller/geometry/point.h"
2020
#include "impeller/geometry/vector.h"
21+
#include "impeller/typographer/text_frame.h"
2122

2223
namespace impeller {
2324

@@ -74,6 +75,10 @@ class Canvas {
7475

7576
void DrawPicture(Picture picture);
7677

78+
void DrawTextFrame(TextFrame text_frame,
79+
std::shared_ptr<GlyphAtlas> atlas,
80+
Point position);
81+
7782
Picture EndRecordingAsPicture();
7883

7984
private:

impeller/aiks/paint.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
namespace impeller {
88

99
std::shared_ptr<Contents> Paint::CreateContentsForEntity() const {
10+
if (contents) {
11+
return contents;
12+
}
13+
1014
switch (style) {
1115
case Style::kFill: {
1216
auto solid_color = std::make_shared<SolidColorContents>();

impeller/aiks/paint.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ struct Paint {
2121
Color color = Color::Black();
2222
Scalar stroke_width = 0.0;
2323
Style style = Style::kFill;
24+
std::shared_ptr<Contents> contents;
2425

2526
std::shared_ptr<Contents> CreateContentsForEntity() const;
2627
};

impeller/base/BUILD.gn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ impeller_component("base") {
88
sources = [
99
"allocation.cc",
1010
"allocation.h",
11+
"backend_cast.h",
1112
"base.h",
1213
"config.h",
1314
"promise.cc",

impeller/base/allocation.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ bool Allocation::Truncate(size_t length, bool npot) {
3838
return true;
3939
}
4040

41-
static uint32_t NextPowerOfTwoSize(uint32_t x) {
41+
uint32_t Allocation::NextPowerOfTwoSize(uint32_t x) {
4242
if (x == 0) {
4343
return 1;
4444
}

impeller/base/allocation.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ class Allocation {
2525

2626
[[nodiscard]] bool Truncate(size_t length, bool npot = true);
2727

28+
static uint32_t NextPowerOfTwoSize(uint32_t x);
29+
2830
private:
2931
uint8_t* buffer_ = nullptr;
3032
size_t length_ = 0;
File renamed without changes.

0 commit comments

Comments
 (0)