1 /* 2 * Copyright 2015 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/SkCanvas.h" 10 #include "include/core/SkColor.h" 11 #include "include/core/SkImage.h" 12 #include "include/core/SkPaint.h" 13 #include "include/core/SkPoint.h" 14 #include "include/core/SkRect.h" 15 #include "include/core/SkRefCnt.h" 16 #include "include/core/SkScalar.h" 17 #include "include/core/SkSize.h" 18 #include "include/core/SkString.h" 19 #include "include/core/SkSurface.h" 20 #include "include/core/SkTypes.h" 21 #include "include/private/SkTArray.h" 22 23 class ImageScaleAlignedGM : public skiagm::GM { 24 protected: onOnceBeforeDraw()25 void onOnceBeforeDraw() override { 26 const SkVector vectors[] = { { 1, 0 }, { 0, 1 } }; 27 28 for (size_t i = 0; i < SK_ARRAY_COUNT(vectors); ++i) { 29 auto& set = fSets.push_back(); 30 31 set.fVector = vectors[i]; 32 set.fImages.push_back() = MakeImage(vectors[i], SK_ColorGREEN); 33 set.fScales.push_back() = 1; 34 set.fImages.push_back() = MakeImage(vectors[i], SK_ColorRED); 35 set.fScales.push_back() = kStretchFactor; 36 set.fImages.push_back() = MakeImage(vectors[i], SK_ColorGREEN); 37 set.fScales.push_back() = 1; 38 } 39 } 40 onShortName()41 SkString onShortName() override { 42 return SkString("image_scale_aligned"); 43 } 44 onISize()45 SkISize onISize() override { 46 return SkISize::Make(580, 780); 47 } 48 onDraw(SkCanvas * canvas)49 void onDraw(SkCanvas* canvas) override { 50 struct { 51 SkPoint offset; 52 SkVector scale; 53 } cfgs[] = { 54 {{ 10, 10 }, { 1, 1 }}, 55 {{ 300.5f, 10 }, { 1, 1 }}, 56 {{ 10, 200.5f }, { 1, 1 }}, 57 {{ 300.5f, 200.5f }, { 1, 1 }}, 58 59 {{ 10.5f, 400.5f }, { 1, 1 }}, 60 {{ 550.5f, 400.5f }, { -1, 1 }}, 61 {{ 10.5f, 750.5f }, { 1, -1 }}, 62 {{ 550.5f, 750.5f }, { -1, -1 }}, 63 }; 64 65 for (size_t i = 0; i < SK_ARRAY_COUNT(cfgs); ++i) { 66 SkAutoCanvasRestore acr(canvas, true); 67 canvas->translate(cfgs[i].offset.x(), cfgs[i].offset.y()); 68 canvas->scale(cfgs[i].scale.x(), cfgs[i].scale.y()); 69 drawSets(canvas); 70 } 71 } 72 73 private: 74 struct ImageSet { 75 SkSTArray<3, sk_sp<SkImage>, true> fImages; 76 SkSTArray<3, SkScalar> fScales; 77 SkVector fVector; 78 }; 79 MakeImage(const SkVector & vec,SkColor color)80 static sk_sp<SkImage> MakeImage(const SkVector& vec, SkColor color) { 81 const SkPoint start = SkPoint::Make(vec.y() * kSegLen / 2, vec.x() * kSegLen / 2); 82 const SkPoint end = SkPoint::Make(start.x() + vec.x() * (kSegLen - 1), 83 start.y() + vec.y() * (kSegLen - 1)); 84 85 auto surface(SkSurface::MakeRasterN32Premul(kSegLen, kSegLen)); 86 surface->getCanvas()->clear(SK_ColorTRANSPARENT); 87 88 SkPaint paint; 89 paint.setAntiAlias(true); 90 const SkRect border = SkRect::MakeIWH(kSegLen, kSegLen).makeInset(.5f, .5f); 91 paint.setColor(SK_ColorBLUE); 92 paint.setStyle(SkPaint::kStroke_Style); 93 surface->getCanvas()->drawRect(border, paint); 94 95 paint.setColor(SK_ColorBLACK); 96 surface->getCanvas()->drawLine(start, end, paint); 97 98 paint.reset(); 99 paint.setColor(color); 100 const SkPoint pts[] = { start, end }; 101 surface->getCanvas()->drawPoints(SkCanvas::kPoints_PointMode, 2, pts, paint); 102 103 return surface->makeImageSnapshot(); 104 } 105 drawSets(SkCanvas * canvas) const106 void drawSets(SkCanvas* canvas) const { 107 SkAutoCanvasRestore acr(canvas, true); 108 109 const SkSamplingOptions samplings[] = { 110 SkSamplingOptions(SkFilterMode::kNearest), 111 SkSamplingOptions(SkFilterMode::kLinear), 112 SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear), 113 SkSamplingOptions(SkCubicResampler::Mitchell()), 114 }; 115 const bool AAs[] = { false, true }; 116 117 SkPaint paint; 118 for (int i = 0; i < fSets.count(); ++i) { 119 auto& set = fSets[i]; 120 SkPoint lastPt; 121 for (size_t j = 0; j < SK_ARRAY_COUNT(AAs); ++j) { 122 paint.setAntiAlias(AAs[j]); 123 for (size_t k = 0; k < SK_ARRAY_COUNT(samplings); ++k) { 124 lastPt = drawSet(canvas, set, samplings[k], paint); 125 canvas->translate((kSegLen + 4) * set.fVector.y(), 126 (kSegLen + 4) * set.fVector.x()); 127 } 128 } 129 canvas->translate(lastPt.x() + kSegLen, 130 - SkIntToScalar(kSegLen + 4) * SK_ARRAY_COUNT(samplings) * SK_ARRAY_COUNT(AAs)); 131 } 132 } 133 drawSet(SkCanvas * canvas,const ImageSet & set,const SkSamplingOptions & sampling,const SkPaint & paint) const134 SkPoint drawSet(SkCanvas* canvas, const ImageSet& set, const SkSamplingOptions& sampling, 135 const SkPaint& paint) const { 136 SkASSERT(set.fImages.count() == set.fScales.count()); 137 138 SkPoint pt = SkPoint::Make(0, 0); 139 for (int i = 0; i < set.fImages.count(); ++i) { 140 auto& img = set.fImages[i]; 141 const SkRect dst = 142 SkRect::MakeXYWH(pt.x(), pt.y(), 143 img->width() * (1 + (set.fScales[i] - 1) * set.fVector.x()), 144 img->height() * (1 + (set.fScales[i] - 1) * set.fVector.y())); 145 146 canvas->drawImageRect(img.get(), dst, sampling, &paint); 147 pt.offset(dst.width() * set.fVector.x(), dst.height() * set.fVector.y()); 148 } 149 150 return pt; 151 } 152 153 inline static constexpr unsigned kSegLen = 15; 154 inline static constexpr unsigned kStretchFactor = 4; 155 SkSTArray<2, ImageSet> fSets; 156 157 using INHERITED = GM; 158 }; 159 160 DEF_GM(return new ImageScaleAlignedGM();) 161