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