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 "include/core/SkCanvas.h"
9cb93a386Sopenharmony_ci#include "include/core/SkPicture.h"
10cb93a386Sopenharmony_ci#include "src/core/SkPictureFlat.h"
11cb93a386Sopenharmony_ci#include "src/core/SkPictureRecord.h"
12cb93a386Sopenharmony_ci#include "tests/Test.h"
13cb93a386Sopenharmony_ci#include "tools/debugger/DebugCanvas.h"
14cb93a386Sopenharmony_ci
15cb93a386Sopenharmony_ci// This test exercises the Matrix/Clip State collapsing system. It generates
16cb93a386Sopenharmony_ci// example skps and the compares the actual stored operations to the expected
17cb93a386Sopenharmony_ci// operations. The test works by emitting canvas operations at three levels:
18cb93a386Sopenharmony_ci// overall structure, bodies that draw something and model/clip state changes.
19cb93a386Sopenharmony_ci//
20cb93a386Sopenharmony_ci// Structure methods only directly emit save and restores but call the
21cb93a386Sopenharmony_ci// ModelClip and Body helper methods to fill in the structure. Since they only
22cb93a386Sopenharmony_ci// emit saves and restores the operations emitted by the structure methods will
23cb93a386Sopenharmony_ci// be completely removed by the matrix/clip collapse. Note: every save in
24cb93a386Sopenharmony_ci// a structure method is followed by a call to a ModelClip helper.
25cb93a386Sopenharmony_ci//
26cb93a386Sopenharmony_ci// Body methods only directly emit draw ops and saveLayer/restore pairs but call
27cb93a386Sopenharmony_ci// the ModelClip helper methods. Since the body methods emit the ops that cannot
28cb93a386Sopenharmony_ci// be collapsed (i.e., draw ops, saveLayer/restore) they also generate the
29cb93a386Sopenharmony_ci// expected result information. Note: every saveLayer in a body method is
30cb93a386Sopenharmony_ci// followed by a call to a ModelClip helper.
31cb93a386Sopenharmony_ci//
32cb93a386Sopenharmony_ci// The ModelClip methods output matrix and clip ops in various orders and
33cb93a386Sopenharmony_ci// combinations. They contribute to the expected result by outputting the
34cb93a386Sopenharmony_ci// expected matrix & clip ops. Note that, currently, the entire clip stack
35cb93a386Sopenharmony_ci// is output for each MC state so the clip operations accumulate down the
36cb93a386Sopenharmony_ci// save/restore stack.
37cb93a386Sopenharmony_ci
38cb93a386Sopenharmony_ci// TODOs:
39cb93a386Sopenharmony_ci//   check on clip offsets
40cb93a386Sopenharmony_ci//      - not sure if this is possible. The desire is to verify that the clip
41cb93a386Sopenharmony_ci//        operations' offsets point to the correct follow-on operations. This
42cb93a386Sopenharmony_ci//        could be difficult since there is no good way to communicate the
43cb93a386Sopenharmony_ci//        offset stored in the SkPicture to the debugger's clip objects
44cb93a386Sopenharmony_ci//   add comparison of rendered before & after images?
45cb93a386Sopenharmony_ci//      - not sure if this would be useful since it somewhat duplicates the
46cb93a386Sopenharmony_ci//        correctness test of running render_pictures in record mode and
47cb93a386Sopenharmony_ci//        rendering before and after images. Additionally the matrix/clip collapse
48cb93a386Sopenharmony_ci//        is sure to cause some small differences so an automated test might
49cb93a386Sopenharmony_ci//        yield too many false positives.
50cb93a386Sopenharmony_ci//   run the matrix/clip collapse system on the 10K skp set
51cb93a386Sopenharmony_ci//      - this should give us warm fuzzies that the matrix clip collapse
52cb93a386Sopenharmony_ci//        system is ready for prime time
53cb93a386Sopenharmony_ci//   bench the recording times with/without matrix/clip collapsing
54cb93a386Sopenharmony_ci
55cb93a386Sopenharmony_ci#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
56cb93a386Sopenharmony_ci
57cb93a386Sopenharmony_ci// Enable/disable debugging helper code
58cb93a386Sopenharmony_ci//#define TEST_COLLAPSE_MATRIX_CLIP_STATE 1
59cb93a386Sopenharmony_ci
60cb93a386Sopenharmony_ci// Extract the command ops from the input SkPicture
61cb93a386Sopenharmony_cistatic void gets_ops(SkPicture& input, SkTDArray<DrawType>* ops) {
62cb93a386Sopenharmony_ci    DebugCanvas debugCanvas(input.width(), input.height());
63cb93a386Sopenharmony_ci    debugCanvas.setBounds(input.width(), input.height());
64cb93a386Sopenharmony_ci    input.draw(&debugCanvas);
65cb93a386Sopenharmony_ci
66cb93a386Sopenharmony_ci    ops->setCount(debugCanvas.getSize());
67cb93a386Sopenharmony_ci    for (int i = 0; i < debugCanvas.getSize(); ++i) {
68cb93a386Sopenharmony_ci        (*ops)[i] = debugCanvas.getDrawCommandAt(i)->getType();
69cb93a386Sopenharmony_ci    }
70cb93a386Sopenharmony_ci}
71cb93a386Sopenharmony_ci
72cb93a386Sopenharmony_cienum ClipType {
73cb93a386Sopenharmony_ci    kNone_ClipType,
74cb93a386Sopenharmony_ci    kRect_ClipType,
75cb93a386Sopenharmony_ci    kRRect_ClipType,
76cb93a386Sopenharmony_ci    kPath_ClipType,
77cb93a386Sopenharmony_ci    kRegion_ClipType,
78cb93a386Sopenharmony_ci
79cb93a386Sopenharmony_ci    kLast_ClipType = kRRect_ClipType
80cb93a386Sopenharmony_ci};
81cb93a386Sopenharmony_ci
82cb93a386Sopenharmony_cistatic const int kClipTypeCount = kLast_ClipType + 1;
83cb93a386Sopenharmony_ci
84cb93a386Sopenharmony_cienum MatType {
85cb93a386Sopenharmony_ci    kNone_MatType,
86cb93a386Sopenharmony_ci    kTranslate_MatType,
87cb93a386Sopenharmony_ci    kScale_MatType,
88cb93a386Sopenharmony_ci    kSkew_MatType,
89cb93a386Sopenharmony_ci    kRotate_MatType,
90cb93a386Sopenharmony_ci    kConcat_MatType,
91cb93a386Sopenharmony_ci    kSetMatrix_MatType,
92cb93a386Sopenharmony_ci
93cb93a386Sopenharmony_ci    kLast_MatType = kScale_MatType
94cb93a386Sopenharmony_ci};
95cb93a386Sopenharmony_ci
96cb93a386Sopenharmony_cistatic const int kMatTypeCount = kLast_MatType + 1;
97cb93a386Sopenharmony_ci
98cb93a386Sopenharmony_ci// TODO: implement the rest of the draw ops
99cb93a386Sopenharmony_cienum DrawOpType {
100cb93a386Sopenharmony_ci    kNone_DrawOpType,
101cb93a386Sopenharmony_ci#if 0
102cb93a386Sopenharmony_ci    kBitmap_DrawOpType,
103cb93a386Sopenharmony_ci    kBitmapMatrix_DrawOpType,
104cb93a386Sopenharmony_ci    kBitmapNone_DrawOpType,
105cb93a386Sopenharmony_ci    kBitmapRectToRect_DrawOpType,
106cb93a386Sopenharmony_ci#endif
107cb93a386Sopenharmony_ci    kClear_DrawOpType,
108cb93a386Sopenharmony_ci#if 0
109cb93a386Sopenharmony_ci    kData_DrawOpType,
110cb93a386Sopenharmony_ci#endif
111cb93a386Sopenharmony_ci    kOval_DrawOpType,
112cb93a386Sopenharmony_ci#if 0
113cb93a386Sopenharmony_ci    kPaint_DrawOpType,
114cb93a386Sopenharmony_ci    kPath_DrawOpType,
115cb93a386Sopenharmony_ci    kPicture_DrawOpType,
116cb93a386Sopenharmony_ci    kPoints_DrawOpType,
117cb93a386Sopenharmony_ci    kPosText_DrawOpType,
118cb93a386Sopenharmony_ci    kPosTextTopBottom_DrawOpType,
119cb93a386Sopenharmony_ci    kPosTextH_DrawOpType,
120cb93a386Sopenharmony_ci    kPosTextHTopBottom_DrawOpType,
121cb93a386Sopenharmony_ci#endif
122cb93a386Sopenharmony_ci    kRect_DrawOpType,
123cb93a386Sopenharmony_ci    kRRect_DrawOpType,
124cb93a386Sopenharmony_ci#if 0
125cb93a386Sopenharmony_ci    kSprite_DrawOpType,
126cb93a386Sopenharmony_ci    kText_DrawOpType,
127cb93a386Sopenharmony_ci    kTextOnPath_DrawOpType,
128cb93a386Sopenharmony_ci    kTextTopBottom_DrawOpType,
129cb93a386Sopenharmony_ci    kDrawVertices_DrawOpType,
130cb93a386Sopenharmony_ci#endif
131cb93a386Sopenharmony_ci
132cb93a386Sopenharmony_ci    kLastNonSaveLayer_DrawOpType = kRect_DrawOpType,
133cb93a386Sopenharmony_ci
134cb93a386Sopenharmony_ci    // saveLayer's have to handled apart from the other draw operations
135cb93a386Sopenharmony_ci    // since they also alter the save/restore structure.
136cb93a386Sopenharmony_ci    kSaveLayer_DrawOpType,
137cb93a386Sopenharmony_ci};
138cb93a386Sopenharmony_ci
139cb93a386Sopenharmony_cistatic const int kNonSaveLayerDrawOpTypeCount = kLastNonSaveLayer_DrawOpType + 1;
140cb93a386Sopenharmony_ci
141cb93a386Sopenharmony_citypedef void (*PFEmitMC)(SkCanvas* canvas, MatType mat, ClipType clip,
142cb93a386Sopenharmony_ci                         DrawOpType draw, SkTDArray<DrawType>* expected,
143cb93a386Sopenharmony_ci                         int accumulatedClips);
144cb93a386Sopenharmony_citypedef void (*PFEmitBody)(SkCanvas* canvas, PFEmitMC emitMC, MatType mat,
145cb93a386Sopenharmony_ci                           ClipType clip, DrawOpType draw,
146cb93a386Sopenharmony_ci                           SkTDArray<DrawType>* expected, int accumulatedClips);
147cb93a386Sopenharmony_citypedef void (*PFEmitStruct)(SkCanvas* canvas, PFEmitMC emitMC, MatType mat,
148cb93a386Sopenharmony_ci                             ClipType clip, PFEmitBody emitBody, DrawOpType draw,
149cb93a386Sopenharmony_ci                             SkTDArray<DrawType>* expected);
150cb93a386Sopenharmony_ci
151cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////
152cb93a386Sopenharmony_ci
153cb93a386Sopenharmony_ci// TODO: expand the testing to include the different ops & AA types!
154cb93a386Sopenharmony_cistatic void emit_clip(SkCanvas* canvas, ClipType clip) {
155cb93a386Sopenharmony_ci    switch (clip) {
156cb93a386Sopenharmony_ci        case kNone_ClipType:
157cb93a386Sopenharmony_ci            break;
158cb93a386Sopenharmony_ci        case kRect_ClipType: {
159cb93a386Sopenharmony_ci            SkRect r = SkRect::MakeLTRB(10, 10, 90, 90);
160cb93a386Sopenharmony_ci            canvas->clipRect(r, SkRegion::kIntersect_Op, true);
161cb93a386Sopenharmony_ci            break;
162cb93a386Sopenharmony_ci        }
163cb93a386Sopenharmony_ci        case kRRect_ClipType: {
164cb93a386Sopenharmony_ci            SkRect r = SkRect::MakeLTRB(10, 10, 90, 90);
165cb93a386Sopenharmony_ci            SkRRect rr;
166cb93a386Sopenharmony_ci            rr.setRectXY(r, 10, 10);
167cb93a386Sopenharmony_ci            canvas->clipRRect(rr, SkRegion::kIntersect_Op, true);
168cb93a386Sopenharmony_ci            break;
169cb93a386Sopenharmony_ci        }
170cb93a386Sopenharmony_ci        case kPath_ClipType: {
171cb93a386Sopenharmony_ci            SkPath p;
172cb93a386Sopenharmony_ci            p.moveTo(5.0f, 5.0f);
173cb93a386Sopenharmony_ci            p.lineTo(50.0f, 50.0f);
174cb93a386Sopenharmony_ci            p.lineTo(100.0f, 5.0f);
175cb93a386Sopenharmony_ci            p.close();
176cb93a386Sopenharmony_ci            canvas->clipPath(p, SkRegion::kIntersect_Op, true);
177cb93a386Sopenharmony_ci            break;
178cb93a386Sopenharmony_ci        }
179cb93a386Sopenharmony_ci        case kRegion_ClipType: {
180cb93a386Sopenharmony_ci            SkIRect rects[2] = {
181cb93a386Sopenharmony_ci                { 1, 1, 55, 55 },
182cb93a386Sopenharmony_ci                { 45, 45, 99, 99 },
183cb93a386Sopenharmony_ci            };
184cb93a386Sopenharmony_ci            SkRegion r;
185cb93a386Sopenharmony_ci            r.setRects(rects, 2);
186cb93a386Sopenharmony_ci            canvas->clipRegion(r, SkRegion::kIntersect_Op);
187cb93a386Sopenharmony_ci            break;
188cb93a386Sopenharmony_ci        }
189cb93a386Sopenharmony_ci        default:
190cb93a386Sopenharmony_ci            SkASSERT(0);
191cb93a386Sopenharmony_ci    }
192cb93a386Sopenharmony_ci}
193cb93a386Sopenharmony_ci
194cb93a386Sopenharmony_cistatic void add_clip(ClipType clip, MatType mat, SkTDArray<DrawType>* expected) {
195cb93a386Sopenharmony_ci    if (nullptr == expected) {
196cb93a386Sopenharmony_ci        // expected is nullptr if this clip will be fused into later clips
197cb93a386Sopenharmony_ci        return;
198cb93a386Sopenharmony_ci    }
199cb93a386Sopenharmony_ci
200cb93a386Sopenharmony_ci    switch (clip) {
201cb93a386Sopenharmony_ci        case kNone_ClipType:
202cb93a386Sopenharmony_ci            break;
203cb93a386Sopenharmony_ci        case kRect_ClipType:
204cb93a386Sopenharmony_ci            *expected->append() = CONCAT;
205cb93a386Sopenharmony_ci            *expected->append() = CLIP_RECT;
206cb93a386Sopenharmony_ci            break;
207cb93a386Sopenharmony_ci        case kRRect_ClipType:
208cb93a386Sopenharmony_ci            *expected->append() = CONCAT;
209cb93a386Sopenharmony_ci            *expected->append() = CLIP_RRECT;
210cb93a386Sopenharmony_ci            break;
211cb93a386Sopenharmony_ci        case kPath_ClipType:
212cb93a386Sopenharmony_ci            *expected->append() = CONCAT;
213cb93a386Sopenharmony_ci            *expected->append() = CLIP_PATH;
214cb93a386Sopenharmony_ci            break;
215cb93a386Sopenharmony_ci        case kRegion_ClipType:
216cb93a386Sopenharmony_ci            *expected->append() = CONCAT;
217cb93a386Sopenharmony_ci            *expected->append() = CLIP_REGION;
218cb93a386Sopenharmony_ci            break;
219cb93a386Sopenharmony_ci        default:
220cb93a386Sopenharmony_ci            SkASSERT(0);
221cb93a386Sopenharmony_ci    }
222cb93a386Sopenharmony_ci}
223cb93a386Sopenharmony_ci
224cb93a386Sopenharmony_cistatic void emit_mat(SkCanvas* canvas, MatType mat) {
225cb93a386Sopenharmony_ci    switch (mat) {
226cb93a386Sopenharmony_ci    case kNone_MatType:
227cb93a386Sopenharmony_ci        break;
228cb93a386Sopenharmony_ci    case kTranslate_MatType:
229cb93a386Sopenharmony_ci        canvas->translate(5.0f, 5.0f);
230cb93a386Sopenharmony_ci        break;
231cb93a386Sopenharmony_ci    case kScale_MatType:
232cb93a386Sopenharmony_ci        canvas->scale(1.1f, 1.1f);
233cb93a386Sopenharmony_ci        break;
234cb93a386Sopenharmony_ci    case kSkew_MatType:
235cb93a386Sopenharmony_ci        canvas->skew(1.1f, 1.1f);
236cb93a386Sopenharmony_ci        break;
237cb93a386Sopenharmony_ci    case kRotate_MatType:
238cb93a386Sopenharmony_ci        canvas->rotate(1.0f);
239cb93a386Sopenharmony_ci        break;
240cb93a386Sopenharmony_ci    case kConcat_MatType: {
241cb93a386Sopenharmony_ci        SkMatrix m;
242cb93a386Sopenharmony_ci        m.setTranslate(1.0f, 1.0f);
243cb93a386Sopenharmony_ci        canvas->concat(m);
244cb93a386Sopenharmony_ci        break;
245cb93a386Sopenharmony_ci    }
246cb93a386Sopenharmony_ci    case kSetMatrix_MatType: {
247cb93a386Sopenharmony_ci        SkMatrix m;
248cb93a386Sopenharmony_ci        m.setTranslate(1.0f, 1.0f);
249cb93a386Sopenharmony_ci        canvas->setMatrix(m);
250cb93a386Sopenharmony_ci        break;
251cb93a386Sopenharmony_ci    }
252cb93a386Sopenharmony_ci    default:
253cb93a386Sopenharmony_ci        SkASSERT(0);
254cb93a386Sopenharmony_ci    }
255cb93a386Sopenharmony_ci}
256cb93a386Sopenharmony_ci
257cb93a386Sopenharmony_cistatic void add_mat(MatType mat, SkTDArray<DrawType>* expected) {
258cb93a386Sopenharmony_ci    if (nullptr == expected) {
259cb93a386Sopenharmony_ci        // expected is nullptr if this matrix call will be fused into later ones
260cb93a386Sopenharmony_ci        return;
261cb93a386Sopenharmony_ci    }
262cb93a386Sopenharmony_ci
263cb93a386Sopenharmony_ci    switch (mat) {
264cb93a386Sopenharmony_ci    case kNone_MatType:
265cb93a386Sopenharmony_ci        break;
266cb93a386Sopenharmony_ci    case kTranslate_MatType:    // fall thru
267cb93a386Sopenharmony_ci    case kScale_MatType:        // fall thru
268cb93a386Sopenharmony_ci    case kSkew_MatType:         // fall thru
269cb93a386Sopenharmony_ci    case kRotate_MatType:       // fall thru
270cb93a386Sopenharmony_ci    case kConcat_MatType:       // fall thru
271cb93a386Sopenharmony_ci    case kSetMatrix_MatType:
272cb93a386Sopenharmony_ci        // TODO: this system currently converts a setMatrix to concat. If we wanted to
273cb93a386Sopenharmony_ci        // really preserve the setMatrix semantics we should keep it a setMatrix. I'm
274cb93a386Sopenharmony_ci        // not sure if this is a good idea though since this would keep things like pinch
275cb93a386Sopenharmony_ci        // zoom from working.
276cb93a386Sopenharmony_ci        *expected->append() = CONCAT;
277cb93a386Sopenharmony_ci        break;
278cb93a386Sopenharmony_ci    default:
279cb93a386Sopenharmony_ci        SkASSERT(0);
280cb93a386Sopenharmony_ci    }
281cb93a386Sopenharmony_ci}
282cb93a386Sopenharmony_ci
283cb93a386Sopenharmony_cistatic void emit_draw(SkCanvas* canvas, DrawOpType draw, SkTDArray<DrawType>* expected) {
284cb93a386Sopenharmony_ci    switch (draw) {
285cb93a386Sopenharmony_ci        case kNone_DrawOpType:
286cb93a386Sopenharmony_ci            break;
287cb93a386Sopenharmony_ci        case kClear_DrawOpType:
288cb93a386Sopenharmony_ci            canvas->clear(SK_ColorRED);
289cb93a386Sopenharmony_ci            *expected->append() = DRAW_CLEAR;
290cb93a386Sopenharmony_ci            break;
291cb93a386Sopenharmony_ci        case kOval_DrawOpType: {
292cb93a386Sopenharmony_ci            SkRect r = SkRect::MakeLTRB(10, 10, 90, 90);
293cb93a386Sopenharmony_ci            SkPaint p;
294cb93a386Sopenharmony_ci            canvas->drawOval(r, p);
295cb93a386Sopenharmony_ci            *expected->append() = DRAW_OVAL;
296cb93a386Sopenharmony_ci            break;
297cb93a386Sopenharmony_ci        }
298cb93a386Sopenharmony_ci        case kRect_DrawOpType: {
299cb93a386Sopenharmony_ci            SkRect r = SkRect::MakeLTRB(10, 10, 90, 90);
300cb93a386Sopenharmony_ci            SkPaint p;
301cb93a386Sopenharmony_ci            canvas->drawRect(r, p);
302cb93a386Sopenharmony_ci            *expected->append() = DRAW_RECT;
303cb93a386Sopenharmony_ci            break;
304cb93a386Sopenharmony_ci        }
305cb93a386Sopenharmony_ci        case kRRect_DrawOpType: {
306cb93a386Sopenharmony_ci            SkRect r = SkRect::MakeLTRB(10.0f, 10.0f, 90.0f, 90.0f);
307cb93a386Sopenharmony_ci            SkRRect rr;
308cb93a386Sopenharmony_ci            rr.setRectXY(r, 5.0f, 5.0f);
309cb93a386Sopenharmony_ci            SkPaint p;
310cb93a386Sopenharmony_ci            canvas->drawRRect(rr, p);
311cb93a386Sopenharmony_ci            *expected->append() = DRAW_RRECT;
312cb93a386Sopenharmony_ci            break;
313cb93a386Sopenharmony_ci        }
314cb93a386Sopenharmony_ci        default:
315cb93a386Sopenharmony_ci            SkASSERT(0);
316cb93a386Sopenharmony_ci    }
317cb93a386Sopenharmony_ci}
318cb93a386Sopenharmony_ci
319cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////
320cb93a386Sopenharmony_ci
321cb93a386Sopenharmony_ci// Emit:
322cb93a386Sopenharmony_ci//  clip
323cb93a386Sopenharmony_ci//  matrix
324cb93a386Sopenharmony_ci// Simple case - the clip isn't effect by the matrix
325cb93a386Sopenharmony_cistatic void emit_clip_and_mat(SkCanvas* canvas, MatType mat, ClipType clip,
326cb93a386Sopenharmony_ci                              DrawOpType draw, SkTDArray<DrawType>* expected,
327cb93a386Sopenharmony_ci                              int accumulatedClips) {
328cb93a386Sopenharmony_ci    emit_clip(canvas, clip);
329cb93a386Sopenharmony_ci    emit_mat(canvas, mat);
330cb93a386Sopenharmony_ci
331cb93a386Sopenharmony_ci    if (kNone_DrawOpType == draw) {
332cb93a386Sopenharmony_ci        return;
333cb93a386Sopenharmony_ci    }
334cb93a386Sopenharmony_ci
335cb93a386Sopenharmony_ci    for (int i = 0; i < accumulatedClips; ++i) {
336cb93a386Sopenharmony_ci        add_clip(clip, mat, expected);
337cb93a386Sopenharmony_ci    }
338cb93a386Sopenharmony_ci    add_mat(mat, expected);
339cb93a386Sopenharmony_ci}
340cb93a386Sopenharmony_ci
341cb93a386Sopenharmony_ci// Emit:
342cb93a386Sopenharmony_ci//  matrix
343cb93a386Sopenharmony_ci//  clip
344cb93a386Sopenharmony_ci// Emitting the matrix first is more challenging since the matrix has to be
345cb93a386Sopenharmony_ci// pushed across (i.e., applied to) the clip.
346cb93a386Sopenharmony_cistatic void emit_mat_and_clip(SkCanvas* canvas, MatType mat, ClipType clip,
347cb93a386Sopenharmony_ci                              DrawOpType draw, SkTDArray<DrawType>* expected,
348cb93a386Sopenharmony_ci                              int accumulatedClips) {
349cb93a386Sopenharmony_ci    emit_mat(canvas, mat);
350cb93a386Sopenharmony_ci    emit_clip(canvas, clip);
351cb93a386Sopenharmony_ci
352cb93a386Sopenharmony_ci    if (kNone_DrawOpType == draw) {
353cb93a386Sopenharmony_ci        return;
354cb93a386Sopenharmony_ci    }
355cb93a386Sopenharmony_ci
356cb93a386Sopenharmony_ci    // the matrix & clip order will be reversed once collapsed!
357cb93a386Sopenharmony_ci    for (int i = 0; i < accumulatedClips; ++i) {
358cb93a386Sopenharmony_ci        add_clip(clip, mat, expected);
359cb93a386Sopenharmony_ci    }
360cb93a386Sopenharmony_ci    add_mat(mat, expected);
361cb93a386Sopenharmony_ci}
362cb93a386Sopenharmony_ci
363cb93a386Sopenharmony_ci// Emit:
364cb93a386Sopenharmony_ci//  matrix
365cb93a386Sopenharmony_ci//  clip
366cb93a386Sopenharmony_ci//  matrix
367cb93a386Sopenharmony_ci//  clip
368cb93a386Sopenharmony_ci// This tests that the matrices and clips coalesce when collapsed
369cb93a386Sopenharmony_cistatic void emit_double_mat_and_clip(SkCanvas* canvas, MatType mat, ClipType clip,
370cb93a386Sopenharmony_ci                                     DrawOpType draw, SkTDArray<DrawType>* expected,
371cb93a386Sopenharmony_ci                                     int accumulatedClips) {
372cb93a386Sopenharmony_ci    emit_mat(canvas, mat);
373cb93a386Sopenharmony_ci    emit_clip(canvas, clip);
374cb93a386Sopenharmony_ci    emit_mat(canvas, mat);
375cb93a386Sopenharmony_ci    emit_clip(canvas, clip);
376cb93a386Sopenharmony_ci
377cb93a386Sopenharmony_ci    if (kNone_DrawOpType == draw) {
378cb93a386Sopenharmony_ci        return;
379cb93a386Sopenharmony_ci    }
380cb93a386Sopenharmony_ci
381cb93a386Sopenharmony_ci    for (int i = 0; i < accumulatedClips; ++i) {
382cb93a386Sopenharmony_ci        add_clip(clip, mat, expected);
383cb93a386Sopenharmony_ci        add_clip(clip, mat, expected);
384cb93a386Sopenharmony_ci    }
385cb93a386Sopenharmony_ci    add_mat(mat, expected);
386cb93a386Sopenharmony_ci}
387cb93a386Sopenharmony_ci
388cb93a386Sopenharmony_ci// Emit:
389cb93a386Sopenharmony_ci//  matrix
390cb93a386Sopenharmony_ci//  clip
391cb93a386Sopenharmony_ci//  clip
392cb93a386Sopenharmony_ci// This tests accumulation of clips in same transform state. It also tests pushing
393cb93a386Sopenharmony_ci// of the matrix across both the clips.
394cb93a386Sopenharmony_cistatic void emit_mat_clip_clip(SkCanvas* canvas, MatType mat, ClipType clip,
395cb93a386Sopenharmony_ci                               DrawOpType draw, SkTDArray<DrawType>* expected,
396cb93a386Sopenharmony_ci                               int accumulatedClips) {
397cb93a386Sopenharmony_ci    emit_mat(canvas, mat);
398cb93a386Sopenharmony_ci    emit_clip(canvas, clip);
399cb93a386Sopenharmony_ci    emit_clip(canvas, clip);
400cb93a386Sopenharmony_ci
401cb93a386Sopenharmony_ci    if (kNone_DrawOpType == draw) {
402cb93a386Sopenharmony_ci        return;
403cb93a386Sopenharmony_ci    }
404cb93a386Sopenharmony_ci
405cb93a386Sopenharmony_ci    for (int i = 0; i < accumulatedClips; ++i) {
406cb93a386Sopenharmony_ci        add_clip(clip, mat, expected);
407cb93a386Sopenharmony_ci        add_clip(clip, mat, expected);
408cb93a386Sopenharmony_ci    }
409cb93a386Sopenharmony_ci    add_mat(mat, expected);
410cb93a386Sopenharmony_ci}
411cb93a386Sopenharmony_ci
412cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////
413cb93a386Sopenharmony_ci
414cb93a386Sopenharmony_ci// Emit:
415cb93a386Sopenharmony_ci//  matrix & clip calls
416cb93a386Sopenharmony_ci//  draw op
417cb93a386Sopenharmony_cistatic void emit_body0(SkCanvas* canvas, PFEmitMC emitMC, MatType mat,
418cb93a386Sopenharmony_ci                       ClipType clip, DrawOpType draw,
419cb93a386Sopenharmony_ci                       SkTDArray<DrawType>* expected, int accumulatedClips) {
420cb93a386Sopenharmony_ci    bool needsSaveRestore = kNone_DrawOpType != draw &&
421cb93a386Sopenharmony_ci                            (kNone_MatType != mat || kNone_ClipType != clip);
422cb93a386Sopenharmony_ci
423cb93a386Sopenharmony_ci    if (needsSaveRestore) {
424cb93a386Sopenharmony_ci        *expected->append() = SAVE;
425cb93a386Sopenharmony_ci    }
426cb93a386Sopenharmony_ci    (*emitMC)(canvas, mat, clip, draw, expected, accumulatedClips+1);
427cb93a386Sopenharmony_ci    emit_draw(canvas, draw, expected);
428cb93a386Sopenharmony_ci    if (needsSaveRestore) {
429cb93a386Sopenharmony_ci        *expected->append() = RESTORE;
430cb93a386Sopenharmony_ci    }
431cb93a386Sopenharmony_ci}
432cb93a386Sopenharmony_ci
433cb93a386Sopenharmony_ci// Emit:
434cb93a386Sopenharmony_ci//  matrix & clip calls
435cb93a386Sopenharmony_ci//  draw op
436cb93a386Sopenharmony_ci//  matrix & clip calls
437cb93a386Sopenharmony_ci//  draw op
438cb93a386Sopenharmony_cistatic void emit_body1(SkCanvas* canvas, PFEmitMC emitMC, MatType mat,
439cb93a386Sopenharmony_ci                       ClipType clip, DrawOpType draw,
440cb93a386Sopenharmony_ci                       SkTDArray<DrawType>* expected, int accumulatedClips) {
441cb93a386Sopenharmony_ci    bool needsSaveRestore = kNone_DrawOpType != draw &&
442cb93a386Sopenharmony_ci                            (kNone_MatType != mat || kNone_ClipType != clip);
443cb93a386Sopenharmony_ci
444cb93a386Sopenharmony_ci    if (needsSaveRestore) {
445cb93a386Sopenharmony_ci        *expected->append() = SAVE;
446cb93a386Sopenharmony_ci    }
447cb93a386Sopenharmony_ci    (*emitMC)(canvas, mat, clip, draw, expected, accumulatedClips+1);
448cb93a386Sopenharmony_ci    emit_draw(canvas, draw, expected);
449cb93a386Sopenharmony_ci    if (needsSaveRestore) {
450cb93a386Sopenharmony_ci        *expected->append() = RESTORE;
451cb93a386Sopenharmony_ci        *expected->append() = SAVE;
452cb93a386Sopenharmony_ci    }
453cb93a386Sopenharmony_ci    (*emitMC)(canvas, mat, clip, draw, expected, accumulatedClips+2);
454cb93a386Sopenharmony_ci    emit_draw(canvas, draw, expected);
455cb93a386Sopenharmony_ci    if (needsSaveRestore) {
456cb93a386Sopenharmony_ci        *expected->append() = RESTORE;
457cb93a386Sopenharmony_ci    }
458cb93a386Sopenharmony_ci}
459cb93a386Sopenharmony_ci
460cb93a386Sopenharmony_ci// Emit:
461cb93a386Sopenharmony_ci//  matrix & clip calls
462cb93a386Sopenharmony_ci//  SaveLayer
463cb93a386Sopenharmony_ci//      matrix & clip calls
464cb93a386Sopenharmony_ci//      draw op
465cb93a386Sopenharmony_ci//  Restore
466cb93a386Sopenharmony_cistatic void emit_body2(SkCanvas* canvas, PFEmitMC emitMC, MatType mat,
467cb93a386Sopenharmony_ci                       ClipType clip, DrawOpType draw,
468cb93a386Sopenharmony_ci                       SkTDArray<DrawType>* expected, int accumulatedClips) {
469cb93a386Sopenharmony_ci    bool needsSaveRestore = kNone_DrawOpType != draw &&
470cb93a386Sopenharmony_ci                            (kNone_MatType != mat || kNone_ClipType != clip);
471cb93a386Sopenharmony_ci
472cb93a386Sopenharmony_ci    if (kNone_MatType != mat || kNone_ClipType != clip) {
473cb93a386Sopenharmony_ci        *expected->append() = SAVE;
474cb93a386Sopenharmony_ci    }
475cb93a386Sopenharmony_ci    (*emitMC)(canvas, mat, clip, kSaveLayer_DrawOpType, expected, accumulatedClips+1);
476cb93a386Sopenharmony_ci    *expected->append() = SAVE_LAYER;
477cb93a386Sopenharmony_ci    // TODO: widen testing to exercise saveLayer's parameters
478cb93a386Sopenharmony_ci    canvas->saveLayer(nullptr, nullptr);
479cb93a386Sopenharmony_ci        if (needsSaveRestore) {
480cb93a386Sopenharmony_ci            *expected->append() = SAVE;
481cb93a386Sopenharmony_ci        }
482cb93a386Sopenharmony_ci        (*emitMC)(canvas, mat, clip, draw, expected, 1);
483cb93a386Sopenharmony_ci        emit_draw(canvas, draw, expected);
484cb93a386Sopenharmony_ci        if (needsSaveRestore) {
485cb93a386Sopenharmony_ci            *expected->append() = RESTORE;
486cb93a386Sopenharmony_ci        }
487cb93a386Sopenharmony_ci    canvas->restore();
488cb93a386Sopenharmony_ci    *expected->append() = RESTORE;
489cb93a386Sopenharmony_ci    if (kNone_MatType != mat || kNone_ClipType != clip) {
490cb93a386Sopenharmony_ci        *expected->append() = RESTORE;
491cb93a386Sopenharmony_ci    }
492cb93a386Sopenharmony_ci}
493cb93a386Sopenharmony_ci
494cb93a386Sopenharmony_ci// Emit:
495cb93a386Sopenharmony_ci//  matrix & clip calls
496cb93a386Sopenharmony_ci//  SaveLayer
497cb93a386Sopenharmony_ci//      matrix & clip calls
498cb93a386Sopenharmony_ci//      SaveLayer
499cb93a386Sopenharmony_ci//          matrix & clip calls
500cb93a386Sopenharmony_ci//          draw op
501cb93a386Sopenharmony_ci//      Restore
502cb93a386Sopenharmony_ci//      matrix & clip calls (will be ignored)
503cb93a386Sopenharmony_ci//  Restore
504cb93a386Sopenharmony_cistatic void emit_body3(SkCanvas* canvas, PFEmitMC emitMC, MatType mat,
505cb93a386Sopenharmony_ci                       ClipType clip, DrawOpType draw,
506cb93a386Sopenharmony_ci                       SkTDArray<DrawType>* expected, int accumulatedClips) {
507cb93a386Sopenharmony_ci    bool needsSaveRestore = kNone_DrawOpType != draw &&
508cb93a386Sopenharmony_ci                            (kNone_MatType != mat || kNone_ClipType != clip);
509cb93a386Sopenharmony_ci
510cb93a386Sopenharmony_ci    if (kNone_MatType != mat || kNone_ClipType != clip) {
511cb93a386Sopenharmony_ci        *expected->append() = SAVE;
512cb93a386Sopenharmony_ci    }
513cb93a386Sopenharmony_ci    (*emitMC)(canvas, mat, clip, kSaveLayer_DrawOpType, expected, accumulatedClips+1);
514cb93a386Sopenharmony_ci    *expected->append() = SAVE_LAYER;
515cb93a386Sopenharmony_ci    // TODO: widen testing to exercise saveLayer's parameters
516cb93a386Sopenharmony_ci    canvas->saveLayer(nullptr, nullptr);
517cb93a386Sopenharmony_ci        (*emitMC)(canvas, mat, clip, kSaveLayer_DrawOpType, expected, 1);
518cb93a386Sopenharmony_ci        if (kNone_MatType != mat || kNone_ClipType != clip) {
519cb93a386Sopenharmony_ci            *expected->append() = SAVE;
520cb93a386Sopenharmony_ci        }
521cb93a386Sopenharmony_ci        *expected->append() = SAVE_LAYER;
522cb93a386Sopenharmony_ci        // TODO: widen testing to exercise saveLayer's parameters
523cb93a386Sopenharmony_ci        canvas->saveLayer(nullptr, nullptr);
524cb93a386Sopenharmony_ci            if (needsSaveRestore) {
525cb93a386Sopenharmony_ci                *expected->append() = SAVE;
526cb93a386Sopenharmony_ci            }
527cb93a386Sopenharmony_ci            (*emitMC)(canvas, mat, clip, draw, expected, 1);
528cb93a386Sopenharmony_ci            emit_draw(canvas, draw, expected);
529cb93a386Sopenharmony_ci            if (needsSaveRestore) {
530cb93a386Sopenharmony_ci                *expected->append() = RESTORE;
531cb93a386Sopenharmony_ci            }
532cb93a386Sopenharmony_ci        canvas->restore();             // for saveLayer
533cb93a386Sopenharmony_ci        *expected->append() = RESTORE; // for saveLayer
534cb93a386Sopenharmony_ci        if (kNone_MatType != mat || kNone_ClipType != clip) {
535cb93a386Sopenharmony_ci            *expected->append() = RESTORE;
536cb93a386Sopenharmony_ci        }
537cb93a386Sopenharmony_ci    canvas->restore();
538cb93a386Sopenharmony_ci    // required to match forced SAVE_LAYER
539cb93a386Sopenharmony_ci    *expected->append() = RESTORE;
540cb93a386Sopenharmony_ci    if (kNone_MatType != mat || kNone_ClipType != clip) {
541cb93a386Sopenharmony_ci        *expected->append() = RESTORE;
542cb93a386Sopenharmony_ci    }
543cb93a386Sopenharmony_ci}
544cb93a386Sopenharmony_ci
545cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////
546cb93a386Sopenharmony_ci
547cb93a386Sopenharmony_ci// Emit:
548cb93a386Sopenharmony_ci//  Save
549cb93a386Sopenharmony_ci//      some body
550cb93a386Sopenharmony_ci//  Restore
551cb93a386Sopenharmony_ci// Note: the outer save/restore are provided by beginRecording/endRecording
552cb93a386Sopenharmony_cistatic void emit_struct0(SkCanvas* canvas,
553cb93a386Sopenharmony_ci                         PFEmitMC emitMC, MatType mat, ClipType clip,
554cb93a386Sopenharmony_ci                         PFEmitBody emitBody, DrawOpType draw,
555cb93a386Sopenharmony_ci                         SkTDArray<DrawType>* expected) {
556cb93a386Sopenharmony_ci    (*emitBody)(canvas, emitMC, mat, clip, draw, expected, 0);
557cb93a386Sopenharmony_ci}
558cb93a386Sopenharmony_ci
559cb93a386Sopenharmony_ci// Emit:
560cb93a386Sopenharmony_ci//  Save
561cb93a386Sopenharmony_ci//      matrix & clip calls
562cb93a386Sopenharmony_ci//      Save
563cb93a386Sopenharmony_ci//          some body
564cb93a386Sopenharmony_ci//      Restore
565cb93a386Sopenharmony_ci//      matrix & clip calls (will be ignored)
566cb93a386Sopenharmony_ci//  Restore
567cb93a386Sopenharmony_ci// Note: the outer save/restore are provided by beginRecording/endRecording
568cb93a386Sopenharmony_cistatic void emit_struct1(SkCanvas* canvas,
569cb93a386Sopenharmony_ci                         PFEmitMC emitMC, MatType mat, ClipType clip,
570cb93a386Sopenharmony_ci                         PFEmitBody emitBody, DrawOpType draw,
571cb93a386Sopenharmony_ci                         SkTDArray<DrawType>* expected) {
572cb93a386Sopenharmony_ci    (*emitMC)(canvas, mat, clip, draw, nullptr, 0); // these get fused into later ops
573cb93a386Sopenharmony_ci    canvas->save();
574cb93a386Sopenharmony_ci        (*emitBody)(canvas, emitMC, mat, clip, draw, expected, 1);
575cb93a386Sopenharmony_ci    canvas->restore();
576cb93a386Sopenharmony_ci    (*emitMC)(canvas, mat, clip, draw, nullptr, 0); // these will get removed
577cb93a386Sopenharmony_ci}
578cb93a386Sopenharmony_ci
579cb93a386Sopenharmony_ci// Emit:
580cb93a386Sopenharmony_ci//  Save
581cb93a386Sopenharmony_ci//      matrix & clip calls
582cb93a386Sopenharmony_ci//      Save
583cb93a386Sopenharmony_ci//          some body
584cb93a386Sopenharmony_ci//      Restore
585cb93a386Sopenharmony_ci//      Save
586cb93a386Sopenharmony_ci//          some body
587cb93a386Sopenharmony_ci//      Restore
588cb93a386Sopenharmony_ci//      matrix & clip calls (will be ignored)
589cb93a386Sopenharmony_ci//  Restore
590cb93a386Sopenharmony_ci// Note: the outer save/restore are provided by beginRecording/endRecording
591cb93a386Sopenharmony_cistatic void emit_struct2(SkCanvas* canvas,
592cb93a386Sopenharmony_ci                         PFEmitMC emitMC, MatType mat, ClipType clip,
593cb93a386Sopenharmony_ci                         PFEmitBody emitBody, DrawOpType draw,
594cb93a386Sopenharmony_ci                         SkTDArray<DrawType>* expected) {
595cb93a386Sopenharmony_ci    (*emitMC)(canvas, mat, clip, draw, nullptr, 1); // these will get fused into later ops
596cb93a386Sopenharmony_ci    canvas->save();
597cb93a386Sopenharmony_ci        (*emitBody)(canvas, emitMC, mat, clip, draw, expected, 1);
598cb93a386Sopenharmony_ci    canvas->restore();
599cb93a386Sopenharmony_ci    canvas->save();
600cb93a386Sopenharmony_ci        (*emitBody)(canvas, emitMC, mat, clip, draw, expected, 1);
601cb93a386Sopenharmony_ci    canvas->restore();
602cb93a386Sopenharmony_ci    (*emitMC)(canvas, mat, clip, draw, nullptr, 1); // these will get removed
603cb93a386Sopenharmony_ci}
604cb93a386Sopenharmony_ci
605cb93a386Sopenharmony_ci// Emit:
606cb93a386Sopenharmony_ci//  Save
607cb93a386Sopenharmony_ci//      matrix & clip calls
608cb93a386Sopenharmony_ci//      Save
609cb93a386Sopenharmony_ci//          some body
610cb93a386Sopenharmony_ci//      Restore
611cb93a386Sopenharmony_ci//      Save
612cb93a386Sopenharmony_ci//          matrix & clip calls
613cb93a386Sopenharmony_ci//          Save
614cb93a386Sopenharmony_ci//              some body
615cb93a386Sopenharmony_ci//          Restore
616cb93a386Sopenharmony_ci//      Restore
617cb93a386Sopenharmony_ci//      matrix & clip calls (will be ignored)
618cb93a386Sopenharmony_ci//  Restore
619cb93a386Sopenharmony_ci// Note: the outer save/restore are provided by beginRecording/endRecording
620cb93a386Sopenharmony_cistatic void emit_struct3(SkCanvas* canvas,
621cb93a386Sopenharmony_ci                         PFEmitMC emitMC, MatType mat, ClipType clip,
622cb93a386Sopenharmony_ci                         PFEmitBody emitBody, DrawOpType draw,
623cb93a386Sopenharmony_ci                         SkTDArray<DrawType>* expected) {
624cb93a386Sopenharmony_ci    (*emitMC)(canvas, mat, clip, draw, nullptr, 0); // these will get fused into later ops
625cb93a386Sopenharmony_ci    canvas->save();
626cb93a386Sopenharmony_ci        (*emitBody)(canvas, emitMC, mat, clip, draw, expected, 1);
627cb93a386Sopenharmony_ci    canvas->restore();
628cb93a386Sopenharmony_ci    canvas->save();
629cb93a386Sopenharmony_ci        (*emitMC)(canvas, mat, clip, draw, nullptr, 1); // these will get fused into later ops
630cb93a386Sopenharmony_ci        canvas->save();
631cb93a386Sopenharmony_ci            (*emitBody)(canvas, emitMC, mat, clip, draw, expected, 2);
632cb93a386Sopenharmony_ci        canvas->restore();
633cb93a386Sopenharmony_ci    canvas->restore();
634cb93a386Sopenharmony_ci    (*emitMC)(canvas, mat, clip, draw, nullptr, 0); // these will get removed
635cb93a386Sopenharmony_ci}
636cb93a386Sopenharmony_ci
637cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////
638cb93a386Sopenharmony_ci
639cb93a386Sopenharmony_ci#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
640cb93a386Sopenharmony_cistatic void print(const SkTDArray<DrawType>& expected, const SkTDArray<DrawType>& actual) {
641cb93a386Sopenharmony_ci    SkDebugf("\n\nexpected %d --- actual %d\n", expected.count(), actual.count());
642cb93a386Sopenharmony_ci    int max = std::max(expected.count(), actual.count());
643cb93a386Sopenharmony_ci
644cb93a386Sopenharmony_ci    for (int i = 0; i < max; ++i) {
645cb93a386Sopenharmony_ci        if (i < expected.count()) {
646cb93a386Sopenharmony_ci            SkDebugf("%16s,    ", DrawCommand::GetCommandString(expected[i]));
647cb93a386Sopenharmony_ci        } else {
648cb93a386Sopenharmony_ci            SkDebugf("%16s,    ", " ");
649cb93a386Sopenharmony_ci        }
650cb93a386Sopenharmony_ci
651cb93a386Sopenharmony_ci        if (i < actual.count()) {
652cb93a386Sopenharmony_ci            SkDebugf("%s\n", DrawCommand::GetCommandString(actual[i]));
653cb93a386Sopenharmony_ci        } else {
654cb93a386Sopenharmony_ci            SkDebugf("\n");
655cb93a386Sopenharmony_ci        }
656cb93a386Sopenharmony_ci    }
657cb93a386Sopenharmony_ci    SkDebugf("\n\n");
658cb93a386Sopenharmony_ci    SkASSERT(0);
659cb93a386Sopenharmony_ci}
660cb93a386Sopenharmony_ci#endif
661cb93a386Sopenharmony_ci
662cb93a386Sopenharmony_cistatic void test_collapse(skiatest::Reporter* reporter) {
663cb93a386Sopenharmony_ci    PFEmitStruct gStructure[] = { emit_struct0, emit_struct1, emit_struct2, emit_struct3 };
664cb93a386Sopenharmony_ci    PFEmitBody gBody[] = { emit_body0, emit_body1, emit_body2, emit_body3 };
665cb93a386Sopenharmony_ci    PFEmitMC gMCs[] = { emit_clip_and_mat, emit_mat_and_clip,
666cb93a386Sopenharmony_ci                        emit_double_mat_and_clip, emit_mat_clip_clip };
667cb93a386Sopenharmony_ci
668cb93a386Sopenharmony_ci    for (size_t i = 0; i < SK_ARRAY_COUNT(gStructure); ++i) {
669cb93a386Sopenharmony_ci        for (size_t j = 0; j < SK_ARRAY_COUNT(gBody); ++j) {
670cb93a386Sopenharmony_ci            for (size_t k = 0; k < SK_ARRAY_COUNT(gMCs); ++k) {
671cb93a386Sopenharmony_ci                for (int l = 0; l < kMatTypeCount; ++l) {
672cb93a386Sopenharmony_ci                    for (int m = 0; m < kClipTypeCount; ++m) {
673cb93a386Sopenharmony_ci                        for (int n = 0; n < kNonSaveLayerDrawOpTypeCount; ++n) {
674cb93a386Sopenharmony_ci#ifdef TEST_COLLAPSE_MATRIX_CLIP_STATE
675cb93a386Sopenharmony_ci                            static int testID = -1;
676cb93a386Sopenharmony_ci                            ++testID;
677cb93a386Sopenharmony_ci                            if (testID < -1) {
678cb93a386Sopenharmony_ci                                continue;
679cb93a386Sopenharmony_ci                            }
680cb93a386Sopenharmony_ci                            SkDebugf("test: %d\n", testID);
681cb93a386Sopenharmony_ci#endif
682cb93a386Sopenharmony_ci
683cb93a386Sopenharmony_ci                            SkTDArray<DrawType> expected, actual;
684cb93a386Sopenharmony_ci
685cb93a386Sopenharmony_ci                            SkPicture picture;
686cb93a386Sopenharmony_ci
687cb93a386Sopenharmony_ci                            // Note: beginRecording/endRecording add a save/restore pair
688cb93a386Sopenharmony_ci                            SkCanvas* canvas = picture.beginRecording(100, 100);
689cb93a386Sopenharmony_ci                            (*gStructure[i])(canvas,
690cb93a386Sopenharmony_ci                                             gMCs[k],
691cb93a386Sopenharmony_ci                                             (MatType) l,
692cb93a386Sopenharmony_ci                                             (ClipType) m,
693cb93a386Sopenharmony_ci                                             gBody[j],
694cb93a386Sopenharmony_ci                                             (DrawOpType) n,
695cb93a386Sopenharmony_ci                                             &expected);
696cb93a386Sopenharmony_ci                            picture.endRecording();
697cb93a386Sopenharmony_ci
698cb93a386Sopenharmony_ci                            gets_ops(picture, &actual);
699cb93a386Sopenharmony_ci
700cb93a386Sopenharmony_ci                            REPORTER_ASSERT(reporter, expected.count() == actual.count());
701cb93a386Sopenharmony_ci
702cb93a386Sopenharmony_ci                            if (expected.count() != actual.count()) {
703cb93a386Sopenharmony_ci#ifdef TEST_COLLAPSE_MATRIX_CLIP_STATE
704cb93a386Sopenharmony_ci                                print(expected, actual);
705cb93a386Sopenharmony_ci#endif
706cb93a386Sopenharmony_ci                                continue;
707cb93a386Sopenharmony_ci                            }
708cb93a386Sopenharmony_ci
709cb93a386Sopenharmony_ci                            for (int i = 0; i < expected.count(); ++i) {
710cb93a386Sopenharmony_ci                                REPORTER_ASSERT(reporter, expected[i] == actual[i]);
711cb93a386Sopenharmony_ci#ifdef TEST_COLLAPSE_MATRIX_CLIP_STATE
712cb93a386Sopenharmony_ci                                if (expected[i] != actual[i]) {
713cb93a386Sopenharmony_ci                                    print(expected, actual);
714cb93a386Sopenharmony_ci                                }
715cb93a386Sopenharmony_ci#endif
716cb93a386Sopenharmony_ci                                break;
717cb93a386Sopenharmony_ci                            }
718cb93a386Sopenharmony_ci                        }
719cb93a386Sopenharmony_ci                    }
720cb93a386Sopenharmony_ci                }
721cb93a386Sopenharmony_ci            }
722cb93a386Sopenharmony_ci        }
723cb93a386Sopenharmony_ci    }
724cb93a386Sopenharmony_ci}
725cb93a386Sopenharmony_ci
726cb93a386Sopenharmony_ciDEF_TEST(MatrixClipCollapse, reporter) {
727cb93a386Sopenharmony_ci    test_collapse(reporter);
728cb93a386Sopenharmony_ci}
729cb93a386Sopenharmony_ci
730cb93a386Sopenharmony_ci#endif
731