xref: /third_party/skia/tests/RecordOptsTest.cpp (revision cb93a386)
1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2014 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 "tests/RecordTestUtils.h"
9cb93a386Sopenharmony_ci#include "tests/Test.h"
10cb93a386Sopenharmony_ci
11cb93a386Sopenharmony_ci#include "include/core/SkColorFilter.h"
12cb93a386Sopenharmony_ci#include "include/core/SkPictureRecorder.h"
13cb93a386Sopenharmony_ci#include "include/core/SkSurface.h"
14cb93a386Sopenharmony_ci#include "include/effects/SkImageFilters.h"
15cb93a386Sopenharmony_ci#include "src/core/SkRecord.h"
16cb93a386Sopenharmony_ci#include "src/core/SkRecordOpts.h"
17cb93a386Sopenharmony_ci#include "src/core/SkRecorder.h"
18cb93a386Sopenharmony_ci#include "src/core/SkRecords.h"
19cb93a386Sopenharmony_ci
20cb93a386Sopenharmony_cistatic const int W = 1920, H = 1080;
21cb93a386Sopenharmony_ci
22cb93a386Sopenharmony_ciDEF_TEST(RecordOpts_NoopDraw, r) {
23cb93a386Sopenharmony_ci    SkRecord record;
24cb93a386Sopenharmony_ci    SkRecorder recorder(&record, W, H);
25cb93a386Sopenharmony_ci
26cb93a386Sopenharmony_ci    recorder.drawRect(SkRect::MakeWH(200, 200), SkPaint());
27cb93a386Sopenharmony_ci    recorder.drawRect(SkRect::MakeWH(300, 300), SkPaint());
28cb93a386Sopenharmony_ci    recorder.drawRect(SkRect::MakeWH(100, 100), SkPaint());
29cb93a386Sopenharmony_ci
30cb93a386Sopenharmony_ci    record.replace<SkRecords::NoOp>(1);  // NoOps should be allowed.
31cb93a386Sopenharmony_ci
32cb93a386Sopenharmony_ci    SkRecordNoopSaveRestores(&record);
33cb93a386Sopenharmony_ci
34cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, 2 == count_instances_of_type<SkRecords::DrawRect>(record));
35cb93a386Sopenharmony_ci}
36cb93a386Sopenharmony_ci
37cb93a386Sopenharmony_ciDEF_TEST(RecordOpts_SingleNoopSaveRestore, r) {
38cb93a386Sopenharmony_ci    SkRecord record;
39cb93a386Sopenharmony_ci    SkRecorder recorder(&record, W, H);
40cb93a386Sopenharmony_ci
41cb93a386Sopenharmony_ci    recorder.save();
42cb93a386Sopenharmony_ci        recorder.clipRect(SkRect::MakeWH(200, 200));
43cb93a386Sopenharmony_ci    recorder.restore();
44cb93a386Sopenharmony_ci
45cb93a386Sopenharmony_ci    SkRecordNoopSaveRestores(&record);
46cb93a386Sopenharmony_ci    for (int i = 0; i < 3; i++) {
47cb93a386Sopenharmony_ci        assert_type<SkRecords::NoOp>(r, record, i);
48cb93a386Sopenharmony_ci    }
49cb93a386Sopenharmony_ci}
50cb93a386Sopenharmony_ci
51cb93a386Sopenharmony_ciDEF_TEST(RecordOpts_NoopSaveRestores, r) {
52cb93a386Sopenharmony_ci    SkRecord record;
53cb93a386Sopenharmony_ci    SkRecorder recorder(&record, W, H);
54cb93a386Sopenharmony_ci
55cb93a386Sopenharmony_ci    // The second pass will clean up this pair after the first pass noops all the innards.
56cb93a386Sopenharmony_ci    recorder.save();
57cb93a386Sopenharmony_ci        // A simple pointless pair of save/restore.
58cb93a386Sopenharmony_ci        recorder.save();
59cb93a386Sopenharmony_ci        recorder.restore();
60cb93a386Sopenharmony_ci
61cb93a386Sopenharmony_ci        // As long as we don't draw in there, everything is a noop.
62cb93a386Sopenharmony_ci        recorder.save();
63cb93a386Sopenharmony_ci            recorder.clipRect(SkRect::MakeWH(200, 200));
64cb93a386Sopenharmony_ci            recorder.clipRect(SkRect::MakeWH(100, 100));
65cb93a386Sopenharmony_ci        recorder.restore();
66cb93a386Sopenharmony_ci    recorder.restore();
67cb93a386Sopenharmony_ci
68cb93a386Sopenharmony_ci    SkRecordNoopSaveRestores(&record);
69cb93a386Sopenharmony_ci    for (int index = 0; index < record.count(); index++) {
70cb93a386Sopenharmony_ci        assert_type<SkRecords::NoOp>(r, record, index);
71cb93a386Sopenharmony_ci    }
72cb93a386Sopenharmony_ci}
73cb93a386Sopenharmony_ci
74cb93a386Sopenharmony_ciDEF_TEST(RecordOpts_SaveSaveLayerRestoreRestore, r) {
75cb93a386Sopenharmony_ci    SkRecord record;
76cb93a386Sopenharmony_ci    SkRecorder recorder(&record, W, H);
77cb93a386Sopenharmony_ci
78cb93a386Sopenharmony_ci    // A previous bug NoOp'd away the first 3 commands.
79cb93a386Sopenharmony_ci    recorder.save();
80cb93a386Sopenharmony_ci        recorder.saveLayer(nullptr, nullptr);
81cb93a386Sopenharmony_ci        recorder.restore();
82cb93a386Sopenharmony_ci    recorder.restore();
83cb93a386Sopenharmony_ci
84cb93a386Sopenharmony_ci    SkRecordNoopSaveRestores(&record);
85cb93a386Sopenharmony_ci    switch (record.count()) {
86cb93a386Sopenharmony_ci        case 4:
87cb93a386Sopenharmony_ci            assert_type<SkRecords::Save>     (r, record, 0);
88cb93a386Sopenharmony_ci            assert_type<SkRecords::SaveLayer>(r, record, 1);
89cb93a386Sopenharmony_ci            assert_type<SkRecords::Restore>  (r, record, 2);
90cb93a386Sopenharmony_ci            assert_type<SkRecords::Restore>  (r, record, 3);
91cb93a386Sopenharmony_ci            break;
92cb93a386Sopenharmony_ci        case 2:
93cb93a386Sopenharmony_ci            assert_type<SkRecords::SaveLayer>(r, record, 0);
94cb93a386Sopenharmony_ci            assert_type<SkRecords::Restore>  (r, record, 1);
95cb93a386Sopenharmony_ci            break;
96cb93a386Sopenharmony_ci        case 0:
97cb93a386Sopenharmony_ci            break;
98cb93a386Sopenharmony_ci        default:
99cb93a386Sopenharmony_ci            REPORTER_ASSERT(r, false);
100cb93a386Sopenharmony_ci    }
101cb93a386Sopenharmony_ci}
102cb93a386Sopenharmony_ci
103cb93a386Sopenharmony_ci#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
104cb93a386Sopenharmony_cistatic void assert_savelayer_restore(skiatest::Reporter* r,
105cb93a386Sopenharmony_ci                                     SkRecord* record,
106cb93a386Sopenharmony_ci                                     int i,
107cb93a386Sopenharmony_ci                                     bool shouldBeNoOped) {
108cb93a386Sopenharmony_ci    SkRecordNoopSaveLayerDrawRestores(record);
109cb93a386Sopenharmony_ci    if (shouldBeNoOped) {
110cb93a386Sopenharmony_ci        assert_type<SkRecords::NoOp>(r, *record, i);
111cb93a386Sopenharmony_ci        assert_type<SkRecords::NoOp>(r, *record, i+1);
112cb93a386Sopenharmony_ci    } else {
113cb93a386Sopenharmony_ci        assert_type<SkRecords::SaveLayer>(r, *record, i);
114cb93a386Sopenharmony_ci        assert_type<SkRecords::Restore>(r, *record, i+1);
115cb93a386Sopenharmony_ci    }
116cb93a386Sopenharmony_ci}
117cb93a386Sopenharmony_ci
118cb93a386Sopenharmony_cistatic void assert_savelayer_draw_restore(skiatest::Reporter* r,
119cb93a386Sopenharmony_ci                                          SkRecord* record,
120cb93a386Sopenharmony_ci                                          int i,
121cb93a386Sopenharmony_ci                                          bool shouldBeNoOped) {
122cb93a386Sopenharmony_ci    SkRecordNoopSaveLayerDrawRestores(record);
123cb93a386Sopenharmony_ci    if (shouldBeNoOped) {
124cb93a386Sopenharmony_ci        assert_type<SkRecords::NoOp>(r, *record, i);
125cb93a386Sopenharmony_ci        assert_type<SkRecords::NoOp>(r, *record, i+2);
126cb93a386Sopenharmony_ci    } else {
127cb93a386Sopenharmony_ci        assert_type<SkRecords::SaveLayer>(r, *record, i);
128cb93a386Sopenharmony_ci        assert_type<SkRecords::Restore>(r, *record, i+2);
129cb93a386Sopenharmony_ci    }
130cb93a386Sopenharmony_ci}
131cb93a386Sopenharmony_ci
132cb93a386Sopenharmony_ciDEF_TEST(RecordOpts_NoopSaveLayerDrawRestore, r) {
133cb93a386Sopenharmony_ci    SkRecord record;
134cb93a386Sopenharmony_ci    SkRecorder recorder(&record, W, H);
135cb93a386Sopenharmony_ci
136cb93a386Sopenharmony_ci    SkRect bounds = SkRect::MakeWH(100, 200);
137cb93a386Sopenharmony_ci    SkRect   draw = SkRect::MakeWH(50, 60);
138cb93a386Sopenharmony_ci
139cb93a386Sopenharmony_ci    SkPaint alphaOnlyLayerPaint, translucentLayerPaint, xfermodeLayerPaint;
140cb93a386Sopenharmony_ci    alphaOnlyLayerPaint.setColor(0x03000000);  // Only alpha.
141cb93a386Sopenharmony_ci    translucentLayerPaint.setColor(0x03040506);  // Not only alpha.
142cb93a386Sopenharmony_ci    xfermodeLayerPaint.setBlendMode(SkBlendMode::kDstIn);  // Any effect will do.
143cb93a386Sopenharmony_ci
144cb93a386Sopenharmony_ci    SkPaint opaqueDrawPaint, translucentDrawPaint;
145cb93a386Sopenharmony_ci    opaqueDrawPaint.setColor(0xFF020202);  // Opaque.
146cb93a386Sopenharmony_ci    translucentDrawPaint.setColor(0x0F020202);  // Not opaque.
147cb93a386Sopenharmony_ci
148cb93a386Sopenharmony_ci    // SaveLayer/Restore removed: No paint = no point.
149cb93a386Sopenharmony_ci    recorder.saveLayer(nullptr, nullptr);
150cb93a386Sopenharmony_ci        recorder.drawRect(draw, opaqueDrawPaint);
151cb93a386Sopenharmony_ci    recorder.restore();
152cb93a386Sopenharmony_ci    assert_savelayer_draw_restore(r, &record, 0, true);
153cb93a386Sopenharmony_ci
154cb93a386Sopenharmony_ci    // Bounds don't matter.
155cb93a386Sopenharmony_ci    recorder.saveLayer(&bounds, nullptr);
156cb93a386Sopenharmony_ci        recorder.drawRect(draw, opaqueDrawPaint);
157cb93a386Sopenharmony_ci    recorder.restore();
158cb93a386Sopenharmony_ci    assert_savelayer_draw_restore(r, &record, 3, true);
159cb93a386Sopenharmony_ci
160cb93a386Sopenharmony_ci    // TODO(mtklein): test case with null draw paint
161cb93a386Sopenharmony_ci
162cb93a386Sopenharmony_ci    // No change: layer paint isn't alpha-only.
163cb93a386Sopenharmony_ci    recorder.saveLayer(nullptr, &translucentLayerPaint);
164cb93a386Sopenharmony_ci        recorder.drawRect(draw, opaqueDrawPaint);
165cb93a386Sopenharmony_ci    recorder.restore();
166cb93a386Sopenharmony_ci    assert_savelayer_draw_restore(r, &record, 6, false);
167cb93a386Sopenharmony_ci
168cb93a386Sopenharmony_ci    // No change: layer paint has an effect.
169cb93a386Sopenharmony_ci    recorder.saveLayer(nullptr, &xfermodeLayerPaint);
170cb93a386Sopenharmony_ci        recorder.drawRect(draw, opaqueDrawPaint);
171cb93a386Sopenharmony_ci    recorder.restore();
172cb93a386Sopenharmony_ci    assert_savelayer_draw_restore(r, &record, 9, false);
173cb93a386Sopenharmony_ci
174cb93a386Sopenharmony_ci    // SaveLayer/Restore removed: we can fold in the alpha!
175cb93a386Sopenharmony_ci    recorder.saveLayer(nullptr, &alphaOnlyLayerPaint);
176cb93a386Sopenharmony_ci        recorder.drawRect(draw, translucentDrawPaint);
177cb93a386Sopenharmony_ci    recorder.restore();
178cb93a386Sopenharmony_ci    assert_savelayer_draw_restore(r, &record, 12, true);
179cb93a386Sopenharmony_ci
180cb93a386Sopenharmony_ci    // SaveLayer/Restore removed: we can fold in the alpha!
181cb93a386Sopenharmony_ci    recorder.saveLayer(nullptr, &alphaOnlyLayerPaint);
182cb93a386Sopenharmony_ci        recorder.drawRect(draw, opaqueDrawPaint);
183cb93a386Sopenharmony_ci    recorder.restore();
184cb93a386Sopenharmony_ci    assert_savelayer_draw_restore(r, &record, 15, true);
185cb93a386Sopenharmony_ci
186cb93a386Sopenharmony_ci    const SkRecords::DrawRect* drawRect = assert_type<SkRecords::DrawRect>(r, record, 16);
187cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, drawRect != nullptr);
188cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, drawRect->paint.getColor() == 0x03020202);
189cb93a386Sopenharmony_ci
190cb93a386Sopenharmony_ci    // saveLayer w/ backdrop should NOT go away
191cb93a386Sopenharmony_ci    sk_sp<SkImageFilter> filter(SkImageFilters::Blur(3, 3, nullptr));
192cb93a386Sopenharmony_ci    recorder.saveLayer({ nullptr, nullptr, filter.get(), 0});
193cb93a386Sopenharmony_ci        recorder.drawRect(draw, opaqueDrawPaint);
194cb93a386Sopenharmony_ci    recorder.restore();
195cb93a386Sopenharmony_ci    assert_savelayer_draw_restore(r, &record, 18, false);
196cb93a386Sopenharmony_ci}
197cb93a386Sopenharmony_ci#endif
198cb93a386Sopenharmony_ci
199cb93a386Sopenharmony_cistatic void assert_merge_svg_opacity_and_filter_layers(skiatest::Reporter* r,
200cb93a386Sopenharmony_ci                                                       SkRecord* record,
201cb93a386Sopenharmony_ci                                                       int i,
202cb93a386Sopenharmony_ci                                                       bool shouldBeNoOped) {
203cb93a386Sopenharmony_ci    SkRecordMergeSvgOpacityAndFilterLayers(record);
204cb93a386Sopenharmony_ci    if (shouldBeNoOped) {
205cb93a386Sopenharmony_ci        assert_type<SkRecords::NoOp>(r, *record, i);
206cb93a386Sopenharmony_ci        assert_type<SkRecords::NoOp>(r, *record, i + 6);
207cb93a386Sopenharmony_ci    } else {
208cb93a386Sopenharmony_ci        assert_type<SkRecords::SaveLayer>(r, *record, i);
209cb93a386Sopenharmony_ci        assert_type<SkRecords::Restore>(r, *record, i + 6);
210cb93a386Sopenharmony_ci    }
211cb93a386Sopenharmony_ci}
212cb93a386Sopenharmony_ci
213cb93a386Sopenharmony_ciDEF_TEST(RecordOpts_MergeSvgOpacityAndFilterLayers, r) {
214cb93a386Sopenharmony_ci    SkRecord record;
215cb93a386Sopenharmony_ci    SkRecorder recorder(&record, W, H);
216cb93a386Sopenharmony_ci
217cb93a386Sopenharmony_ci    SkRect bounds = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(200));
218cb93a386Sopenharmony_ci    SkRect clip = SkRect::MakeWH(SkIntToScalar(50), SkIntToScalar(60));
219cb93a386Sopenharmony_ci
220cb93a386Sopenharmony_ci    SkPaint alphaOnlyLayerPaint;
221cb93a386Sopenharmony_ci    alphaOnlyLayerPaint.setColor(0x03000000);  // Only alpha.
222cb93a386Sopenharmony_ci    SkPaint translucentLayerPaint;
223cb93a386Sopenharmony_ci    translucentLayerPaint.setColor(0x03040506);  // Not only alpha.
224cb93a386Sopenharmony_ci    SkPaint xfermodePaint;
225cb93a386Sopenharmony_ci    xfermodePaint.setBlendMode(SkBlendMode::kDstIn);
226cb93a386Sopenharmony_ci    SkPaint colorFilterPaint;
227cb93a386Sopenharmony_ci    colorFilterPaint.setColorFilter(
228cb93a386Sopenharmony_ci        SkColorFilters::Blend(SK_ColorLTGRAY, SkBlendMode::kSrcIn));
229cb93a386Sopenharmony_ci
230cb93a386Sopenharmony_ci    SkPaint opaqueFilterLayerPaint;
231cb93a386Sopenharmony_ci    opaqueFilterLayerPaint.setColor(0xFF020202);  // Opaque.
232cb93a386Sopenharmony_ci    SkPaint translucentFilterLayerPaint;
233cb93a386Sopenharmony_ci    translucentFilterLayerPaint.setColor(0x0F020202);  // Not opaque.
234cb93a386Sopenharmony_ci    sk_sp<SkPicture> shape;
235cb93a386Sopenharmony_ci    {
236cb93a386Sopenharmony_ci        SkPictureRecorder picRecorder;
237cb93a386Sopenharmony_ci        SkCanvas* canvas = picRecorder.beginRecording(SkIntToScalar(100), SkIntToScalar(100));
238cb93a386Sopenharmony_ci        SkPaint shapePaint;
239cb93a386Sopenharmony_ci        shapePaint.setColor(SK_ColorWHITE);
240cb93a386Sopenharmony_ci        canvas->drawRect(SkRect::MakeWH(SkIntToScalar(50), SkIntToScalar(50)), shapePaint);
241cb93a386Sopenharmony_ci        shape = picRecorder.finishRecordingAsPicture();
242cb93a386Sopenharmony_ci    }
243cb93a386Sopenharmony_ci    translucentFilterLayerPaint.setImageFilter(SkImageFilters::Picture(shape));
244cb93a386Sopenharmony_ci
245cb93a386Sopenharmony_ci    int index = 0;
246cb93a386Sopenharmony_ci
247cb93a386Sopenharmony_ci    {
248cb93a386Sopenharmony_ci        sk_sp<SkImageFilter> filter(SkImageFilters::Blur(3, 3, nullptr));
249cb93a386Sopenharmony_ci        // first (null) should be optimized, 2nd should not
250cb93a386Sopenharmony_ci        SkImageFilter* filters[] = { nullptr, filter.get() };
251cb93a386Sopenharmony_ci
252cb93a386Sopenharmony_ci        // Any combination of these should cause the pattern to be optimized.
253cb93a386Sopenharmony_ci        SkRect* firstBounds[] = { nullptr, &bounds };
254cb93a386Sopenharmony_ci        SkPaint* firstPaints[] = { nullptr, &alphaOnlyLayerPaint };
255cb93a386Sopenharmony_ci        SkRect* secondBounds[] = { nullptr, &bounds };
256cb93a386Sopenharmony_ci        SkPaint* secondPaints[] = { &opaqueFilterLayerPaint, &translucentFilterLayerPaint };
257cb93a386Sopenharmony_ci
258cb93a386Sopenharmony_ci        for (auto outerF : filters) {
259cb93a386Sopenharmony_ci            bool outerNoOped = !outerF;
260cb93a386Sopenharmony_ci            for (auto innerF : filters) {
261cb93a386Sopenharmony_ci                for (size_t i = 0; i < SK_ARRAY_COUNT(firstBounds); ++ i) {
262cb93a386Sopenharmony_ci                    for (size_t j = 0; j < SK_ARRAY_COUNT(firstPaints); ++j) {
263cb93a386Sopenharmony_ci                        for (size_t k = 0; k < SK_ARRAY_COUNT(secondBounds); ++k) {
264cb93a386Sopenharmony_ci                            for (size_t m = 0; m < SK_ARRAY_COUNT(secondPaints); ++m) {
265cb93a386Sopenharmony_ci                                bool innerNoOped = !secondBounds[k] && !secondPaints[m] && !innerF;
266cb93a386Sopenharmony_ci
267cb93a386Sopenharmony_ci                                recorder.saveLayer({firstBounds[i], firstPaints[j], outerF, 0});
268cb93a386Sopenharmony_ci                                recorder.save();
269cb93a386Sopenharmony_ci                                recorder.clipRect(clip);
270cb93a386Sopenharmony_ci                                recorder.saveLayer({secondBounds[k], secondPaints[m], innerF, 0});
271cb93a386Sopenharmony_ci                                recorder.restore();
272cb93a386Sopenharmony_ci                                recorder.restore();
273cb93a386Sopenharmony_ci                                recorder.restore();
274cb93a386Sopenharmony_ci                                assert_merge_svg_opacity_and_filter_layers(r, &record, index,
275cb93a386Sopenharmony_ci                                                                           outerNoOped);
276cb93a386Sopenharmony_ci                            #ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
277cb93a386Sopenharmony_ci                                assert_savelayer_restore(r, &record, index + 3, innerNoOped);
278cb93a386Sopenharmony_ci                            #endif
279cb93a386Sopenharmony_ci                                index += 7;
280cb93a386Sopenharmony_ci                            }
281cb93a386Sopenharmony_ci                        }
282cb93a386Sopenharmony_ci                    }
283cb93a386Sopenharmony_ci                }
284cb93a386Sopenharmony_ci            }
285cb93a386Sopenharmony_ci        }
286cb93a386Sopenharmony_ci    }
287cb93a386Sopenharmony_ci
288cb93a386Sopenharmony_ci    // These should cause the pattern to stay unoptimized:
289cb93a386Sopenharmony_ci    struct {
290cb93a386Sopenharmony_ci        SkPaint* firstPaint;
291cb93a386Sopenharmony_ci        SkPaint* secondPaint;
292cb93a386Sopenharmony_ci    } noChangeTests[] = {
293cb93a386Sopenharmony_ci        // No change: nullptr filter layer paint not implemented.
294cb93a386Sopenharmony_ci        { &alphaOnlyLayerPaint, nullptr },
295cb93a386Sopenharmony_ci        // No change: layer paint is not alpha-only.
296cb93a386Sopenharmony_ci        { &translucentLayerPaint, &opaqueFilterLayerPaint },
297cb93a386Sopenharmony_ci        // No change: layer paint has an xfereffect.
298cb93a386Sopenharmony_ci        { &xfermodePaint, &opaqueFilterLayerPaint },
299cb93a386Sopenharmony_ci        // No change: filter layer paint has an xfereffect.
300cb93a386Sopenharmony_ci        { &alphaOnlyLayerPaint, &xfermodePaint },
301cb93a386Sopenharmony_ci        // No change: layer paint has a color filter.
302cb93a386Sopenharmony_ci        { &colorFilterPaint, &opaqueFilterLayerPaint },
303cb93a386Sopenharmony_ci        // No change: filter layer paint has a color filter (until the optimization accounts for
304cb93a386Sopenharmony_ci        // constant color draws that can filter the color).
305cb93a386Sopenharmony_ci        { &alphaOnlyLayerPaint, &colorFilterPaint }
306cb93a386Sopenharmony_ci    };
307cb93a386Sopenharmony_ci
308cb93a386Sopenharmony_ci    for (size_t i = 0; i < SK_ARRAY_COUNT(noChangeTests); ++i) {
309cb93a386Sopenharmony_ci        recorder.saveLayer(nullptr, noChangeTests[i].firstPaint);
310cb93a386Sopenharmony_ci        recorder.save();
311cb93a386Sopenharmony_ci        recorder.clipRect(clip);
312cb93a386Sopenharmony_ci        recorder.saveLayer(nullptr, noChangeTests[i].secondPaint);
313cb93a386Sopenharmony_ci        recorder.restore();
314cb93a386Sopenharmony_ci        recorder.restore();
315cb93a386Sopenharmony_ci        recorder.restore();
316cb93a386Sopenharmony_ci        assert_merge_svg_opacity_and_filter_layers(r, &record, index, false);
317cb93a386Sopenharmony_ci        index += 7;
318cb93a386Sopenharmony_ci    }
319cb93a386Sopenharmony_ci
320cb93a386Sopenharmony_ci    // Test the folded alpha value.
321cb93a386Sopenharmony_ci    recorder.saveLayer(nullptr, &alphaOnlyLayerPaint);
322cb93a386Sopenharmony_ci    recorder.save();
323cb93a386Sopenharmony_ci    recorder.clipRect(clip);
324cb93a386Sopenharmony_ci    recorder.saveLayer(nullptr, &opaqueFilterLayerPaint);
325cb93a386Sopenharmony_ci    recorder.restore();
326cb93a386Sopenharmony_ci    recorder.restore();
327cb93a386Sopenharmony_ci    recorder.restore();
328cb93a386Sopenharmony_ci    assert_merge_svg_opacity_and_filter_layers(r, &record, index, true);
329cb93a386Sopenharmony_ci
330cb93a386Sopenharmony_ci    const SkRecords::SaveLayer* saveLayer = assert_type<SkRecords::SaveLayer>(r, record, index + 3);
331cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, saveLayer != nullptr);
332cb93a386Sopenharmony_ci    REPORTER_ASSERT(r, saveLayer->paint->getColor() == 0x03020202);
333cb93a386Sopenharmony_ci
334cb93a386Sopenharmony_ci    index += 7;
335cb93a386Sopenharmony_ci
336cb93a386Sopenharmony_ci    // Test that currently we do not fold alphas for patterns without the clip. This is just not
337cb93a386Sopenharmony_ci    // implemented.
338cb93a386Sopenharmony_ci    recorder.saveLayer(nullptr, &alphaOnlyLayerPaint);
339cb93a386Sopenharmony_ci    recorder.saveLayer(nullptr, &opaqueFilterLayerPaint);
340cb93a386Sopenharmony_ci    recorder.restore();
341cb93a386Sopenharmony_ci    recorder.restore();
342cb93a386Sopenharmony_ci    SkRecordMergeSvgOpacityAndFilterLayers(&record);
343cb93a386Sopenharmony_ci    assert_type<SkRecords::SaveLayer>(r, record, index);
344cb93a386Sopenharmony_ci    assert_type<SkRecords::SaveLayer>(r, record, index + 1);
345cb93a386Sopenharmony_ci    assert_type<SkRecords::Restore>(r, record, index + 2);
346cb93a386Sopenharmony_ci    assert_type<SkRecords::Restore>(r, record, index + 3);
347cb93a386Sopenharmony_ci    index += 4;
348cb93a386Sopenharmony_ci}
349cb93a386Sopenharmony_ci
350cb93a386Sopenharmony_cistatic void do_draw(SkCanvas* canvas, SkColor color, bool doLayer) {
351cb93a386Sopenharmony_ci    canvas->drawColor(SK_ColorWHITE);
352cb93a386Sopenharmony_ci
353cb93a386Sopenharmony_ci    SkPaint p;
354cb93a386Sopenharmony_ci    p.setColor(color);
355cb93a386Sopenharmony_ci
356cb93a386Sopenharmony_ci    if (doLayer) {
357cb93a386Sopenharmony_ci        canvas->saveLayer(nullptr, nullptr);
358cb93a386Sopenharmony_ci        p.setBlendMode(SkBlendMode::kSrc);
359cb93a386Sopenharmony_ci        canvas->drawPaint(p);
360cb93a386Sopenharmony_ci        canvas->restore();
361cb93a386Sopenharmony_ci    } else {
362cb93a386Sopenharmony_ci        canvas->drawPaint(p);
363cb93a386Sopenharmony_ci    }
364cb93a386Sopenharmony_ci}
365cb93a386Sopenharmony_ci
366cb93a386Sopenharmony_cistatic bool is_equal(SkSurface* a, SkSurface* b) {
367cb93a386Sopenharmony_ci    const SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
368cb93a386Sopenharmony_ci    SkPMColor ca, cb;
369cb93a386Sopenharmony_ci    a->readPixels(info, &ca, sizeof(SkPMColor), 0, 0);
370cb93a386Sopenharmony_ci    b->readPixels(info, &cb, sizeof(SkPMColor), 0, 0);
371cb93a386Sopenharmony_ci    return ca == cb;
372cb93a386Sopenharmony_ci}
373cb93a386Sopenharmony_ci
374cb93a386Sopenharmony_ci// Test drawing w/ and w/o a simple layer (no bounds or paint), so see that drawing ops
375cb93a386Sopenharmony_ci// that *should* draw the same in fact do.
376cb93a386Sopenharmony_ci//
377cb93a386Sopenharmony_ci// Perform this test twice : once directly, and once via a picture
378cb93a386Sopenharmony_ci//
379cb93a386Sopenharmony_cistatic void do_savelayer_srcmode(skiatest::Reporter* r, SkColor color) {
380cb93a386Sopenharmony_ci    for (int doPicture = 0; doPicture <= 1; ++doPicture) {
381cb93a386Sopenharmony_ci        sk_sp<SkSurface> surf0 = SkSurface::MakeRasterN32Premul(10, 10);
382cb93a386Sopenharmony_ci        sk_sp<SkSurface> surf1 = SkSurface::MakeRasterN32Premul(10, 10);
383cb93a386Sopenharmony_ci        SkCanvas* c0 = surf0->getCanvas();
384cb93a386Sopenharmony_ci        SkCanvas* c1 = surf1->getCanvas();
385cb93a386Sopenharmony_ci
386cb93a386Sopenharmony_ci        SkPictureRecorder rec0, rec1;
387cb93a386Sopenharmony_ci        if (doPicture) {
388cb93a386Sopenharmony_ci            c0 = rec0.beginRecording(10, 10);
389cb93a386Sopenharmony_ci            c1 = rec1.beginRecording(10, 10);
390cb93a386Sopenharmony_ci        }
391cb93a386Sopenharmony_ci
392cb93a386Sopenharmony_ci        do_draw(c0, color, false);
393cb93a386Sopenharmony_ci        do_draw(c1, color, true);
394cb93a386Sopenharmony_ci
395cb93a386Sopenharmony_ci        if (doPicture) {
396cb93a386Sopenharmony_ci            surf0->getCanvas()->drawPicture(rec0.finishRecordingAsPicture());
397cb93a386Sopenharmony_ci            surf1->getCanvas()->drawPicture(rec1.finishRecordingAsPicture());
398cb93a386Sopenharmony_ci        }
399cb93a386Sopenharmony_ci
400cb93a386Sopenharmony_ci        // we replicate the assert so we can see which line is reported if there is a failure
401cb93a386Sopenharmony_ci        if (doPicture) {
402cb93a386Sopenharmony_ci            REPORTER_ASSERT(r, is_equal(surf0.get(), surf1.get()));
403cb93a386Sopenharmony_ci        } else {
404cb93a386Sopenharmony_ci            REPORTER_ASSERT(r, is_equal(surf0.get(), surf1.get()));
405cb93a386Sopenharmony_ci        }
406cb93a386Sopenharmony_ci    }
407cb93a386Sopenharmony_ci}
408cb93a386Sopenharmony_ci
409cb93a386Sopenharmony_ciDEF_TEST(savelayer_srcmode_opaque, r) {
410cb93a386Sopenharmony_ci    do_savelayer_srcmode(r, SK_ColorRED);
411cb93a386Sopenharmony_ci}
412cb93a386Sopenharmony_ci
413cb93a386Sopenharmony_ciDEF_TEST(savelayer_srcmode_alpha, r) {
414cb93a386Sopenharmony_ci    do_savelayer_srcmode(r, 0x80FF0000);
415cb93a386Sopenharmony_ci}
416cb93a386Sopenharmony_ci
417