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 "SkBitmapDevice.h" 9 #include "SkCanvas.h" 10 #include "SkCanvasStateUtils.h" 11 #include "SkDrawFilter.h" 12 #include "SkError.h" 13 #include "SkPaint.h" 14 #include "SkRRect.h" 15 #include "SkRect.h" 16 #include "Test.h" 17 18 static void test_complex_layers(skiatest::Reporter* reporter) { 19 #ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG 20 const int WIDTH = 400; 21 const int HEIGHT = 400; 22 const int SPACER = 10; 23 24 SkRect rect = SkRect::MakeXYWH(SkIntToScalar(SPACER), SkIntToScalar(SPACER), 25 SkIntToScalar(WIDTH-(2*SPACER)), 26 SkIntToScalar((HEIGHT-(2*SPACER)) / 7)); 27 28 const SkColorType colorTypes[] = { 29 kRGB_565_SkColorType, kN32_SkColorType 30 }; 31 const int configCount = sizeof(colorTypes) / 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].allocPixels(SkImageInfo::Make(WIDTH, HEIGHT, 45 colorTypes[i], 46 kPremul_SkAlphaType)); 47 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 } 91 #endif 92 } 93 94 //////////////////////////////////////////////////////////////////////////////// 95 96 static void test_complex_clips(skiatest::Reporter* reporter) { 97 #ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG 98 const int WIDTH = 400; 99 const int HEIGHT = 400; 100 const int SPACER = 10; 101 102 SkIRect layerRect = SkIRect::MakeWH(WIDTH, HEIGHT / 4); 103 layerRect.inset(2*SPACER, 2*SPACER); 104 105 SkIRect clipRect = layerRect; 106 clipRect.fRight = clipRect.fLeft + (clipRect.width() / 2) - (2*SPACER); 107 clipRect.outset(SPACER, SPACER); 108 109 SkIRect regionBounds = clipRect; 110 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) { 133 bitmaps[i].allocN32Pixels(WIDTH, HEIGHT); 134 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) { 142 SkRect layerBounds = SkRect::Make(layerRect); 143 canvas.saveLayerAlpha(&layerBounds, 128, flags[j]); 144 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(); 157 tmpCanvas->clipRect(SkRect::Make(clipRect), clipOps[j]); 158 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 170 canvas.translate(0, SkIntToScalar(2*(layerRect.height() + (SPACER)))); 171 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())); 180 #endif 181 } 182 183 //////////////////////////////////////////////////////////////////////////////// 184 185 class TestDrawFilter : public SkDrawFilter { 186 public: 187 virtual bool filter(SkPaint*, Type) SK_OVERRIDE { return true; } 188 }; 189 190 static void test_draw_filters(skiatest::Reporter* reporter) { 191 TestDrawFilter drawFilter; 192 SkBitmap bitmap; 193 bitmap.allocN32Pixels(10, 10); 194 SkCanvas canvas(bitmap); 195 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 212 // we need this function to prevent SkError from printing to stdout 213 static void error_callback(SkError code, void* ctx) {} 214 215 static void test_soft_clips(skiatest::Reporter* reporter) { 216 SkBitmap bitmap; 217 bitmap.allocN32Pixels(10, 10); 218 SkCanvas canvas(bitmap); 219 220 SkRRect roundRect; 221 roundRect.setOval(SkRect::MakeWH(5, 5)); 222 223 canvas.clipRRect(roundRect, SkRegion::kIntersect_Op, true); 224 225 SkSetErrorCallback(error_callback, NULL); 226 227 SkCanvasState* state = SkCanvasStateUtils::CaptureCanvasState(&canvas); 228 REPORTER_ASSERT(reporter, !state); 229 230 REPORTER_ASSERT(reporter, kInvalidOperation_SkError == SkGetLastError()); 231 SkClearLastError(); 232 } 233 234 static void test_saveLayer_clip(skiatest::Reporter* reporter) { 235 #ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG 236 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(); 266 #endif 267 } 268 269 DEF_TEST(CanvasState, reporter) { 270 test_complex_layers(reporter); 271 test_complex_clips(reporter); 272 test_draw_filters(reporter); 273 test_soft_clips(reporter); 274 test_saveLayer_clip(reporter); 275 } 276