| Flutter Impeller |

text_contents_unittests.cc
Go to the documentation of this file.
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 "flutter/impeller/geometry/geometry_asserts.h"
6 #include "flutter/impeller/renderer/testing/mocks.h"
7 #include "flutter/testing/testing.h"
8 #include "impeller/entity/contents/text_contents.h"
9 #include "impeller/playground/playground_test.h"
10 #include "impeller/typographer/backends/skia/text_frame_skia.h"
11 #include "impeller/typographer/backends/skia/typographer_context_skia.h"
12 #include "third_party/googletest/googletest/include/gtest/gtest.h"
13 #include "txt/platform.h"
14
15 #pragma GCC diagnostic ignored "-Wunreachable-code"
16
17 namespace impeller {
18 namespace testing {
19
20 using TextContentsTest = PlaygroundTest;
21 INSTANTIATE_PLAYGROUND_SUITE(TextContentsTest);
22
23 using ::testing::Return;
24
25 namespace {
26 std::shared_ptr<TextFrame> MakeTextFrame(const std::string& text,
27 const std::string_view& font_fixture,
28 Scalar font_size) {
29 auto c_font_fixture = std::string(font_fixture);
30 auto mapping = flutter::testing::OpenFixtureAsSkData(c_font_fixture.c_str());
31 if (!mapping) {
32 return nullptr;
33 }
34 sk_sp<SkFontMgr> font_mgr = txt::GetDefaultFontManager();
35 SkFont sk_font(font_mgr->makeFromData(mapping), font_size);
36 auto blob = SkTextBlob::MakeFromString(text.c_str(), sk_font);
37 if (!blob) {
38 return nullptr;
39 }
40
41 return MakeTextFrameFromTextBlobSkia(blob);
42 }
43
44 std::shared_ptr<GlyphAtlas> CreateGlyphAtlas(
45 Context& context,
46 const TypographerContext* typographer_context,
47 HostBuffer& host_buffer,
48 GlyphAtlas::Type type,
49 Scalar scale,
50 const std::shared_ptr<GlyphAtlasContext>& atlas_context,
51 const std::shared_ptr<TextFrame>& frame) {
52 frame->SetPerFrameData(scale, /*offset=*/Point(0, 0),
53 /*transform=*/Matrix(), /*properties=*/std::nullopt);
54 return typographer_context->CreateGlyphAtlas(context, type, host_buffer,
55 atlas_context, {frame});
56 }
57
58 Rect PerVertexDataPositionToRect(
59 GlyphAtlasPipeline::VertexShader::PerVertexData data[6]) {
60 Scalar right = FLT_MIN;
61 Scalar left = FLT_MAX;
62 Scalar top = FLT_MAX;
63 Scalar bottom = FLT_MIN;
64 for (int i = 0; i < 6; ++i) {
65 right = std::max(right, data[i].position.x);
66 left = std::min(left, data[i].position.x);
67 top = std::min(top, data[i].position.y);
68 bottom = std::max(bottom, data[i].position.y);
69 }
70
71 return Rect::MakeLTRB(left, top, right, bottom);
72 }
73
74 Rect PerVertexDataUVToRect(
75 GlyphAtlasPipeline::VertexShader::PerVertexData data[6],
76 ISize texture_size) {
77 Scalar right = FLT_MIN;
78 Scalar left = FLT_MAX;
79 Scalar top = FLT_MAX;
80 Scalar bottom = FLT_MIN;
81 for (int i = 0; i < 6; ++i) {
82 right = std::max(right, data[i].uv.x * texture_size.width);
83 left = std::min(left, data[i].uv.x * texture_size.width);
84 top = std::min(top, data[i].uv.y * texture_size.height);
85 bottom = std::max(bottom, data[i].uv.y * texture_size.height);
86 }
87
88 return Rect::MakeLTRB(left, top, right, bottom);
89 }
90
91 double GetAspectRatio(Rect rect) {
92 return static_cast<double>(rect.GetWidth()) / rect.GetHeight();
93 }
94 } // namespace
95
96 TEST_P(TextContentsTest, SimpleComputeVertexData) {
97 #ifndef FML_OS_MACOSX
98 GTEST_SKIP() << "Results aren't stable across linux and macos.";
99 #endif
100
101 GlyphAtlasPipeline::VertexShader::PerVertexData data[6];
102
103 std::shared_ptr<TextFrame> text_frame =
104 MakeTextFrame("1", "ahem.ttf", /*font_size=*/50);
105
106 std::shared_ptr<TypographerContext> context = TypographerContextSkia::Make();
107 std::shared_ptr<GlyphAtlasContext> atlas_context =
108 context->CreateGlyphAtlasContext(GlyphAtlas::Type::kAlphaBitmap);
109 std::shared_ptr<HostBuffer> host_buffer = HostBuffer::Create(
110 GetContext()->GetResourceAllocator(), GetContext()->GetIdleWaiter());
111 ASSERT_TRUE(context && context->IsValid());
112 std::shared_ptr<GlyphAtlas> atlas =
113 CreateGlyphAtlas(*GetContext(), context.get(), *host_buffer,
114 GlyphAtlas::Type::kAlphaBitmap, /*scale=*/1.0f,
115 atlas_context, text_frame);
116
117 ISize texture_size = atlas->GetTexture()->GetSize();
118 TextContents::ComputeVertexData(data, text_frame, /*scale=*/1.0,
119 /*entity_transform=*/Matrix(),
120 /*offset=*/Vector2(0, 0),
121 /*glyph_properties=*/std::nullopt, atlas);
122
123 Rect position_rect = PerVertexDataPositionToRect(data);
124 Rect uv_rect = PerVertexDataUVToRect(data, texture_size);
125 // The -1 offset comes from Skia in `ComputeGlyphSize`. So since the font size
126 // is 50, the math appears to be to get back a 50x50 rect and apply 1 pixel
127 // of padding.
128 EXPECT_RECT_NEAR(position_rect, Rect::MakeXYWH(-1, -41, 52, 52));
129 EXPECT_RECT_NEAR(uv_rect, Rect::MakeXYWH(1.0, 1.0, 52, 52));
130 }
131
132 TEST_P(TextContentsTest, SimpleComputeVertexData2x) {
133 #ifndef FML_OS_MACOSX
134 GTEST_SKIP() << "Results aren't stable across linux and macos.";
135 #endif
136
137 GlyphAtlasPipeline::VertexShader::PerVertexData data[6];
138
139 std::shared_ptr<TextFrame> text_frame =
140 MakeTextFrame("1", "ahem.ttf", /*font_size=*/50);
141
142 std::shared_ptr<TypographerContext> context = TypographerContextSkia::Make();
143 std::shared_ptr<GlyphAtlasContext> atlas_context =
144 context->CreateGlyphAtlasContext(GlyphAtlas::Type::kAlphaBitmap);
145 std::shared_ptr<HostBuffer> host_buffer = HostBuffer::Create(
146 GetContext()->GetResourceAllocator(), GetContext()->GetIdleWaiter());
147 ASSERT_TRUE(context && context->IsValid());
148 Scalar font_scale = 2.f;
149 std::shared_ptr<GlyphAtlas> atlas = CreateGlyphAtlas(
150 *GetContext(), context.get(), *host_buffer,
151 GlyphAtlas::Type::kAlphaBitmap, font_scale, atlas_context, text_frame);
152
153 ISize texture_size = atlas->GetTexture()->GetSize();
154 TextContents::ComputeVertexData(
155 data, text_frame, font_scale,
156 /*entity_transform=*/Matrix::MakeScale({font_scale, font_scale, 1}),
157 /*offset=*/Vector2(0, 0),
158 /*glyph_properties=*/std::nullopt, atlas);
159
160 Rect position_rect = PerVertexDataPositionToRect(data);
161 Rect uv_rect = PerVertexDataUVToRect(data, texture_size);
162 EXPECT_RECT_NEAR(position_rect, Rect::MakeXYWH(-1, -81, 102, 102));
163 EXPECT_RECT_NEAR(uv_rect, Rect::MakeXYWH(1.0, 1.0, 102, 102));
164 }
165
166 TEST_P(TextContentsTest, MaintainsShape) {
167 std::shared_ptr<TextFrame> text_frame =
168 MakeTextFrame("th", "ahem.ttf", /*font_size=*/50);
169
170 std::shared_ptr<TypographerContext> context = TypographerContextSkia::Make();
171 std::shared_ptr<GlyphAtlasContext> atlas_context =
172 context->CreateGlyphAtlasContext(GlyphAtlas::Type::kAlphaBitmap);
173 std::shared_ptr<HostBuffer> host_buffer = HostBuffer::Create(
174 GetContext()->GetResourceAllocator(), GetContext()->GetIdleWaiter());
175 ASSERT_TRUE(context && context->IsValid());
176 for (int i = 0; i <= 1000; ++i) {
177 Scalar font_scale = 0.440 + (i / 1000.0);
178 Rect position_rect[2];
179 Rect uv_rect[2];
180
181 {
182 GlyphAtlasPipeline::VertexShader::PerVertexData data[12];
183 std::shared_ptr<GlyphAtlas> atlas =
184 CreateGlyphAtlas(*GetContext(), context.get(), *host_buffer,
185 GlyphAtlas::Type::kAlphaBitmap, font_scale,
186 atlas_context, text_frame);
187 ISize texture_size = atlas->GetTexture()->GetSize();
188
189 TextContents::ComputeVertexData(
190 data, text_frame, font_scale,
191 /*entity_transform=*/Matrix::MakeScale({font_scale, font_scale, 1}),
192 /*offset=*/Vector2(0, 0),
193 /*glyph_properties=*/std::nullopt, atlas);
194 position_rect[0] = PerVertexDataPositionToRect(data);
195 uv_rect[0] = PerVertexDataUVToRect(data, texture_size);
196 position_rect[1] = PerVertexDataPositionToRect(data + 6);
197 uv_rect[1] = PerVertexDataUVToRect(data + 6, texture_size);
198 }
199 EXPECT_NEAR(GetAspectRatio(position_rect[1]), GetAspectRatio(uv_rect[1]),
200 0.001)
201 << i;
202 }
203 }
204
205 } // namespace testing
206 } // namespace impeller
text_contents.h
impeller::ISize
ISize64 ISize
Definition: size.h:174
impeller::Scalar
float Scalar
Definition: scalar.h:18
impeller::GlyphAtlas::Type::kAlphaBitmap
@ kAlphaBitmap
geometry_asserts.h
playground_test.h
impeller::TRect< Scalar >::MakeXYWH
constexpr static TRect MakeXYWH(Type x, Type y, Type width, Type height)
Definition: rect.h:136
impeller::HostBuffer::Create
static std::shared_ptr< HostBuffer > Create(const std::shared_ptr< Allocator > &allocator, const std::shared_ptr< const IdleWaiter > &idle_waiter)
Definition: host_buffer.cc:21
data
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:64
impeller::Vector2
Point Vector2
Definition: point.h:331
EXPECT_RECT_NEAR
#define EXPECT_RECT_NEAR(a, b)
Definition: geometry_asserts.h:203
typographer_context_skia.h
impeller::testing::INSTANTIATE_PLAYGROUND_SUITE
INSTANTIATE_PLAYGROUND_SUITE(AiksTest)
text_frame_skia.h
impeller::TSize
Definition: size.h:25
impeller::Point
TPoint< Scalar > Point
Definition: point.h:327
impeller::TextContents::ComputeVertexData
static void ComputeVertexData(GlyphAtlasPipeline::VertexShader::PerVertexData *vtx_contents, const std::shared_ptr< TextFrame > &frame, Scalar scale, const Matrix &entity_transform, Vector2 offset, std::optional< GlyphProperties > glyph_properties, const std::shared_ptr< GlyphAtlas > &atlas)
Definition: text_contents.cc:80
impeller::GlyphAtlas::Type
Type
Describes how the glyphs are represented in the texture.
Definition: glyph_atlas.h:74
type
GLenum type
Definition: blit_command_gles.cc:151
impeller::Rect
TRect< Scalar > Rect
Definition: rect.h:792
impeller::MakeTextFrameFromTextBlobSkia
std::shared_ptr< TextFrame > MakeTextFrameFromTextBlobSkia(const sk_sp< SkTextBlob > &blob)
Definition: text_frame_skia.cc:42
impeller::testing::TEST_P
TEST_P(AiksTest, DrawAtlasNoColor)
Definition: aiks_dl_atlas_unittests.cc:57
impeller::testing::CreateGlyphAtlas
static std::shared_ptr< GlyphAtlas > CreateGlyphAtlas(Context &context, const TypographerContext *typographer_context, HostBuffer &host_buffer, GlyphAtlas::Type type, Scalar scale, const std::shared_ptr< GlyphAtlasContext > &atlas_context, const std::shared_ptr< TextFrame > &frame)
Definition: typographer_unittests.cc:32
scale
const Scalar scale
Definition: stroke_path_geometry.cc:316
impeller::TRect< Scalar >::MakeLTRB
constexpr static TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
Definition: rect.h:129
impeller::PlaygroundTest
Definition: playground_test.h:21
impeller
Definition: allocation.cc:12
impeller::Matrix::MakeScale
static constexpr Matrix MakeScale(const Vector3 &s)
Definition: matrix.h:104
impeller::TypographerContextSkia::Make
static std::shared_ptr< TypographerContext > Make()
Definition: typographer_context_skia.cc:77
impeller::TRect
Definition: rect.h:122
impeller::Matrix
A 4x4 matrix using column-major storage.
Definition: matrix.h:37