Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
aiks_dl_text_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
26
28#include "txt/platform.h"
29
30using namespace flutter;
31/////////////////////////////////////////////////////
32
33namespace impeller {
34namespace testing {
35
37 bool stroke = false;
42 std::shared_ptr<DlMaskFilter> filter;
43 bool is_subpixel = false;
44};
45
46bool RenderTextInCanvasSkia(const std::shared_ptr<Context>& context,
47 DisplayListBuilder& canvas,
48 const std::string& text,
49 const std::string_view& font_fixture,
50 const TextRenderOptions& options = {},
51 const std::optional<SkFont>& font = std::nullopt) {
52 // Draw the baseline.
53 DlPaint paint;
54 paint.setColor(DlColor::kAqua().withAlpha(255 * 0.25));
55 canvas.DrawRect(
56 DlRect::MakeXYWH(options.position.x - 50, options.position.y, 900, 10),
57 paint);
58
59 // Mark the point at which the text is drawn.
60 paint.setColor(DlColor::kRed().withAlpha(255 * 0.25));
61 canvas.DrawCircle(options.position, 5.0, paint);
62
63 // Construct the text blob.
64 SkFont selected_font;
65 if (!font.has_value()) {
66 auto c_font_fixture = std::string(font_fixture);
67 auto mapping =
68 flutter::testing::OpenFixtureAsSkData(c_font_fixture.c_str());
69 if (!mapping) {
70 return false;
71 }
72 sk_sp<SkFontMgr> font_mgr = txt::GetDefaultFontManager();
73 selected_font = SkFont(font_mgr->makeFromData(mapping), options.font_size);
74 if (options.is_subpixel) {
75 selected_font.setSubpixel(true);
76 }
77 } else {
78 selected_font = font.value();
79 }
80 auto blob = SkTextBlob::MakeFromString(text.c_str(), selected_font);
81 if (!blob) {
82 return false;
83 }
84
85 // Create the Impeller text frame and draw it at the designated baseline.
86 auto frame = MakeTextFrameFromTextBlobSkia(blob);
87
88 DlPaint text_paint;
89 text_paint.setColor(options.color);
90 text_paint.setMaskFilter(options.filter);
91 text_paint.setStrokeWidth(options.stroke_width);
92 text_paint.setDrawStyle(options.stroke ? DlDrawStyle::kStroke
94 canvas.DrawText(DlTextImpeller::Make(frame), options.position.x,
95 options.position.y, text_paint);
96 return true;
97}
98
99TEST_P(AiksTest, CanRenderTextFrame) {
100 DisplayListBuilder builder;
101
102 DlPaint paint;
103 paint.setColor(DlColor::ARGB(1, 0.1, 0.1, 0.1));
104 builder.DrawPaint(paint);
105 ASSERT_TRUE(RenderTextInCanvasSkia(
106 GetContext(), builder, "the quick brown fox jumped over the lazy dog!.?",
107 "Roboto-Regular.ttf"));
108
109 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
110}
111
112TEST_P(AiksTest, CanRenderTextFrameWithInvertedTransform) {
113 DisplayListBuilder builder;
114
115 DlPaint paint;
116 paint.setColor(DlColor::ARGB(1, 0.1, 0.1, 0.1));
117 builder.DrawPaint(paint);
118 builder.Translate(1000, 0);
119 builder.Scale(-1, 1);
120
121 ASSERT_TRUE(RenderTextInCanvasSkia(
122 GetContext(), builder, "the quick brown fox jumped over the lazy dog!.?",
123 "Roboto-Regular.ttf"));
124
125 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
126}
127
128TEST_P(AiksTest, CanRenderStrokedTextFrame) {
129 DisplayListBuilder builder;
130
131 DlPaint paint;
132 paint.setColor(DlColor::ARGB(1, 0.1, 0.1, 0.1));
133 builder.DrawPaint(paint);
134
135 ASSERT_TRUE(RenderTextInCanvasSkia(
136 GetContext(), builder, "the quick brown fox jumped over the lazy dog!.?",
137 "Roboto-Regular.ttf",
138 {
139 .stroke = true,
140 }));
141 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
142}
143
144TEST_P(AiksTest, CanRenderTextStrokeWidth) {
145 DisplayListBuilder builder;
146
147 DlPaint paint;
148 paint.setColor(DlColor::ARGB(1, 0.1, 0.1, 0.1));
149 builder.DrawPaint(paint);
150
151 ASSERT_TRUE(RenderTextInCanvasSkia(GetContext(), builder, "LMNOP VWXYZ",
152 "Roboto-Medium.ttf",
153 {
154 .stroke = true,
155 .stroke_width = 4,
156 }));
157 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
158}
159
160TEST_P(AiksTest, CanRenderTextFrameWithHalfScaling) {
161 DisplayListBuilder builder;
162
163 DlPaint paint;
164 paint.setColor(DlColor::ARGB(1, 0.1, 0.1, 0.1));
165 builder.DrawPaint(paint);
166 builder.Scale(0.5, 0.5);
167
168 ASSERT_TRUE(RenderTextInCanvasSkia(
169 GetContext(), builder, "the quick brown fox jumped over the lazy dog!.?",
170 "Roboto-Regular.ttf"));
171 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
172}
173
174// This is a test that looks for glyph artifacts we've see.
175TEST_P(AiksTest, ScaledK) {
176 DisplayListBuilder builder;
177 DlPaint paint;
178 paint.setColor(DlColor::ARGB(1, 0.1, 0.1, 0.1));
179 builder.DrawPaint(paint);
180 for (int i = 0; i < 6; ++i) {
181 builder.Save();
182 builder.Translate(300 * i, 0);
183 Scalar scale = 0.445 - (i / 1000.f);
184 builder.Scale(scale, scale);
186 GetContext(), builder, "k", "Roboto-Regular.ttf",
187 TextRenderOptions{.font_size = 600, .position = DlPoint(10, 500)});
189 GetContext(), builder, "k", "Roboto-Regular.ttf",
190 TextRenderOptions{.font_size = 300, .position = DlPoint(10, 800)});
191 builder.Restore();
192 }
193 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
194}
195
196// This is a test that looks for glyph artifacts we've see.
197TEST_P(AiksTest, MassiveScaleConvertToPath) {
198 Scalar scale = 16.0;
199 auto callback = [&]() -> sk_sp<DisplayList> {
200 if (AiksTest::ImGuiBegin("Controls", nullptr,
201 ImGuiWindowFlags_AlwaysAutoResize)) {
202 ImGui::SliderFloat("Scale", &scale, 4, 20);
203 ImGui::End();
204 }
205
206 DisplayListBuilder builder;
207 DlPaint paint;
208 paint.setColor(DlColor::ARGB(1, 0.1, 0.1, 0.1));
209 builder.DrawPaint(paint);
210
211 builder.Scale(scale, scale);
213 GetContext(), builder, "HELLO", "Roboto-Regular.ttf",
215 .color = (16 * scale >= 250) ? DlColor::kYellow()
217 .position = DlPoint(0, 20)});
218 return builder.Build();
219 };
220
221 ASSERT_TRUE(OpenPlaygroundHere(callback));
222}
223
224TEST_P(AiksTest, CanRenderTextFrameWithScalingOverflow) {
225 Scalar scale = 60.0;
226 Scalar offsetx = -500.0;
227 Scalar offsety = 700.0;
228 auto callback = [&]() -> sk_sp<DisplayList> {
229 if (AiksTest::ImGuiBegin("Controls", nullptr,
230 ImGuiWindowFlags_AlwaysAutoResize)) {
231 ImGui::SliderFloat("scale", &scale, 1.f, 300.f);
232 ImGui::SliderFloat("offsetx", &offsetx, -600.f, 100.f);
233 ImGui::SliderFloat("offsety", &offsety, 600.f, 2048.f);
234 ImGui::End();
235 }
236 DisplayListBuilder builder;
237 builder.Scale(GetContentScale().x, GetContentScale().y);
238 DlPaint paint;
239 paint.setColor(DlColor::ARGB(1, 0.1, 0.1, 0.1));
240 builder.DrawPaint(paint);
241 builder.Scale(scale, scale);
242
244 GetContext(), builder, "test", "Roboto-Regular.ttf",
246 .position = DlPoint(offsetx / scale, offsety / scale),
247 });
248 return builder.Build();
249 };
250 ASSERT_TRUE(OpenPlaygroundHere(callback));
251}
252
253TEST_P(AiksTest, CanRenderTextFrameWithFractionScaling) {
254 Scalar fine_scale = 0.f;
255 bool is_subpixel = false;
256 auto callback = [&]() -> sk_sp<DisplayList> {
257 if (AiksTest::ImGuiBegin("Controls", nullptr,
258 ImGuiWindowFlags_AlwaysAutoResize)) {
259 ImGui::SliderFloat("Fine Scale", &fine_scale, -1, 1);
260 ImGui::Checkbox("subpixel", &is_subpixel);
261 ImGui::End();
262 }
263
264 DisplayListBuilder builder;
265 DlPaint paint;
266 paint.setColor(DlColor::ARGB(1, 0.1, 0.1, 0.1));
267 builder.DrawPaint(paint);
268 Scalar scale = 2.625 + fine_scale;
269 builder.Scale(scale, scale);
270 RenderTextInCanvasSkia(GetContext(), builder,
271 "the quick brown fox jumped over the lazy dog!.?",
272 "Roboto-Regular.ttf",
274 return builder.Build();
275 };
276
277 ASSERT_TRUE(OpenPlaygroundHere(callback));
278}
279
280// https://github.com/flutter/flutter/issues/164958
281TEST_P(AiksTest, TextRotated180Degrees) {
282 float fpivot[2] = {200 + 30, 200 - 20};
283 float rotation = 180;
284 float foffset[2] = {200, 200};
285
286 auto callback = [&]() -> sk_sp<DisplayList> {
287 if (AiksTest::ImGuiBegin("Controls", nullptr,
288 ImGuiWindowFlags_AlwaysAutoResize)) {
289 ImGui::SliderFloat("pivotx", &fpivot[0], 0, 300);
290 ImGui::SliderFloat("pivoty", &fpivot[1], 0, 300);
291 ImGui::SliderFloat("rotation", &rotation, 0, 360);
292 ImGui::SliderFloat("foffsetx", &foffset[0], 0, 300);
293 ImGui::SliderFloat("foffsety", &foffset[1], 0, 300);
294 ImGui::End();
295 }
296 DisplayListBuilder builder;
297 builder.Scale(GetContentScale().x, GetContentScale().y);
298 builder.DrawPaint(DlPaint().setColor(DlColor(0xffffeeff)));
299
300 builder.Save();
301 DlPoint pivot = Point(fpivot[0], fpivot[1]);
302 builder.Translate(pivot.x, pivot.y);
303 builder.Rotate(rotation);
304 builder.Translate(-pivot.x, -pivot.y);
305
306 RenderTextInCanvasSkia(GetContext(), builder, "test", "Roboto-Regular.ttf",
309 .position = DlPoint(foffset[0], foffset[1]),
310 });
311
312 builder.Restore();
313 return builder.Build();
314 };
315 ASSERT_TRUE(OpenPlaygroundHere(callback));
316}
317
318TEST_P(AiksTest, TextFrameSubpixelAlignment) {
319 // "Random" numbers between 0 and 1. Hardcoded to avoid flakiness in goldens.
320 std::array<Scalar, 20> phase_offsets = {
321 7.82637e-06, 0.131538, 0.755605, 0.45865, 0.532767,
322 0.218959, 0.0470446, 0.678865, 0.679296, 0.934693,
323 0.383502, 0.519416, 0.830965, 0.0345721, 0.0534616,
324 0.5297, 0.671149, 0.00769819, 0.383416, 0.0668422};
325 auto callback = [&]() -> sk_sp<DisplayList> {
326 static float font_size = 20;
327 static float phase_variation = 0.2;
328 static float speed = 0.5;
329 static float magnitude = 100;
330 if (AiksTest::ImGuiBegin("Controls", nullptr,
331 ImGuiWindowFlags_AlwaysAutoResize)) {
332 ImGui::SliderFloat("Font size", &font_size, 5, 50);
333 ImGui::SliderFloat("Phase variation", &phase_variation, 0, 1);
334 ImGui::SliderFloat("Oscillation speed", &speed, 0, 2);
335 ImGui::SliderFloat("Oscillation magnitude", &magnitude, 0, 300);
336 ImGui::End();
337 }
338
339 DisplayListBuilder builder;
340 builder.Scale(GetContentScale().x, GetContentScale().y);
341
342 for (size_t i = 0; i < phase_offsets.size(); i++) {
343 DlPoint position = DlPoint(
344 200 +
345 magnitude * std::sin((-phase_offsets[i] * k2Pi * phase_variation +
346 GetSecondsElapsed() * speed)), //
347 200 + i * font_size * 1.1 //
348 );
350 GetContext(), builder,
351 "the quick brown fox jumped over "
352 "the lazy dog!.?",
353 "Roboto-Regular.ttf",
354 {.font_size = font_size, .position = position})) {
355 return nullptr;
356 }
357 }
358 return builder.Build();
359 };
360
361 ASSERT_TRUE(OpenPlaygroundHere(callback));
362}
363
364TEST_P(AiksTest, CanRenderItalicizedText) {
365 DisplayListBuilder builder;
366
367 DlPaint paint;
368 paint.setColor(DlColor::ARGB(1, 0.1, 0.1, 0.1));
369 builder.DrawPaint(paint);
370
371 ASSERT_TRUE(RenderTextInCanvasSkia(
372 GetContext(), builder, "the quick brown fox jumped over the lazy dog!.?",
373 "HomemadeApple.ttf"));
374 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
375}
376
377static constexpr std::string_view kFontFixture =
378#if FML_OS_MACOSX
379 "Apple Color Emoji.ttc";
380#else
381 "NotoColorEmoji.ttf";
382#endif
383
384TEST_P(AiksTest, CanRenderEmojiTextFrame) {
385 DisplayListBuilder builder;
386
387 DlPaint paint;
388 paint.setColor(DlColor::ARGB(1, 0.1, 0.1, 0.1));
389 builder.DrawPaint(paint);
390
391 ASSERT_TRUE(RenderTextInCanvasSkia(
392 GetContext(), builder, "😀 😃 😄 😁 😆 😅 😂 🤣 🥲 😊", kFontFixture));
393 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
394}
395
396TEST_P(AiksTest, CanRenderEmojiTextFrameWithBlur) {
397 DisplayListBuilder builder;
398
399 builder.Scale(GetContentScale().x, GetContentScale().y);
400 DlPaint paint;
401 paint.setColor(DlColor::ARGB(1, 0.1, 0.1, 0.1));
402 builder.DrawPaint(paint);
403
404 ASSERT_TRUE(RenderTextInCanvasSkia(
405 GetContext(), builder, "😀 😃 😄 😁 😆 😅 😂 🤣 🥲 😊", kFontFixture,
408 .filter = DlBlurMaskFilter::Make(DlBlurStyle::kNormal, 4)}));
409 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
410}
411
412TEST_P(AiksTest, CanRenderEmojiTextFrameWithAlpha) {
413 DisplayListBuilder builder;
414
415 DlPaint paint;
416 paint.setColor(DlColor::ARGB(1, 0.1, 0.1, 0.1));
417 builder.DrawPaint(paint);
418
419 ASSERT_TRUE(RenderTextInCanvasSkia(
420 GetContext(), builder, "😀 😃 😄 😁 😆 😅 😂 🤣 🥲 😊", kFontFixture,
421 {.color = DlColor::kBlack().modulateOpacity(0.5)}));
422 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
423}
424
425TEST_P(AiksTest, CanRenderTextInSaveLayer) {
426 DisplayListBuilder builder;
427
428 DlPaint paint;
429 paint.setColor(DlColor::ARGB(0.1, 0.1, 0.1, 0.1));
430 builder.DrawPaint(paint);
431
432 builder.Translate(100, 100);
433 builder.Scale(0.5, 0.5);
434
435 // Blend the layer with the parent pass using kClear to expose the coverage.
436 paint.setBlendMode(DlBlendMode::kClear);
437 builder.SaveLayer(std::nullopt, &paint);
438 ASSERT_TRUE(RenderTextInCanvasSkia(
439 GetContext(), builder, "the quick brown fox jumped over the lazy dog!.?",
440 "Roboto-Regular.ttf"));
441 builder.Restore();
442
443 // Render the text again over the cleared coverage rect.
444 ASSERT_TRUE(RenderTextInCanvasSkia(
445 GetContext(), builder, "the quick brown fox jumped over the lazy dog!.?",
446 "Roboto-Regular.ttf"));
447
448 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
449}
450
451TEST_P(AiksTest, CanRenderTextOutsideBoundaries) {
452 DisplayListBuilder builder;
453 builder.Translate(200, 150);
454
455 // Construct the text blob.
456 auto mapping = flutter::testing::OpenFixtureAsSkData("wtf.otf");
457 ASSERT_NE(mapping, nullptr);
458
459 Scalar font_size = 80;
460 sk_sp<SkFontMgr> font_mgr = txt::GetDefaultFontManager();
461 SkFont sk_font(font_mgr->makeFromData(mapping), font_size);
462
463 DlPaint text_paint;
464 text_paint.setColor(DlColor::kBlue().withAlpha(255 * 0.8));
465
466 struct {
467 DlPoint position;
468 const char* text;
469 } text[] = {{DlPoint(0, 0), "0F0F0F0"},
470 {DlPoint(1, 2), "789"},
471 {DlPoint(1, 3), "456"},
472 {DlPoint(1, 4), "123"},
473 {DlPoint(0, 6), "0F0F0F0"}};
474 for (auto& t : text) {
475 builder.Save();
476 builder.Translate(t.position.x * font_size * 2,
477 t.position.y * font_size * 1.1);
478 {
479 auto blob = SkTextBlob::MakeFromString(t.text, sk_font);
480 ASSERT_NE(blob, nullptr);
481 auto frame = MakeTextFrameFromTextBlobSkia(blob);
482 builder.DrawText(DlTextImpeller::Make(frame), 0, 0, text_paint);
483 }
484 builder.Restore();
485 }
486
487 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
488}
489
490TEST_P(AiksTest, TextRotated) {
491 DisplayListBuilder builder;
492
493 builder.Scale(GetContentScale().x, GetContentScale().y);
494 DlPaint paint;
495 paint.setColor(DlColor::ARGB(0.1, 0.1, 0.1, 1.0));
496 builder.DrawPaint(paint);
497
498 builder.Transform(Matrix(0.25, -0.3, 0, -0.002, //
499 0, 0.5, 0, 0, //
500 0, 0, 0.3, 0, //
501 100, 100, 0, 1.3));
502 ASSERT_TRUE(RenderTextInCanvasSkia(
503 GetContext(), builder, "the quick brown fox jumped over the lazy dog!.?",
504 "Roboto-Regular.ttf"));
505
506 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
507}
508
509TEST_P(AiksTest, DrawScaledTextWithPerspectiveNoSaveLayer) {
510 DisplayListBuilder builder;
511
512 Matrix matrix = Matrix(1.0, 0.0, 0.0, 0.0, //
513 0.0, 1.0, 0.0, 0.0, //
514 0.0, 0.0, 1.0, 0.01, //
515 0.0, 0.0, 0.0, 1.0) * //
517
518 builder.Transform(matrix);
519
520 ASSERT_TRUE(RenderTextInCanvasSkia(GetContext(), builder, "Hello world",
521 "Roboto-Regular.ttf"));
522 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
523}
524
525TEST_P(AiksTest, DrawScaledTextWithPerspectiveSaveLayer) {
526 DisplayListBuilder builder;
527
528 Matrix matrix = Matrix(1.0, 0.0, 0.0, 0.0, //
529 0.0, 1.0, 0.0, 0.0, //
530 0.0, 0.0, 1.0, 0.01, //
531 0.0, 0.0, 0.0, 1.0) * //
533
534 DlPaint save_paint;
535 DlRect window_bounds =
536 DlRect::MakeXYWH(0, 0, GetWindowSize().width, GetWindowSize().height);
537 // Note: bounds were not needed by the AIKS version, which may indicate a bug.
538 builder.SaveLayer(window_bounds, &save_paint);
539 builder.Transform(matrix);
540
541 ASSERT_TRUE(RenderTextInCanvasSkia(GetContext(), builder, "Hello world",
542 "Roboto-Regular.ttf"));
543
544 builder.Restore();
545 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
546}
547
548TEST_P(AiksTest, CanRenderTextWithLargePerspectiveTransform) {
549 // Verifies that text scales are clamped to work around
550 // https://github.com/flutter/flutter/issues/136112 .
551
552 DisplayListBuilder builder;
553
554 DlPaint save_paint;
555 builder.SaveLayer(std::nullopt, &save_paint);
556 builder.Transform(Matrix(2000, 0, 0, 0, //
557 0, 2000, 0, 0, //
558 0, 0, -1, 9000, //
559 0, 0, -1, 7000 //
560 ));
561
562 ASSERT_TRUE(RenderTextInCanvasSkia(GetContext(), builder, "Hello world",
563 "Roboto-Regular.ttf"));
564 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
565}
566
567TEST_P(AiksTest, CanRenderTextWithPerspectiveTransformInSublist) {
568 DisplayListBuilder text_builder;
569 ASSERT_TRUE(RenderTextInCanvasSkia(GetContext(), text_builder, "Hello world",
570 "Roboto-Regular.ttf"));
571 auto text_display_list = text_builder.Build();
572
573 DisplayListBuilder builder;
574
575 Matrix matrix = Matrix::MakeRow(2.0, 0.0, 0.0, 0.0, //
576 0.0, 2.0, 0.0, 0.0, //
577 0.0, 0.0, 1.0, 0.0, //
578 0.0, 0.002, 0.0, 1.0);
579
580 DlPaint save_paint;
581 DlRect window_bounds =
582 DlRect::MakeXYWH(0, 0, GetWindowSize().width, GetWindowSize().height);
583 builder.SaveLayer(window_bounds, &save_paint);
584 builder.Transform(matrix);
585 builder.DrawDisplayList(text_display_list, 1.0f);
586 builder.Restore();
587
588 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
589}
590
591// This currently renders solid blue, as the support for text color sources was
592// moved into DLDispatching. Path data requires the SkTextBlobs which are not
593// used in impeller::TextFrames.
594TEST_P(AiksTest, TextForegroundShaderWithTransform) {
595 auto mapping = flutter::testing::OpenFixtureAsSkData("Roboto-Regular.ttf");
596 ASSERT_NE(mapping, nullptr);
597
598 Scalar font_size = 100;
599 sk_sp<SkFontMgr> font_mgr = txt::GetDefaultFontManager();
600 SkFont sk_font(font_mgr->makeFromData(mapping), font_size);
601
602 DlPaint text_paint;
603 text_paint.setColor(DlColor::kBlue());
604
605 std::vector<DlColor> colors = {DlColor::RGBA(0.9568, 0.2627, 0.2118, 1.0),
606 DlColor::RGBA(0.1294, 0.5882, 0.9529, 1.0)};
607 std::vector<Scalar> stops = {
608 0.0,
609 1.0,
610 };
612 /*start_point=*/DlPoint(0, 0), //
613 /*end_point=*/DlPoint(100, 100), //
614 /*stop_count=*/2, //
615 /*colors=*/colors.data(), //
616 /*stops=*/stops.data(), //
617 /*tile_mode=*/DlTileMode::kRepeat //
618 ));
619
620 DisplayListBuilder builder;
621 builder.Translate(100, 100);
622 builder.Rotate(45);
623
624 auto blob = SkTextBlob::MakeFromString("Hello", sk_font);
625 ASSERT_NE(blob, nullptr);
626 auto frame = MakeTextFrameFromTextBlobSkia(blob);
627 builder.DrawText(DlTextImpeller::Make(frame), 0, 0, text_paint);
628
629 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
630}
631
632// Regression test for https://github.com/flutter/flutter/issues/157885.
633TEST_P(AiksTest, DifferenceClipsMustRenderIdenticallyAcrossBackends) {
634 DisplayListBuilder builder;
635
636 DlPaint paint;
637 DlColor clear_color(1.0, 0.5, 0.5, 0.5, DlColorSpace::kSRGB);
638 paint.setColor(clear_color);
639 builder.DrawPaint(paint);
640
641 DlMatrix identity = {
642 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0,
643 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0,
644 };
645 builder.Save();
646 builder.Transform(identity);
647
648 DlRect frame = DlRect::MakeLTRB(1.0, 1.0, 1278.0, 763.0);
649 DlColor white(1.0, 1.0, 1.0, 1.0, DlColorSpace::kSRGB);
650 paint.setColor(white);
651 builder.DrawRect(frame, paint);
652
653 builder.Save();
654 builder.ClipRect(frame, DlClipOp::kIntersect);
655
656 DlMatrix rect_xform = {
657 0.8241262, 0.56640625, 0.0, 0.0, -0.56640625, 0.8241262, 0.0, 0.0,
658 0.0, 0.0, 1.0, 0.0, 271.1137, 489.4733, 0.0, 1.0,
659 };
660 builder.Save();
661 builder.Transform(rect_xform);
662
663 DlRect rect = DlRect::MakeLTRB(0.0, 0.0, 100.0, 100.0);
664 DlColor bluish(1.0, 0.184, 0.501, 0.929, DlColorSpace::kSRGB);
665 paint.setColor(bluish);
666 DlRoundRect rrect = DlRoundRect::MakeRectRadius(rect, 18.0);
667 builder.DrawRoundRect(rrect, paint);
668
669 builder.Save();
670 builder.ClipRect(rect, DlClipOp::kIntersect);
671 builder.Restore();
672
673 builder.Restore();
674
675 DlMatrix path_xform = {
676 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0,
677 0.0, 0.0, 1.0, 0.0, 675.0, 279.5, 0.0, 1.0,
678 };
679 builder.Save();
680 builder.Transform(path_xform);
681
682 DlPathBuilder path_builder;
683 path_builder.MoveTo(DlPoint(87.5, 349.5));
684 path_builder.LineTo(DlPoint(25.0, 29.5));
685 path_builder.LineTo(DlPoint(150.0, 118.0));
686 path_builder.LineTo(DlPoint(25.0, 118.0));
687 path_builder.LineTo(DlPoint(150.0, 29.5));
688 path_builder.Close();
689 DlPath path = path_builder.TakePath();
690
691 DlColor fill_color(1.0, 1.0, 0.0, 0.0, DlColorSpace::kSRGB);
692 DlColor stroke_color(1.0, 0.0, 0.0, 0.0, DlColorSpace::kSRGB);
693 paint.setColor(fill_color);
694 paint.setDrawStyle(DlDrawStyle::kFill);
695 builder.DrawPath(path, paint);
696
697 paint.setColor(stroke_color);
698 paint.setStrokeWidth(2.0);
699 paint.setDrawStyle(DlDrawStyle::kStroke);
700 builder.DrawPath(path, paint);
701
702 builder.Restore();
703 builder.Restore();
704 builder.Restore();
705
706 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
707}
708
709TEST_P(AiksTest, TextContentsMismatchedTransformTest) {
710 AiksContext aiks_context(GetContext(),
711 std::make_shared<TypographerContextSkia>());
712
713 // Verifies that TextContents only use the scale/transform that is
714 // computed during preroll.
715 constexpr const char* font_fixture = "Roboto-Regular.ttf";
716
717 // Construct the text blob.
718 auto c_font_fixture = std::string(font_fixture);
719 auto mapping = flutter::testing::OpenFixtureAsSkData(c_font_fixture.c_str());
720 ASSERT_TRUE(mapping);
721
722 sk_sp<SkFontMgr> font_mgr = txt::GetDefaultFontManager();
723 SkFont sk_font(font_mgr->makeFromData(mapping), 16);
724
725 auto blob = SkTextBlob::MakeFromString("Hello World", sk_font);
726 ASSERT_TRUE(blob);
727
728 auto text_frame = MakeTextFrameFromTextBlobSkia(blob);
729
730 // Simulate recording the text frame during preroll.
731 Matrix preroll_matrix =
732 Matrix::MakeTranslateScale({1.5, 1.5, 1}, {100, 50, 0});
733 Point preroll_point = Point{23, 45};
734 {
735 aiks_context.GetContentContext().GetLazyGlyphAtlas()->AddTextFrame(
736 text_frame, //
737 preroll_point, //
738 preroll_matrix, //
739 GlyphProperties{} //
740 );
741 }
742
743 // Now simulate rendering with a slightly different scale factor.
744 RenderTarget render_target =
745 aiks_context.GetContentContext()
747 ->CreateOffscreenMSAA(*aiks_context.GetContext(), {100, 100}, 1);
748
749 TextContents text_contents;
750 text_contents.SetTextFrame(text_frame);
751 text_contents.SetPosition(preroll_point);
752 text_contents.SetScreenTransform(preroll_matrix);
753 text_contents.SetColor(Color::Aqua());
754
755 Matrix not_preroll_matrix =
756 preroll_matrix * Matrix::MakeScale({2.0f, 2.0f, 1.0f});
757
758 Entity entity;
759 entity.SetTransform(not_preroll_matrix);
760
761 std::shared_ptr<CommandBuffer> command_buffer =
762 aiks_context.GetContext()->CreateCommandBuffer();
763 std::shared_ptr<RenderPass> render_pass =
764 command_buffer->CreateRenderPass(render_target);
765
766 EXPECT_TRUE(text_contents.Render(aiks_context.GetContentContext(), entity,
767 *render_pass));
768}
769
770TEST_P(AiksTest, CanRenderTextFrameWithThinLightAndDarkColors) {
771 DisplayListBuilder builder;
772 DlPaint paint;
773 paint.setColor(DlColor::ARGB(1, 0.1, 0.1, 0.1));
774 builder.DrawPaint(paint);
775
776 auto mapping =
777 flutter::testing::OpenFixtureAsSkData("RobotoSlab-VariableFont_wght.ttf");
778 ASSERT_TRUE(mapping);
779 sk_sp<SkFontMgr> font_mgr = txt::GetDefaultFontManager();
780
781 // Set the variation axis for weight to 100 (typically "Thin").
782 SkFontArguments::VariationPosition::Coordinate weight_coord{
783 SkSetFourByteTag('w', 'g', 'h', 't'), 100.0f};
784 SkFontArguments args;
785 args.setVariationDesignPosition({&weight_coord, 1});
786
787 SkFont thin_font(font_mgr->makeFromData(mapping)->makeClone(args), 25);
788
789 // Render light text
790 ASSERT_TRUE(RenderTextInCanvasSkia(
791 GetContext(), builder, "the quick brown fox jumped over the lazy dog!.?",
792 "RobotoSlab-VariableFont_wght.ttf",
794 .position = DlPoint(100, 200)},
795 thin_font));
796
797 // Render dark text on a light background
798 DlPaint dart_text_background_paint;
799 dart_text_background_paint.setColor(DlColor::ARGB(1, 0.9, 0.9, 0.9));
800 builder.DrawRect(DlRect::MakeXYWH(50, 250, 900, 100),
801 dart_text_background_paint);
802 ASSERT_TRUE(RenderTextInCanvasSkia(
803 GetContext(), builder, "the quick brown fox jumped over the lazy dog!.?",
804 "RobotoSlab-VariableFont_wght.ttf",
806 .position = DlPoint(100, 300)},
807 thin_font));
808
809 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
810}
811
812TEST_P(AiksTest, TextWithShadowCache) {
813 DisplayListBuilder builder;
814 builder.Scale(GetContentScale().x, GetContentScale().y);
815 DlPaint paint;
816 paint.setColor(DlColor::ARGB(1, 0.1, 0.1, 0.1));
817 builder.DrawPaint(paint);
818
819 AiksContext aiks_context(GetContext(),
820 std::make_shared<TypographerContextSkia>());
821 // Cache empty
822 EXPECT_EQ(aiks_context.GetContentContext()
825 0u);
826
827 ASSERT_TRUE(RenderTextInCanvasSkia(
828 GetContext(), builder, "Hello World", kFontFixture,
831 .filter = DlBlurMaskFilter::Make(DlBlurStyle::kNormal, 4)}));
832
833 DisplayListToTexture(builder.Build(), {400, 400}, aiks_context);
834
835 // Text should be cached.
836 EXPECT_EQ(aiks_context.GetContentContext()
839 1u);
840}
841
842TEST_P(AiksTest, MultipleTextWithShadowCache) {
843 DisplayListBuilder builder;
844 builder.Scale(GetContentScale().x, GetContentScale().y);
845 DlPaint paint;
846 paint.setColor(DlColor::ARGB(1, 0.1, 0.1, 0.1));
847 builder.DrawPaint(paint);
848
849 AiksContext aiks_context(GetContext(),
850 std::make_shared<TypographerContextSkia>());
851 // Cache empty
852 EXPECT_EQ(aiks_context.GetContentContext()
855 0u);
856
857 for (auto i = 0; i < 5; i++) {
858 ASSERT_TRUE(RenderTextInCanvasSkia(
859 GetContext(), builder, "Hello World", kFontFixture,
862 .filter = DlBlurMaskFilter::Make(DlBlurStyle::kNormal, 4)}));
863 }
864
865 DisplayListToTexture(builder.Build(), {400, 400}, aiks_context);
866
867 // Text should be cached. Each text gets its own entry as we don't analyze the
868 // strings.
869 EXPECT_EQ(aiks_context.GetContentContext()
872 5u);
873}
874
875TEST_P(AiksTest, MultipleColorWithShadowCache) {
876 DisplayListBuilder builder;
877 builder.Scale(GetContentScale().x, GetContentScale().y);
878 DlPaint paint;
879 paint.setColor(DlColor::kWhite());
880 builder.DrawPaint(paint);
881
882 AiksContext aiks_context(GetContext(),
883 std::make_shared<TypographerContextSkia>());
884 // Cache empty
885 EXPECT_EQ(aiks_context.GetContentContext()
888 0u);
889
890 SkFont sk_font = flutter::testing::CreateTestFontOfSize(12);
891
892 std::array<DlColor, 4> colors{DlColor::kRed(), DlColor::kGreen(),
894 for (const auto& color : colors) {
895 ASSERT_TRUE(RenderTextInCanvasSkia(
896 GetContext(), builder, "A", kFontFixture,
898 .color = color,
899 .filter = DlBlurMaskFilter::Make(DlBlurStyle::kNormal, 4)},
900 sk_font));
901 }
902
903 DisplayListToTexture(builder.Build(), {400, 400}, aiks_context);
904
905 // The count of cache entries should match the number of distinct colors
906 // in the list. Repeated usage of a color should not add to the cache.
907 EXPECT_EQ(aiks_context.GetContentContext()
910 3u);
911}
912
913TEST_P(AiksTest, SingleIconShadowTest) {
914 DisplayListBuilder builder;
915 builder.Scale(GetContentScale().x, GetContentScale().y);
916 DlPaint paint;
917 paint.setColor(DlColor::ARGB(1, 0.1, 0.1, 0.1));
918 builder.DrawPaint(paint);
919
920 AiksContext aiks_context(GetContext(),
921 std::make_shared<TypographerContextSkia>());
922 // Cache empty
923 EXPECT_EQ(aiks_context.GetContentContext()
926 0u);
927
928 // Create font instance outside loop so all draws use identical font instance.
929 auto c_font_fixture = std::string(kFontFixture);
930 auto mapping = flutter::testing::OpenFixtureAsSkData(c_font_fixture.c_str());
931 ASSERT_TRUE(mapping);
932 sk_sp<SkFontMgr> font_mgr = txt::GetDefaultFontManager();
933 SkFont sk_font(font_mgr->makeFromData(mapping), 50);
934
935 for (auto i = 0; i < 10; i++) {
936 ASSERT_TRUE(RenderTextInCanvasSkia(
937 GetContext(), builder, "A", kFontFixture,
940 .filter = DlBlurMaskFilter::Make(DlBlurStyle::kNormal, 4)},
941 sk_font));
942 }
943
944 DisplayListToTexture(builder.Build(), {400, 400}, aiks_context);
945
946 // Text should be cached. All 10 glyphs use the same cache entry.
947 EXPECT_EQ(aiks_context.GetContentContext()
950 1u);
951}
952
953TEST_P(AiksTest, VarietyOfTextScalesShowingRasterAndPath) {
954 DisplayListBuilder builder;
955 DlPaint paint;
956 paint.setColor(DlColor::ARGB(1, 0.1, 0.1, 0.1));
957 builder.DrawPaint(paint);
958 builder.Scale(GetContentScale().x, GetContentScale().y);
959
960 std::vector<Scalar> scales = {4, 8, 16, 24, 32};
961 std::vector<Scalar> spacing = {8, 8, 8, 8, 8};
962 Scalar space = 16;
963 Scalar x = 0;
964 for (auto i = 0u; i < scales.size(); i++) {
965 builder.Save();
966 builder.Scale(scales[i], scales[i]);
968 GetContext(), builder, "lo", "Roboto-Regular.ttf",
969 TextRenderOptions{.font_size = 16, .position = DlPoint(x, space)});
970 space += spacing[i];
971 if (i == 3) {
972 x = 10;
973 space = 16;
974 }
975 builder.Restore();
976 }
977 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
978}
979
980namespace {
981std::shared_ptr<TextFrame> MakeDefaultTextFrame(const std::string& text,
983 // Construct the text blob.
984 auto mapping = flutter::testing::OpenFixtureAsSkData("Roboto-Regular.ttf");
985 if (mapping == nullptr) {
986 return nullptr;
987 }
988
989 sk_sp<SkFontMgr> font_mgr = txt::GetDefaultFontManager();
990 SkFont sk_font(font_mgr->makeFromData(mapping), font_size);
991 sk_sp<SkTextBlob> blob = SkTextBlob::MakeFromString("Hi", sk_font);
992
993 std::shared_ptr<TextFrame> text_frame = MakeTextFrameFromTextBlobSkia(blob);
994 return text_frame;
995}
996
997void DrawTextFramesMultipleScalesWithReuse(AiksTest* test,
998 Scalar first_scale,
999 Scalar second_scale) {
1000 DisplayListBuilder builder;
1001 builder.Scale(test->GetContentScale().x, test->GetContentScale().y);
1002 builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
1003
1004 std::shared_ptr<TextFrame> reuse_frame = MakeDefaultTextFrame("Hi", 20.0f);
1005 ASSERT_NE(reuse_frame, nullptr);
1006
1007 builder.Save();
1008 builder.Translate(100, 100);
1009 builder.Scale(first_scale, first_scale);
1010 builder.DrawText(DlTextImpeller::Make(reuse_frame), 0, 0,
1012 builder.Restore();
1013
1014 builder.Save();
1015 builder.Translate(400, 100);
1016 builder.Scale(second_scale, second_scale);
1017 builder.DrawText(DlTextImpeller::Make(reuse_frame), 0, 0,
1019 builder.Restore();
1020
1021 builder.Save();
1022 builder.Translate(100, 400);
1023 builder.Scale(first_scale, first_scale);
1024 std::shared_ptr<TextFrame> single_use_frame1 =
1025 MakeDefaultTextFrame("Hi", 20.0f);
1026 builder.DrawText(DlTextImpeller::Make(single_use_frame1), 0, 0,
1028 builder.Restore();
1029
1030 builder.Save();
1031 builder.Translate(400, 400);
1032 builder.Scale(second_scale, second_scale);
1033 std::shared_ptr<TextFrame> single_use_frame2 =
1034 MakeDefaultTextFrame("Hi", 20.0f);
1035 builder.DrawText(DlTextImpeller::Make(single_use_frame2), 0, 0,
1037 builder.Restore();
1038
1039 ASSERT_TRUE(test->OpenPlaygroundHere(builder.Build()));
1040}
1041} // namespace
1042
1043TEST_P(AiksTest, TextFramesDoNotShareRenderDataBigSmall) {
1044 DrawTextFramesMultipleScalesWithReuse(this, //
1045 /*first_scale=*/4.0f, //
1046 /*second_scale=*/0.5f);
1047}
1048
1049TEST_P(AiksTest, TextFramesDoNotShareRenderDataSmallBig) {
1050 DrawTextFramesMultipleScalesWithReuse(this, //
1051 /*first_scale=*/0.5f, //
1052 /*second_scale=*/4.0f);
1053}
1054
1055// Verifies that non-uniform (anisotropic) scaling uses bilinear filtering
1056// to avoid jagged/aliased text, while uniform scaling remains pixel-perfect.
1057// Regression test for https://github.com/flutter/flutter/issues/182143
1058TEST_P(AiksTest, TextWithNonUniformScale) {
1059 DisplayListBuilder builder;
1060
1061 DlPaint paint;
1062 paint.setColor(DlColor::ARGB(1, 0.1, 0.1, 0.1));
1063 builder.DrawPaint(paint);
1064
1065 // Row 1: Uniform scale (should use nearest-neighbor, pixel-perfect).
1066 builder.Save();
1067 builder.Scale(2, 2);
1068 ASSERT_TRUE(RenderTextInCanvasSkia(
1069 GetContext(), builder, "Uniform 2x2", "Roboto-Regular.ttf",
1070 TextRenderOptions{.font_size = 30, .position = DlPoint(20, 40)}));
1071 builder.Restore();
1072
1073 // Row 2: Non-uniform scale Y-only (ratio 2.0, triggers bilinear).
1074 builder.Save();
1075 builder.Scale(1, 2);
1076 ASSERT_TRUE(RenderTextInCanvasSkia(
1077 GetContext(), builder, "ScaleY 1x2", "Roboto-Regular.ttf",
1078 TextRenderOptions{.font_size = 30, .position = DlPoint(20, 140)}));
1079 builder.Restore();
1080
1081 // Row 3: Non-uniform scale X-only (ratio 3.0, triggers bilinear).
1082 builder.Save();
1083 builder.Scale(3, 1);
1084 ASSERT_TRUE(RenderTextInCanvasSkia(
1085 GetContext(), builder, "ScaleX 3x1", "Roboto-Regular.ttf",
1086 TextRenderOptions{.font_size = 30, .position = DlPoint(20, 300)}));
1087 builder.Restore();
1088
1089 // Row 4: Slightly non-uniform (ratio 1.1, below threshold, nearest).
1090 builder.Save();
1091 builder.Scale(2, 2.2);
1092 ASSERT_TRUE(RenderTextInCanvasSkia(
1093 GetContext(), builder, "Near-uniform 2x2.2", "Roboto-Regular.ttf",
1094 TextRenderOptions{.font_size = 30, .position = DlPoint(20, 200)}));
1095 builder.Restore();
1096
1097 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1098}
1099
1100} // namespace testing
1101} // namespace impeller
void ClipRect(const DlRect &rect, DlClipOp clip_op=DlClipOp::kIntersect, bool is_aa=false) override
void DrawRoundRect(const DlRoundRect &rrect, const DlPaint &paint) override
void DrawColor(DlColor color, DlBlendMode mode) override
void DrawCircle(const DlPoint &center, DlScalar radius, const DlPaint &paint) override
void SaveLayer(const std::optional< DlRect > &bounds, const DlPaint *paint=nullptr, const DlImageFilter *backdrop=nullptr, std::optional< int64_t > backdrop_id=std::nullopt) override
void Rotate(DlScalar degrees) override
void DrawText(const std::shared_ptr< DlText > &text, DlScalar x, DlScalar y, const DlPaint &paint) override
void Scale(DlScalar sx, DlScalar sy) override
void DrawDisplayList(const sk_sp< DisplayList > display_list, DlScalar opacity=SK_Scalar1) override
void Translate(DlScalar tx, DlScalar ty) override
void DrawPaint(const DlPaint &paint) override
sk_sp< DisplayList > Build()
void DrawPath(const DlPath &path, const DlPaint &paint) override
void Transform(const DlMatrix &matrix) override
void DrawRect(const DlRect &rect, const DlPaint &paint) override
static std::shared_ptr< DlMaskFilter > Make(DlBlurStyle style, SkScalar sigma, bool respect_ctm=true)
static std::shared_ptr< DlColorSource > MakeLinear(const DlPoint start_point, const DlPoint end_point, uint32_t stop_count, const DlColor *colors, const float *stops, DlTileMode tile_mode, const DlMatrix *matrix=nullptr)
DlPaint & setColor(DlColor color)
Definition dl_paint.h:70
DlPaint & setStrokeWidth(float width)
Definition dl_paint.h:115
DlPaint & setBlendMode(DlBlendMode mode)
Definition dl_paint.h:85
DlPaint & setMaskFilter(std::nullptr_t filter)
Definition dl_paint.h:185
DlPaint & setDrawStyle(DlDrawStyle style)
Definition dl_paint.h:93
DlPaint & setColorSource(std::nullptr_t source)
Definition dl_paint.h:131
DlPathBuilder & LineTo(DlPoint p2)
Draw a line from the current point to the indicated point p2.
DlPathBuilder & MoveTo(DlPoint p2)
Start a new contour that will originate at the indicated point p2.
const DlPath TakePath()
Returns the path constructed by this path builder and resets its internal state to the default state ...
DlPathBuilder & Close()
The path is closed back to the location of the most recent MoveTo call. Contours that are filled are ...
static std::shared_ptr< DlTextImpeller > Make(const std::shared_ptr< impeller::TextFrame > &frame)
ContentContext & GetContentContext() const
std::shared_ptr< Context > GetContext() const
static bool ImGuiBegin(const char *name, bool *p_open, ImGuiWindowFlags flags)
const std::shared_ptr< RenderTargetAllocator > & GetRenderTargetCache() const
const std::shared_ptr< LazyGlyphAtlas > & GetLazyGlyphAtlas() const
TextShadowCache & GetTextShadowCache() const
void SetTransform(const Matrix &transform)
Set the global transform matrix for this Entity.
Definition entity.cc:62
void SetPosition(Point position)
void SetScreenTransform(const Matrix &transform)
bool Render(const ContentContext &renderer, const Entity &entity, RenderPass &pass) const override
void SetTextFrame(const std::shared_ptr< TextFrame > &frame)
void SetColor(Color color)
size_t GetCacheSizeForTesting() const
int32_t x
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
FlutterDesktopBinaryReply callback
std::u16string text
double y
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.
Definition testing.cc:63
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
Definition switch_defs.h:52
DlDrawStyle
Definition dl_paint.h:19
@ kFill
fills interior of shapes
impeller::Point DlPoint
AiksPlayground AiksTest
bool RenderTextInCanvasSkia(const std::shared_ptr< Context > &context, DisplayListBuilder &canvas, const std::string &text, const std::string_view &font_fixture, const TextRenderOptions &options={}, const std::optional< SkFont > &font=std::nullopt)
TEST_P(AiksTest, DrawAtlasNoColor)
static constexpr std::string_view kFontFixture
constexpr float k2Pi
Definition constants.h:29
float Scalar
Definition scalar.h:19
std::shared_ptr< Texture > DisplayListToTexture(const sk_sp< flutter::DisplayList > &display_list, ISize size, AiksContext &context, bool reset_host_buffer, bool generate_mips, std::optional< PixelFormat > target_pixel_format)
Render the provided display list to a texture with the given size.
std::shared_ptr< TextFrame > MakeTextFrameFromTextBlobSkia(const sk_sp< SkTextBlob > &blob)
sk_sp< SkFontMgr > GetDefaultFontManager(uint32_t font_initialization_data)
Definition platform.cc:17
int32_t height
int32_t width
static constexpr DlColor kWhite()
Definition dl_color.h:70
static constexpr DlColor kBlue()
Definition dl_color.h:73
static constexpr DlColor RGBA(DlScalar r, DlScalar g, DlScalar b, DlScalar a)
Construct a 32 bit color from floating point R, G, B, and A color channels.
Definition dl_color.h:48
static constexpr DlColor kBlack()
Definition dl_color.h:69
static constexpr DlColor ARGB(DlScalar a, DlScalar r, DlScalar g, DlScalar b)
Construct a 32 bit color from floating point A, R, G, and B color channels.
Definition dl_color.h:57
static constexpr DlColor kAqua()
Definition dl_color.h:86
static constexpr DlColor kYellow()
Definition dl_color.h:76
static constexpr DlColor kPurple()
Definition dl_color.h:88
static constexpr DlColor kDarkGreen()
Definition dl_color.h:93
static constexpr DlColor kRed()
Definition dl_color.h:71
static constexpr DlColor kGreen()
Definition dl_color.h:72
static constexpr DlColor kOrange()
Definition dl_color.h:87
constexpr DlColor modulateOpacity(DlScalar opacity) const
Definition dl_color.h:150
static constexpr Color Aqua()
Definition color.h:295
A 4x4 matrix using column-major storage.
Definition matrix.h:37
static Matrix MakeRotationY(Radians r)
Definition matrix.h:208
static constexpr Matrix MakeRow(Scalar m0, Scalar m1, Scalar m2, Scalar m3, Scalar m4, Scalar m5, Scalar m6, Scalar m7, Scalar m8, Scalar m9, Scalar m10, Scalar m11, Scalar m12, Scalar m13, Scalar m14, Scalar m15)
Definition matrix.h:83
static constexpr Matrix MakeTranslateScale(const Vector3 &s, const Vector3 &t)
Definition matrix.h:113
static constexpr Matrix MakeScale(const Vector3 &s)
Definition matrix.h:104
static RoundRect MakeRectRadius(const Rect &rect, Scalar radius)
Definition round_rect.h:27
static constexpr TRect MakeXYWH(Type x, Type y, Type width, Type height)
Definition rect.h:136
static constexpr TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
Definition rect.h:129
std::shared_ptr< DlMaskFilter > filter
Scalar font_size
bool is_subpixel