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 "gm/gm.h" 9 #include "include/core/SkBitmap.h" 10 #include "include/core/SkCanvas.h" 11 #include "include/core/SkColor.h" 12 #include "include/core/SkImage.h" 13 #include "include/core/SkImageFilter.h" 14 #include "include/core/SkMatrix.h" 15 #include "include/core/SkPaint.h" 16 #include "include/core/SkRect.h" 17 #include "include/core/SkRefCnt.h" 18 #include "include/core/SkScalar.h" 19 #include "include/core/SkSize.h" 20 #include "include/core/SkString.h" 21 #include "include/effects/SkImageFilters.h" 22 #include "src/core/SkImageFilter_Base.h" 23 #include "tools/ToolUtils.h" 24 25 #include <utility> 26 27 #define WIDTH 600 28 #define HEIGHT 100 29 #define MARGIN 12 30 31 class OffsetImageFilterGM : public skiagm::GM { 32 public: OffsetImageFilterGM()33 OffsetImageFilterGM() { 34 this->setBGColor(0xFF000000); 35 } 36 37 protected: onShortName()38 SkString onShortName() override { 39 return SkString("offsetimagefilter"); 40 } 41 onISize()42 SkISize onISize() override { 43 return SkISize::Make(WIDTH, HEIGHT); 44 } 45 onOnceBeforeDraw()46 void onOnceBeforeDraw() override { 47 fBitmap = ToolUtils::create_string_image(80, 80, 0xD000D000, 15, 65, 96, "e"); 48 49 fCheckerboard = ToolUtils::create_checkerboard_image(80, 80, 0xFFA0A0A0, 0xFF404040, 8); 50 } 51 onDraw(SkCanvas * canvas)52 void onDraw(SkCanvas* canvas) override { 53 canvas->clear(SK_ColorBLACK); 54 SkPaint paint; 55 56 for (int i = 0; i < 4; i++) { 57 sk_sp<SkImage> image = (i & 0x01) ? fCheckerboard : fBitmap; 58 SkIRect cropRect = SkIRect::MakeXYWH(i * 12, 59 i * 8, 60 image->width() - i * 8, 61 image->height() - i * 12); 62 sk_sp<SkImageFilter> tileInput(SkImageFilters::Image(image)); 63 SkScalar dx = SkIntToScalar(i*5); 64 SkScalar dy = SkIntToScalar(i*10); 65 paint.setImageFilter(SkImageFilters::Offset(dx, dy, std::move(tileInput), &cropRect)); 66 DrawClippedImage(canvas, image.get(), paint, 1, cropRect); 67 canvas->translate(SkIntToScalar(image->width() + MARGIN), 0); 68 } 69 70 SkIRect cropRect = SkIRect::MakeXYWH(0, 0, 100, 100); 71 paint.setImageFilter(SkImageFilters::Offset(-5, -10, nullptr, &cropRect)); 72 DrawClippedImage(canvas, fBitmap.get(), paint, 2, cropRect); 73 } 74 private: DrawClippedImage(SkCanvas * canvas,const SkImage * image,const SkPaint & paint,SkScalar scale,const SkIRect & cropRect)75 static void DrawClippedImage(SkCanvas* canvas, const SkImage* image, const SkPaint& paint, 76 SkScalar scale, const SkIRect& cropRect) { 77 SkRect clipRect = SkRect::MakeIWH(image->width(), image->height()); 78 79 canvas->save(); 80 canvas->clipRect(clipRect); 81 canvas->scale(scale, scale); 82 canvas->drawImage(image, 0, 0, SkSamplingOptions(), &paint); 83 canvas->restore(); 84 85 // Draw a boundary rect around the intersection of the clip rect and crop rect. 86 SkRect cropRectFloat; 87 SkMatrix::Scale(scale, scale).mapRect(&cropRectFloat, SkRect::Make(cropRect)); 88 if (clipRect.intersect(cropRectFloat)) { 89 SkPaint strokePaint; 90 strokePaint.setStyle(SkPaint::kStroke_Style); 91 strokePaint.setStrokeWidth(2); 92 strokePaint.setColor(SK_ColorRED); 93 canvas->drawRect(clipRect, strokePaint); 94 } 95 } 96 97 sk_sp<SkImage> fBitmap, fCheckerboard; 98 99 using INHERITED = skiagm::GM; 100 }; 101 DEF_GM( return new OffsetImageFilterGM; ) 102 103 ////////////////////////////////////////////////////////////////////////////// 104 105 class SimpleOffsetImageFilterGM : public skiagm::GM { 106 public: SimpleOffsetImageFilterGM()107 SimpleOffsetImageFilterGM() {} 108 109 protected: onShortName()110 SkString onShortName() override { 111 return SkString("simple-offsetimagefilter"); 112 } 113 onISize()114 SkISize onISize() override { return SkISize::Make(640, 200); } 115 doDraw(SkCanvas * canvas,const SkRect & r,sk_sp<SkImageFilter> imgf,const SkIRect * cropR=nullptr,const SkRect * clipR=nullptr)116 void doDraw(SkCanvas* canvas, const SkRect& r, sk_sp<SkImageFilter> imgf, 117 const SkIRect* cropR = nullptr, const SkRect* clipR = nullptr) { 118 SkPaint p; 119 120 if (clipR) { 121 p.setColor(0xFF00FF00); 122 p.setStyle(SkPaint::kStroke_Style); 123 canvas->drawRect(clipR->makeInset(SK_ScalarHalf, SK_ScalarHalf), p); 124 p.setStyle(SkPaint::kFill_Style); 125 } 126 127 // Visualize the crop rect for debugging 128 if (imgf && cropR) { 129 p.setColor(0x66FF00FF); 130 p.setStyle(SkPaint::kStroke_Style); 131 132 SkRect cr = SkRect::Make(*cropR).makeInset(SK_ScalarHalf, SK_ScalarHalf); 133 canvas->drawRect(cr, p); 134 p.setStyle(SkPaint::kFill_Style); 135 } 136 137 p.setColor(0x660000FF); 138 canvas->drawRect(r, p); 139 140 if (clipR) { 141 canvas->save(); 142 canvas->clipRect(*clipR); 143 } 144 if (imgf) { 145 p.setImageFilter(std::move(imgf)); 146 } 147 p.setColor(0x66FF0000); 148 canvas->drawRect(r, p); 149 150 if (clipR) { 151 canvas->restore(); 152 } 153 } 154 onDraw(SkCanvas * canvas)155 void onDraw(SkCanvas* canvas) override { 156 SkIRect cr0 = SkIRect::MakeWH(40, 40); 157 SkIRect cr1 = SkIRect::MakeWH(20, 20); 158 SkIRect cr2 = SkIRect::MakeXYWH(40, 0, 40, 40); 159 const SkRect r = SkRect::Make(cr0); 160 const SkRect r2 = SkRect::Make(cr2); 161 162 canvas->translate(40, 40); 163 164 canvas->save(); 165 this->doDraw(canvas, r, nullptr); 166 167 canvas->translate(100, 0); 168 this->doDraw(canvas, r, SkImageFilters::Offset(20, 20, nullptr)); 169 170 canvas->translate(100, 0); 171 this->doDraw(canvas, r, SkImageFilters::Offset(20, 20, nullptr, &cr0), &cr0); 172 173 canvas->translate(100, 0); 174 this->doDraw(canvas, r, SkImageFilters::Offset(20, 20, nullptr), /* cropR */ nullptr, &r); 175 176 canvas->translate(100, 0); 177 this->doDraw(canvas, r, SkImageFilters::Offset(20, 20, nullptr, &cr1), &cr1); 178 179 SkRect clipR = SkRect::MakeXYWH(40, 40, 40, 40); 180 canvas->translate(100, 0); 181 this->doDraw(canvas, r, SkImageFilters::Offset(20, 20, nullptr), /* cropR */ nullptr, &clipR); 182 canvas->restore(); 183 184 // 2nd row 185 canvas->translate(0, 80); 186 187 /* 188 * combos of clip and crop rects that align with src and dst 189 */ 190 191 // crop==clip==src 192 this->doDraw(canvas, r, SkImageFilters::Offset(40, 0, nullptr, &cr0), &cr0, &r); 193 194 // crop==src, clip==dst 195 canvas->translate(100, 0); 196 this->doDraw(canvas, r, SkImageFilters::Offset(40, 0, nullptr, &cr0), &cr0, &r2); 197 198 // crop==dst, clip==src 199 canvas->translate(100, 0); 200 this->doDraw(canvas, r, SkImageFilters::Offset(40, 0, nullptr, &cr2), &cr2, &r); 201 202 // crop==clip==dst 203 canvas->translate(100, 0); 204 this->doDraw(canvas, r, SkImageFilters::Offset(40, 0, nullptr, &cr2), &cr2, &r2); 205 } 206 207 private: 208 using INHERITED = skiagm::GM; 209 }; 210 DEF_GM( return new SimpleOffsetImageFilterGM; ) 211