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"
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);
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());
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());
129 ASSERT_TRUE(mapping);
131 SkFont emoji_font(font_mgr->makeFromData(mapping), 50.0);
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());
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());
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‡°·‚—±Œ„´‰Á¨Ø∏”’/"
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 *data_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());
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());
310 ASSERT_TRUE(mapping);
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());
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());
447 auto blob = SkTextBlob::MakeFromString(
"A", sk_font);
457 constexpr ISize expected_sizes[13] = {
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,
483 sk_font.getPos({
buffer.glyphs, count}, {
buffer.points(), count},
488 add_char(sk_font,
'A');
489 add_char(sk_font_small,
'B');
490 auto blob = builder.make();
496 ASSERT_TRUE(!!atlas);
497 EXPECT_EQ(atlas->GetTexture()->GetTextureDescriptor().size,
504 ASSERT_EQ(atlas->GetGlyphCount(), 2u);
509 auto blob = SkTextBlob::MakeFromString(
510 "the quick brown fox jumped over the lazy dog.", font);
514 EXPECT_FALSE(frame->IsFrameComplete());
520 GetContext()->GetResourceAllocator(), GetContext()->GetIdleWaiter(),
521 GetContext()->GetCapabilities()->GetMinimumUniformAlignment());
523 auto atlas =
CreateGlyphAtlas(*GetContext(), context.get(), *data_host_buffer,
529 EXPECT_TRUE(frame->IsFrameComplete());
530 EXPECT_TRUE(frame->GetFrameBounds(0).is_placeholder);
537 EXPECT_TRUE(frame->IsFrameComplete());
538 EXPECT_FALSE(frame->GetFrameBounds(0).is_placeholder);
543 auto blob = SkTextBlob::MakeFromString(
544 "the quick brown fox jumped over the lazy dog.", font);
548 EXPECT_FALSE(frame->IsFrameComplete());
554 GetContext()->GetResourceAllocator(), GetContext()->GetIdleWaiter(),
555 GetContext()->GetCapabilities()->GetMinimumUniformAlignment());
557 auto atlas =
CreateGlyphAtlas(*GetContext(), context.get(), *data_host_buffer,
563 EXPECT_TRUE(frame->IsFrameComplete());
564 EXPECT_TRUE(frame->GetFrameBounds(0).is_placeholder);
573 EXPECT_TRUE(frame->IsFrameComplete());
574 EXPECT_TRUE(frame->GetFrameBounds(0).is_placeholder);
579 auto blob = SkTextBlob::MakeFromString(
580 "the quick brown fox jumped over the lazy dog.", font);
584 EXPECT_FALSE(frame->IsFrameComplete());
590 GetContext()->GetResourceAllocator(), GetContext()->GetIdleWaiter(),
591 GetContext()->GetCapabilities()->GetMinimumUniformAlignment());
593 auto atlas =
CreateGlyphAtlas(*GetContext(), context.get(), *data_host_buffer,
599 EXPECT_TRUE(frame->IsFrameComplete());
600 EXPECT_TRUE(frame->GetFrameBounds(0).is_placeholder);
603 EXPECT_EQ(frame->GetAtlasGenerationAndID().first, 1u);
605 EXPECT_EQ(frame->GetAtlasGenerationAndID().first, 0u);
613 EXPECT_TRUE(frame->IsFrameComplete());
614 EXPECT_FALSE(frame->GetFrameBounds(0).is_placeholder);
616 EXPECT_EQ(frame->GetAtlasGenerationAndID().first, 1u);
618 EXPECT_EQ(frame->GetAtlasGenerationAndID().first, 0u);
622 atlas_context->GetGlyphAtlas()->SetAtlasGeneration(2u);
627 EXPECT_EQ(frame->GetAtlasGenerationAndID().first, 2u);
632 auto blob = SkTextBlob::MakeFromString(
633 "the quick brown fox jumped over the lazy dog.", font);
637 EXPECT_FALSE(frame->IsFrameComplete());
643 GetContext()->GetResourceAllocator(), GetContext()->GetIdleWaiter(),
644 GetContext()->GetCapabilities()->GetMinimumUniformAlignment());
646 auto atlas =
CreateGlyphAtlas(*GetContext(), context.get(), *data_host_buffer,
652 EXPECT_TRUE(frame->IsFrameComplete());
653 EXPECT_TRUE(frame->GetFrameBounds(0).is_placeholder);
656 EXPECT_EQ(frame->GetAtlasGenerationAndID().first, 1u);
658 EXPECT_EQ(frame->GetAtlasGenerationAndID().first, 0u);
662 auto second_atlas_context =
665 EXPECT_FALSE(second_atlas_context->GetGlyphAtlas()->IsValid());
669 Rational(1), second_atlas_context, frame);
671 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()
SkFont CreateTestFontOfSize(DlScalar scalar)
sk_sp< SkData > OpenFixtureAsSkData(const std::string &fixture_name)
Opens a fixture of the given file name and returns a Skia SkData holding its contents.
bool NumberNear(double a, double b)
TEST(FrameTimingsRecorderTest, RecordVsync)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set profile Make the profiler discard new samples once the profiler sample buffer is full When this flag is not the profiler sample buffer is used as a ring buffer
TEST_P(AiksTest, DrawAtlasNoColor)
static std::shared_ptr< GlyphAtlas > CreateGlyphAtlas(Context &context, const TypographerContext *typographer_context, HostBuffer &data_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)
sk_sp< SkFontMgr > GetDefaultFontManager(uint32_t font_initialization_data)
#define INSTANTIATE_PLAYGROUND_SUITE(playground)
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.