1/* 2 * Copyright 2011 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 "sk_tool_utils.h" 10#include "SkBlurMask.h" 11#include "SkBlurMaskFilter.h" 12#include "SkColorPriv.h" 13#include "SkGradientShader.h" 14#include "SkImage.h" 15#include "SkImage_Base.h" 16#include "SkMathPriv.h" 17#include "SkShader.h" 18#include "SkSurface.h" 19 20 21static SkBitmap make_chessbm(int w, int h) { 22 SkBitmap bm; 23 bm.allocN32Pixels(w, h); 24 25 for (int y = 0; y < bm.height(); y++) { 26 uint32_t* p = bm.getAddr32(0, y); 27 for (int x = 0; x < bm.width(); x++) { 28 p[x] = ((x + y) & 1) ? SK_ColorWHITE : SK_ColorBLACK; 29 } 30 } 31 bm.unlockPixels(); 32 return bm; 33} 34 35// Creates a bitmap and a matching image. 36static sk_sp<SkImage> makebm(SkCanvas* origCanvas, SkBitmap* resultBM, int w, int h) { 37 SkImageInfo info = SkImageInfo::MakeN32Premul(w, h); 38 39 auto surface(origCanvas->makeSurface(info)); 40 if (nullptr == surface) { 41 // picture canvas will return null, so fall-back to raster 42 surface = SkSurface::MakeRaster(info); 43 } 44 45 SkCanvas* canvas = surface->getCanvas(); 46 47 canvas->clear(SK_ColorTRANSPARENT); 48 49 SkScalar wScalar = SkIntToScalar(w); 50 SkScalar hScalar = SkIntToScalar(h); 51 52 SkPoint pt = { wScalar / 2, hScalar / 2 }; 53 54 SkScalar radius = 4 * SkMaxScalar(wScalar, hScalar); 55 56 SkColor colors[] = { SK_ColorRED, SK_ColorYELLOW, 57 SK_ColorGREEN, SK_ColorMAGENTA, 58 SK_ColorBLUE, SK_ColorCYAN, 59 SK_ColorRED}; 60 61 SkScalar pos[] = {0, 62 SK_Scalar1 / 6, 63 2 * SK_Scalar1 / 6, 64 3 * SK_Scalar1 / 6, 65 4 * SK_Scalar1 / 6, 66 5 * SK_Scalar1 / 6, 67 SK_Scalar1}; 68 69 SkPaint paint; 70 SkRect rect = SkRect::MakeWH(wScalar, hScalar); 71 SkMatrix mat = SkMatrix::I(); 72 for (int i = 0; i < 4; ++i) { 73 paint.setShader(SkGradientShader::MakeRadial( 74 pt, radius, 75 colors, pos, 76 SK_ARRAY_COUNT(colors), 77 SkShader::kRepeat_TileMode, 78 0, &mat)); 79 canvas->drawRect(rect, paint); 80 rect.inset(wScalar / 8, hScalar / 8); 81 mat.postScale(SK_Scalar1 / 4, SK_Scalar1 / 4); 82 } 83 84 auto image = surface->makeImageSnapshot(); 85 86 SkBitmap tempBM; 87 88 image->asLegacyBitmap(&tempBM, SkImage::kRO_LegacyBitmapMode); 89 90 // Let backends know we won't change this, so they don't have to deep copy it defensively. 91 tempBM.setImmutable(); 92 *resultBM = tempBM; 93 94 return image; 95} 96 97static void bitmapproc(SkCanvas* canvas, SkImage*, const SkBitmap& bm, const SkIRect& srcR, 98 const SkRect& dstR, const SkPaint* paint) { 99 canvas->drawBitmapRect(bm, srcR, dstR, paint); 100} 101 102static void bitmapsubsetproc(SkCanvas* canvas, SkImage*, const SkBitmap& bm, const SkIRect& srcR, 103 const SkRect& dstR, const SkPaint* paint) { 104 if (!bm.bounds().contains(srcR)) { 105 bitmapproc(canvas, nullptr, bm, srcR, dstR, paint); 106 return; 107 } 108 109 SkBitmap subset; 110 if (bm.extractSubset(&subset, srcR)) { 111 canvas->drawBitmapRect(subset, dstR, paint); 112 } 113} 114 115static void imageproc(SkCanvas* canvas, SkImage* image, const SkBitmap&, const SkIRect& srcR, 116 const SkRect& dstR, const SkPaint* paint) { 117 canvas->drawImageRect(image, srcR, dstR, paint); 118} 119 120static void imagesubsetproc(SkCanvas* canvas, SkImage* image, const SkBitmap& bm, 121 const SkIRect& srcR, const SkRect& dstR, const SkPaint* paint) { 122 if (!image->bounds().contains(srcR)) { 123 imageproc(canvas, image, bm, srcR, dstR, paint); 124 return; 125 } 126 127 if (sk_sp<SkImage> subset = image->makeSubset(srcR)) { 128 canvas->drawImageRect(subset, dstR, paint); 129 } 130} 131 132typedef void DrawRectRectProc(SkCanvas*, SkImage*, const SkBitmap&, const SkIRect&, const SkRect&, 133 const SkPaint*); 134 135constexpr int gSize = 1024; 136constexpr int gBmpSize = 2048; 137 138class DrawBitmapRectGM : public skiagm::GM { 139public: 140 DrawBitmapRectGM(DrawRectRectProc proc, const char suffix[]) : fProc(proc) { 141 fName.set("drawbitmaprect"); 142 if (suffix) { 143 fName.append(suffix); 144 } 145 } 146 147 DrawRectRectProc* fProc; 148 SkBitmap fLargeBitmap; 149 sk_sp<SkImage> fImage; 150 SkString fName; 151 152protected: 153 SkString onShortName() override { return fName; } 154 155 SkISize onISize() override { return SkISize::Make(gSize, gSize); } 156 157 void setupImage(SkCanvas* canvas) { 158 fImage = makebm(canvas, &fLargeBitmap, gBmpSize, gBmpSize); 159 } 160 161 void onDraw(SkCanvas* canvas) override { 162 if (!fImage) { 163 this->setupImage(canvas); 164 } 165 166 SkRect dstRect = { 0, 0, SkIntToScalar(64), SkIntToScalar(64)}; 167 const int kMaxSrcRectSize = 1 << (SkNextLog2(gBmpSize) + 2); 168 169 const int kPadX = 30; 170 const int kPadY = 40; 171 SkPaint paint; 172 paint.setAlpha(0x20); 173 canvas->drawImageRect(fImage, SkRect::MakeIWH(gSize, gSize), &paint); 174 canvas->translate(SK_Scalar1 * kPadX / 2, 175 SK_Scalar1 * kPadY / 2); 176 SkPaint blackPaint; 177 SkScalar titleHeight = SK_Scalar1 * 24; 178 blackPaint.setColor(SK_ColorBLACK); 179 blackPaint.setTextSize(titleHeight); 180 blackPaint.setAntiAlias(true); 181 sk_tool_utils::set_portable_typeface(&blackPaint); 182 SkString title; 183 title.printf("Bitmap size: %d x %d", gBmpSize, gBmpSize); 184 canvas->drawText(title.c_str(), title.size(), 0, 185 titleHeight, blackPaint); 186 187 canvas->translate(0, SK_Scalar1 * kPadY / 2 + titleHeight); 188 int rowCount = 0; 189 canvas->save(); 190 for (int w = 1; w <= kMaxSrcRectSize; w *= 4) { 191 for (int h = 1; h <= kMaxSrcRectSize; h *= 4) { 192 193 SkIRect srcRect = SkIRect::MakeXYWH((gBmpSize - w) / 2, (gBmpSize - h) / 2, w, h); 194 fProc(canvas, fImage.get(), fLargeBitmap, srcRect, dstRect, nullptr); 195 196 SkString label; 197 label.appendf("%d x %d", w, h); 198 blackPaint.setAntiAlias(true); 199 blackPaint.setStyle(SkPaint::kFill_Style); 200 blackPaint.setTextSize(SK_Scalar1 * 10); 201 SkScalar baseline = dstRect.height() + 202 blackPaint.getTextSize() + SK_Scalar1 * 3; 203 canvas->drawText(label.c_str(), label.size(), 204 0, baseline, 205 blackPaint); 206 blackPaint.setStyle(SkPaint::kStroke_Style); 207 blackPaint.setStrokeWidth(SK_Scalar1); 208 blackPaint.setAntiAlias(false); 209 canvas->drawRect(dstRect, blackPaint); 210 211 canvas->translate(dstRect.width() + SK_Scalar1 * kPadX, 0); 212 ++rowCount; 213 if ((dstRect.width() + kPadX) * rowCount > gSize) { 214 canvas->restore(); 215 canvas->translate(0, dstRect.height() + SK_Scalar1 * kPadY); 216 canvas->save(); 217 rowCount = 0; 218 } 219 } 220 } 221 222 { 223 // test the following code path: 224 // SkGpuDevice::drawPath() -> SkGpuDevice::drawWithMaskFilter() 225 SkIRect srcRect; 226 SkPaint paint; 227 SkBitmap bm; 228 229 bm = make_chessbm(5, 5); 230 paint.setFilterQuality(kLow_SkFilterQuality); 231 232 srcRect.setXYWH(1, 1, 3, 3); 233 paint.setMaskFilter(SkBlurMaskFilter::Make( 234 kNormal_SkBlurStyle, 235 SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(5)), 236 SkBlurMaskFilter::kHighQuality_BlurFlag)); 237 238 sk_sp<SkImage> image(SkImage::MakeFromBitmap(bm)); 239 fProc(canvas, image.get(), bm, srcRect, dstRect, &paint); 240 } 241 } 242 243private: 244 typedef skiagm::GM INHERITED; 245}; 246 247DEF_GM( return new DrawBitmapRectGM(bitmapproc , nullptr); ) 248DEF_GM( return new DrawBitmapRectGM(bitmapsubsetproc, "-subset"); ) 249DEF_GM( return new DrawBitmapRectGM(imageproc , "-imagerect"); ) 250DEF_GM( return new DrawBitmapRectGM(imagesubsetproc , "-imagerect-subset"); ) 251