|  | /* | 
|  | * Copyright 2015 Google Inc. | 
|  | * | 
|  | * Use of this source code is governed by a BSD-style license that can be | 
|  | * found in the LICENSE file. | 
|  | */ | 
|  |  | 
|  | #include "gm.h" | 
|  |  | 
|  | #include "SkImage.h" | 
|  | #include "SkSurface.h" | 
|  | #include "SkTArray.h" | 
|  |  | 
|  | class ImageScaleAlignedGM : public skiagm::GM { | 
|  | protected: | 
|  | void onOnceBeforeDraw() override { | 
|  | const SkVector vectors[] = { { 1, 0 }, { 0, 1 } }; | 
|  |  | 
|  | for (size_t i = 0; i < SK_ARRAY_COUNT(vectors); ++i) { | 
|  | auto& set = fSets.push_back(); | 
|  |  | 
|  | set.fVector = vectors[i]; | 
|  | set.fImages.push_back() = MakeImage(vectors[i], SK_ColorGREEN); | 
|  | set.fScales.push_back() = 1; | 
|  | set.fImages.push_back() = MakeImage(vectors[i], SK_ColorRED); | 
|  | set.fScales.push_back() = kStretchFactor; | 
|  | set.fImages.push_back() = MakeImage(vectors[i], SK_ColorGREEN); | 
|  | set.fScales.push_back() = 1; | 
|  | } | 
|  | } | 
|  |  | 
|  | SkString onShortName() override { | 
|  | return SkString("image_scale_aligned"); | 
|  | } | 
|  |  | 
|  | SkISize onISize() override { | 
|  | return SkISize::Make(580, 780); | 
|  | } | 
|  |  | 
|  | void onDraw(SkCanvas* canvas) override { | 
|  | struct { | 
|  | SkPoint offset; | 
|  | SkVector scale; | 
|  | } cfgs[] = { | 
|  | {{  10,    10    }, { 1, 1 }}, | 
|  | {{ 300.5f, 10    }, { 1, 1 }}, | 
|  | {{  10,    200.5f }, { 1, 1 }}, | 
|  | {{ 300.5f, 200.5f }, { 1, 1 }}, | 
|  |  | 
|  | {{  10.5f, 400.5f }, {  1,  1 }}, | 
|  | {{ 550.5f, 400.5f }, { -1,  1 }}, | 
|  | {{  10.5f, 750.5f }, {  1, -1 }}, | 
|  | {{ 550.5f, 750.5f }, { -1, -1 }}, | 
|  | }; | 
|  |  | 
|  | for (size_t i = 0; i < SK_ARRAY_COUNT(cfgs); ++i) { | 
|  | SkAutoCanvasRestore acr(canvas, true); | 
|  | canvas->translate(cfgs[i].offset.x(), cfgs[i].offset.y()); | 
|  | canvas->scale(cfgs[i].scale.x(), cfgs[i].scale.y()); | 
|  | drawSets(canvas); | 
|  | } | 
|  | } | 
|  |  | 
|  | private: | 
|  | struct ImageSet { | 
|  | SkSTArray<3, sk_sp<SkImage>, true>  fImages; | 
|  | SkSTArray<3, SkScalar>              fScales; | 
|  | SkVector                            fVector; | 
|  | }; | 
|  |  | 
|  | static sk_sp<SkImage> MakeImage(const SkVector& vec, SkColor color) { | 
|  | const SkPoint start = SkPoint::Make(vec.y() * kSegLen / 2, vec.x() * kSegLen / 2); | 
|  | const SkPoint end   = SkPoint::Make(start.x() + vec.x() * (kSegLen - 1), | 
|  | start.y() + vec.y() * (kSegLen - 1)); | 
|  |  | 
|  | auto surface(SkSurface::MakeRasterN32Premul(kSegLen, kSegLen)); | 
|  | surface->getCanvas()->clear(SK_ColorTRANSPARENT); | 
|  |  | 
|  | SkPaint paint; | 
|  | paint.setAntiAlias(true); | 
|  | const SkRect border = SkRect::MakeIWH(kSegLen, kSegLen).makeInset(.5f, .5f); | 
|  | paint.setColor(SK_ColorBLUE); | 
|  | paint.setStyle(SkPaint::kStroke_Style); | 
|  | surface->getCanvas()->drawRect(border, paint); | 
|  |  | 
|  | paint.setColor(SK_ColorBLACK); | 
|  | surface->getCanvas()->drawLine(start, end, paint); | 
|  |  | 
|  | paint.reset(); | 
|  | paint.setColor(color); | 
|  | const SkPoint pts[] = { start, end }; | 
|  | surface->getCanvas()->drawPoints(SkCanvas::kPoints_PointMode, 2, pts, paint); | 
|  |  | 
|  | return surface->makeImageSnapshot(); | 
|  | } | 
|  |  | 
|  | void drawSets(SkCanvas* canvas) const { | 
|  | SkAutoCanvasRestore acr(canvas, true); | 
|  |  | 
|  | const SkFilterQuality filters[] = { | 
|  | kNone_SkFilterQuality, | 
|  | kLow_SkFilterQuality, | 
|  | kMedium_SkFilterQuality, | 
|  | kHigh_SkFilterQuality | 
|  | }; | 
|  | const bool AAs[] = { false, true }; | 
|  |  | 
|  | SkPaint paint; | 
|  | for (int i = 0; i < fSets.count(); ++i) { | 
|  | auto& set = fSets[i]; | 
|  | SkPoint lastPt; | 
|  | for (size_t j = 0; j < SK_ARRAY_COUNT(AAs); ++j) { | 
|  | paint.setAntiAlias(AAs[j]); | 
|  | for (size_t k = 0; k < SK_ARRAY_COUNT(filters); ++k) { | 
|  | paint.setFilterQuality(filters[k]); | 
|  | lastPt = drawSet(canvas, set, paint); | 
|  | canvas->translate((kSegLen + 4) * set.fVector.y(), | 
|  | (kSegLen + 4) * set.fVector.x()); | 
|  | } | 
|  | } | 
|  | canvas->translate(lastPt.x() + kSegLen, | 
|  | - SkIntToScalar(kSegLen + 4) * SK_ARRAY_COUNT(filters) * SK_ARRAY_COUNT(AAs)); | 
|  | } | 
|  | } | 
|  |  | 
|  | SkPoint drawSet(SkCanvas* canvas, const ImageSet& set, const SkPaint& paint) const { | 
|  | SkASSERT(set.fImages.count() == set.fScales.count()); | 
|  |  | 
|  | SkPoint pt = SkPoint::Make(0, 0); | 
|  | for (int i = 0; i < set.fImages.count(); ++i) { | 
|  | auto& img = set.fImages[i]; | 
|  | const SkRect dst = | 
|  | SkRect::MakeXYWH(pt.x(), pt.y(), | 
|  | img->width() * (1 + (set.fScales[i] - 1) * set.fVector.x()), | 
|  | img->height() * (1 + (set.fScales[i] - 1) * set.fVector.y())); | 
|  |  | 
|  | canvas->drawImageRect(img.get(), dst, &paint); | 
|  | pt.offset(dst.width() * set.fVector.x(), dst.height() * set.fVector.y()); | 
|  | } | 
|  |  | 
|  | return pt; | 
|  | } | 
|  |  | 
|  | static constexpr unsigned  kSegLen = 15; | 
|  | static constexpr unsigned  kStretchFactor = 4; | 
|  | SkSTArray<2, ImageSet> fSets; | 
|  |  | 
|  | typedef GM INHERITED; | 
|  | }; | 
|  |  | 
|  | DEF_GM(return new ImageScaleAlignedGM();) |