1 /* 2 * Copyright 2016 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 "gm.h" 9 #include "SkSurface.h" 10 #include "sk_tool_utils.h" 11 12 static sk_sp<SkSurface> make_surface(SkCanvas* root, int N, int padLeft, int padTop, 13 int padRight, int padBottom) { 14 SkImageInfo info = SkImageInfo::MakeN32Premul(N + padLeft + padRight, N + padTop + padBottom); 15 return sk_tool_utils::makeSurface(root, info); 16 } 17 18 static sk_sp<SkImage> make_image(SkCanvas* root, int* xDivs, int* yDivs, int padLeft, int padTop, 19 int padRight, int padBottom) { 20 const int kCap = 28; 21 const int kMid = 8; 22 const int kSize = 2*kCap + 3*kMid; 23 24 auto surface(make_surface(root, kSize, padLeft, padTop, padRight, padBottom)); 25 SkCanvas* canvas = surface->getCanvas(); 26 canvas->translate((float) padLeft, (float) padTop); 27 28 SkRect r = SkRect::MakeWH(SkIntToScalar(kSize), SkIntToScalar(kSize)); 29 const SkScalar strokeWidth = SkIntToScalar(6); 30 const SkScalar radius = SkIntToScalar(kCap) - strokeWidth/2; 31 32 xDivs[0] = kCap + padLeft; 33 yDivs[0] = kCap + padTop; 34 xDivs[1] = kCap + kMid + padLeft; 35 yDivs[1] = kCap + kMid + padTop; 36 xDivs[2] = kCap + 2 * kMid + padLeft; 37 yDivs[2] = kCap + 2 * kMid + padTop; 38 xDivs[3] = kCap + 3 * kMid + padLeft; 39 yDivs[3] = kCap + 3 * kMid + padTop; 40 41 SkPaint paint; 42 paint.setAntiAlias(true); 43 44 paint.setColor(0xFFFFFF00); 45 canvas->drawRoundRect(r, radius, radius, paint); 46 47 r.setXYWH(SkIntToScalar(kCap), 0, SkIntToScalar(kMid), SkIntToScalar(kSize)); 48 paint.setColor(0x8800FF00); 49 canvas->drawRect(r, paint); 50 r.setXYWH(SkIntToScalar(kCap + kMid), 0, SkIntToScalar(kMid), SkIntToScalar(kSize)); 51 paint.setColor(0x880000FF); 52 canvas->drawRect(r, paint); 53 r.setXYWH(SkIntToScalar(kCap + 2*kMid), 0, SkIntToScalar(kMid), SkIntToScalar(kSize)); 54 paint.setColor(0x88FF00FF); 55 canvas->drawRect(r, paint); 56 57 r.setXYWH(0, SkIntToScalar(kCap), SkIntToScalar(kSize), SkIntToScalar(kMid)); 58 paint.setColor(0x8800FF00); 59 canvas->drawRect(r, paint); 60 r.setXYWH(0, SkIntToScalar(kCap + kMid), SkIntToScalar(kSize), SkIntToScalar(kMid)); 61 paint.setColor(0x880000FF); 62 canvas->drawRect(r, paint); 63 r.setXYWH(0, SkIntToScalar(kCap + 2*kMid), SkIntToScalar(kSize), SkIntToScalar(kMid)); 64 paint.setColor(0x88FF00FF); 65 canvas->drawRect(r, paint); 66 67 return surface->makeImageSnapshot(); 68 } 69 70 static void image_to_bitmap(const SkImage* image, SkBitmap* bm) { 71 SkImageInfo info = SkImageInfo::MakeN32Premul(image->width(), image->height()); 72 bm->allocPixels(info); 73 image->readPixels(info, bm->getPixels(), bm->rowBytes(), 0, 0); 74 } 75 76 /** 77 * This is similar to NinePatchStretchGM, but it also tests "ninepatch" images with more 78 * than nine patches. 79 */ 80 class LatticeGM : public skiagm::GM { 81 public: 82 LatticeGM() {} 83 84 protected: 85 SkString onShortName() override { 86 return SkString("lattice"); 87 } 88 89 SkISize onISize() override { 90 return SkISize::Make(800, 800); 91 } 92 93 void onDrawHelper(SkCanvas* canvas, int padLeft, int padTop, int padRight, int padBottom) { 94 canvas->save(); 95 96 int xDivs[5]; 97 int yDivs[5]; 98 xDivs[0] = padLeft; 99 yDivs[0] = padTop; 100 101 SkBitmap bitmap; 102 sk_sp<SkImage> image = make_image(canvas, xDivs + 1, yDivs + 1, padLeft, padTop, 103 padRight, padBottom); 104 image_to_bitmap(image.get(), &bitmap); 105 106 const SkSize size[] = { 107 { 50, 50, }, // shrink in both axes 108 { 50, 200, }, // shrink in X 109 { 200, 50, }, // shrink in Y 110 { 200, 200, }, 111 }; 112 113 canvas->drawImage(image, 10, 10, nullptr); 114 115 SkScalar x = SkIntToScalar(100); 116 SkScalar y = SkIntToScalar(100); 117 118 SkCanvas::Lattice lattice; 119 lattice.fXCount = 4; 120 lattice.fXDivs = xDivs + 1; 121 lattice.fYCount = 4; 122 lattice.fYDivs = yDivs + 1; 123 lattice.fRectTypes = nullptr; 124 lattice.fColors = nullptr; 125 126 SkIRect bounds = SkIRect::MakeLTRB(padLeft, padTop, 127 image->width() - padRight, image->height() - padBottom); 128 lattice.fBounds = (bounds == SkIRect::MakeWH(image->width(), image->height())) ? 129 nullptr : &bounds; 130 131 for (int iy = 0; iy < 2; ++iy) { 132 for (int ix = 0; ix < 2; ++ix) { 133 int i = ix * 2 + iy; 134 SkRect r = SkRect::MakeXYWH(x + ix * 60, y + iy * 60, 135 size[i].width(), size[i].height()); 136 canvas->drawBitmapLattice(bitmap, lattice, r); 137 } 138 } 139 140 // Provide hints about 3 solid color rects. These colors match 141 // what was already in the bitmap. 142 int fixedColorX[3] = {2, 4, 1}; 143 int fixedColorY[3] = {1, 1, 2}; 144 SkColor fixedColor[3] = {SK_ColorBLACK, SK_ColorBLACK, SK_ColorBLACK}; 145 const SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, 146 kUnpremul_SkAlphaType); 147 for (int rectNum = 0; rectNum < 3; rectNum++) { 148 int srcX = xDivs[fixedColorX[rectNum]-1]; 149 int srcY = yDivs[fixedColorY[rectNum]-1]; 150 image->readPixels(info, &fixedColor[rectNum], 4, srcX, srcY); 151 } 152 153 // Include the degenerate first div. While normally the first patch is "scalable", 154 // this will mean that the first non-degenerate patch is "fixed". 155 lattice.fXCount = 5; 156 lattice.fXDivs = xDivs; 157 lattice.fYCount = 5; 158 lattice.fYDivs = yDivs; 159 160 // Let's skip a few rects. 161 SkCanvas::Lattice::RectType flags[36]; 162 sk_bzero(flags, 36 * sizeof(SkCanvas::Lattice::RectType)); 163 flags[4] = SkCanvas::Lattice::kTransparent; 164 flags[9] = SkCanvas::Lattice::kTransparent; 165 flags[12] = SkCanvas::Lattice::kTransparent; 166 flags[19] = SkCanvas::Lattice::kTransparent; 167 for (int rectNum = 0; rectNum < 3; rectNum++) { 168 flags[fixedColorY[rectNum]*6 + fixedColorX[rectNum]] 169 = SkCanvas::Lattice::kFixedColor; 170 } 171 lattice.fRectTypes = flags; 172 173 SkColor colors[36]; 174 sk_bzero(colors, 36 * sizeof(SkColor)); 175 for (int rectNum = 0; rectNum < 3; rectNum++) { 176 colors[fixedColorY[rectNum]*6 + fixedColorX[rectNum]] 177 = fixedColor[rectNum]; 178 } 179 180 lattice.fColors = colors; 181 182 canvas->translate(400, 0); 183 for (int iy = 0; iy < 2; ++iy) { 184 for (int ix = 0; ix < 2; ++ix) { 185 int i = ix * 2 + iy; 186 SkRect r = SkRect::MakeXYWH(x + ix * 60, y + iy * 60, 187 size[i].width(), size[i].height()); 188 canvas->drawImageLattice(image.get(), lattice, r); 189 } 190 } 191 192 canvas->restore(); 193 } 194 195 void onDraw(SkCanvas* canvas) override { 196 this->onDrawHelper(canvas, 0, 0, 0, 0); 197 canvas->translate(0.0f, 400.0f); 198 this->onDrawHelper(canvas, 3, 7, 4, 11); 199 } 200 201 private: 202 typedef skiagm::GM INHERITED; 203 }; 204 DEF_GM( return new LatticeGM; ) 205 206 207 // LatticeGM2 exercises code paths that draw fixed color and 1x1 rectangles. 208 class LatticeGM2 : public skiagm::GM { 209 public: 210 LatticeGM2() {} 211 SkString onShortName() override { 212 return SkString("lattice2"); 213 } 214 215 SkISize onISize() override { 216 return SkISize::Make(800, 800); 217 } 218 219 sk_sp<SkImage> makeImage(SkCanvas* root, int padLeft, int padTop, int padRight, int padBottom) { 220 const int kSize = 80; 221 auto surface(make_surface(root, kSize, padLeft, padTop, padRight, padBottom)); 222 SkCanvas* canvas = surface->getCanvas(); 223 SkPaint paint; 224 paint.setAntiAlias(false); 225 SkRect r; 226 227 //first line 228 r.setXYWH(0, 0, 4, 1); //4x1 green rect 229 paint.setColor(0xFF00FF00); 230 canvas->drawRect(r, paint); 231 232 r.setXYWH(4, 0, 1, 1); //1x1 blue pixel -> draws as rectangle 233 paint.setColor(0xFF0000FF); 234 canvas->drawRect(r, paint); 235 236 r.setXYWH(5, 0, kSize-5, 1); //the rest of the line is red 237 paint.setColor(0xFFFF0000); 238 canvas->drawRect(r, paint); 239 240 241 //second line -> draws as fixed color rectangles 242 r.setXYWH(0, 1, 4, 1); //4x1 red rect 243 paint.setColor(0xFFFF0000); 244 canvas->drawRect(r, paint); 245 246 r.setXYWH(4, 1, 1, 1); //1x1 blue pixel with alpha 247 paint.setColor(0x880000FF); 248 canvas->drawRect(r, paint); 249 250 r.setXYWH(5, 1, kSize-5, 1); //the rest of the line is green 251 paint.setColor(0xFF00FF00); 252 canvas->drawRect(r, paint); 253 254 255 //third line - does not draw, because it is transparent 256 r.setXYWH(0, 2, 4, kSize-2); //4x78 green rect 257 paint.setColor(0xFF00FF00); 258 canvas->drawRect(r, paint); 259 260 r.setXYWH(4, 2, 1, kSize-2); //1x78 red pixel with alpha 261 paint.setColor(0x88FF0000); 262 canvas->drawRect(r, paint); 263 264 r.setXYWH(5, 2, kSize-5, kSize-2); //the rest of the image is blue 265 paint.setColor(0xFF0000FF); 266 canvas->drawRect(r, paint); 267 268 return surface->makeImageSnapshot(); 269 } 270 271 void onDrawHelper(SkCanvas* canvas, int padLeft, int padTop, int padRight, int padBottom, 272 SkPaint& paint) { 273 int xDivs[2] = {4, 5}; 274 int yDivs[2] = {1, 2}; 275 276 canvas->save(); 277 278 sk_sp<SkImage> image = makeImage(canvas, padLeft, padTop, padRight, padBottom); 279 280 canvas->drawImage(image, 10, 10, nullptr); 281 282 SkCanvas::Lattice lattice; 283 lattice.fXCount = 2; 284 lattice.fXDivs = xDivs; 285 lattice.fYCount = 2; 286 lattice.fYDivs = yDivs; 287 lattice.fBounds = nullptr; 288 289 SkCanvas::Lattice::RectType flags[9]; 290 sk_bzero(flags, 9 * sizeof(SkCanvas::Lattice::RectType)); 291 flags[3] = SkCanvas::Lattice::kFixedColor; 292 flags[4] = SkCanvas::Lattice::kFixedColor; 293 flags[5] = SkCanvas::Lattice::kFixedColor; 294 295 flags[6] = SkCanvas::Lattice::kTransparent; 296 flags[7] = SkCanvas::Lattice::kTransparent; 297 flags[8] = SkCanvas::Lattice::kTransparent; 298 lattice.fRectTypes = flags; 299 300 SkColor colors[9] = {SK_ColorBLACK, SK_ColorBLACK, SK_ColorBLACK, 301 0xFFFF0000, 0x880000FF, 0xFF00FF00, 302 SK_ColorBLACK, SK_ColorBLACK, SK_ColorBLACK}; 303 lattice.fColors = colors; 304 paint.setColor(0xFFFFFFFF); 305 canvas->drawImageLattice(image.get(), lattice, 306 SkRect::MakeXYWH(100, 100, 200, 200), &paint); 307 308 //draw the same content with alpha 309 canvas->translate(400, 0); 310 paint.setColor(0x80000FFF); 311 canvas->drawImageLattice(image.get(), lattice, 312 SkRect::MakeXYWH(100, 100, 200, 200), &paint); 313 314 canvas->restore(); 315 } 316 317 void onDraw(SkCanvas* canvas) override { 318 319 //draw a rectangle in the background with transparent pixels 320 SkPaint paint; 321 paint.setColor(0x7F123456); 322 paint.setBlendMode(SkBlendMode::kSrc); 323 canvas->drawRect( SkRect::MakeXYWH(300, 0, 300, 800), paint); 324 325 //draw image lattice with kSrcOver blending 326 paint.setBlendMode(SkBlendMode::kSrcOver); 327 this->onDrawHelper(canvas, 0, 0, 0, 0, paint); 328 329 //draw image lattice with kSrcATop blending 330 canvas->translate(0.0f, 400.0f); 331 paint.setBlendMode(SkBlendMode::kSrcATop); 332 this->onDrawHelper(canvas, 0, 0, 0, 0, paint); 333 } 334 335 private: 336 typedef skiagm::GM INHERITED; 337 }; 338 DEF_GM( return new LatticeGM2; ) 339 340 // Code paths that incorporate the paint color when drawing the lattice (using an alpha image) 341 DEF_SIMPLE_GM_BG(lattice_alpha, canvas, 120, 120, SK_ColorWHITE) { 342 auto surface = sk_tool_utils::makeSurface(canvas, SkImageInfo::MakeA8(100, 100)); 343 surface->getCanvas()->clear(0); 344 surface->getCanvas()->drawCircle(50, 50, 50, SkPaint()); 345 auto image = surface->makeImageSnapshot(); 346 347 int divs[] = { 20, 40, 60, 80 }; 348 349 SkCanvas::Lattice lattice; 350 lattice.fXCount = 4; 351 lattice.fXDivs = divs; 352 lattice.fYCount = 4; 353 lattice.fYDivs = divs; 354 lattice.fRectTypes = nullptr; 355 lattice.fColors = nullptr; 356 lattice.fBounds = nullptr; 357 358 SkPaint paint; 359 paint.setColor(SK_ColorMAGENTA); 360 canvas->drawImageLattice(image.get(), lattice, SkRect::MakeWH(120, 120), &paint); 361 } 362