blob: f1c35929d60875186018003a2e57fe8d78cb60a4 [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) {
djsollen@google.com5587ac02013-08-29 20:20:40 +000019 const int WIDTH = 400;
20 const int HEIGHT = 400;
21 const int SPACER = 10;
22
djsollen@google.com20146b32013-08-29 20:36:22 +000023 SkRect rect = SkRect::MakeXYWH(SkIntToScalar(SPACER), SkIntToScalar(SPACER),
24 SkIntToScalar(WIDTH-(2*SPACER)),
25 SkIntToScalar((HEIGHT-(2*SPACER)) / 7));
djsollen@google.com5587ac02013-08-29 20:20:40 +000026
27 const SkBitmap::Config configs[] = { SkBitmap::kRGB_565_Config,
28 SkBitmap::kARGB_8888_Config
29 };
30 const int configCount = sizeof(configs) / sizeof(SkBitmap::Config);
31
32 const int layerAlpha[] = { 255, 255, 0 };
33 const SkCanvas::SaveFlags flags[] = { SkCanvas::kARGB_NoClipLayer_SaveFlag,
34 SkCanvas::kARGB_ClipLayer_SaveFlag,
35 SkCanvas::kARGB_NoClipLayer_SaveFlag
36 };
37 REPORTER_ASSERT(reporter, sizeof(layerAlpha) == sizeof(flags));
38 const int layerCombinations = sizeof(layerAlpha) / sizeof(int);
39
40 for (int i = 0; i < configCount; ++i) {
41 SkBitmap bitmaps[2];
42 for (int j = 0; j < 2; ++j) {
43 bitmaps[j].setConfig(configs[i], WIDTH, HEIGHT);
44 bitmaps[j].allocPixels();
45
46 SkCanvas canvas(bitmaps[j]);
47
48 canvas.drawColor(SK_ColorRED);
49
50 for (int k = 0; k < layerCombinations; ++k) {
51 // draw a rect within the layer's bounds and again outside the layer's bounds
52 canvas.saveLayerAlpha(&rect, layerAlpha[k], flags[k]);
53
54 SkCanvasState* state = NULL;
55 SkCanvas* tmpCanvas = NULL;
56 if (j) {
57 state = SkCanvasStateUtils::CaptureCanvasState(&canvas);
58 REPORTER_ASSERT(reporter, state);
59 tmpCanvas = SkCanvasStateUtils::CreateFromCanvasState(state);
60 REPORTER_ASSERT(reporter, tmpCanvas);
61 } else {
62 tmpCanvas = SkRef(&canvas);
63 }
64
65 SkPaint bluePaint;
66 bluePaint.setColor(SK_ColorBLUE);
67 bluePaint.setStyle(SkPaint::kFill_Style);
68
69 tmpCanvas->drawRect(rect, bluePaint);
70 tmpCanvas->translate(0, rect.height() + SPACER);
71 tmpCanvas->drawRect(rect, bluePaint);
72
73 tmpCanvas->unref();
74 SkCanvasStateUtils::ReleaseCanvasState(state);
75
76 canvas.restore();
77
78 // translate the canvas for the next iteration
79 canvas.translate(0, 2*(rect.height() + SPACER));
80 }
81 }
82
83 // now we memcmp the two bitmaps
84 REPORTER_ASSERT(reporter, bitmaps[0].getSize() == bitmaps[1].getSize());
85 REPORTER_ASSERT(reporter, !memcmp(bitmaps[0].getPixels(),
86 bitmaps[1].getPixels(),
87 bitmaps[0].getSize()));
88 }
89}
90
91////////////////////////////////////////////////////////////////////////////////
92
djsollen@google.com339e79f2013-09-04 17:16:00 +000093static void test_complex_clips(skiatest::Reporter* reporter) {
94
95 const int WIDTH = 400;
96 const int HEIGHT = 400;
djsollen@google.com1037c7b2013-09-04 18:20:30 +000097 const int SPACER = 10;
djsollen@google.com339e79f2013-09-04 17:16:00 +000098
djsollen@google.com1037c7b2013-09-04 18:20:30 +000099 SkIRect layerRect = SkIRect::MakeWH(WIDTH, HEIGHT / 4);
djsollen@google.com339e79f2013-09-04 17:16:00 +0000100 layerRect.inset(2*SPACER, 2*SPACER);
101
djsollen@google.com1037c7b2013-09-04 18:20:30 +0000102 SkIRect clipRect = layerRect;
djsollen@google.com339e79f2013-09-04 17:16:00 +0000103 clipRect.fRight = clipRect.fLeft + (clipRect.width() / 2) - (2*SPACER);
104 clipRect.outset(SPACER, SPACER);
105
djsollen@google.com1037c7b2013-09-04 18:20:30 +0000106 SkIRect regionBounds = clipRect;
djsollen@google.com339e79f2013-09-04 17:16:00 +0000107 regionBounds.offset(clipRect.width() + (2*SPACER), 0);
108
109 SkIRect regionInterior = regionBounds;
110 regionInterior.inset(SPACER*3, SPACER*3);
111
112 SkRegion clipRegion;
113 clipRegion.setRect(regionBounds);
114 clipRegion.op(regionInterior, SkRegion::kDifference_Op);
115
116
117 const SkRegion::Op clipOps[] = { SkRegion::kIntersect_Op,
118 SkRegion::kIntersect_Op,
119 SkRegion::kReplace_Op,
120 };
121 const SkCanvas::SaveFlags flags[] = { SkCanvas::kARGB_NoClipLayer_SaveFlag,
122 SkCanvas::kARGB_ClipLayer_SaveFlag,
123 SkCanvas::kARGB_NoClipLayer_SaveFlag,
124 };
125 REPORTER_ASSERT(reporter, sizeof(clipOps) == sizeof(flags));
126 const int layerCombinations = sizeof(flags) / sizeof(SkCanvas::SaveFlags);
127
128 SkBitmap bitmaps[2];
129 for (int i = 0; i < 2; ++i) {
130 bitmaps[i].setConfig(SkBitmap::kARGB_8888_Config, WIDTH, HEIGHT);
131 bitmaps[i].allocPixels();
132
133 SkCanvas canvas(bitmaps[i]);
134
135 canvas.drawColor(SK_ColorRED);
136
137 SkRegion localRegion = clipRegion;
138
139 for (int j = 0; j < layerCombinations; ++j) {
djsollen@google.com1037c7b2013-09-04 18:20:30 +0000140 SkRect layerBounds = SkRect::Make(layerRect);
141 canvas.saveLayerAlpha(&layerBounds, 128, flags[j]);
djsollen@google.com339e79f2013-09-04 17:16:00 +0000142
143 SkCanvasState* state = NULL;
144 SkCanvas* tmpCanvas = NULL;
145 if (i) {
146 state = SkCanvasStateUtils::CaptureCanvasState(&canvas);
147 REPORTER_ASSERT(reporter, state);
148 tmpCanvas = SkCanvasStateUtils::CreateFromCanvasState(state);
149 REPORTER_ASSERT(reporter, tmpCanvas);
150 } else {
151 tmpCanvas = SkRef(&canvas);
152 }
153
154 tmpCanvas->save();
djsollen@google.com1037c7b2013-09-04 18:20:30 +0000155 tmpCanvas->clipRect(SkRect::Make(clipRect), clipOps[j]);
djsollen@google.com339e79f2013-09-04 17:16:00 +0000156 tmpCanvas->drawColor(SK_ColorBLUE);
157 tmpCanvas->restore();
158
159 tmpCanvas->clipRegion(localRegion, clipOps[j]);
160 tmpCanvas->drawColor(SK_ColorBLUE);
161
162 tmpCanvas->unref();
163 SkCanvasStateUtils::ReleaseCanvasState(state);
164
165 canvas.restore();
166
167 // translate the canvas and region for the next iteration
djsollen@google.com1037c7b2013-09-04 18:20:30 +0000168 canvas.translate(0, SkIntToScalar(2*(layerRect.height() + (SPACER))));
djsollen@google.com339e79f2013-09-04 17:16:00 +0000169 localRegion.translate(0, 2*(layerRect.height() + SPACER));
170 }
171 }
172
173 // now we memcmp the two bitmaps
174 REPORTER_ASSERT(reporter, bitmaps[0].getSize() == bitmaps[1].getSize());
175 REPORTER_ASSERT(reporter, !memcmp(bitmaps[0].getPixels(),
176 bitmaps[1].getPixels(),
177 bitmaps[0].getSize()));
178}
179
180////////////////////////////////////////////////////////////////////////////////
181
djsollen@google.com5587ac02013-08-29 20:20:40 +0000182class TestDrawFilter : public SkDrawFilter {
183public:
184 virtual bool filter(SkPaint*, Type) SK_OVERRIDE { return true; }
185};
186
187static void test_draw_filters(skiatest::Reporter* reporter) {
188 TestDrawFilter drawFilter;
189 SkBitmapDevice device(SkBitmap::kARGB_8888_Config, 10, 10);
190 SkCanvas canvas(&device);
191
192 canvas.setDrawFilter(&drawFilter);
193
194 SkCanvasState* state = SkCanvasStateUtils::CaptureCanvasState(&canvas);
195 REPORTER_ASSERT(reporter, state);
196 SkCanvas* tmpCanvas = SkCanvasStateUtils::CreateFromCanvasState(state);
197 REPORTER_ASSERT(reporter, tmpCanvas);
198
199 REPORTER_ASSERT(reporter, NULL != canvas.getDrawFilter());
200 REPORTER_ASSERT(reporter, NULL == tmpCanvas->getDrawFilter());
201
202 tmpCanvas->unref();
203 SkCanvasStateUtils::ReleaseCanvasState(state);
204}
205
206////////////////////////////////////////////////////////////////////////////////
207
commit-bot@chromium.org07f6cf32013-09-18 20:15:12 +0000208// we need this function to prevent SkError from printing to stdout
209static void error_callback(SkError code, void* ctx) {}
210
djsollen@google.com5587ac02013-08-29 20:20:40 +0000211static void test_soft_clips(skiatest::Reporter* reporter) {
212 SkBitmapDevice device(SkBitmap::kARGB_8888_Config, 10, 10);
213 SkCanvas canvas(&device);
214
215 SkRRect roundRect;
216 roundRect.setOval(SkRect::MakeWH(5, 5));
217
218 canvas.clipRRect(roundRect, SkRegion::kIntersect_Op, true);
219
commit-bot@chromium.org07f6cf32013-09-18 20:15:12 +0000220 SkSetErrorCallback(error_callback, NULL);
221
djsollen@google.com5587ac02013-08-29 20:20:40 +0000222 SkCanvasState* state = SkCanvasStateUtils::CaptureCanvasState(&canvas);
223 REPORTER_ASSERT(reporter, !state);
commit-bot@chromium.org07f6cf32013-09-18 20:15:12 +0000224
225 REPORTER_ASSERT(reporter, kInvalidOperation_SkError == SkGetLastError());
226 SkClearLastError();
djsollen@google.com5587ac02013-08-29 20:20:40 +0000227}
228
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +0000229DEF_TEST(CanvasState, reporter) {
djsollen@google.com5587ac02013-08-29 20:20:40 +0000230 test_complex_layers(reporter);
djsollen@google.com339e79f2013-09-04 17:16:00 +0000231 test_complex_clips(reporter);
djsollen@google.com5587ac02013-08-29 20:20:40 +0000232 test_draw_filters(reporter);
233 test_soft_clips(reporter);
234}