blob: 212b14ab3ef7f7046346c32a6300ca3de9e9cd06 [file] [log] [blame]
djsollen@google.com5587ac02013-08-29 20:20:40 +00001/*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
djsollen@google.com5587ac02013-08-29 20:20:40 +00008#include "SkBitmapDevice.h"
9#include "SkCanvas.h"
10#include "SkCanvasStateUtils.h"
11#include "SkDrawFilter.h"
commit-bot@chromium.org07f6cf32013-09-18 20:15:12 +000012#include "SkError.h"
djsollen@google.com5587ac02013-08-29 20:20:40 +000013#include "SkPaint.h"
djsollen@google.com5587ac02013-08-29 20:20:40 +000014#include "SkRRect.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000015#include "SkRect.h"
16#include "Test.h"
djsollen@google.com5587ac02013-08-29 20:20:40 +000017
18static void test_complex_layers(skiatest::Reporter* reporter) {
reed@google.comb93ba452014-03-10 19:47:58 +000019#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
djsollen@google.com5587ac02013-08-29 20:20:40 +000020 const int WIDTH = 400;
21 const int HEIGHT = 400;
22 const int SPACER = 10;
23
djsollen@google.com20146b32013-08-29 20:36:22 +000024 SkRect rect = SkRect::MakeXYWH(SkIntToScalar(SPACER), SkIntToScalar(SPACER),
25 SkIntToScalar(WIDTH-(2*SPACER)),
26 SkIntToScalar((HEIGHT-(2*SPACER)) / 7));
djsollen@google.com5587ac02013-08-29 20:20:40 +000027
commit-bot@chromium.orgfa9e5fa2014-02-13 22:00:04 +000028 const SkColorType colorTypes[] = {
commit-bot@chromium.org757ebd22014-04-10 22:36:34 +000029 kRGB_565_SkColorType, kPMColor_SkColorType
djsollen@google.com5587ac02013-08-29 20:20:40 +000030 };
commit-bot@chromium.orgfa9e5fa2014-02-13 22:00:04 +000031 const int configCount = sizeof(colorTypes) / sizeof(SkBitmap::Config);
djsollen@google.com5587ac02013-08-29 20:20:40 +000032
33 const int layerAlpha[] = { 255, 255, 0 };
34 const SkCanvas::SaveFlags flags[] = { SkCanvas::kARGB_NoClipLayer_SaveFlag,
35 SkCanvas::kARGB_ClipLayer_SaveFlag,
36 SkCanvas::kARGB_NoClipLayer_SaveFlag
37 };
38 REPORTER_ASSERT(reporter, sizeof(layerAlpha) == sizeof(flags));
39 const int layerCombinations = sizeof(layerAlpha) / sizeof(int);
40
41 for (int i = 0; i < configCount; ++i) {
42 SkBitmap bitmaps[2];
43 for (int j = 0; j < 2; ++j) {
commit-bot@chromium.orgfa9e5fa2014-02-13 22:00:04 +000044 bitmaps[j].allocPixels(SkImageInfo::Make(WIDTH, HEIGHT,
45 colorTypes[i],
46 kPremul_SkAlphaType));
djsollen@google.com5587ac02013-08-29 20:20:40 +000047
48 SkCanvas canvas(bitmaps[j]);
49
50 canvas.drawColor(SK_ColorRED);
51
52 for (int k = 0; k < layerCombinations; ++k) {
53 // draw a rect within the layer's bounds and again outside the layer's bounds
54 canvas.saveLayerAlpha(&rect, layerAlpha[k], flags[k]);
55
56 SkCanvasState* state = NULL;
57 SkCanvas* tmpCanvas = NULL;
58 if (j) {
59 state = SkCanvasStateUtils::CaptureCanvasState(&canvas);
60 REPORTER_ASSERT(reporter, state);
61 tmpCanvas = SkCanvasStateUtils::CreateFromCanvasState(state);
62 REPORTER_ASSERT(reporter, tmpCanvas);
63 } else {
64 tmpCanvas = SkRef(&canvas);
65 }
66
67 SkPaint bluePaint;
68 bluePaint.setColor(SK_ColorBLUE);
69 bluePaint.setStyle(SkPaint::kFill_Style);
70
71 tmpCanvas->drawRect(rect, bluePaint);
72 tmpCanvas->translate(0, rect.height() + SPACER);
73 tmpCanvas->drawRect(rect, bluePaint);
74
75 tmpCanvas->unref();
76 SkCanvasStateUtils::ReleaseCanvasState(state);
77
78 canvas.restore();
79
80 // translate the canvas for the next iteration
81 canvas.translate(0, 2*(rect.height() + SPACER));
82 }
83 }
84
85 // now we memcmp the two bitmaps
86 REPORTER_ASSERT(reporter, bitmaps[0].getSize() == bitmaps[1].getSize());
87 REPORTER_ASSERT(reporter, !memcmp(bitmaps[0].getPixels(),
88 bitmaps[1].getPixels(),
89 bitmaps[0].getSize()));
90 }
reed@google.comb93ba452014-03-10 19:47:58 +000091#endif
djsollen@google.com5587ac02013-08-29 20:20:40 +000092}
93
94////////////////////////////////////////////////////////////////////////////////
95
djsollen@google.com339e79f2013-09-04 17:16:00 +000096static void test_complex_clips(skiatest::Reporter* reporter) {
reed@google.comb93ba452014-03-10 19:47:58 +000097#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
djsollen@google.com339e79f2013-09-04 17:16:00 +000098 const int WIDTH = 400;
99 const int HEIGHT = 400;
djsollen@google.com1037c7b2013-09-04 18:20:30 +0000100 const int SPACER = 10;
djsollen@google.com339e79f2013-09-04 17:16:00 +0000101
djsollen@google.com1037c7b2013-09-04 18:20:30 +0000102 SkIRect layerRect = SkIRect::MakeWH(WIDTH, HEIGHT / 4);
djsollen@google.com339e79f2013-09-04 17:16:00 +0000103 layerRect.inset(2*SPACER, 2*SPACER);
104
djsollen@google.com1037c7b2013-09-04 18:20:30 +0000105 SkIRect clipRect = layerRect;
djsollen@google.com339e79f2013-09-04 17:16:00 +0000106 clipRect.fRight = clipRect.fLeft + (clipRect.width() / 2) - (2*SPACER);
107 clipRect.outset(SPACER, SPACER);
108
djsollen@google.com1037c7b2013-09-04 18:20:30 +0000109 SkIRect regionBounds = clipRect;
djsollen@google.com339e79f2013-09-04 17:16:00 +0000110 regionBounds.offset(clipRect.width() + (2*SPACER), 0);
111
112 SkIRect regionInterior = regionBounds;
113 regionInterior.inset(SPACER*3, SPACER*3);
114
115 SkRegion clipRegion;
116 clipRegion.setRect(regionBounds);
117 clipRegion.op(regionInterior, SkRegion::kDifference_Op);
118
119
120 const SkRegion::Op clipOps[] = { SkRegion::kIntersect_Op,
121 SkRegion::kIntersect_Op,
122 SkRegion::kReplace_Op,
123 };
124 const SkCanvas::SaveFlags flags[] = { SkCanvas::kARGB_NoClipLayer_SaveFlag,
125 SkCanvas::kARGB_ClipLayer_SaveFlag,
126 SkCanvas::kARGB_NoClipLayer_SaveFlag,
127 };
128 REPORTER_ASSERT(reporter, sizeof(clipOps) == sizeof(flags));
129 const int layerCombinations = sizeof(flags) / sizeof(SkCanvas::SaveFlags);
130
131 SkBitmap bitmaps[2];
132 for (int i = 0; i < 2; ++i) {
commit-bot@chromium.orgfa9e5fa2014-02-13 22:00:04 +0000133 bitmaps[i].allocN32Pixels(WIDTH, HEIGHT);
djsollen@google.com339e79f2013-09-04 17:16:00 +0000134
135 SkCanvas canvas(bitmaps[i]);
136
137 canvas.drawColor(SK_ColorRED);
138
139 SkRegion localRegion = clipRegion;
140
141 for (int j = 0; j < layerCombinations; ++j) {
djsollen@google.com1037c7b2013-09-04 18:20:30 +0000142 SkRect layerBounds = SkRect::Make(layerRect);
143 canvas.saveLayerAlpha(&layerBounds, 128, flags[j]);
djsollen@google.com339e79f2013-09-04 17:16:00 +0000144
145 SkCanvasState* state = NULL;
146 SkCanvas* tmpCanvas = NULL;
147 if (i) {
148 state = SkCanvasStateUtils::CaptureCanvasState(&canvas);
149 REPORTER_ASSERT(reporter, state);
150 tmpCanvas = SkCanvasStateUtils::CreateFromCanvasState(state);
151 REPORTER_ASSERT(reporter, tmpCanvas);
152 } else {
153 tmpCanvas = SkRef(&canvas);
154 }
155
156 tmpCanvas->save();
djsollen@google.com1037c7b2013-09-04 18:20:30 +0000157 tmpCanvas->clipRect(SkRect::Make(clipRect), clipOps[j]);
djsollen@google.com339e79f2013-09-04 17:16:00 +0000158 tmpCanvas->drawColor(SK_ColorBLUE);
159 tmpCanvas->restore();
160
161 tmpCanvas->clipRegion(localRegion, clipOps[j]);
162 tmpCanvas->drawColor(SK_ColorBLUE);
163
164 tmpCanvas->unref();
165 SkCanvasStateUtils::ReleaseCanvasState(state);
166
167 canvas.restore();
168
169 // translate the canvas and region for the next iteration
djsollen@google.com1037c7b2013-09-04 18:20:30 +0000170 canvas.translate(0, SkIntToScalar(2*(layerRect.height() + (SPACER))));
djsollen@google.com339e79f2013-09-04 17:16:00 +0000171 localRegion.translate(0, 2*(layerRect.height() + SPACER));
172 }
173 }
174
175 // now we memcmp the two bitmaps
176 REPORTER_ASSERT(reporter, bitmaps[0].getSize() == bitmaps[1].getSize());
177 REPORTER_ASSERT(reporter, !memcmp(bitmaps[0].getPixels(),
178 bitmaps[1].getPixels(),
179 bitmaps[0].getSize()));
reed@google.comb93ba452014-03-10 19:47:58 +0000180#endif
djsollen@google.com339e79f2013-09-04 17:16:00 +0000181}
182
183////////////////////////////////////////////////////////////////////////////////
184
djsollen@google.com5587ac02013-08-29 20:20:40 +0000185class TestDrawFilter : public SkDrawFilter {
186public:
187 virtual bool filter(SkPaint*, Type) SK_OVERRIDE { return true; }
188};
189
190static void test_draw_filters(skiatest::Reporter* reporter) {
191 TestDrawFilter drawFilter;
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000192 SkBitmap bitmap;
193 bitmap.allocN32Pixels(10, 10);
194 SkCanvas canvas(bitmap);
djsollen@google.com5587ac02013-08-29 20:20:40 +0000195
196 canvas.setDrawFilter(&drawFilter);
197
198 SkCanvasState* state = SkCanvasStateUtils::CaptureCanvasState(&canvas);
199 REPORTER_ASSERT(reporter, state);
200 SkCanvas* tmpCanvas = SkCanvasStateUtils::CreateFromCanvasState(state);
201 REPORTER_ASSERT(reporter, tmpCanvas);
202
203 REPORTER_ASSERT(reporter, NULL != canvas.getDrawFilter());
204 REPORTER_ASSERT(reporter, NULL == tmpCanvas->getDrawFilter());
205
206 tmpCanvas->unref();
207 SkCanvasStateUtils::ReleaseCanvasState(state);
208}
209
210////////////////////////////////////////////////////////////////////////////////
211
commit-bot@chromium.org07f6cf32013-09-18 20:15:12 +0000212// we need this function to prevent SkError from printing to stdout
213static void error_callback(SkError code, void* ctx) {}
214
djsollen@google.com5587ac02013-08-29 20:20:40 +0000215static void test_soft_clips(skiatest::Reporter* reporter) {
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000216 SkBitmap bitmap;
217 bitmap.allocN32Pixels(10, 10);
218 SkCanvas canvas(bitmap);
djsollen@google.com5587ac02013-08-29 20:20:40 +0000219
220 SkRRect roundRect;
221 roundRect.setOval(SkRect::MakeWH(5, 5));
222
223 canvas.clipRRect(roundRect, SkRegion::kIntersect_Op, true);
224
commit-bot@chromium.org07f6cf32013-09-18 20:15:12 +0000225 SkSetErrorCallback(error_callback, NULL);
226
djsollen@google.com5587ac02013-08-29 20:20:40 +0000227 SkCanvasState* state = SkCanvasStateUtils::CaptureCanvasState(&canvas);
228 REPORTER_ASSERT(reporter, !state);
commit-bot@chromium.org07f6cf32013-09-18 20:15:12 +0000229
230 REPORTER_ASSERT(reporter, kInvalidOperation_SkError == SkGetLastError());
231 SkClearLastError();
djsollen@google.com5587ac02013-08-29 20:20:40 +0000232}
233
senorblanco@chromium.org89f077c2014-02-24 15:16:42 +0000234static void test_saveLayer_clip(skiatest::Reporter* reporter) {
reed@google.comb93ba452014-03-10 19:47:58 +0000235#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
senorblanco@chromium.org89f077c2014-02-24 15:16:42 +0000236 const int WIDTH = 100;
237 const int HEIGHT = 100;
238 const int LAYER_WIDTH = 50;
239 const int LAYER_HEIGHT = 50;
240
241 SkBitmap bitmap;
242 bitmap.allocN32Pixels(WIDTH, HEIGHT);
243 SkCanvas canvas(bitmap);
244
245 SkRect bounds = SkRect::MakeWH(SkIntToScalar(LAYER_WIDTH), SkIntToScalar(LAYER_HEIGHT));
246 canvas.clipRect(SkRect::MakeWH(SkIntToScalar(WIDTH), SkIntToScalar(HEIGHT)));
247
248 // Check that saveLayer without the kClipToLayer_SaveFlag leaves the
249 // clip stack unchanged.
250 canvas.saveLayer(&bounds, NULL, SkCanvas::kARGB_NoClipLayer_SaveFlag);
251 SkRect clipStackBounds;
252 SkClipStack::BoundsType boundsType;
253 canvas.getClipStack()->getBounds(&clipStackBounds, &boundsType);
254 REPORTER_ASSERT(reporter, clipStackBounds.width() == WIDTH);
255 REPORTER_ASSERT(reporter, clipStackBounds.height() == HEIGHT);
256 canvas.restore();
257
258 // Check that saveLayer with the kClipToLayer_SaveFlag sets the clip
259 // stack to the layer bounds.
260 canvas.saveLayer(&bounds, NULL, SkCanvas::kARGB_ClipLayer_SaveFlag);
261 canvas.getClipStack()->getBounds(&clipStackBounds, &boundsType);
262 REPORTER_ASSERT(reporter, clipStackBounds.width() == LAYER_WIDTH);
263 REPORTER_ASSERT(reporter, clipStackBounds.height() == LAYER_HEIGHT);
264
265 canvas.restore();
reed@google.comb93ba452014-03-10 19:47:58 +0000266#endif
senorblanco@chromium.org89f077c2014-02-24 15:16:42 +0000267}
268
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +0000269DEF_TEST(CanvasState, reporter) {
djsollen@google.com5587ac02013-08-29 20:20:40 +0000270 test_complex_layers(reporter);
djsollen@google.com339e79f2013-09-04 17:16:00 +0000271 test_complex_clips(reporter);
djsollen@google.com5587ac02013-08-29 20:20:40 +0000272 test_draw_filters(reporter);
273 test_soft_clips(reporter);
senorblanco@chromium.org89f077c2014-02-24 15:16:42 +0000274 test_saveLayer_clip(reporter);
djsollen@google.com5587ac02013-08-29 20:20:40 +0000275}