CanvasStateTest.cpp revision fa0ab893eb60a41aac6945ab26d2b3a7e38443c4
1
2/*
3 * Copyright 2013 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9#include "Test.h"
10#include "SkCanvas.h"
11#include "SkCanvasStateUtils.h"
12#include "SkDevice.h"
13#include "SkDrawFilter.h"
14#include "SkPaint.h"
15#include "SkRect.h"
16#include "SkRRect.h"
17
18static void test_complex_layers(skiatest::Reporter* reporter) {
19    const int WIDTH = 400;
20    const int HEIGHT = 400;
21    const int SPACER = 10;
22
23    SkRect rect = SkRect::MakeXYWH(SPACER, SPACER, WIDTH-(2*SPACER), (HEIGHT-(2*SPACER)) / 7);
24
25    const SkBitmap::Config configs[] = { SkBitmap::kRGB_565_Config,
26                                         SkBitmap::kARGB_8888_Config
27    };
28    const int configCount = sizeof(configs) / sizeof(SkBitmap::Config);
29
30    const int layerAlpha[] = { 255, 255, 0 };
31    const SkCanvas::SaveFlags flags[] = { SkCanvas::kARGB_NoClipLayer_SaveFlag,
32                                          SkCanvas::kARGB_ClipLayer_SaveFlag,
33                                          SkCanvas::kARGB_NoClipLayer_SaveFlag
34    };
35    REPORTER_ASSERT(reporter, sizeof(layerAlpha) == sizeof(flags));
36    const int layerCombinations = sizeof(layerAlpha) / sizeof(int);
37
38    for (int i = 0; i < configCount; ++i) {
39        SkBitmap bitmaps[2];
40        for (int j = 0; j < 2; ++j) {
41            bitmaps[j].setConfig(configs[i], WIDTH, HEIGHT);
42            bitmaps[j].allocPixels();
43
44            SkCanvas canvas(bitmaps[j]);
45
46            canvas.drawColor(SK_ColorRED);
47
48            for (int k = 0; k < layerCombinations; ++k) {
49                // draw a rect within the layer's bounds and again outside the layer's bounds
50                canvas.saveLayerAlpha(&rect, layerAlpha[k], flags[k]);
51
52                SkCanvasState* state = NULL;
53                SkCanvas* tmpCanvas = NULL;
54                if (j) {
55                    state = SkCanvasStateUtils::CaptureCanvasState(&canvas);
56                    REPORTER_ASSERT(reporter, state);
57                    tmpCanvas = SkCanvasStateUtils::CreateFromCanvasState(state);
58                    REPORTER_ASSERT(reporter, tmpCanvas);
59                } else {
60                    tmpCanvas = SkRef(&canvas);
61                }
62
63                SkPaint bluePaint;
64                bluePaint.setColor(SK_ColorBLUE);
65                bluePaint.setStyle(SkPaint::kFill_Style);
66
67                tmpCanvas->drawRect(rect, bluePaint);
68                tmpCanvas->translate(0, rect.height() + SPACER);
69                tmpCanvas->drawRect(rect, bluePaint);
70
71                tmpCanvas->unref();
72                SkCanvasStateUtils::ReleaseCanvasState(state);
73
74                canvas.restore();
75
76                // translate the canvas for the next iteration
77                canvas.translate(0, 2*(rect.height() + SPACER));
78            }
79        }
80
81        // now we memcmp the two bitmaps
82        REPORTER_ASSERT(reporter, bitmaps[0].getSize() == bitmaps[1].getSize());
83        REPORTER_ASSERT(reporter, !memcmp(bitmaps[0].getPixels(),
84                                          bitmaps[1].getPixels(),
85                                          bitmaps[0].getSize()));
86    }
87}
88
89////////////////////////////////////////////////////////////////////////////////
90
91static void test_complex_clips(skiatest::Reporter* reporter) {
92
93    const int WIDTH = 400;
94    const int HEIGHT = 400;
95    const SkScalar SPACER = SkIntToScalar(10);
96
97    SkRect layerRect = SkRect::MakeWH(SkIntToScalar(WIDTH), SkIntToScalar(HEIGHT / 4));
98    layerRect.inset(2*SPACER, 2*SPACER);
99
100    SkRect clipRect = layerRect;
101    clipRect.fRight = clipRect.fLeft + (clipRect.width() / 2) - (2*SPACER);
102    clipRect.outset(SPACER, SPACER);
103
104    SkIRect regionBounds;
105    clipRect.roundIn(&regionBounds);
106    regionBounds.offset(clipRect.width() + (2*SPACER), 0);
107
108    SkIRect regionInterior = regionBounds;
109    regionInterior.inset(SPACER*3, SPACER*3);
110
111    SkRegion clipRegion;
112    clipRegion.setRect(regionBounds);
113    clipRegion.op(regionInterior, SkRegion::kDifference_Op);
114
115
116    const SkRegion::Op clipOps[] = { SkRegion::kIntersect_Op,
117                                     SkRegion::kIntersect_Op,
118                                     SkRegion::kReplace_Op,
119    };
120    const SkCanvas::SaveFlags flags[] = { SkCanvas::kARGB_NoClipLayer_SaveFlag,
121                                          SkCanvas::kARGB_ClipLayer_SaveFlag,
122                                          SkCanvas::kARGB_NoClipLayer_SaveFlag,
123    };
124    REPORTER_ASSERT(reporter, sizeof(clipOps) == sizeof(flags));
125    const int layerCombinations = sizeof(flags) / sizeof(SkCanvas::SaveFlags);
126
127    SkBitmap bitmaps[2];
128    for (int i = 0; i < 2; ++i) {
129        bitmaps[i].setConfig(SkBitmap::kARGB_8888_Config, WIDTH, HEIGHT);
130        bitmaps[i].allocPixels();
131
132        SkCanvas canvas(bitmaps[i]);
133
134        canvas.drawColor(SK_ColorRED);
135
136        SkRegion localRegion = clipRegion;
137
138        for (int j = 0; j < layerCombinations; ++j) {
139            canvas.saveLayerAlpha(&layerRect, 128, flags[j]);
140
141            SkCanvasState* state = NULL;
142            SkCanvas* tmpCanvas = NULL;
143            if (i) {
144                state = SkCanvasStateUtils::CaptureCanvasState(&canvas);
145                REPORTER_ASSERT(reporter, state);
146                tmpCanvas = SkCanvasStateUtils::CreateFromCanvasState(state);
147                REPORTER_ASSERT(reporter, tmpCanvas);
148            } else {
149                tmpCanvas = SkRef(&canvas);
150            }
151
152            tmpCanvas->save();
153            tmpCanvas->clipRect(clipRect, clipOps[j]);
154            tmpCanvas->drawColor(SK_ColorBLUE);
155            tmpCanvas->restore();
156
157            tmpCanvas->clipRegion(localRegion, clipOps[j]);
158            tmpCanvas->drawColor(SK_ColorBLUE);
159
160            tmpCanvas->unref();
161            SkCanvasStateUtils::ReleaseCanvasState(state);
162
163            canvas.restore();
164
165            // translate the canvas and region for the next iteration
166            canvas.translate(0, 2*(layerRect.height() + SPACER));
167            localRegion.translate(0, 2*(layerRect.height() + SPACER));
168        }
169    }
170
171    // now we memcmp the two bitmaps
172    REPORTER_ASSERT(reporter, bitmaps[0].getSize() == bitmaps[1].getSize());
173    REPORTER_ASSERT(reporter, !memcmp(bitmaps[0].getPixels(),
174                                      bitmaps[1].getPixels(),
175                                      bitmaps[0].getSize()));
176}
177
178////////////////////////////////////////////////////////////////////////////////
179
180class TestDrawFilter : public SkDrawFilter {
181public:
182    virtual bool filter(SkPaint*, Type) SK_OVERRIDE { return true; }
183};
184
185static void test_draw_filters(skiatest::Reporter* reporter) {
186    TestDrawFilter drawFilter;
187    SkDevice device(SkBitmap::kARGB_8888_Config, 10, 10);
188    SkCanvas canvas(&device);
189
190    canvas.setDrawFilter(&drawFilter);
191
192    SkCanvasState* state = SkCanvasStateUtils::CaptureCanvasState(&canvas);
193    REPORTER_ASSERT(reporter, state);
194    SkCanvas* tmpCanvas = SkCanvasStateUtils::CreateFromCanvasState(state);
195    REPORTER_ASSERT(reporter, tmpCanvas);
196
197    REPORTER_ASSERT(reporter, NULL != canvas.getDrawFilter());
198    REPORTER_ASSERT(reporter, NULL == tmpCanvas->getDrawFilter());
199
200    tmpCanvas->unref();
201    SkCanvasStateUtils::ReleaseCanvasState(state);
202}
203
204////////////////////////////////////////////////////////////////////////////////
205
206static void test_soft_clips(skiatest::Reporter* reporter) {
207    SkDevice device(SkBitmap::kARGB_8888_Config, 10, 10);
208    SkCanvas canvas(&device);
209
210    SkRRect roundRect;
211    roundRect.setOval(SkRect::MakeWH(5, 5));
212
213    canvas.clipRRect(roundRect, SkRegion::kIntersect_Op, true);
214
215    SkCanvasState* state = SkCanvasStateUtils::CaptureCanvasState(&canvas);
216    REPORTER_ASSERT(reporter, !state);
217}
218
219////////////////////////////////////////////////////////////////////////////////
220
221static void test_canvas_state_utils(skiatest::Reporter* reporter) {
222    test_complex_layers(reporter);
223    test_complex_clips(reporter);
224    test_draw_filters(reporter);
225    test_soft_clips(reporter);
226}
227
228#include "TestClassDef.h"
229DEFINE_TESTCLASS("CanvasState", TestCanvasStateClass, test_canvas_state_utils)
230