Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit f39f4e9

Browse files
committed
Engine-fy, upgrade to head, add TextFrame shaper factory, and add Aiks test
1 parent 2bd9d97 commit f39f4e9

File tree

13 files changed

+401
-471
lines changed

13 files changed

+401
-471
lines changed

impeller/aiks/aiks_unittests.cc

Lines changed: 77 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@
3737
#include "impeller/scene/node.h"
3838
#include "impeller/typographer/backends/skia/text_frame_skia.h"
3939
#include "impeller/typographer/backends/skia/text_render_context_skia.h"
40+
#include "impeller/typographer/backends/stb/text_frame_stb.h"
41+
#include "impeller/typographer/backends/stb/text_render_context_stb.h"
42+
#include "impeller/typographer/backends/stb/typeface_stb.h"
4043
#include "third_party/imgui/imgui.h"
4144
#include "third_party/skia/include/core/SkData.h"
4245

@@ -1249,11 +1252,11 @@ struct TextRenderOptions {
12491252
Point position = Vector2(100, 200);
12501253
};
12511254

1252-
bool RenderTextInCanvas(const std::shared_ptr<Context>& context,
1253-
Canvas& canvas,
1254-
const std::string& text,
1255-
const std::string& font_fixture,
1256-
TextRenderOptions options = {}) {
1255+
bool RenderTextInCanvasSkia(const std::shared_ptr<Context>& context,
1256+
Canvas& canvas,
1257+
const std::string& text,
1258+
const std::string& font_fixture,
1259+
TextRenderOptions options = {}) {
12571260
// Draw the baseline.
12581261
canvas.DrawRect({options.position.x - 50, options.position.y, 900, 10},
12591262
Paint{.color = Color::Aqua().WithAlpha(0.25)});
@@ -1274,7 +1277,36 @@ bool RenderTextInCanvas(const std::shared_ptr<Context>& context,
12741277
}
12751278

12761279
// Create the Impeller text frame and draw it at the designated baseline.
1277-
auto frame = TextFrameFromTextBlob(blob);
1280+
auto frame = MakeTextFrameFromTextBlobSkia(blob);
1281+
1282+
Paint text_paint;
1283+
text_paint.color = Color::Yellow().WithAlpha(options.alpha);
1284+
canvas.DrawTextFrame(frame, options.position, text_paint);
1285+
return true;
1286+
}
1287+
1288+
bool RenderTextInCanvasSTB(const std::shared_ptr<Context>& context,
1289+
Canvas& canvas,
1290+
const std::string& text,
1291+
const std::string& font_fixture,
1292+
TextRenderOptions options = {}) {
1293+
// Draw the baseline.
1294+
canvas.DrawRect({options.position.x - 50, options.position.y, 900, 10},
1295+
Paint{.color = Color::Aqua().WithAlpha(0.25)});
1296+
1297+
// Mark the point at which the text is drawn.
1298+
canvas.DrawCircle(options.position, 5.0,
1299+
Paint{.color = Color::Red().WithAlpha(0.25)});
1300+
1301+
// Construct the text blob.
1302+
auto mapping = flutter::testing::OpenFixtureAsMapping(font_fixture.c_str());
1303+
if (!mapping) {
1304+
return false;
1305+
}
1306+
auto typeface_stb = std::make_shared<TypefaceSTB>(std::move(mapping));
1307+
1308+
auto frame = MakeTextFrameSTB(
1309+
typeface_stb, Font::Metrics{.point_size = options.font_size}, text);
12781310

12791311
Paint text_paint;
12801312
text_paint.color = Color::Yellow().WithAlpha(options.alpha);
@@ -1285,12 +1317,22 @@ bool RenderTextInCanvas(const std::shared_ptr<Context>& context,
12851317
TEST_P(AiksTest, CanRenderTextFrame) {
12861318
Canvas canvas;
12871319
canvas.DrawPaint({.color = Color(0.1, 0.1, 0.1, 1.0)});
1288-
ASSERT_TRUE(RenderTextInCanvas(
1320+
ASSERT_TRUE(RenderTextInCanvasSkia(
12891321
GetContext(), canvas, "the quick brown fox jumped over the lazy dog!.?",
12901322
"Roboto-Regular.ttf"));
12911323
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
12921324
}
12931325

1326+
TEST_P(AiksTest, CanRenderTextFrameSTB) {
1327+
Canvas canvas;
1328+
canvas.DrawPaint({.color = Color(0.1, 0.1, 0.1, 1.0)});
1329+
ASSERT_TRUE(RenderTextInCanvasSTB(
1330+
GetContext(), canvas, "the quick brown fox jumped over the lazy dog!.?",
1331+
"Roboto-Regular.ttf"));
1332+
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture(),
1333+
TextRenderContextSTB::Make()));
1334+
}
1335+
12941336
TEST_P(AiksTest, TextFrameSubpixelAlignment) {
12951337
std::array<Scalar, 20> phase_offsets;
12961338
for (Scalar& offset : phase_offsets) {
@@ -1320,11 +1362,12 @@ TEST_P(AiksTest, TextFrameSubpixelAlignment) {
13201362
GetSecondsElapsed() * speed)), //
13211363
200 + i * font_size * 1.1 //
13221364
);
1323-
if (!RenderTextInCanvas(GetContext(), canvas,
1324-
"the quick brown fox jumped over "
1325-
"the lazy dog!.?",
1326-
"Roboto-Regular.ttf",
1327-
{.font_size = font_size, .position = position})) {
1365+
if (!RenderTextInCanvasSkia(
1366+
GetContext(), canvas,
1367+
"the quick brown fox jumped over "
1368+
"the lazy dog!.?",
1369+
"Roboto-Regular.ttf",
1370+
{.font_size = font_size, .position = position})) {
13281371
return false;
13291372
}
13301373
}
@@ -1338,7 +1381,7 @@ TEST_P(AiksTest, CanRenderItalicizedText) {
13381381
Canvas canvas;
13391382
canvas.DrawPaint({.color = Color(0.1, 0.1, 0.1, 1.0)});
13401383

1341-
ASSERT_TRUE(RenderTextInCanvas(
1384+
ASSERT_TRUE(RenderTextInCanvasSkia(
13421385
GetContext(), canvas, "the quick brown fox jumped over the lazy dog!.?",
13431386
"HomemadeApple.ttf"));
13441387
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
@@ -1348,12 +1391,12 @@ TEST_P(AiksTest, CanRenderEmojiTextFrame) {
13481391
Canvas canvas;
13491392
canvas.DrawPaint({.color = Color(0.1, 0.1, 0.1, 1.0)});
13501393

1351-
ASSERT_TRUE(RenderTextInCanvas(GetContext(), canvas,
1352-
"😀 😃 😄 😁 😆 😅 😂 🤣 🥲 😊",
1394+
ASSERT_TRUE(RenderTextInCanvasSkia(GetContext(), canvas,
1395+
"😀 😃 😄 😁 😆 😅 😂 🤣 🥲 😊",
13531396
#if FML_OS_MACOSX
1354-
"Apple Color Emoji.ttc"));
1397+
"Apple Color Emoji.ttc"));
13551398
#else
1356-
"NotoColorEmoji.ttf"));
1399+
"NotoColorEmoji.ttf"));
13571400
#endif
13581401
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
13591402
}
@@ -1362,14 +1405,14 @@ TEST_P(AiksTest, CanRenderEmojiTextFrameWithAlpha) {
13621405
Canvas canvas;
13631406
canvas.DrawPaint({.color = Color(0.1, 0.1, 0.1, 1.0)});
13641407

1365-
ASSERT_TRUE(RenderTextInCanvas(GetContext(), canvas,
1366-
"😀 😃 😄 😁 😆 😅 😂 🤣 🥲 😊",
1408+
ASSERT_TRUE(RenderTextInCanvasSkia(GetContext(), canvas,
1409+
"😀 😃 😄 😁 😆 😅 😂 🤣 🥲 😊",
13671410
#if FML_OS_MACOSX
1368-
"Apple Color Emoji.ttc", { .alpha = 0.5 }
1411+
"Apple Color Emoji.ttc", { .alpha = 0.5 }
13691412
#else
1370-
"NotoColorEmoji.ttf", {.alpha = 0.5}
1413+
"NotoColorEmoji.ttf", {.alpha = 0.5}
13711414
#endif
1372-
));
1415+
));
13731416
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
13741417
}
13751418

@@ -1382,13 +1425,13 @@ TEST_P(AiksTest, CanRenderTextInSaveLayer) {
13821425

13831426
// Blend the layer with the parent pass using kClear to expose the coverage.
13841427
canvas.SaveLayer({.blend_mode = BlendMode::kClear});
1385-
ASSERT_TRUE(RenderTextInCanvas(
1428+
ASSERT_TRUE(RenderTextInCanvasSkia(
13861429
GetContext(), canvas, "the quick brown fox jumped over the lazy dog!.?",
13871430
"Roboto-Regular.ttf"));
13881431
canvas.Restore();
13891432

13901433
// Render the text again over the cleared coverage rect.
1391-
ASSERT_TRUE(RenderTextInCanvas(
1434+
ASSERT_TRUE(RenderTextInCanvasSkia(
13921435
GetContext(), canvas, "the quick brown fox jumped over the lazy dog!.?",
13931436
"Roboto-Regular.ttf"));
13941437

@@ -1423,7 +1466,7 @@ TEST_P(AiksTest, CanRenderTextOutsideBoundaries) {
14231466
{
14241467
auto blob = SkTextBlob::MakeFromString(t.text, sk_font);
14251468
ASSERT_NE(blob, nullptr);
1426-
auto frame = TextFrameFromTextBlob(blob);
1469+
auto frame = MakeTextFrameFromTextBlobSkia(blob);
14271470
canvas.DrawTextFrame(frame, Point(), text_paint);
14281471
}
14291472
canvas.Restore();
@@ -1441,7 +1484,7 @@ TEST_P(AiksTest, TextRotated) {
14411484
0, 0.5, 0, 0, //
14421485
0, 0, 0.3, 0, //
14431486
100, 100, 0, 1.3));
1444-
ASSERT_TRUE(RenderTextInCanvas(
1487+
ASSERT_TRUE(RenderTextInCanvasSkia(
14451488
GetContext(), canvas, "the quick brown fox jumped over the lazy dog!.?",
14461489
"Roboto-Regular.ttf"));
14471490

@@ -3011,7 +3054,7 @@ TEST_P(AiksTest, TextForegroundShaderWithTransform) {
30113054

30123055
auto blob = SkTextBlob::MakeFromString("Hello", sk_font);
30133056
ASSERT_NE(blob, nullptr);
3014-
auto frame = TextFrameFromTextBlob(blob);
3057+
auto frame = MakeTextFrameFromTextBlobSkia(blob);
30153058
canvas.DrawTextFrame(frame, Point(), text_paint);
30163059

30173060
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
@@ -3033,12 +3076,12 @@ TEST_P(AiksTest, CanCanvasDrawPicture) {
30333076

30343077
TEST_P(AiksTest, DrawPictureWithText) {
30353078
Canvas subcanvas;
3036-
ASSERT_TRUE(RenderTextInCanvas(
3079+
ASSERT_TRUE(RenderTextInCanvasSkia(
30373080
GetContext(), subcanvas,
30383081
"the quick brown fox jumped over the lazy dog!.?", "Roboto-Regular.ttf"));
30393082
subcanvas.Translate({0, 10});
30403083
subcanvas.Scale(Vector2(3, 3));
3041-
ASSERT_TRUE(RenderTextInCanvas(
3084+
ASSERT_TRUE(RenderTextInCanvasSkia(
30423085
GetContext(), subcanvas,
30433086
"the quick brown fox jumped over the very big lazy dog!.?",
30443087
"Roboto-Regular.ttf"));
@@ -3053,7 +3096,7 @@ TEST_P(AiksTest, DrawPictureWithText) {
30533096
canvas.Restore();
30543097

30553098
canvas.Scale(Vector2(1.5, 1.5));
3056-
ASSERT_TRUE(RenderTextInCanvas(
3099+
ASSERT_TRUE(RenderTextInCanvasSkia(
30573100
GetContext(), canvas,
30583101
"the quick brown fox jumped over the smaller lazy dog!.?",
30593102
"Roboto-Regular.ttf"));
@@ -3181,8 +3224,8 @@ TEST_P(AiksTest, DrawScaledTextWithPerspectiveNoSaveLayer) {
31813224
));
31823225
// clang-format on
31833226

3184-
ASSERT_TRUE(RenderTextInCanvas(GetContext(), canvas, "Hello world",
3185-
"Roboto-Regular.ttf"));
3227+
ASSERT_TRUE(RenderTextInCanvasSkia(GetContext(), canvas, "Hello world",
3228+
"Roboto-Regular.ttf"));
31863229

31873230
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
31883231
}
@@ -3200,8 +3243,8 @@ TEST_P(AiksTest, DrawScaledTextWithPerspectiveSaveLayer) {
32003243
));
32013244
// clang-format on
32023245

3203-
ASSERT_TRUE(RenderTextInCanvas(GetContext(), canvas, "Hello world",
3204-
"Roboto-Regular.ttf"));
3246+
ASSERT_TRUE(RenderTextInCanvasSkia(GetContext(), canvas, "Hello world",
3247+
"Roboto-Regular.ttf"));
32053248
}
32063249

32073250
TEST_P(AiksTest, PipelineBlendSingleParameter) {

impeller/display_list/dl_dispatcher.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1108,7 +1108,7 @@ void DlDispatcher::drawDisplayList(
11081108
void DlDispatcher::drawTextBlob(const sk_sp<SkTextBlob> blob,
11091109
SkScalar x,
11101110
SkScalar y) {
1111-
const auto text_frame = TextFrameFromTextBlob(blob);
1111+
const auto text_frame = MakeTextFrameFromTextBlobSkia(blob);
11121112
if (paint_.style == Paint::Style::kStroke) {
11131113
auto path = skia_conversions::PathDataFromTextBlob(blob);
11141114
auto bounds = text_frame.GetBounds();

impeller/entity/entity_unittests.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2174,7 +2174,7 @@ TEST_P(EntityTest, InheritOpacityTest) {
21742174
SkFont font;
21752175
font.setSize(30);
21762176
auto blob = SkTextBlob::MakeFromString("A", font);
2177-
auto frame = TextFrameFromTextBlob(blob);
2177+
auto frame = MakeTextFrameFromTextBlobSkia(blob);
21782178
auto lazy_glyph_atlas =
21792179
std::make_shared<LazyGlyphAtlas>(TextRenderContextSkia::Make());
21802180
lazy_glyph_atlas->AddTextFrame(frame, 1.0f);

impeller/typographer/backends/skia/text_frame_skia.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ static Rect ToRect(const SkRect& rect) {
3939

4040
static constexpr Scalar kScaleSize = 100000.0f;
4141

42-
TextFrame TextFrameFromTextBlob(const sk_sp<SkTextBlob>& blob) {
42+
TextFrame MakeTextFrameFromTextBlobSkia(const sk_sp<SkTextBlob>& blob) {
4343
if (!blob) {
4444
return {};
4545
}

impeller/typographer/backends/skia/text_frame_skia.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@
1010

1111
namespace impeller {
1212

13-
TextFrame TextFrameFromTextBlob(const sk_sp<SkTextBlob>& blob);
13+
TextFrame MakeTextFrameFromTextBlobSkia(const sk_sp<SkTextBlob>& blob);
1414

1515
} // namespace impeller

impeller/typographer/backends/stb/BUILD.gn

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ impeller_component("typographer_stb_backend") {
88
testonly = true
99

1010
sources = [
11+
"text_frame_stb.cc",
12+
"text_frame_stb.h",
1113
"text_render_context_stb.cc",
1214
"text_render_context_stb.h",
1315
"typeface_stb.cc",
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
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/typographer/backends/stb/text_frame_stb.h"
6+
7+
#include "impeller/typographer/font.h"
8+
9+
namespace impeller {
10+
11+
TextFrame MakeTextFrameSTB(const std::shared_ptr<TypefaceSTB>& typeface_stb,
12+
Font::Metrics metrics,
13+
const std::string& text) {
14+
TextRun run(Font(typeface_stb, metrics));
15+
16+
// Shape the text run using STB. The glyph positions could also be resolved
17+
// using a more advanced text shaper such as harfbuzz.
18+
19+
float scale = stbtt_ScaleForPixelHeight(
20+
typeface_stb->GetFontInfo(),
21+
metrics.point_size * TypefaceSTB::kPointsToPixels);
22+
23+
int ascent, descent, line_gap;
24+
stbtt_GetFontVMetrics(typeface_stb->GetFontInfo(), &ascent, &descent,
25+
&line_gap);
26+
ascent = std::round(ascent * scale);
27+
descent = std::round(descent * scale);
28+
29+
float x = 0;
30+
for (size_t i = 0; i < text.size(); i++) {
31+
int glyph_index =
32+
stbtt_FindGlyphIndex(typeface_stb->GetFontInfo(), text[i]);
33+
34+
int x0, y0, x1, y1;
35+
stbtt_GetGlyphBitmapBox(typeface_stb->GetFontInfo(), glyph_index, scale,
36+
scale, &x0, &y0, &x1, &y1);
37+
float y = y0;
38+
39+
int advance_width;
40+
int left_side_bearing;
41+
stbtt_GetGlyphHMetrics(typeface_stb->GetFontInfo(), glyph_index,
42+
&advance_width, &left_side_bearing);
43+
44+
Glyph glyph(glyph_index, Glyph::Type::kPath,
45+
Rect::MakeXYWH(0, 0, x1 - x0, y1 - y0));
46+
run.AddGlyph(glyph, {x + (left_side_bearing * scale), y});
47+
48+
if (i + 1 < text.size()) {
49+
int kerning = stbtt_GetCodepointKernAdvance(typeface_stb->GetFontInfo(),
50+
text[i], text[i + 1]);
51+
x += std::round((advance_width + kerning) * scale);
52+
}
53+
}
54+
55+
TextFrame frame;
56+
frame.AddTextRun(run);
57+
58+
return frame;
59+
}
60+
61+
} // namespace impeller
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
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/fml/macros.h"
8+
#include "impeller/typographer/backends/stb/typeface_stb.h"
9+
#include "impeller/typographer/text_frame.h"
10+
11+
namespace impeller {
12+
13+
TextFrame MakeTextFrameSTB(const std::shared_ptr<TypefaceSTB>& typeface_stb,
14+
Font::Metrics metrics,
15+
const std::string& text);
16+
17+
} // namespace impeller

0 commit comments

Comments
 (0)