8f77fb4d49f33b1c31eaacdd634b01cf30a1b6e5
[platform/upstream/libSkiaSharp.git] / tests / CanvasStateTest.cpp
1 /*
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
8 #include "CanvasStateHelpers.h"
9 #include "SkCanvas.h"
10 #include "SkCanvasStateUtils.h"
11 #include "SkCommandLineFlags.h"
12 #include "SkDrawFilter.h"
13 #include "SkError.h"
14 #include "SkPaint.h"
15 #include "SkRRect.h"
16 #include "SkRect.h"
17 #include "Test.h"
18
19 // dlopen and the library flag are only used for tests which require this flag.
20 #ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
21 #include <dlfcn.h>
22
23 DEFINE_string(library, "", "Support library to use for CanvasState test. If empty (the default), "
24                            "the test will be run without crossing a library boundary. Otherwise, "
25                            "it is expected to be a full path to a shared library file, which will"
26                            " be dynamically loaded. Functions from the library will be called to "
27                            "test SkCanvasState. Instructions for generating the library are in "
28                            "gyp/canvas_state_lib.gyp");
29
30
31 // This class calls dlopen on the library passed in to the command line flag library, and handles
32 // calling dlclose when it goes out of scope.
33 class OpenLibResult {
34 public:
35     // If the flag library was passed to this run of the test, attempt to open it using dlopen and
36     // report whether it succeeded.
37     OpenLibResult(skiatest::Reporter* reporter) {
38         if (FLAGS_library.count() == 1) {
39             fHandle = dlopen(FLAGS_library[0], RTLD_LAZY | RTLD_LOCAL);
40             REPORTER_ASSERT_MESSAGE(reporter, fHandle != NULL, "Failed to open library!");
41         } else {
42             fHandle = NULL;
43         }
44     }
45
46     // Automatically call dlclose when going out of scope.
47     ~OpenLibResult() {
48         if (fHandle) {
49             dlclose(fHandle);
50         }
51     }
52
53     // Pointer to the shared library object.
54     void* handle() { return fHandle; }
55
56 private:
57     void* fHandle;
58 };
59
60 DEF_TEST(CanvasState_test_complex_layers, reporter) {
61     const int WIDTH = 400;
62     const int HEIGHT = 400;
63     const int SPACER = 10;
64
65     SkRect rect = SkRect::MakeXYWH(SkIntToScalar(SPACER), SkIntToScalar(SPACER),
66                                    SkIntToScalar(WIDTH-(2*SPACER)),
67                                    SkIntToScalar((HEIGHT-(2*SPACER)) / 7));
68
69     const SkColorType colorTypes[] = {
70         kRGB_565_SkColorType, kN32_SkColorType
71     };
72
73     const int layerAlpha[] = { 255, 255, 0 };
74     const SkCanvas::SaveFlags flags[] = { SkCanvas::kARGB_NoClipLayer_SaveFlag,
75                                           SkCanvas::kARGB_ClipLayer_SaveFlag,
76                                           SkCanvas::kARGB_NoClipLayer_SaveFlag
77     };
78     REPORTER_ASSERT(reporter, sizeof(layerAlpha) == sizeof(flags));
79
80     bool (*drawFn)(SkCanvasState* state, float l, float t,
81                    float r, float b, int32_t s);
82
83     OpenLibResult openLibResult(reporter);
84     if (openLibResult.handle() != NULL) {
85         *(void**) (&drawFn) = dlsym(openLibResult.handle(),
86                                     "complex_layers_draw_from_canvas_state");
87     } else {
88         drawFn = complex_layers_draw_from_canvas_state;
89     }
90
91     REPORTER_ASSERT(reporter, drawFn);
92     if (!drawFn) {
93         return;
94     }
95
96     for (size_t i = 0; i < SK_ARRAY_COUNT(colorTypes); ++i) {
97         SkBitmap bitmaps[2];
98         for (int j = 0; j < 2; ++j) {
99             bitmaps[j].allocPixels(SkImageInfo::Make(WIDTH, HEIGHT,
100                                                      colorTypes[i],
101                                                      kPremul_SkAlphaType));
102
103             SkCanvas canvas(bitmaps[j]);
104
105             canvas.drawColor(SK_ColorRED);
106
107             for (size_t k = 0; k < SK_ARRAY_COUNT(layerAlpha); ++k) {
108                 // draw a rect within the layer's bounds and again outside the layer's bounds
109                 canvas.saveLayerAlpha(&rect, layerAlpha[k], flags[k]);
110
111                 if (j) {
112                     // Capture from the first Skia.
113                     SkCanvasState* state = SkCanvasStateUtils::CaptureCanvasState(&canvas);
114                     REPORTER_ASSERT(reporter, state);
115
116                     // And draw to it in the second Skia.
117                     bool success = complex_layers_draw_from_canvas_state(state,
118                             rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, SPACER);
119                     REPORTER_ASSERT(reporter, success);
120
121                     // And release it in the *first* Skia.
122                     SkCanvasStateUtils::ReleaseCanvasState(state);
123                 } else {
124                     // Draw in the first Skia.
125                     complex_layers_draw(&canvas, rect.fLeft, rect.fTop,
126                                         rect.fRight, rect.fBottom, SPACER);
127                 }
128
129                 canvas.restore();
130
131                 // translate the canvas for the next iteration
132                 canvas.translate(0, 2*(rect.height() + SPACER));
133             }
134         }
135
136         // now we memcmp the two bitmaps
137         REPORTER_ASSERT(reporter, bitmaps[0].getSize() == bitmaps[1].getSize());
138         REPORTER_ASSERT(reporter, !memcmp(bitmaps[0].getPixels(),
139                                           bitmaps[1].getPixels(),
140                                           bitmaps[0].getSize()));
141     }
142 }
143 #endif
144
145 ////////////////////////////////////////////////////////////////////////////////
146
147 #ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
148 DEF_TEST(CanvasState_test_complex_clips, reporter) {
149     const int WIDTH = 400;
150     const int HEIGHT = 400;
151     const int SPACER = 10;
152
153     SkIRect layerRect = SkIRect::MakeWH(WIDTH, HEIGHT / 4);
154     layerRect.inset(2*SPACER, 2*SPACER);
155
156     SkIRect clipRect = layerRect;
157     clipRect.fRight = clipRect.fLeft + (clipRect.width() / 2) - (2*SPACER);
158     clipRect.outset(SPACER, SPACER);
159
160     SkIRect regionBounds = clipRect;
161     regionBounds.offset(clipRect.width() + (2*SPACER), 0);
162
163     SkIRect regionInterior = regionBounds;
164     regionInterior.inset(SPACER*3, SPACER*3);
165
166     SkRegion clipRegion;
167     clipRegion.setRect(regionBounds);
168     clipRegion.op(regionInterior, SkRegion::kDifference_Op);
169
170
171     const SkRegion::Op clipOps[] = { SkRegion::kIntersect_Op,
172                                      SkRegion::kIntersect_Op,
173                                      SkRegion::kReplace_Op,
174     };
175     const SkCanvas::SaveFlags flags[] = { SkCanvas::kARGB_NoClipLayer_SaveFlag,
176                                           SkCanvas::kARGB_ClipLayer_SaveFlag,
177                                           SkCanvas::kARGB_NoClipLayer_SaveFlag,
178     };
179     REPORTER_ASSERT(reporter, sizeof(clipOps) == sizeof(flags));
180
181     bool (*drawFn)(SkCanvasState* state, int32_t l, int32_t t,
182                    int32_t r, int32_t b, int32_t clipOp,
183                    int32_t regionRects, int32_t* rectCoords);
184
185     OpenLibResult openLibResult(reporter);
186     if (openLibResult.handle() != NULL) {
187         *(void**) (&drawFn) = dlsym(openLibResult.handle(),
188                                     "complex_clips_draw_from_canvas_state");
189     } else {
190         drawFn = complex_clips_draw_from_canvas_state;
191     }
192
193     REPORTER_ASSERT(reporter, drawFn);
194     if (!drawFn) {
195         return;
196     }
197
198     SkBitmap bitmaps[2];
199     for (int i = 0; i < 2; ++i) {
200         bitmaps[i].allocN32Pixels(WIDTH, HEIGHT);
201
202         SkCanvas canvas(bitmaps[i]);
203
204         canvas.drawColor(SK_ColorRED);
205
206         SkRegion localRegion = clipRegion;
207
208         for (size_t j = 0; j < SK_ARRAY_COUNT(flags); ++j) {
209             SkRect layerBounds = SkRect::Make(layerRect);
210             canvas.saveLayerAlpha(&layerBounds, 128, flags[j]);
211
212             if (i) {
213                 SkCanvasState* state = SkCanvasStateUtils::CaptureCanvasState(&canvas);
214                 REPORTER_ASSERT(reporter, state);
215
216                 SkRegion::Iterator iter(localRegion);
217                 SkTDArray<int32_t> rectCoords;
218                 for (; !iter.done(); iter.next()) {
219                     const SkIRect& rect = iter.rect();
220                     *rectCoords.append() = rect.fLeft;
221                     *rectCoords.append() = rect.fTop;
222                     *rectCoords.append() = rect.fRight;
223                     *rectCoords.append() = rect.fBottom;
224                 }
225                 bool success = drawFn(state, clipRect.fLeft, clipRect.fTop,
226                                       clipRect.fRight, clipRect.fBottom, clipOps[j],
227                                       rectCoords.count() / 4, rectCoords.begin());
228                 REPORTER_ASSERT(reporter, success);
229
230                 SkCanvasStateUtils::ReleaseCanvasState(state);
231             } else {
232                 complex_clips_draw(&canvas, clipRect.fLeft, clipRect.fTop,
233                                    clipRect.fRight, clipRect.fBottom, clipOps[j],
234                                    localRegion);
235             }
236
237             canvas.restore();
238
239             // translate the canvas and region for the next iteration
240             canvas.translate(0, SkIntToScalar(2*(layerRect.height() + (SPACER))));
241             localRegion.translate(0, 2*(layerRect.height() + SPACER));
242         }
243     }
244
245     // now we memcmp the two bitmaps
246     REPORTER_ASSERT(reporter, bitmaps[0].getSize() == bitmaps[1].getSize());
247     REPORTER_ASSERT(reporter, !memcmp(bitmaps[0].getPixels(),
248                                       bitmaps[1].getPixels(),
249                                       bitmaps[0].getSize()));
250 }
251 #endif
252
253 ////////////////////////////////////////////////////////////////////////////////
254
255 class TestDrawFilter : public SkDrawFilter {
256 public:
257     bool filter(SkPaint*, Type) SK_OVERRIDE { return true; }
258 };
259
260 DEF_TEST(CanvasState_test_draw_filters, reporter) {
261     TestDrawFilter drawFilter;
262     SkBitmap bitmap;
263     bitmap.allocN32Pixels(10, 10);
264     SkCanvas canvas(bitmap);
265
266     canvas.setDrawFilter(&drawFilter);
267
268     SkCanvasState* state = SkCanvasStateUtils::CaptureCanvasState(&canvas);
269     REPORTER_ASSERT(reporter, state);
270     SkCanvas* tmpCanvas = SkCanvasStateUtils::CreateFromCanvasState(state);
271     REPORTER_ASSERT(reporter, tmpCanvas);
272
273     REPORTER_ASSERT(reporter, canvas.getDrawFilter());
274     REPORTER_ASSERT(reporter, NULL == tmpCanvas->getDrawFilter());
275
276     tmpCanvas->unref();
277     SkCanvasStateUtils::ReleaseCanvasState(state);
278 }
279
280 ////////////////////////////////////////////////////////////////////////////////
281
282 // we need this function to prevent SkError from printing to stdout
283 static void error_callback(SkError code, void* ctx) {}
284
285 DEF_TEST(CanvasState_test_soft_clips, reporter) {
286     SkBitmap bitmap;
287     bitmap.allocN32Pixels(10, 10);
288     SkCanvas canvas(bitmap);
289
290     SkRRect roundRect;
291     roundRect.setOval(SkRect::MakeWH(5, 5));
292
293     canvas.clipRRect(roundRect, SkRegion::kIntersect_Op, true);
294
295     SkSetErrorCallback(error_callback, NULL);
296
297     SkCanvasState* state = SkCanvasStateUtils::CaptureCanvasState(&canvas);
298     REPORTER_ASSERT(reporter, !state);
299
300     REPORTER_ASSERT(reporter, kInvalidOperation_SkError == SkGetLastError());
301     SkClearLastError();
302 }
303
304 #ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
305 DEF_TEST(CanvasState_test_saveLayer_clip, reporter) {
306     const int WIDTH = 100;
307     const int HEIGHT = 100;
308     const int LAYER_WIDTH = 50;
309     const int LAYER_HEIGHT = 50;
310
311     SkBitmap bitmap;
312     bitmap.allocN32Pixels(WIDTH, HEIGHT);
313     SkCanvas canvas(bitmap);
314
315     SkRect bounds = SkRect::MakeWH(SkIntToScalar(LAYER_WIDTH), SkIntToScalar(LAYER_HEIGHT));
316     canvas.clipRect(SkRect::MakeWH(SkIntToScalar(WIDTH), SkIntToScalar(HEIGHT)));
317
318     // Check that saveLayer without the kClipToLayer_SaveFlag leaves the
319     // clip stack unchanged.
320     canvas.saveLayer(&bounds, NULL, SkCanvas::kARGB_NoClipLayer_SaveFlag);
321     SkRect clipStackBounds;
322     SkClipStack::BoundsType boundsType;
323     canvas.getClipStack()->getBounds(&clipStackBounds, &boundsType);
324     REPORTER_ASSERT(reporter, clipStackBounds.width() == WIDTH);
325     REPORTER_ASSERT(reporter, clipStackBounds.height() == HEIGHT);
326     canvas.restore();
327
328     // Check that saveLayer with the kClipToLayer_SaveFlag sets the clip
329     // stack to the layer bounds.
330     canvas.saveLayer(&bounds, NULL, SkCanvas::kARGB_ClipLayer_SaveFlag);
331     canvas.getClipStack()->getBounds(&clipStackBounds, &boundsType);
332     REPORTER_ASSERT(reporter, clipStackBounds.width() == LAYER_WIDTH);
333     REPORTER_ASSERT(reporter, clipStackBounds.height() == LAYER_HEIGHT);
334
335     canvas.restore();
336 }
337 #endif