blob: 7cba71e7260879ad7677dd9ba92ab7e815ad9037 [file] [log] [blame]
djsollen@google.com5587ac02013-08-29 20:20:40 +00001
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 "SkBitmapDevice.h"
11#include "SkCanvas.h"
12#include "SkCanvasStateUtils.h"
13#include "SkDrawFilter.h"
commit-bot@chromium.org07f6cf32013-09-18 20:15:12 +000014#include "SkError.h"
djsollen@google.com5587ac02013-08-29 20:20:40 +000015#include "SkPaint.h"
16#include "SkRect.h"
17#include "SkRRect.h"
18
19static void test_complex_layers(skiatest::Reporter* reporter) {
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
28 const SkBitmap::Config configs[] = { SkBitmap::kRGB_565_Config,
29 SkBitmap::kARGB_8888_Config
30 };
31 const int configCount = sizeof(configs) / sizeof(SkBitmap::Config);
32
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) {
44 bitmaps[j].setConfig(configs[i], WIDTH, HEIGHT);
45 bitmaps[j].allocPixels();
46
47 SkCanvas canvas(bitmaps[j]);
48
49 canvas.drawColor(SK_ColorRED);
50
51 for (int k = 0; k < layerCombinations; ++k) {
52 // draw a rect within the layer's bounds and again outside the layer's bounds
53 canvas.saveLayerAlpha(&rect, layerAlpha[k], flags[k]);
54
55 SkCanvasState* state = NULL;
56 SkCanvas* tmpCanvas = NULL;
57 if (j) {
58 state = SkCanvasStateUtils::CaptureCanvasState(&canvas);
59 REPORTER_ASSERT(reporter, state);
60 tmpCanvas = SkCanvasStateUtils::CreateFromCanvasState(state);
61 REPORTER_ASSERT(reporter, tmpCanvas);
62 } else {
63 tmpCanvas = SkRef(&canvas);
64 }
65
66 SkPaint bluePaint;
67 bluePaint.setColor(SK_ColorBLUE);
68 bluePaint.setStyle(SkPaint::kFill_Style);
69
70 tmpCanvas->drawRect(rect, bluePaint);
71 tmpCanvas->translate(0, rect.height() + SPACER);
72 tmpCanvas->drawRect(rect, bluePaint);
73
74 tmpCanvas->unref();
75 SkCanvasStateUtils::ReleaseCanvasState(state);
76
77 canvas.restore();
78
79 // translate the canvas for the next iteration
80 canvas.translate(0, 2*(rect.height() + SPACER));
81 }
82 }
83
84 // now we memcmp the two bitmaps
85 REPORTER_ASSERT(reporter, bitmaps[0].getSize() == bitmaps[1].getSize());
86 REPORTER_ASSERT(reporter, !memcmp(bitmaps[0].getPixels(),
87 bitmaps[1].getPixels(),
88 bitmaps[0].getSize()));
89 }
90}
91
92////////////////////////////////////////////////////////////////////////////////
93
djsollen@google.com339e79f2013-09-04 17:16:00 +000094static void test_complex_clips(skiatest::Reporter* reporter) {
95
96 const int WIDTH = 400;
97 const int HEIGHT = 400;
djsollen@google.com1037c7b2013-09-04 18:20:30 +000098 const int SPACER = 10;
djsollen@google.com339e79f2013-09-04 17:16:00 +000099
djsollen@google.com1037c7b2013-09-04 18:20:30 +0000100 SkIRect layerRect = SkIRect::MakeWH(WIDTH, HEIGHT / 4);
djsollen@google.com339e79f2013-09-04 17:16:00 +0000101 layerRect.inset(2*SPACER, 2*SPACER);
102
djsollen@google.com1037c7b2013-09-04 18:20:30 +0000103 SkIRect clipRect = layerRect;
djsollen@google.com339e79f2013-09-04 17:16:00 +0000104 clipRect.fRight = clipRect.fLeft + (clipRect.width() / 2) - (2*SPACER);
105 clipRect.outset(SPACER, SPACER);
106
djsollen@google.com1037c7b2013-09-04 18:20:30 +0000107 SkIRect regionBounds = clipRect;
djsollen@google.com339e79f2013-09-04 17:16:00 +0000108 regionBounds.offset(clipRect.width() + (2*SPACER), 0);
109
110 SkIRect regionInterior = regionBounds;
111 regionInterior.inset(SPACER*3, SPACER*3);
112
113 SkRegion clipRegion;
114 clipRegion.setRect(regionBounds);
115 clipRegion.op(regionInterior, SkRegion::kDifference_Op);
116
117
118 const SkRegion::Op clipOps[] = { SkRegion::kIntersect_Op,
119 SkRegion::kIntersect_Op,
120 SkRegion::kReplace_Op,
121 };
122 const SkCanvas::SaveFlags flags[] = { SkCanvas::kARGB_NoClipLayer_SaveFlag,
123 SkCanvas::kARGB_ClipLayer_SaveFlag,
124 SkCanvas::kARGB_NoClipLayer_SaveFlag,
125 };
126 REPORTER_ASSERT(reporter, sizeof(clipOps) == sizeof(flags));
127 const int layerCombinations = sizeof(flags) / sizeof(SkCanvas::SaveFlags);
128
129 SkBitmap bitmaps[2];
130 for (int i = 0; i < 2; ++i) {
131 bitmaps[i].setConfig(SkBitmap::kARGB_8888_Config, WIDTH, HEIGHT);
132 bitmaps[i].allocPixels();
133
134 SkCanvas canvas(bitmaps[i]);
135
136 canvas.drawColor(SK_ColorRED);
137
138 SkRegion localRegion = clipRegion;
139
140 for (int j = 0; j < layerCombinations; ++j) {
djsollen@google.com1037c7b2013-09-04 18:20:30 +0000141 SkRect layerBounds = SkRect::Make(layerRect);
142 canvas.saveLayerAlpha(&layerBounds, 128, flags[j]);
djsollen@google.com339e79f2013-09-04 17:16:00 +0000143
144 SkCanvasState* state = NULL;
145 SkCanvas* tmpCanvas = NULL;
146 if (i) {
147 state = SkCanvasStateUtils::CaptureCanvasState(&canvas);
148 REPORTER_ASSERT(reporter, state);
149 tmpCanvas = SkCanvasStateUtils::CreateFromCanvasState(state);
150 REPORTER_ASSERT(reporter, tmpCanvas);
151 } else {
152 tmpCanvas = SkRef(&canvas);
153 }
154
155 tmpCanvas->save();
djsollen@google.com1037c7b2013-09-04 18:20:30 +0000156 tmpCanvas->clipRect(SkRect::Make(clipRect), clipOps[j]);
djsollen@google.com339e79f2013-09-04 17:16:00 +0000157 tmpCanvas->drawColor(SK_ColorBLUE);
158 tmpCanvas->restore();
159
160 tmpCanvas->clipRegion(localRegion, clipOps[j]);
161 tmpCanvas->drawColor(SK_ColorBLUE);
162
163 tmpCanvas->unref();
164 SkCanvasStateUtils::ReleaseCanvasState(state);
165
166 canvas.restore();
167
168 // translate the canvas and region for the next iteration
djsollen@google.com1037c7b2013-09-04 18:20:30 +0000169 canvas.translate(0, SkIntToScalar(2*(layerRect.height() + (SPACER))));
djsollen@google.com339e79f2013-09-04 17:16:00 +0000170 localRegion.translate(0, 2*(layerRect.height() + SPACER));
171 }
172 }
173
174 // now we memcmp the two bitmaps
175 REPORTER_ASSERT(reporter, bitmaps[0].getSize() == bitmaps[1].getSize());
176 REPORTER_ASSERT(reporter, !memcmp(bitmaps[0].getPixels(),
177 bitmaps[1].getPixels(),
178 bitmaps[0].getSize()));
179}
180
181////////////////////////////////////////////////////////////////////////////////
182
djsollen@google.com5587ac02013-08-29 20:20:40 +0000183class TestDrawFilter : public SkDrawFilter {
184public:
185 virtual bool filter(SkPaint*, Type) SK_OVERRIDE { return true; }
186};
187
188static void test_draw_filters(skiatest::Reporter* reporter) {
189 TestDrawFilter drawFilter;
190 SkBitmapDevice device(SkBitmap::kARGB_8888_Config, 10, 10);
191 SkCanvas canvas(&device);
192
193 canvas.setDrawFilter(&drawFilter);
194
195 SkCanvasState* state = SkCanvasStateUtils::CaptureCanvasState(&canvas);
196 REPORTER_ASSERT(reporter, state);
197 SkCanvas* tmpCanvas = SkCanvasStateUtils::CreateFromCanvasState(state);
198 REPORTER_ASSERT(reporter, tmpCanvas);
199
200 REPORTER_ASSERT(reporter, NULL != canvas.getDrawFilter());
201 REPORTER_ASSERT(reporter, NULL == tmpCanvas->getDrawFilter());
202
203 tmpCanvas->unref();
204 SkCanvasStateUtils::ReleaseCanvasState(state);
205}
206
207////////////////////////////////////////////////////////////////////////////////
208
commit-bot@chromium.org07f6cf32013-09-18 20:15:12 +0000209// we need this function to prevent SkError from printing to stdout
210static void error_callback(SkError code, void* ctx) {}
211
djsollen@google.com5587ac02013-08-29 20:20:40 +0000212static void test_soft_clips(skiatest::Reporter* reporter) {
213 SkBitmapDevice device(SkBitmap::kARGB_8888_Config, 10, 10);
214 SkCanvas canvas(&device);
215
216 SkRRect roundRect;
217 roundRect.setOval(SkRect::MakeWH(5, 5));
218
219 canvas.clipRRect(roundRect, SkRegion::kIntersect_Op, true);
220
commit-bot@chromium.org07f6cf32013-09-18 20:15:12 +0000221 SkSetErrorCallback(error_callback, NULL);
222
djsollen@google.com5587ac02013-08-29 20:20:40 +0000223 SkCanvasState* state = SkCanvasStateUtils::CaptureCanvasState(&canvas);
224 REPORTER_ASSERT(reporter, !state);
commit-bot@chromium.org07f6cf32013-09-18 20:15:12 +0000225
226 REPORTER_ASSERT(reporter, kInvalidOperation_SkError == SkGetLastError());
227 SkClearLastError();
djsollen@google.com5587ac02013-08-29 20:20:40 +0000228}
229
230////////////////////////////////////////////////////////////////////////////////
231
232static void test_canvas_state_utils(skiatest::Reporter* reporter) {
233 test_complex_layers(reporter);
djsollen@google.com339e79f2013-09-04 17:16:00 +0000234 test_complex_clips(reporter);
djsollen@google.com5587ac02013-08-29 20:20:40 +0000235 test_draw_filters(reporter);
236 test_soft_clips(reporter);
237}
238
239#include "TestClassDef.h"
240DEFINE_TESTCLASS("CanvasState", TestCanvasStateClass, test_canvas_state_utils)