Flutter Engine
The Flutter Engine
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
dl_op_spy_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/display_list/display_list.h"
6#include "flutter/display_list/dl_builder.h"
7#include "flutter/display_list/testing/dl_test_snippets.h"
8#include "flutter/shell/common/dl_op_spy.h"
9#include "flutter/testing/testing.h"
13
14namespace flutter {
15namespace testing {
16
17// The following macros demonstrate that the DlOpSpy class is equivalent
18// to DisplayList::affects_transparent_surface() now that DisplayListBuilder
19// implements operation culling.
20// See https://github.com/flutter/flutter/issues/125403
21#define ASSERT_DID_DRAW(spy, dl) \
22 do { \
23 ASSERT_TRUE(spy.did_draw()); \
24 ASSERT_TRUE(dl->modifies_transparent_black()); \
25 } while (0)
26
27#define ASSERT_NO_DRAW(spy, dl) \
28 do { \
29 ASSERT_FALSE(spy.did_draw()); \
30 ASSERT_FALSE(dl->modifies_transparent_black()); \
31 } while (0)
32
33TEST(DlOpSpy, DidDrawIsFalseByDefault) {
34 DlOpSpy dl_op_spy;
35 ASSERT_FALSE(dl_op_spy.did_draw());
36}
37
38TEST(DlOpSpy, EmptyDisplayList) {
40 sk_sp<DisplayList> dl = builder.Build();
41 DlOpSpy dl_op_spy;
42 dl->Dispatch(dl_op_spy);
43 ASSERT_NO_DRAW(dl_op_spy, dl);
44}
45
46TEST(DlOpSpy, SetColor) {
47 { // No Color set.
50 builder.DrawRect(SkRect::MakeWH(5, 5), paint);
51 sk_sp<DisplayList> dl = builder.Build();
52 DlOpSpy dl_op_spy;
53 dl->Dispatch(dl_op_spy);
54 ASSERT_DID_DRAW(dl_op_spy, dl);
55 }
56 { // Set transparent color.
59 builder.DrawRect(SkRect::MakeWH(5, 5), paint);
60 sk_sp<DisplayList> dl = builder.Build();
61 DlOpSpy dl_op_spy;
62 dl->Dispatch(dl_op_spy);
63 ASSERT_NO_DRAW(dl_op_spy, dl);
64 }
65 { // Set black color.
68 builder.DrawRect(SkRect::MakeWH(5, 5), paint);
69 sk_sp<DisplayList> dl = builder.Build();
70 DlOpSpy dl_op_spy;
71 dl->Dispatch(dl_op_spy);
72 ASSERT_DID_DRAW(dl_op_spy, dl);
73 }
74}
75
76TEST(DlOpSpy, SetColorSource) {
77 { // Set null source
80 paint.setColorSource(nullptr);
81 builder.DrawRect(SkRect::MakeWH(5, 5), paint);
82 sk_sp<DisplayList> dl = builder.Build();
83 DlOpSpy dl_op_spy;
84 dl->Dispatch(dl_op_spy);
85 ASSERT_DID_DRAW(dl_op_spy, dl);
86 }
87 { // Set transparent color.
91 DlColorColorSource color_source_transparent(color);
92 paint.setColorSource(color_source_transparent.shared());
93 builder.DrawRect(SkRect::MakeWH(5, 5), paint);
94 sk_sp<DisplayList> dl = builder.Build();
95 DlOpSpy dl_op_spy;
96 dl->Dispatch(dl_op_spy);
97 ASSERT_NO_DRAW(dl_op_spy, dl);
98 }
99 { // Set black color.
102 auto color = DlColor::kBlack();
103 DlColorColorSource color_source_transparent(color);
104 paint.setColorSource(color_source_transparent.shared());
105 builder.DrawRect(SkRect::MakeWH(5, 5), paint);
106 sk_sp<DisplayList> dl = builder.Build();
107 DlOpSpy dl_op_spy;
108 dl->Dispatch(dl_op_spy);
109 ASSERT_DID_DRAW(dl_op_spy, dl);
110 }
111}
112
113TEST(DlOpSpy, DrawColor) {
114 { // Black color source.
116 auto color = DlColor::kBlack();
117 builder.DrawColor(color, DlBlendMode::kSrc);
118 sk_sp<DisplayList> dl = builder.Build();
119 DlOpSpy dl_op_spy;
120 dl->Dispatch(dl_op_spy);
121 ASSERT_DID_DRAW(dl_op_spy, dl);
122 }
123 { // Transparent color with kSrc.
126 builder.DrawColor(color, DlBlendMode::kSrc);
127 sk_sp<DisplayList> dl = builder.Build();
128 DlOpSpy dl_op_spy;
129 dl->Dispatch(dl_op_spy);
130 ASSERT_NO_DRAW(dl_op_spy, dl);
131 }
132 { // Transparent color with kSrcOver.
136 sk_sp<DisplayList> dl = builder.Build();
137 DlOpSpy dl_op_spy;
138 dl->Dispatch(dl_op_spy);
139 ASSERT_NO_DRAW(dl_op_spy, dl);
140 }
141}
142
143TEST(DlOpSpy, DrawPaint) {
144 { // Transparent color in paint.
147 builder.DrawPaint(paint);
148 sk_sp<DisplayList> dl = builder.Build();
149 DlOpSpy dl_op_spy;
150 dl->Dispatch(dl_op_spy);
151 ASSERT_NO_DRAW(dl_op_spy, dl);
152 }
153 { // black color in paint.
156 builder.DrawPaint(paint);
157 sk_sp<DisplayList> dl = builder.Build();
158 DlOpSpy dl_op_spy;
159 dl->Dispatch(dl_op_spy);
160 ASSERT_DID_DRAW(dl_op_spy, dl);
161 }
162}
163
164TEST(DlOpSpy, DrawLine) {
165 { // black
168 builder.DrawLine(SkPoint::Make(0, 1), SkPoint::Make(1, 2), paint);
169 sk_sp<DisplayList> dl = builder.Build();
170 DlOpSpy dl_op_spy;
171 dl->Dispatch(dl_op_spy);
172 ASSERT_DID_DRAW(dl_op_spy, dl);
173 }
174 { // transparent
177 builder.DrawLine(SkPoint::Make(0, 1), SkPoint::Make(1, 2), paint);
178 sk_sp<DisplayList> dl = builder.Build();
179 DlOpSpy dl_op_spy;
180 dl->Dispatch(dl_op_spy);
181 ASSERT_NO_DRAW(dl_op_spy, dl);
182 }
183}
184
185TEST(DlOpSpy, DrawDashedLine) {
186 { // black
189 builder.DrawDashedLine(DlPoint(0, 1), DlPoint(1, 2), 1.0f, 1.0f, paint);
190 sk_sp<DisplayList> dl = builder.Build();
191 DlOpSpy dl_op_spy;
192 dl->Dispatch(dl_op_spy);
193 ASSERT_DID_DRAW(dl_op_spy, dl);
194 }
195 { // transparent
198 builder.DrawDashedLine(DlPoint(0, 1), DlPoint(1, 2), 1.0f, 1.0f, paint);
199 sk_sp<DisplayList> dl = builder.Build();
200 DlOpSpy dl_op_spy;
201 dl->Dispatch(dl_op_spy);
202 ASSERT_NO_DRAW(dl_op_spy, dl);
203 }
204}
205
206TEST(DlOpSpy, DrawRect) {
207 { // black
210 builder.DrawRect(SkRect::MakeWH(5, 5), paint);
211 sk_sp<DisplayList> dl = builder.Build();
212 DlOpSpy dl_op_spy;
213 dl->Dispatch(dl_op_spy);
214 ASSERT_DID_DRAW(dl_op_spy, dl);
215 }
216 { // transparent
219 builder.DrawRect(SkRect::MakeWH(5, 5), paint);
220 sk_sp<DisplayList> dl = builder.Build();
221 DlOpSpy dl_op_spy;
222 dl->Dispatch(dl_op_spy);
223 ASSERT_NO_DRAW(dl_op_spy, dl);
224 }
225}
226
227TEST(DlOpSpy, DrawOval) {
228 { // black
231 builder.DrawOval(SkRect::MakeWH(5, 5), paint);
232 sk_sp<DisplayList> dl = builder.Build();
233 DlOpSpy dl_op_spy;
234 dl->Dispatch(dl_op_spy);
235 ASSERT_DID_DRAW(dl_op_spy, dl);
236 }
237 { // transparent
240 builder.DrawOval(SkRect::MakeWH(5, 5), paint);
241 sk_sp<DisplayList> dl = builder.Build();
242 DlOpSpy dl_op_spy;
243 dl->Dispatch(dl_op_spy);
244 ASSERT_NO_DRAW(dl_op_spy, dl);
245 }
246}
247
248TEST(DlOpSpy, DrawCircle) {
249 { // black
252 builder.DrawCircle(SkPoint::Make(5, 5), 1.0, paint);
253 sk_sp<DisplayList> dl = builder.Build();
254 DlOpSpy dl_op_spy;
255 dl->Dispatch(dl_op_spy);
256 ASSERT_DID_DRAW(dl_op_spy, dl);
257 }
258 { // transparent
261 builder.DrawCircle(SkPoint::Make(5, 5), 1.0, paint);
262 sk_sp<DisplayList> dl = builder.Build();
263 DlOpSpy dl_op_spy;
264 dl->Dispatch(dl_op_spy);
265 ASSERT_NO_DRAW(dl_op_spy, dl);
266 }
267}
268
269TEST(DlOpSpy, DrawRRect) {
270 { // black
274 sk_sp<DisplayList> dl = builder.Build();
275 DlOpSpy dl_op_spy;
276 dl->Dispatch(dl_op_spy);
277 ASSERT_DID_DRAW(dl_op_spy, dl);
278 }
279 { // transparent
283 sk_sp<DisplayList> dl = builder.Build();
284 DlOpSpy dl_op_spy;
285 dl->Dispatch(dl_op_spy);
286 ASSERT_NO_DRAW(dl_op_spy, dl);
287 }
288}
289
290TEST(DlOpSpy, DrawPath) {
291 { // black line
294 paint.setDrawStyle(DlDrawStyle::kStroke);
295 builder.DrawPath(SkPath::Line(SkPoint::Make(0, 1), SkPoint::Make(1, 1)),
296 paint);
297 sk_sp<DisplayList> dl = builder.Build();
298 DlOpSpy dl_op_spy;
299 dl->Dispatch(dl_op_spy);
300 ASSERT_DID_DRAW(dl_op_spy, dl);
301 }
302 { // triangle
305 SkPath path;
306 path.moveTo({0, 0});
307 path.lineTo({1, 0});
308 path.lineTo({0, 1});
309 builder.DrawPath(path, paint);
310 sk_sp<DisplayList> dl = builder.Build();
311 DlOpSpy dl_op_spy;
312 dl->Dispatch(dl_op_spy);
313 ASSERT_DID_DRAW(dl_op_spy, dl);
314 }
315 { // transparent line
318 paint.setDrawStyle(DlDrawStyle::kStroke);
319 builder.DrawPath(SkPath::Line(SkPoint::Make(0, 1), SkPoint::Make(1, 1)),
320 paint);
321 sk_sp<DisplayList> dl = builder.Build();
322 DlOpSpy dl_op_spy;
323 dl->Dispatch(dl_op_spy);
324 ASSERT_NO_DRAW(dl_op_spy, dl);
325 }
326}
327
328TEST(DlOpSpy, DrawArc) {
329 { // black
332 builder.DrawArc(SkRect::MakeWH(5, 5), 0, 1, true, paint);
333 sk_sp<DisplayList> dl = builder.Build();
334 DlOpSpy dl_op_spy;
335 dl->Dispatch(dl_op_spy);
336 ASSERT_DID_DRAW(dl_op_spy, dl);
337 }
338 { // transparent
341 builder.DrawArc(SkRect::MakeWH(5, 5), 0, 1, true, paint);
342 sk_sp<DisplayList> dl = builder.Build();
343 DlOpSpy dl_op_spy;
344 dl->Dispatch(dl_op_spy);
345 ASSERT_NO_DRAW(dl_op_spy, dl);
346 }
347}
348
349TEST(DlOpSpy, DrawPoints) {
350 { // black
353 const SkPoint points[] = {SkPoint::Make(5, 4)};
355 sk_sp<DisplayList> dl = builder.Build();
356 DlOpSpy dl_op_spy;
357 dl->Dispatch(dl_op_spy);
358 ASSERT_DID_DRAW(dl_op_spy, dl);
359 }
360 { // transparent
363 const SkPoint points[] = {SkPoint::Make(5, 4)};
365 sk_sp<DisplayList> dl = builder.Build();
366 DlOpSpy dl_op_spy;
367 dl->Dispatch(dl_op_spy);
368 ASSERT_NO_DRAW(dl_op_spy, dl);
369 }
370}
371
372TEST(DlOpSpy, DrawVertices) {
373 { // black
376 const SkPoint vertices[] = {
377 SkPoint::Make(5, 5),
378 SkPoint::Make(5, 15),
379 SkPoint::Make(15, 5),
380 };
381 const SkPoint texture_coordinates[] = {
382 SkPoint::Make(5, 5),
383 SkPoint::Make(15, 5),
384 SkPoint::Make(5, 15),
385 };
386 const DlColor colors[] = {
390 };
391 auto dl_vertices = DlVertices::Make(DlVertexMode::kTriangles, 3, vertices,
392 texture_coordinates, colors, 0);
393 builder.DrawVertices(dl_vertices.get(), DlBlendMode::kSrc, paint);
394 sk_sp<DisplayList> dl = builder.Build();
395 DlOpSpy dl_op_spy;
396 dl->Dispatch(dl_op_spy);
397 ASSERT_DID_DRAW(dl_op_spy, dl);
398 }
399 { // transparent
402 const SkPoint vertices[] = {
403 SkPoint::Make(5, 5),
404 SkPoint::Make(5, 15),
405 SkPoint::Make(15, 5),
406 };
407 const SkPoint texture_coordinates[] = {
408 SkPoint::Make(5, 5),
409 SkPoint::Make(15, 5),
410 SkPoint::Make(5, 15),
411 };
412 const DlColor colors[] = {
416 };
417 auto dl_vertices = DlVertices::Make(DlVertexMode::kTriangles, 3, vertices,
418 texture_coordinates, colors, 0);
419 builder.DrawVertices(dl_vertices.get(), DlBlendMode::kSrc, paint);
420 sk_sp<DisplayList> dl = builder.Build();
421 DlOpSpy dl_op_spy;
422 dl->Dispatch(dl_op_spy);
423 ASSERT_NO_DRAW(dl_op_spy, dl);
424 }
425}
426
427TEST(DlOpSpy, Images) {
428 { // DrawImage
435 bitmap.allocPixels(info, 0);
436 auto sk_image = SkImages::RasterFromBitmap(bitmap);
437 builder.DrawImage(DlImage::Make(sk_image), SkPoint::Make(5, 5),
439 sk_sp<DisplayList> dl = builder.Build();
440 DlOpSpy dl_op_spy;
441 dl->Dispatch(dl_op_spy);
442 ASSERT_DID_DRAW(dl_op_spy, dl);
443 }
444 { // DrawImageRect
451 bitmap.allocPixels(info, 0);
452 auto sk_image = SkImages::RasterFromBitmap(bitmap);
453 builder.DrawImageRect(DlImage::Make(sk_image), SkRect::MakeWH(5, 5),
455 sk_sp<DisplayList> dl = builder.Build();
456 DlOpSpy dl_op_spy;
457 dl->Dispatch(dl_op_spy);
458 ASSERT_DID_DRAW(dl_op_spy, dl);
459 }
460 { // DrawImageNine
467 bitmap.allocPixels(info, 0);
468 auto sk_image = SkImages::RasterFromBitmap(bitmap);
469 builder.DrawImageNine(DlImage::Make(sk_image), SkIRect::MakeWH(5, 5),
471 sk_sp<DisplayList> dl = builder.Build();
472 DlOpSpy dl_op_spy;
473 dl->Dispatch(dl_op_spy);
474 ASSERT_DID_DRAW(dl_op_spy, dl);
475 }
476 { // DrawAtlas
483 bitmap.allocPixels(info, 0);
484 auto sk_image = SkImages::RasterFromBitmap(bitmap);
485 const SkRSXform xform[] = {SkRSXform::Make(1, 0, 0, 0)};
486 const SkRect tex[] = {SkRect::MakeXYWH(10, 10, 10, 10)};
487 SkRect cull_rect = SkRect::MakeWH(5, 5);
488 builder.DrawAtlas(DlImage::Make(sk_image), xform, tex, nullptr, 1,
490 sk_sp<DisplayList> dl = builder.Build();
491 DlOpSpy dl_op_spy;
492 dl->Dispatch(dl_op_spy);
493 ASSERT_DID_DRAW(dl_op_spy, dl);
494 }
495}
496
497TEST(DlOpSpy, DrawDisplayList) {
498 { // Recursive Transparent DisplayList
501 builder.DrawPaint(paint);
502 sk_sp<DisplayList> dl = builder.Build();
503
504 DisplayListBuilder builder_parent;
505 DlPaint paint_parent(DlColor::kTransparent());
506 builder_parent.DrawPaint(paint_parent);
507 builder_parent.DrawDisplayList(dl, 1);
508 sk_sp<DisplayList> dl2 = builder_parent.Build();
509
510 DlOpSpy dl_op_spy;
511 dl2->Dispatch(dl_op_spy);
512 ASSERT_NO_DRAW(dl_op_spy, dl2);
513 }
514 { // Sub non-transparent DisplayList,
517 builder.DrawPaint(paint);
518 sk_sp<DisplayList> dl = builder.Build();
519
520 DisplayListBuilder builder_parent;
521 DlPaint paint_parent(DlColor::kTransparent());
522 builder_parent.DrawPaint(paint_parent);
523 builder_parent.DrawDisplayList(dl, 1);
524 sk_sp<DisplayList> dl2 = builder_parent.Build();
525
526 DlOpSpy dl_op_spy;
527 dl2->Dispatch(dl_op_spy);
528 ASSERT_DID_DRAW(dl_op_spy, dl2);
529 }
530
531 { // Sub non-transparent DisplayList, 0 opacity
534 builder.DrawPaint(paint);
535 sk_sp<DisplayList> dl = builder.Build();
536
537 DisplayListBuilder builder_parent;
538 DlPaint paint_parent(DlColor::kTransparent());
539 builder_parent.DrawPaint(paint_parent);
540 builder_parent.DrawDisplayList(dl, 0);
541 sk_sp<DisplayList> dl2 = builder_parent.Build();
542
543 DlOpSpy dl_op_spy;
544 dl2->Dispatch(dl_op_spy);
545 ASSERT_NO_DRAW(dl_op_spy, dl2);
546 }
547
548 { // Parent non-transparent DisplayList
551 builder.DrawPaint(paint);
552 sk_sp<DisplayList> dl = builder.Build();
553
554 DisplayListBuilder builder_parent;
555 DlPaint paint_parent(DlColor::kBlack());
556 builder_parent.DrawPaint(paint_parent);
557 builder_parent.DrawDisplayList(dl, 0);
558 sk_sp<DisplayList> dl2 = builder_parent.Build();
559
560 DlOpSpy dl_op_spy;
561 dl2->Dispatch(dl_op_spy);
562 ASSERT_DID_DRAW(dl_op_spy, dl2);
563 }
564}
565
566TEST(DlOpSpy, DrawTextBlob) {
567 { // Non-transparent color.
570 std::string string = "xx";
572 auto text_blob = SkTextBlob::MakeFromString(string.c_str(), font);
573 builder.DrawTextBlob(text_blob, 1, 1, paint);
574 sk_sp<DisplayList> dl = builder.Build();
575 DlOpSpy dl_op_spy;
576 dl->Dispatch(dl_op_spy);
577 ASSERT_DID_DRAW(dl_op_spy, dl);
578 }
579 { // transparent color.
582 std::string string = "xx";
584 auto text_blob = SkTextBlob::MakeFromString(string.c_str(), font);
585 builder.DrawTextBlob(text_blob, 1, 1, paint);
586 sk_sp<DisplayList> dl = builder.Build();
587 DlOpSpy dl_op_spy;
588 dl->Dispatch(dl_op_spy);
589 ASSERT_NO_DRAW(dl_op_spy, dl);
590 }
591}
592
593TEST(DlOpSpy, DrawShadow) {
594 { // valid shadow
599 builder.DrawShadow(path, color, 1, false, 1);
600 sk_sp<DisplayList> dl = builder.Build();
601 DlOpSpy dl_op_spy;
602 dl->Dispatch(dl_op_spy);
603 ASSERT_DID_DRAW(dl_op_spy, dl);
604 }
605 { // transparent color
610 builder.DrawShadow(path, color, 1, false, 1);
611 sk_sp<DisplayList> dl = builder.Build();
612 DlOpSpy dl_op_spy;
613 dl->Dispatch(dl_op_spy);
614 ASSERT_NO_DRAW(dl_op_spy, dl);
615 }
616}
617
618} // namespace testing
619} // namespace flutter
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
static const int points[]
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition: SkAlphaType.h:29
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
Definition: SkColorType.h:24
Definition: SkFont.h:35
Definition: SkPath.h:59
static SkPath Line(const SkPoint a, const SkPoint b)
Definition: SkPath.h:106
static SkRRect MakeRect(const SkRect &r)
Definition: SkRRect.h:149
static sk_sp< SkTextBlob > MakeFromString(const char *string, const SkFont &font, SkTextEncoding encoding=SkTextEncoding::kUTF8)
Definition: SkTextBlob.h:115
void DrawPaint(const DlPaint &paint) override
Definition: dl_builder.cc:1053
sk_sp< DisplayList > Build()
Definition: dl_builder.cc:67
void DrawDisplayList(const sk_sp< DisplayList > display_list, SkScalar opacity=SK_Scalar1) override
Definition: dl_builder.cc:1535
@ kPoints
draw each point separately
std::shared_ptr< DlColorSource > shared() const override
static sk_sp< DlImage > Make(const SkImage *image)
Definition: dl_image.cc:11
bool did_draw()
Returns true if any non transparent content has been drawn.
Definition: dl_op_spy.cc:9
static std::shared_ptr< DlVertices > Make(DlVertexMode mode, int vertex_count, const SkPoint vertices[], const SkPoint texture_coordinates[], const DlColor colors[], int index_count=0, const uint16_t indices[]=nullptr)
Constructs a DlVector with compact inline storage for all of its required and optional lists of data.
Definition: dl_vertices.cc:39
const Paint & paint
Definition: color_source.cc:38
DlColor color
#define ASSERT_DID_DRAW(spy, dl)
#define ASSERT_NO_DRAW(spy, dl)
SK_API sk_sp< SkImage > RasterFromBitmap(const SkBitmap &bitmap)
PODArray< SkColor > colors
Definition: SkRecords.h:276
Definition: bitmap.py:1
SkFont CreateTestFontOfSize(SkScalar scalar)
TEST(DisplayListComplexity, EmptyDisplayList)
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: switches.h:57
@ kTriangles
The vertices are taken 3 at a time to form a triangle.
@ kStroke
strokes boundary of shapes
impeller::Point DlPoint
@ kSrcOver
r = s + (1-sa)*d
font
Font Metadata and Metrics.
static constexpr SkIRect MakeWH(int32_t w, int32_t h)
Definition: SkRect.h:56
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
static constexpr SkPoint Make(float x, float y)
Definition: SkPoint_impl.h:173
static SkRSXform Make(SkScalar scos, SkScalar ssin, SkScalar tx, SkScalar ty)
Definition: SkRSXform.h:24
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
Definition: SkRect.h:659
static constexpr SkRect MakeWH(float w, float h)
Definition: SkRect.h:609
static constexpr DlColor kBlack()
Definition: dl_color.h:22
static constexpr DlColor kTransparent()
Definition: dl_color.h:21
static constexpr DlColor kRed()
Definition: dl_color.h:24
static constexpr DlColor kGreen()
Definition: dl_color.h:25