5 #include "flutter/display_list/testing/dl_test_snippets.h"
6 #include "flutter/testing/testing.h"
7 #include "gtest/gtest.h"
16 #include "third_party/skia/include/core/SkFont.h"
17 #include "third_party/skia/include/core/SkFontMgr.h"
18 #include "third_party/skia/include/core/SkRect.h"
19 #include "third_party/skia/include/core/SkTextBlob.h"
20 #include "third_party/skia/include/core/SkTypeface.h"
21 #include "txt/platform.h"
38 const std::shared_ptr<GlyphAtlasContext>& atlas_context,
39 const std::shared_ptr<TextFrame>& frame) {
40 frame->SetPerFrameData(scale, {0, 0},
Matrix(), std::nullopt);
42 atlas_context, {frame});
51 const std::shared_ptr<GlyphAtlasContext>& atlas_context,
52 const std::vector<std::shared_ptr<TextFrame>>& frames,
53 const std::vector<std::optional<GlyphProperties>>& properties) {
55 for (
auto& frame : frames) {
56 frame->SetPerFrameData(scale, {0, 0},
Matrix(), properties[offset++]);
59 atlas_context, frames);
63 SkFont font = flutter::testing::CreateTestFontOfSize(12);
64 auto blob = SkTextBlob::MakeFromString(
65 "the quick brown fox jumped over the lazy dog.", font);
68 ASSERT_EQ(frame->GetRunCount(), 1u);
69 for (
const auto& run : frame->GetRuns()) {
70 ASSERT_TRUE(run.IsValid());
71 ASSERT_EQ(run.GetGlyphCount(), 45u);
77 ASSERT_TRUE(context && context->IsValid());
85 GetContext()->GetResourceAllocator(), GetContext()->GetIdleWaiter(),
86 GetContext()->GetCapabilities()->GetMinimumUniformAlignment());
87 ASSERT_TRUE(context && context->IsValid());
88 SkFont sk_font = flutter::testing::CreateTestFontOfSize(12);
89 auto blob = SkTextBlob::MakeFromString(
"hello", sk_font);
96 ASSERT_NE(atlas,
nullptr);
97 ASSERT_NE(atlas->GetTexture(),
nullptr);
99 ASSERT_EQ(atlas->GetGlyphCount(), 4llu);
101 std::optional<impeller::ScaledFont> first_scaled_font;
102 std::optional<impeller::SubpixelGlyph> first_glyph;
104 atlas->IterateGlyphs([&](
const ScaledFont& scaled_font,
106 const Rect& rect) ->
bool {
107 first_scaled_font = scaled_font;
113 ASSERT_TRUE(first_scaled_font.has_value());
115 ->FindFontGlyphBounds(
116 {first_scaled_font.value(), first_glyph.value()})
122 GetContext()->GetResourceAllocator(), GetContext()->GetIdleWaiter(),
123 GetContext()->GetCapabilities()->GetMinimumUniformAlignment());
125 auto mapping = flutter::testing::OpenFixtureAsSkData(
"Apple Color Emoji.ttc");
127 auto mapping = flutter::testing::OpenFixtureAsSkData(
"NotoColorEmoji.ttf");
129 ASSERT_TRUE(mapping);
130 sk_sp<SkFontMgr> font_mgr = txt::GetDefaultFontManager();
131 SkFont emoji_font(font_mgr->makeFromData(mapping), 50.0);
132 SkFont sk_font = flutter::testing::CreateTestFontOfSize(12);
134 auto blob = SkTextBlob::MakeFromString(
"hello", sk_font);
145 SkTextBlob::MakeFromString(
"😀 ", emoji_font));
158 ASSERT_FALSE(color_atlas == bitmap_atlas);
166 GetContext()->GetResourceAllocator(), GetContext()->GetIdleWaiter(),
167 GetContext()->GetCapabilities()->GetMinimumUniformAlignment());
168 ASSERT_TRUE(context && context->IsValid());
169 SkFont sk_font = flutter::testing::CreateTestFontOfSize(12);
170 auto blob = SkTextBlob::MakeFromString(
"AGH", sk_font);
176 ASSERT_NE(atlas,
nullptr);
177 ASSERT_NE(atlas->GetTexture(),
nullptr);
179 EXPECT_EQ(atlas->GetTexture()->GetSize().width, 4096u);
180 EXPECT_EQ(atlas->GetTexture()->GetSize().height, 1024u);
188 GetContext()->GetResourceAllocator(), GetContext()->GetIdleWaiter(),
189 GetContext()->GetCapabilities()->GetMinimumUniformAlignment());
190 ASSERT_TRUE(context && context->IsValid());
191 SkFont sk_font = flutter::testing::CreateTestFontOfSize(12);
192 auto blob = SkTextBlob::MakeFromString(
"spooky skellingtons", sk_font);
198 ASSERT_NE(atlas,
nullptr);
199 ASSERT_NE(atlas->GetTexture(),
nullptr);
200 ASSERT_EQ(atlas, atlas_context->GetGlyphAtlas());
208 ASSERT_EQ(atlas, next_atlas);
209 ASSERT_EQ(atlas_context->GetGlyphAtlas(), atlas);
214 GetContext()->GetResourceAllocator(), GetContext()->GetIdleWaiter(),
215 GetContext()->GetCapabilities()->GetMinimumUniformAlignment());
219 ASSERT_TRUE(context && context->IsValid());
221 const char* test_string =
222 "QWERTYUIOPASDFGHJKLZXCVBNMqewrtyuiopasdfghjklzxcvbnm,.<>[]{};':"
223 "2134567890-=!@#$%^&*()_+"
224 "œ∑´®†¥¨ˆøπ““‘‘åß∂ƒ©˙∆˚¬…æ≈ç√∫˜µ≤≥≥≥≥÷¡™£¢∞§¶•ªº–≠⁄€‹›fifl‡°·‚—±Œ„´‰Á¨Ø∏”’/"
227 SkFont sk_font = flutter::testing::CreateTestFontOfSize(12);
228 auto blob = SkTextBlob::MakeFromString(test_string, sk_font);
231 size_t size_count = 8;
232 std::vector<std::shared_ptr<TextFrame>> frames;
233 for (
size_t index = 0; index < size_count; index += 1) {
235 frames.back()->SetPerFrameData(
Rational(6 * index, 10), {0, 0},
Matrix(),
240 *host_buffer, atlas_context, frames);
241 ASSERT_NE(atlas,
nullptr);
242 ASSERT_NE(atlas->GetTexture(),
nullptr);
244 std::set<uint16_t> unique_glyphs;
245 std::vector<uint16_t> total_glyphs;
246 atlas->IterateGlyphs([&](
const ScaledFont& scaled_font,
254 EXPECT_LE(unique_glyphs.size() * size_count, atlas->GetGlyphCount());
255 EXPECT_EQ(total_glyphs.size(), atlas->GetGlyphCount());
257 EXPECT_TRUE(atlas->GetGlyphCount() > 0);
258 EXPECT_TRUE(atlas->GetTexture()->GetSize().width > 0);
259 EXPECT_TRUE(atlas->GetTexture()->GetSize().height > 0);
264 GetContext()->GetResourceAllocator(), GetContext()->GetIdleWaiter(),
265 GetContext()->GetCapabilities()->GetMinimumUniformAlignment());
269 ASSERT_TRUE(context && context->IsValid());
270 SkFont sk_font = flutter::testing::CreateTestFontOfSize(12);
271 auto blob = SkTextBlob::MakeFromString(
"spooky 1", sk_font);
277 auto old_packer = atlas_context->GetRectPacker();
279 ASSERT_NE(atlas,
nullptr);
280 ASSERT_NE(atlas->GetTexture(),
nullptr);
281 ASSERT_EQ(atlas, atlas_context->GetGlyphAtlas());
283 auto* first_texture = atlas->GetTexture().get();
287 auto blob2 = SkTextBlob::MakeFromString(
"spooky 2", sk_font);
292 ASSERT_EQ(atlas, next_atlas);
293 auto* second_texture = next_atlas->GetTexture().get();
295 auto new_packer = atlas_context->GetRectPacker();
297 ASSERT_EQ(second_texture, first_texture);
298 ASSERT_EQ(old_packer, new_packer);
303 GetContext()->GetResourceAllocator(), GetContext()->GetIdleWaiter(),
304 GetContext()->GetCapabilities()->GetMinimumUniformAlignment());
306 auto mapping = flutter::testing::OpenFixtureAsSkData(
"Apple Color Emoji.ttc");
308 auto mapping = flutter::testing::OpenFixtureAsSkData(
"NotoColorEmoji.ttf");
310 ASSERT_TRUE(mapping);
311 sk_sp<SkFontMgr> font_mgr = txt::GetDefaultFontManager();
312 SkFont emoji_font(font_mgr->makeFromData(mapping), 50.0);
321 SkTextBlob::MakeFromString(
"😂", emoji_font));
323 SkTextBlob::MakeFromString(
"😂", emoji_font));
324 std::vector<std::optional<GlyphProperties>> properties = {
332 atlas_context, {frame, frame_2}, properties);
334 EXPECT_EQ(next_atlas->GetGlyphCount(), 2u);
339 GetContext()->GetResourceAllocator(), GetContext()->GetIdleWaiter(),
340 GetContext()->GetCapabilities()->GetMinimumUniformAlignment());
341 sk_sp<SkFontMgr> font_mgr = txt::GetDefaultFontManager();
342 sk_sp<SkTypeface> typeface =
343 font_mgr->matchFamilyStyle(
"Arial", SkFontStyle::Normal());
344 SkFont sk_font(typeface, 0.5f);
356 std::vector<std::optional<GlyphProperties>> properties = {
364 atlas_context, {frame, frame_2}, properties);
366 EXPECT_EQ(next_atlas->GetGlyphCount(), 1u);
371 ASSERT_NE(packer,
nullptr);
372 ASSERT_EQ(packer->PercentFull(), 0);
374 const SkIRect packer_area = SkIRect::MakeXYWH(0, 0, 200, 100);
377 ASSERT_TRUE(packer->AddRect(20, 20, &first_output));
380 const SkIRect first_rect =
381 SkIRect::MakeXYWH(first_output.
x(), first_output.
y(), 20, 20);
382 ASSERT_TRUE(SkIRect::Intersects(packer_area, first_rect));
389 ASSERT_TRUE(packer->AddRect(140, 90, &second_output));
390 const SkIRect second_rect =
391 SkIRect::MakeXYWH(second_output.
x(), second_output.
y(), 140, 90);
394 ASSERT_TRUE(SkIRect::Intersects(packer_area, second_rect));
395 ASSERT_FALSE(SkIRect::Intersects(first_rect, second_rect));
404 ASSERT_FALSE(packer->AddRect(50, 50, &output));
410 ASSERT_EQ(packer->PercentFull(), 0);
418 for (
auto i = 0u; i < 16; i++) {
419 skyline->AddRect(16, 16, &loc);
422 EXPECT_EQ(loc.
x(), 256 - 16);
423 EXPECT_EQ(loc.
y(), 0);
426 for (
auto i = 0u; i < 16; i++) {
427 skyline->AddRect(16, 16, &loc);
430 EXPECT_EQ(loc.
x(), 256 - 16);
431 EXPECT_EQ(loc.
y(), 16);
436 GTEST_SKIP() <<
"Atlas growth isn't supported for OpenGLES currently.";
440 GetContext()->GetResourceAllocator(), GetContext()->GetIdleWaiter(),
441 GetContext()->GetCapabilities()->GetMinimumUniformAlignment());
445 ASSERT_TRUE(context && context->IsValid());
446 SkFont sk_font = flutter::testing::CreateTestFontOfSize(12);
447 auto blob = SkTextBlob::MakeFromString(
"A", sk_font);
457 constexpr
ISize expected_sizes[13] = {
473 SkFont sk_font_small = flutter::testing::CreateTestFontOfSize(10);
475 for (
int i = 0; i < 13; i++) {
476 SkTextBlobBuilder builder;
478 auto add_char = [&](
const SkFont& sk_font,
char c) {
479 int count = sk_font.countText(&c, 1, SkTextEncoding::kUTF8);
480 auto buffer = builder.allocRunPos(sk_font, count);
481 sk_font.textToGlyphs(&c, 1, SkTextEncoding::kUTF8, buffer.glyphs, count);
482 sk_font.getPos(buffer.glyphs, count, buffer.points(), {0, 0});
485 SkFont sk_font = flutter::testing::CreateTestFontOfSize(50 + i);
486 add_char(sk_font,
'A');
487 add_char(sk_font_small,
'B');
488 auto blob = builder.make();
494 ASSERT_TRUE(!!atlas);
495 EXPECT_EQ(atlas->GetTexture()->GetTextureDescriptor().size,
502 ASSERT_EQ(atlas->GetGlyphCount(), 2u);
506 SkFont font = flutter::testing::CreateTestFontOfSize(12);
507 auto blob = SkTextBlob::MakeFromString(
508 "the quick brown fox jumped over the lazy dog.", font);
512 EXPECT_FALSE(frame->IsFrameComplete());
518 GetContext()->GetResourceAllocator(), GetContext()->GetIdleWaiter(),
519 GetContext()->GetCapabilities()->GetMinimumUniformAlignment());
527 EXPECT_TRUE(frame->IsFrameComplete());
528 EXPECT_TRUE(frame->GetFrameBounds(0).is_placeholder);
535 EXPECT_TRUE(frame->IsFrameComplete());
536 EXPECT_FALSE(frame->GetFrameBounds(0).is_placeholder);
540 SkFont font = flutter::testing::CreateTestFontOfSize(12);
541 auto blob = SkTextBlob::MakeFromString(
542 "the quick brown fox jumped over the lazy dog.", font);
546 EXPECT_FALSE(frame->IsFrameComplete());
552 GetContext()->GetResourceAllocator(), GetContext()->GetIdleWaiter(),
553 GetContext()->GetCapabilities()->GetMinimumUniformAlignment());
561 EXPECT_TRUE(frame->IsFrameComplete());
562 EXPECT_TRUE(frame->GetFrameBounds(0).is_placeholder);
571 EXPECT_TRUE(frame->IsFrameComplete());
572 EXPECT_TRUE(frame->GetFrameBounds(0).is_placeholder);
576 SkFont font = flutter::testing::CreateTestFontOfSize(12);
577 auto blob = SkTextBlob::MakeFromString(
578 "the quick brown fox jumped over the lazy dog.", font);
582 EXPECT_FALSE(frame->IsFrameComplete());
588 GetContext()->GetResourceAllocator(), GetContext()->GetIdleWaiter(),
589 GetContext()->GetCapabilities()->GetMinimumUniformAlignment());
597 EXPECT_TRUE(frame->IsFrameComplete());
598 EXPECT_TRUE(frame->GetFrameBounds(0).is_placeholder);
601 EXPECT_EQ(frame->GetAtlasGenerationAndID().first, 1u);
603 EXPECT_EQ(frame->GetAtlasGenerationAndID().first, 0u);
611 EXPECT_TRUE(frame->IsFrameComplete());
612 EXPECT_FALSE(frame->GetFrameBounds(0).is_placeholder);
614 EXPECT_EQ(frame->GetAtlasGenerationAndID().first, 1u);
616 EXPECT_EQ(frame->GetAtlasGenerationAndID().first, 0u);
620 atlas_context->GetGlyphAtlas()->SetAtlasGeneration(2u);
625 EXPECT_EQ(frame->GetAtlasGenerationAndID().first, 2u);
629 SkFont font = flutter::testing::CreateTestFontOfSize(12);
630 auto blob = SkTextBlob::MakeFromString(
631 "the quick brown fox jumped over the lazy dog.", font);
635 EXPECT_FALSE(frame->IsFrameComplete());
641 GetContext()->GetResourceAllocator(), GetContext()->GetIdleWaiter(),
642 GetContext()->GetCapabilities()->GetMinimumUniformAlignment());
650 EXPECT_TRUE(frame->IsFrameComplete());
651 EXPECT_TRUE(frame->GetFrameBounds(0).is_placeholder);
654 EXPECT_EQ(frame->GetAtlasGenerationAndID().first, 1u);
656 EXPECT_EQ(frame->GetAtlasGenerationAndID().first, 0u);
660 auto second_atlas_context =
663 EXPECT_FALSE(second_atlas_context->GetGlyphAtlas()->IsValid());
667 Rational(1), second_atlas_context, frame);
669 EXPECT_TRUE(second_atlas_context->GetGlyphAtlas()->IsValid());
To do anything rendering related with Impeller, you need a context.
Type
Describes how the glyphs are represented in the texture.
static std::shared_ptr< HostBuffer > Create(const std::shared_ptr< Allocator > &allocator, const std::shared_ptr< const IdleWaiter > &idle_waiter, size_t minimum_uniform_alignment)
const std::shared_ptr< GlyphAtlas > & CreateOrGetGlyphAtlas(Context &context, HostBuffer &host_buffer, GlyphAtlas::Type type) const
void AddTextFrame(const std::shared_ptr< TextFrame > &frame, Rational scale, Point offset, const Matrix &transform, std::optional< GlyphProperties > properties)
static std::shared_ptr< RectanglePacker > Factory(int width, int height)
Return an empty packer with area specified by width and height.
The graphics context necessary to render text.
virtual std::shared_ptr< GlyphAtlas > CreateGlyphAtlas(Context &context, GlyphAtlas::Type type, HostBuffer &host_buffer, const std::shared_ptr< GlyphAtlasContext > &atlas_context, const std::vector< std::shared_ptr< TextFrame >> &text_frames) const =0
static std::shared_ptr< TypographerContext > Make()
bool NumberNear(double a, double b)
TEST(AllocationSizeTest, CanCreateTypedAllocations)
TEST_P(AiksTest, DrawAtlasNoColor)
INSTANTIATE_PLAYGROUND_SUITE(AiksTest)
static std::shared_ptr< GlyphAtlas > CreateGlyphAtlas(Context &context, const TypographerContext *typographer_context, HostBuffer &host_buffer, GlyphAtlas::Type type, Rational scale, const std::shared_ptr< GlyphAtlasContext > &atlas_context, const std::shared_ptr< TextFrame > &frame)
std::shared_ptr< TextFrame > MakeTextFrameFromTextBlobSkia(const sk_sp< SkTextBlob > &blob)
static constexpr Color Red()
static constexpr Color Blue()
A 4x4 matrix using column-major storage.
A font and a scale. Used as a key that represents a typeface within a glyph atlas.
A glyph and its subpixel position.