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) {
46 atlas_context, {render_frame});
55 const std::shared_ptr<GlyphAtlasContext>& atlas_context,
56 const std::vector<std::shared_ptr<TextFrame>>& frames,
57 const std::vector<GlyphProperties>& properties) {
59 std::vector<RenderableText> render_frames;
60 render_frames.reserve(frames.size());
61 for (
auto& frame : frames) {
62 render_frames.emplace_back(frame,
transform, properties[offset++]);
65 atlas_context, render_frames);
70 auto blob = SkTextBlob::MakeFromString(
71 "the quick brown fox jumped over the lazy dog.", font);
74 ASSERT_EQ(frame->GetRunCount(), 1u);
75 for (
const auto& run : frame->GetRuns()) {
76 ASSERT_TRUE(run.IsValid());
77 ASSERT_EQ(run.GetGlyphCount(), 45u);
83 ASSERT_TRUE(context && context->IsValid());
91 GetContext()->GetResourceAllocator(), GetContext()->GetIdleWaiter(),
92 GetContext()->GetCapabilities()->GetMinimumUniformAlignment());
93 ASSERT_TRUE(context && context->IsValid());
95 auto blob = SkTextBlob::MakeFromString(
"hello", sk_font);
102 ASSERT_NE(atlas,
nullptr);
103 ASSERT_NE(atlas->GetTexture(),
nullptr);
105 ASSERT_EQ(atlas->GetGlyphCount(), 4llu);
107 std::optional<impeller::ScaledFont> first_scaled_font;
108 std::optional<impeller::SubpixelGlyph> first_glyph;
110 atlas->IterateGlyphs([&](
const ScaledFont& scaled_font,
112 const Rect& rect) ->
bool {
113 first_scaled_font = scaled_font;
119 ASSERT_TRUE(first_scaled_font.has_value());
121 ->FindFontGlyphBounds(
122 {first_scaled_font.value(), first_glyph.value()})
128 GetContext()->GetResourceAllocator(), GetContext()->GetIdleWaiter(),
129 GetContext()->GetCapabilities()->GetMinimumUniformAlignment());
135 ASSERT_TRUE(mapping);
137 SkFont emoji_font(font_mgr->makeFromData(mapping), 50.0);
140 auto blob = SkTextBlob::MakeFromString(
"hello", sk_font);
151 SkTextBlob::MakeFromString(
"😀 ", emoji_font));
164 ASSERT_FALSE(color_atlas == bitmap_atlas);
172 GetContext()->GetResourceAllocator(), GetContext()->GetIdleWaiter(),
173 GetContext()->GetCapabilities()->GetMinimumUniformAlignment());
174 ASSERT_TRUE(context && context->IsValid());
176 auto blob = SkTextBlob::MakeFromString(
"AGH", sk_font);
182 ASSERT_NE(atlas,
nullptr);
183 ASSERT_NE(atlas->GetTexture(),
nullptr);
185 EXPECT_EQ(atlas->GetTexture()->GetSize().width, 4096u);
186 EXPECT_EQ(atlas->GetTexture()->GetSize().height, 1024u);
194 GetContext()->GetResourceAllocator(), GetContext()->GetIdleWaiter(),
195 GetContext()->GetCapabilities()->GetMinimumUniformAlignment());
196 ASSERT_TRUE(context && context->IsValid());
198 auto blob = SkTextBlob::MakeFromString(
"spooky skellingtons", sk_font);
204 ASSERT_NE(atlas,
nullptr);
205 ASSERT_NE(atlas->GetTexture(),
nullptr);
206 ASSERT_EQ(atlas, atlas_context->GetGlyphAtlas());
214 ASSERT_EQ(atlas, next_atlas);
215 ASSERT_EQ(atlas_context->GetGlyphAtlas(), atlas);
220 GetContext()->GetResourceAllocator(), GetContext()->GetIdleWaiter(),
221 GetContext()->GetCapabilities()->GetMinimumUniformAlignment());
225 ASSERT_TRUE(context && context->IsValid());
227 const char* test_string =
228 "QWERTYUIOPASDFGHJKLZXCVBNMqewrtyuiopasdfghjklzxcvbnm,.<>[]{};':"
229 "2134567890-=!@#$%^&*()_+"
230 "œ∑´®†¥¨ˆøπ““‘‘åß∂ƒ©˙∆˚¬…æ≈ç√∫˜µ≤≥≥≥≥÷¡™£¢∞§¶•ªº–≠⁄€‹›fifl‡°·‚—±Œ„´‰Á¨Ø∏”’/"
234 auto blob = SkTextBlob::MakeFromString(test_string, sk_font);
237 size_t size_count = 8;
238 std::vector<RenderableText> render_frames;
239 for (
size_t index = 0; index < size_count; index += 1) {
240 Scalar scale = 6.0f * index / 10.0f;
245 auto atlas = context->CreateGlyphAtlas(
247 atlas_context, render_frames);
248 ASSERT_NE(atlas,
nullptr);
249 ASSERT_NE(atlas->GetTexture(),
nullptr);
251 std::set<uint16_t> unique_glyphs;
252 std::vector<uint16_t> total_glyphs;
253 atlas->IterateGlyphs([&](
const ScaledFont& scaled_font,
261 EXPECT_LE(unique_glyphs.size() * size_count, atlas->GetGlyphCount());
262 EXPECT_EQ(total_glyphs.size(), atlas->GetGlyphCount());
264 EXPECT_TRUE(atlas->GetGlyphCount() > 0);
265 EXPECT_TRUE(atlas->GetTexture()->GetSize().width > 0);
266 EXPECT_TRUE(atlas->GetTexture()->GetSize().height > 0);
271 GetContext()->GetResourceAllocator(), GetContext()->GetIdleWaiter(),
272 GetContext()->GetCapabilities()->GetMinimumUniformAlignment());
276 ASSERT_TRUE(context && context->IsValid());
278 auto blob = SkTextBlob::MakeFromString(
"spooky 1", sk_font);
284 auto old_packer = atlas_context->GetRectPacker();
286 ASSERT_NE(atlas,
nullptr);
287 ASSERT_NE(atlas->GetTexture(),
nullptr);
288 ASSERT_EQ(atlas, atlas_context->GetGlyphAtlas());
290 auto* first_texture = atlas->GetTexture().get();
294 auto blob2 = SkTextBlob::MakeFromString(
"spooky 2", sk_font);
299 ASSERT_EQ(atlas, next_atlas);
300 auto* second_texture = next_atlas->GetTexture().get();
302 auto new_packer = atlas_context->GetRectPacker();
304 ASSERT_EQ(second_texture, first_texture);
305 ASSERT_EQ(old_packer, new_packer);
310 GetContext()->GetResourceAllocator(), GetContext()->GetIdleWaiter(),
311 GetContext()->GetCapabilities()->GetMinimumUniformAlignment());
317 ASSERT_TRUE(mapping);
319 SkFont emoji_font(font_mgr->makeFromData(mapping), 50.0);
328 SkTextBlob::MakeFromString(
"😂", emoji_font));
330 SkTextBlob::MakeFromString(
"😂", emoji_font));
331 std::vector<GlyphProperties> properties = {
339 {frame, frame_2}, properties);
341 EXPECT_EQ(next_atlas->GetGlyphCount(), 2u);
346 GetContext()->GetResourceAllocator(), GetContext()->GetIdleWaiter(),
347 GetContext()->GetCapabilities()->GetMinimumUniformAlignment());
349 sk_sp<SkTypeface> typeface =
350 font_mgr->matchFamilyStyle(
"Arial", SkFontStyle::Normal());
351 SkFont sk_font(typeface, 0.5f);
363 std::vector<GlyphProperties> properties = {
371 {frame, frame_2}, properties);
373 EXPECT_EQ(next_atlas->GetGlyphCount(), 1u);
378 GetContext()->GetResourceAllocator(), GetContext()->GetIdleWaiter(),
379 GetContext()->GetCapabilities()->GetMinimumUniformAlignment());
385 auto blob1 = SkTextBlob::MakeFromString(
"A", sk_font);
386 auto blob2 = SkTextBlob::MakeFromString(
"A", sk_font);
390 std::vector<GlyphProperties> properties = {
401 {frame1, frame2}, properties);
403#if defined(FML_OS_MACOSX)
405 EXPECT_EQ(next_atlas->GetGlyphCount(), 2u);
408 EXPECT_EQ(next_atlas->GetGlyphCount(), 1u);
414 ASSERT_NE(packer,
nullptr);
415 ASSERT_EQ(packer->PercentFull(), 0);
417 const SkIRect packer_area = SkIRect::MakeXYWH(0, 0, 200, 100);
420 ASSERT_TRUE(packer->AddRect(20, 20, &first_output));
423 const SkIRect first_rect =
424 SkIRect::MakeXYWH(first_output.
x(), first_output.
y(), 20, 20);
425 ASSERT_TRUE(SkIRect::Intersects(packer_area, first_rect));
432 ASSERT_TRUE(packer->AddRect(140, 90, &second_output));
433 const SkIRect second_rect =
434 SkIRect::MakeXYWH(second_output.
x(), second_output.
y(), 140, 90);
437 ASSERT_TRUE(SkIRect::Intersects(packer_area, second_rect));
438 ASSERT_FALSE(SkIRect::Intersects(first_rect, second_rect));
447 ASSERT_FALSE(packer->AddRect(50, 50, &output));
453 ASSERT_EQ(packer->PercentFull(), 0);
461 for (
auto i = 0u;
i < 16;
i++) {
462 skyline->AddRect(16, 16, &loc);
465 EXPECT_EQ(loc.
x(), 256 - 16);
466 EXPECT_EQ(loc.
y(), 0);
469 for (
auto i = 0u;
i < 16;
i++) {
470 skyline->AddRect(16, 16, &loc);
473 EXPECT_EQ(loc.
x(), 256 - 16);
474 EXPECT_EQ(loc.
y(), 16);
479 GTEST_SKIP() <<
"Atlas growth isn't supported for OpenGLES currently.";
483 GetContext()->GetResourceAllocator(), GetContext()->GetIdleWaiter(),
484 GetContext()->GetCapabilities()->GetMinimumUniformAlignment());
488 ASSERT_TRUE(context && context->IsValid());
490 auto blob = SkTextBlob::MakeFromString(
"A", sk_font);
500 constexpr ISize expected_sizes[13] = {
518 for (
int i = 0;
i < 13;
i++) {
519 SkTextBlobBuilder builder;
521 auto add_char = [&](
const SkFont& sk_font,
char c) {
522 int count = sk_font.countText(&
c, 1, SkTextEncoding::kUTF8);
523 auto buffer = builder.allocRunPos(sk_font, count);
524 sk_font.textToGlyphs(&
c, 1, SkTextEncoding::kUTF8,
526 sk_font.getPos({
buffer.glyphs, count}, {
buffer.points(), count},
531 add_char(sk_font,
'A');
532 add_char(sk_font_small,
'B');
533 auto blob = builder.make();
540 ASSERT_TRUE(!!atlas);
541 EXPECT_EQ(atlas->GetTexture()->GetTextureDescriptor().size,
548 ASSERT_EQ(atlas->GetGlyphCount(), 2u);
553 auto blob = SkTextBlob::MakeFromString(
554 "the quick brown fox jumped over the lazy dog.", font);
562 GetContext()->GetResourceAllocator(), GetContext()->GetIdleWaiter(),
563 GetContext()->GetCapabilities()->GetMinimumUniformAlignment());
565 auto atlas =
CreateGlyphAtlas(*GetContext(), context.get(), *data_host_buffer,
567 atlas_context, frame);
570 auto second_atlas_context =
573 EXPECT_FALSE(second_atlas_context->GetGlyphAtlas()->IsValid());
577 Matrix(), second_atlas_context, frame);
579 EXPECT_TRUE(second_atlas_context->GetGlyphAtlas()->IsValid());
587 GetContext()->GetResourceAllocator(), GetContext()->GetIdleWaiter(),
588 GetContext()->GetCapabilities()->GetMinimumUniformAlignment());
589 ASSERT_TRUE(context && context->IsValid());
591 auto blob = SkTextBlob::MakeFromString(
"A", sk_font);
599 *atlas,
Size{100, 100},
false);
600 EXPECT_EQ(image_info.colorType(), kRGBA_8888_SkColorType);
608 GetContext()->GetResourceAllocator(), GetContext()->GetIdleWaiter(),
609 GetContext()->GetCapabilities()->GetMinimumUniformAlignment());
610 ASSERT_TRUE(context && context->IsValid());
612 auto blob = SkTextBlob::MakeFromString(
"A", sk_font);
620 *atlas,
Size{100, 100},
false);
621 EXPECT_EQ(image_info.colorType(), kAlpha_8_SkColorType);
629 GetContext()->GetResourceAllocator(), GetContext()->GetIdleWaiter(),
630 GetContext()->GetCapabilities()->GetMinimumUniformAlignment());
631 ASSERT_TRUE(context && context->IsValid());
633 auto blob = SkTextBlob::MakeFromString(
"A", sk_font);
641 *atlas,
Size{100, 100},
true);
642 EXPECT_EQ(image_info.colorType(), kRGBA_8888_SkColorType);
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)
void AddTextFrame(const std::shared_ptr< TextFrame > &frame, Point position, const Matrix &transform, const GlyphProperties &properties)
const std::shared_ptr< GlyphAtlas > & CreateOrGetGlyphAtlas(Context &context, HostBuffer &host_buffer, GlyphAtlas::Type type)
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< RenderableText > &text_frames) const =0
static SkImageInfo GetImageInfo(const GlyphAtlas &atlas, Size size, bool support_light_glyphs)
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
static std::shared_ptr< GlyphAtlas > CreateGlyphAtlas(Context &context, const TypographerContext *typographer_context, HostBuffer &data_host_buffer, GlyphAtlas::Type type, const Matrix &transform, const std::shared_ptr< GlyphAtlasContext > &atlas_context, const std::shared_ptr< TextFrame > &frame)
TEST_P(AiksTest, DrawAtlasNoColor)
std::shared_ptr< TextFrame > MakeTextFrameFromTextBlobSkia(const sk_sp< SkTextBlob > &blob)
sk_sp< SkFontMgr > GetDefaultFontManager(uint32_t font_initialization_data)
#define INSTANTIATE_PLAYGROUND_SUITE(playground)
impeller::ShaderType type
static constexpr Color Crimson()
static constexpr Color Beige()
static constexpr Color Red()
static constexpr Color Blue()
static Tone ComputeTone(const Color &c)
ToneOrColor tone_or_color
A 4x4 matrix using column-major storage.
static constexpr Matrix MakeScale(const Vector3 &s)
const std::shared_ptr< TextFrame > text_frame
The TextFrame being rendered.
A font and a scale. Used as a key that represents a typeface within a glyph atlas.
A glyph and its subpixel position.