1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2015 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "include/core/SkBitmap.h"
9cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h"
10cb93a386Sopenharmony_ci#include "include/core/SkPath.h"
11cb93a386Sopenharmony_ci#include "include/core/SkRect.h"
12cb93a386Sopenharmony_ci#include "src/core/SkRectPriv.h"
13cb93a386Sopenharmony_ci#include "tests/Test.h"
14cb93a386Sopenharmony_ci
15cb93a386Sopenharmony_ci#include <limits.h>
16cb93a386Sopenharmony_ci
17cb93a386Sopenharmony_cistatic bool has_green_pixels(const SkBitmap& bm) {
18cb93a386Sopenharmony_ci    for (int j = 0; j < bm.height(); ++j) {
19cb93a386Sopenharmony_ci        for (int i = 0; i < bm.width(); ++i) {
20cb93a386Sopenharmony_ci            if (SkColorGetG(bm.getColor(i, j))) {
21cb93a386Sopenharmony_ci                return true;
22cb93a386Sopenharmony_ci            }
23cb93a386Sopenharmony_ci        }
24cb93a386Sopenharmony_ci    }
25cb93a386Sopenharmony_ci
26cb93a386Sopenharmony_ci    return false;
27cb93a386Sopenharmony_ci}
28cb93a386Sopenharmony_ci
29cb93a386Sopenharmony_cistatic void test_stroke_width_clipping(skiatest::Reporter* reporter) {
30cb93a386Sopenharmony_ci    SkBitmap bm;
31cb93a386Sopenharmony_ci    bm.allocN32Pixels(100, 10);
32cb93a386Sopenharmony_ci    bm.eraseColor(SK_ColorTRANSPARENT);
33cb93a386Sopenharmony_ci
34cb93a386Sopenharmony_ci    SkCanvas canvas(bm);
35cb93a386Sopenharmony_ci    SkPaint paint;
36cb93a386Sopenharmony_ci    paint.setStyle(SkPaint::kStroke_Style);
37cb93a386Sopenharmony_ci    paint.setStrokeWidth(10);
38cb93a386Sopenharmony_ci    paint.setColor(0xff00ff00);
39cb93a386Sopenharmony_ci
40cb93a386Sopenharmony_ci    // clip out the left half of our canvas
41cb93a386Sopenharmony_ci    canvas.clipRect(SkRect::MakeXYWH(51, 0, 49, 100));
42cb93a386Sopenharmony_ci
43cb93a386Sopenharmony_ci    // no stroke bleed should be visible
44cb93a386Sopenharmony_ci    canvas.drawRect(SkRect::MakeWH(44, 100), paint);
45cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, !has_green_pixels(bm));
46cb93a386Sopenharmony_ci
47cb93a386Sopenharmony_ci    // right stroke edge should bleed into the visible area
48cb93a386Sopenharmony_ci    canvas.scale(2, 2);
49cb93a386Sopenharmony_ci    canvas.drawRect(SkRect::MakeWH(22, 50), paint);
50cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, has_green_pixels(bm));
51cb93a386Sopenharmony_ci}
52cb93a386Sopenharmony_ci
53cb93a386Sopenharmony_cistatic void test_skbug4406(skiatest::Reporter* reporter) {
54cb93a386Sopenharmony_ci    SkBitmap bm;
55cb93a386Sopenharmony_ci    bm.allocN32Pixels(10, 10);
56cb93a386Sopenharmony_ci    bm.eraseColor(SK_ColorTRANSPARENT);
57cb93a386Sopenharmony_ci
58cb93a386Sopenharmony_ci    SkCanvas canvas(bm);
59cb93a386Sopenharmony_ci    const SkRect r = { 1.5f, 1, 3.5f, 3 };
60cb93a386Sopenharmony_ci    // draw filled green rect first
61cb93a386Sopenharmony_ci    SkPaint paint;
62cb93a386Sopenharmony_ci    paint.setStyle(SkPaint::kFill_Style);
63cb93a386Sopenharmony_ci    paint.setColor(0xff00ff00);
64cb93a386Sopenharmony_ci    paint.setStrokeWidth(1);
65cb93a386Sopenharmony_ci    paint.setAntiAlias(true);
66cb93a386Sopenharmony_ci    canvas.drawRect(r, paint);
67cb93a386Sopenharmony_ci
68cb93a386Sopenharmony_ci    // paint black with stroke rect (that asserts in bug 4406)
69cb93a386Sopenharmony_ci    // over the filled rect, it should cover it
70cb93a386Sopenharmony_ci    paint.setStyle(SkPaint::kStroke_Style);
71cb93a386Sopenharmony_ci    paint.setColor(0xff000000);
72cb93a386Sopenharmony_ci    paint.setStrokeWidth(1);
73cb93a386Sopenharmony_ci    canvas.drawRect(r, paint);
74cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, !has_green_pixels(bm));
75cb93a386Sopenharmony_ci
76cb93a386Sopenharmony_ci    // do it again with thinner stroke
77cb93a386Sopenharmony_ci    paint.setStyle(SkPaint::kFill_Style);
78cb93a386Sopenharmony_ci    paint.setColor(0xff00ff00);
79cb93a386Sopenharmony_ci    paint.setStrokeWidth(1);
80cb93a386Sopenharmony_ci    paint.setAntiAlias(true);
81cb93a386Sopenharmony_ci    canvas.drawRect(r, paint);
82cb93a386Sopenharmony_ci    // paint black with stroke rect (that asserts in bug 4406)
83cb93a386Sopenharmony_ci    // over the filled rect, it doesnt cover it completelly with thinner stroke
84cb93a386Sopenharmony_ci    paint.setStyle(SkPaint::kStroke_Style);
85cb93a386Sopenharmony_ci    paint.setColor(0xff000000);
86cb93a386Sopenharmony_ci    paint.setStrokeWidth(0.99f);
87cb93a386Sopenharmony_ci    canvas.drawRect(r, paint);
88cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, has_green_pixels(bm));
89cb93a386Sopenharmony_ci}
90cb93a386Sopenharmony_ci
91cb93a386Sopenharmony_ciDEF_TEST(Rect, reporter) {
92cb93a386Sopenharmony_ci    test_stroke_width_clipping(reporter);
93cb93a386Sopenharmony_ci    test_skbug4406(reporter);
94cb93a386Sopenharmony_ci}
95cb93a386Sopenharmony_ci
96cb93a386Sopenharmony_ciDEF_TEST(Rect_grow, reporter) {
97cb93a386Sopenharmony_ci    test_stroke_width_clipping(reporter);
98cb93a386Sopenharmony_ci    test_skbug4406(reporter);
99cb93a386Sopenharmony_ci}
100cb93a386Sopenharmony_ci
101cb93a386Sopenharmony_ciDEF_TEST(Rect_path_nan, reporter) {
102cb93a386Sopenharmony_ci    SkRect r = { 0, 0, SK_ScalarNaN, 100 };
103cb93a386Sopenharmony_ci    SkPath p;
104cb93a386Sopenharmony_ci    p.addRect(r);
105cb93a386Sopenharmony_ci    // path normally just jams its bounds to be r, but it must notice that r is non-finite
106cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, !p.isFinite());
107cb93a386Sopenharmony_ci}
108cb93a386Sopenharmony_ci
109cb93a386Sopenharmony_ciDEF_TEST(Rect_largest, reporter) {
110cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, !SkRectPriv::MakeILarge().isEmpty());
111cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter,  SkRectPriv::MakeILargestInverted().isEmpty());
112cb93a386Sopenharmony_ci
113cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, !SkRectPriv::MakeLargest().isEmpty());
114cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, !SkRectPriv::MakeLargeS32().isEmpty());
115cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter,  SkRectPriv::MakeLargestInverted().isEmpty());
116cb93a386Sopenharmony_ci}
117cb93a386Sopenharmony_ci
118cb93a386Sopenharmony_ci/*
119cb93a386Sopenharmony_ci *  Test the setBounds always handles non-finite values correctly:
120cb93a386Sopenharmony_ci *  - setBoundsCheck should return false, and set the rect to all zeros
121cb93a386Sopenharmony_ci *  - setBoundsNoCheck should ensure that rect.isFinite() is false (definitely NOT all zeros)
122cb93a386Sopenharmony_ci */
123cb93a386Sopenharmony_ciDEF_TEST(Rect_setbounds, reporter) {
124cb93a386Sopenharmony_ci    const SkPoint p0[] = { { SK_ScalarInfinity, 0 }, { 1, 1 }, { 2, 2 }, { 3, 3 } };
125cb93a386Sopenharmony_ci    const SkPoint p1[] = { { 0, SK_ScalarInfinity }, { 1, 1 }, { 2, 2 }, { 3, 3 } };
126cb93a386Sopenharmony_ci    const SkPoint p2[] = { { SK_ScalarNaN, 0 }, { 1, 1 }, { 2, 2 }, { 3, 3 } };
127cb93a386Sopenharmony_ci    const SkPoint p3[] = { { 0, SK_ScalarNaN }, { 1, 1 }, { 2, 2 }, { 3, 3 } };
128cb93a386Sopenharmony_ci
129cb93a386Sopenharmony_ci    SkRect r;
130cb93a386Sopenharmony_ci    const SkRect zeror = { 0, 0, 0, 0 };
131cb93a386Sopenharmony_ci    for (const SkPoint* pts : { p0, p1, p2, p3 }) {
132cb93a386Sopenharmony_ci        for (int n = 1; n <= 4; ++n) {
133cb93a386Sopenharmony_ci            bool isfinite = r.setBoundsCheck(pts, n);
134cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, !isfinite);
135cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, r == zeror);
136cb93a386Sopenharmony_ci
137cb93a386Sopenharmony_ci            r.setBoundsNoCheck(pts, n);
138cb93a386Sopenharmony_ci            if (r.isFinite())
139cb93a386Sopenharmony_ci                r.setBoundsNoCheck(pts, n);
140cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, !r.isFinite());
141cb93a386Sopenharmony_ci        }
142cb93a386Sopenharmony_ci    }
143cb93a386Sopenharmony_ci}
144cb93a386Sopenharmony_ci
145cb93a386Sopenharmony_cistatic float make_big_value(skiatest::Reporter* reporter) {
146cb93a386Sopenharmony_ci    // need to make a big value, one that will cause rect.width() to overflow to inf.
147cb93a386Sopenharmony_ci    // however, the windows compiler wants about this if it can see the big value inlined.
148cb93a386Sopenharmony_ci    // hence, this stupid trick to try to fool their compiler.
149cb93a386Sopenharmony_ci    SkASSERT(reporter);
150cb93a386Sopenharmony_ci    return reporter ? SK_ScalarMax * 0.75f : 0;
151cb93a386Sopenharmony_ci}
152cb93a386Sopenharmony_ci
153cb93a386Sopenharmony_ciDEF_TEST(Rect_whOverflow, reporter) {
154cb93a386Sopenharmony_ci    const SkScalar big = make_big_value(reporter);
155cb93a386Sopenharmony_ci    const SkRect r = { -big, -big, big, big };
156cb93a386Sopenharmony_ci
157cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, r.isFinite());
158cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, !SkScalarIsFinite(r.width()));
159cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, !SkScalarIsFinite(r.height()));
160cb93a386Sopenharmony_ci
161cb93a386Sopenharmony_ci    // ensure we can compute center even when the width/height might overflow
162cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, SkScalarIsFinite(r.centerX()));
163cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, SkScalarIsFinite(r.centerY()));
164cb93a386Sopenharmony_ci
165cb93a386Sopenharmony_ci
166cb93a386Sopenharmony_ci    // ensure we can compute halfWidth and halfHeight even when width/height might overflow,
167cb93a386Sopenharmony_ci    // i.e. for use computing the radii filling a rectangle.
168cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, SkScalarIsFinite(SkRectPriv::HalfWidth(r)));
169cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, SkScalarIsFinite(SkRectPriv::HalfHeight(r)));
170cb93a386Sopenharmony_ci}
171cb93a386Sopenharmony_ci
172cb93a386Sopenharmony_ciDEF_TEST(Rect_subtract, reporter) {
173cb93a386Sopenharmony_ci    struct Expectation {
174cb93a386Sopenharmony_ci        SkIRect fA;
175cb93a386Sopenharmony_ci        SkIRect fB;
176cb93a386Sopenharmony_ci        SkIRect fExpected;
177cb93a386Sopenharmony_ci        bool    fExact;
178cb93a386Sopenharmony_ci    };
179cb93a386Sopenharmony_ci
180cb93a386Sopenharmony_ci    SkIRect a = SkIRect::MakeLTRB(2, 3, 12, 15);
181cb93a386Sopenharmony_ci    Expectation tests[] = {
182cb93a386Sopenharmony_ci        // B contains A == empty rect
183cb93a386Sopenharmony_ci        {a, a.makeOutset(2, 2), SkIRect::MakeEmpty(), true},
184cb93a386Sopenharmony_ci        // A contains B, producing 4x12 (left), 2x12 (right), 4x10(top), and 5x10(bottom)
185cb93a386Sopenharmony_ci        {a, {6, 6, 10, 10}, {2, 10, 12, 15}, false},
186cb93a386Sopenharmony_ci        // A is empty, B is not == empty rect
187cb93a386Sopenharmony_ci        {SkIRect::MakeEmpty(), a, SkIRect::MakeEmpty(), true},
188cb93a386Sopenharmony_ci        // A is not empty, B is empty == a
189cb93a386Sopenharmony_ci        {a, SkIRect::MakeEmpty(), a, true},
190cb93a386Sopenharmony_ci        // A and B are empty == empty
191cb93a386Sopenharmony_ci        {SkIRect::MakeEmpty(), SkIRect::MakeEmpty(), SkIRect::MakeEmpty(), true},
192cb93a386Sopenharmony_ci        // A and B do not intersect == a
193cb93a386Sopenharmony_ci        {a, {15, 17, 20, 40}, a, true},
194cb93a386Sopenharmony_ci        // B cuts off left side of A, producing 6x12 (right)
195cb93a386Sopenharmony_ci        {a, {0, 0, 6, 20}, {6, 3, 12, 15}, true},
196cb93a386Sopenharmony_ci        // B cuts off right side of A, producing 4x12 (left)
197cb93a386Sopenharmony_ci        {a, {6, 0, 20, 20}, {2, 3, 6, 15}, true},
198cb93a386Sopenharmony_ci        // B cuts off top side of A, producing 10x9 (bottom)
199cb93a386Sopenharmony_ci        {a, {0, 0, 20, 6}, {2, 6, 12, 15}, true},
200cb93a386Sopenharmony_ci        // B cuts off bottom side of A, producing 10x7 (top)
201cb93a386Sopenharmony_ci        {a, {0, 10, 20, 20}, {2, 3, 12, 10}, true},
202cb93a386Sopenharmony_ci        // B splits A horizontally, producing 10x3 (top) or 10x5 (bottom)
203cb93a386Sopenharmony_ci        {a, {0, 6, 20, 10}, {2, 10, 12, 15}, false},
204cb93a386Sopenharmony_ci        // B splits A vertically, producing 4x12 (left) or 2x12 (right)
205cb93a386Sopenharmony_ci        {a, {6, 0, 10, 20}, {2, 3, 6, 15}, false},
206cb93a386Sopenharmony_ci        // B cuts top-left of A, producing 8x12 (right) or 10x11 (bottom)
207cb93a386Sopenharmony_ci        {a, {0, 0, 4, 4}, {2, 4, 12, 15}, false},
208cb93a386Sopenharmony_ci        // B cuts top-right of A, producing 8x12 (left) or 10x8 (bottom)
209cb93a386Sopenharmony_ci        {a, {10, 0, 14, 7}, {2, 3, 10, 15}, false},
210cb93a386Sopenharmony_ci        // B cuts bottom-left of A, producing 7x12 (right) or 10x9 (top)
211cb93a386Sopenharmony_ci        {a, {0, 12, 5, 20}, {2, 3, 12, 12}, false},
212cb93a386Sopenharmony_ci        // B cuts bottom-right of A, producing 8x12 (left) or 10x9 (top)
213cb93a386Sopenharmony_ci        {a, {10, 12, 20, 20}, {2, 3, 10, 15}, false},
214cb93a386Sopenharmony_ci        // B crosses the left of A, producing 4x12 (right) or 10x3 (top) or 10x5 (bottom)
215cb93a386Sopenharmony_ci        {a, {0, 6, 8, 10}, {2, 10, 12, 15}, false},
216cb93a386Sopenharmony_ci        // B crosses the right side of A, producing 6x12 (left) or 10x3 (top) or 10x5 (bottom)
217cb93a386Sopenharmony_ci        {a, {8, 6, 20, 10}, {2, 3, 8, 15}, false},
218cb93a386Sopenharmony_ci        // B crosses the top side of A, producing 4x12 (left) or 2x12 (right) or 10x8 (bottom)
219cb93a386Sopenharmony_ci        {a, {6, 0, 10, 7}, {2, 7, 12, 15}, false},
220cb93a386Sopenharmony_ci        // B crosses the bottom side of A, producing 1x12 (left) or 4x12 (right) or 10x3 (top)
221cb93a386Sopenharmony_ci        {a, {4, 6, 8, 20}, {8, 3, 12, 15}, false}
222cb93a386Sopenharmony_ci    };
223cb93a386Sopenharmony_ci
224cb93a386Sopenharmony_ci    for (const Expectation& e : tests) {
225cb93a386Sopenharmony_ci        SkIRect difference;
226cb93a386Sopenharmony_ci        bool exact = SkRectPriv::Subtract(e.fA, e.fB, &difference);
227cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, exact == e.fExact);
228cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, difference == e.fExpected);
229cb93a386Sopenharmony_ci
230cb93a386Sopenharmony_ci        // Generate equivalent tests for the SkRect case by moving the input rects by 0.5px
231cb93a386Sopenharmony_ci        SkRect af = SkRect::Make(e.fA);
232cb93a386Sopenharmony_ci        SkRect bf = SkRect::Make(e.fB);
233cb93a386Sopenharmony_ci        SkRect ef = SkRect::Make(e.fExpected);
234cb93a386Sopenharmony_ci        af.offset(0.5f, 0.5f);
235cb93a386Sopenharmony_ci        bf.offset(0.5f, 0.5f);
236cb93a386Sopenharmony_ci        ef.offset(0.5f, 0.5f);
237cb93a386Sopenharmony_ci
238cb93a386Sopenharmony_ci        SkRect df;
239cb93a386Sopenharmony_ci        exact = SkRectPriv::Subtract(af, bf, &df);
240cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, exact == e.fExact);
241cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, (df.isEmpty() && ef.isEmpty()) || (df == ef));
242cb93a386Sopenharmony_ci    }
243cb93a386Sopenharmony_ci}
244cb93a386Sopenharmony_ci
245cb93a386Sopenharmony_ciDEF_TEST(Rect_subtract_overflow, reporter) {
246cb93a386Sopenharmony_ci    // This rectangle is sorted but whose int32 width overflows and appears negative (so
247cb93a386Sopenharmony_ci    // isEmpty() returns true).
248cb93a386Sopenharmony_ci    SkIRect reallyBig = SkIRect::MakeLTRB(-INT_MAX + 1000, 0, INT_MAX - 1000, 100);
249cb93a386Sopenharmony_ci    // However, because it's sorted, an intersection with a reasonably sized rectangle is still
250cb93a386Sopenharmony_ci    // valid so the assumption that SkIRect::Intersects() returns false when either input is
251cb93a386Sopenharmony_ci    // empty is invalid, leading to incorrect use of negative width (see crbug.com/1243206)
252cb93a386Sopenharmony_ci    SkIRect reasonable = SkIRect::MakeLTRB(-50, -5, 50, 125);
253cb93a386Sopenharmony_ci
254cb93a386Sopenharmony_ci    // Ignoring overflow, "reallyBig - reasonable" should report exact = false and select either the
255cb93a386Sopenharmony_ci    // left or right portion of 'reallyBig' that excludes 'reasonable', e.g.
256cb93a386Sopenharmony_ci    // {-INT_MAX+1000, 0, -50, 100} or {150, 0, INT_MAX-1000, 100}.
257cb93a386Sopenharmony_ci    // This used to assert, but now it should be detected that 'reallyBig' overflows and is
258cb93a386Sopenharmony_ci    // technically empty, so the result should be itself and exact.
259cb93a386Sopenharmony_ci    SkIRect difference;
260cb93a386Sopenharmony_ci    bool exact = SkRectPriv::Subtract(reallyBig, reasonable, &difference);
261cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, exact);
262cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, difference == reallyBig);
263cb93a386Sopenharmony_ci
264cb93a386Sopenharmony_ci    // Similarly, if we subtract 'reallyBig', since it's technically empty then we expect the
265cb93a386Sopenharmony_ci    // answer to remain 'reasonable'.
266cb93a386Sopenharmony_ci    exact = SkRectPriv::Subtract(reasonable, reallyBig, &difference);
267cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, exact);
268cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, difference == reasonable);
269cb93a386Sopenharmony_ci}
270cb93a386Sopenharmony_ci
271cb93a386Sopenharmony_ci#include "include/core/SkSurface.h"
272cb93a386Sopenharmony_ci
273cb93a386Sopenharmony_ci// Before the fix, this sequence would trigger a release_assert in the Tiler
274cb93a386Sopenharmony_ci// in SkBitmapDevice.cpp
275cb93a386Sopenharmony_ciDEF_TEST(big_tiled_rect_crbug_927075, reporter) {
276cb93a386Sopenharmony_ci    // since part of the regression test allocates a huge buffer, don't bother trying on
277cb93a386Sopenharmony_ci    // 32-bit devices (e.g. chromecast) so we avoid them failing to allocated.
278cb93a386Sopenharmony_ci
279cb93a386Sopenharmony_ci    if (sizeof(void*) == 8) {
280cb93a386Sopenharmony_ci        const int w = 67108863;
281cb93a386Sopenharmony_ci        const int h = 1;
282cb93a386Sopenharmony_ci        const auto info = SkImageInfo::MakeN32Premul(w, h);
283cb93a386Sopenharmony_ci
284cb93a386Sopenharmony_ci        auto surf = SkSurface::MakeRaster(info);
285cb93a386Sopenharmony_ci        auto canvas = surf->getCanvas();
286cb93a386Sopenharmony_ci
287cb93a386Sopenharmony_ci        const SkRect r = { 257, 213, 67109120, 214 };
288cb93a386Sopenharmony_ci        SkPaint paint;
289cb93a386Sopenharmony_ci        paint.setAntiAlias(true);
290cb93a386Sopenharmony_ci
291cb93a386Sopenharmony_ci        canvas->translate(-r.fLeft, -r.fTop);
292cb93a386Sopenharmony_ci        canvas->drawRect(r, paint);
293cb93a386Sopenharmony_ci    }
294cb93a386Sopenharmony_ci}
295