blob: b6e86c4126c5c303924e91d9b1833ef288a91d45 [file] [log] [blame]
Florin Malitaca795352016-11-16 14:45:34 -05001/*
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.h"
9#include "SkImage.h"
10#include "SkImageGenerator.h"
11#include "SkMutex.h"
12#include "SkSurface.h"
13#include "SkTArray.h"
14
15namespace {
16
Florin Malita58cda8f2016-11-23 10:49:20 -050017void release_proc(void*, void* releaseCtx) {
18 reinterpret_cast<SkImage*>(releaseCtx)->unref();
19}
20
Florin Malitaca795352016-11-16 14:45:34 -050021class ExternalGenerator : public SkImageGenerator {
22public:
23 ExternalGenerator(const SkISize size)
24 : INHERITED(SkImageInfo::MakeN32Premul(size.width(), size.height())) {
25
26 int level = 0;
27 for (int size = kMaxSize; size; size /= 2) {
28 sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(size, size);
29 DrawRings(surface->getCanvas(), 0xff008000, level++);
30 fMips.emplace_back(surface->makeImageSnapshot());
31 }
32 }
33
34 virtual ~ExternalGenerator() {}
35
36protected:
37 bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
38 SkPMColor[], int*) override {
39 sk_sp<SkSurface> s = SkSurface::MakeRasterDirect(info, pixels, rowBytes);
40 s->getCanvas()->clear(SK_ColorTRANSPARENT);
41 DrawRings(s->getCanvas(), SK_ColorRED);
42 return true;
43 }
44
45 bool onAccessScaledImage(const SkRect& src, const SkMatrix& matrix, SkFilterQuality,
46 ScaledImageRec* rec) override {
47 // Not strictly needed for this immutable class.
48 SkAutoExclusive lock(fMutex);
49
50 SkSize scaleSize;
51 if (!matrix.decomposeScale(&scaleSize, nullptr)) {
52 return false;
53 }
54 scaleSize.set(scaleSize.width() * this->getInfo().width() / kMaxSize,
55 scaleSize.height() * this->getInfo().height() / kMaxSize);
56
57 const SkScalar scale = SkTMin(scaleSize.width(), scaleSize.height());
58 const int lvl = SkScalarFloorToInt(-SkScalarLog2(scale));
59
Florin Malita58cda8f2016-11-23 10:49:20 -050060 const sk_sp<SkImage>& img = fMips[SkTPin(lvl, 0, fMips.count())];
61 SkAssertResult(img->peekPixels(&rec->fPixmap));
Florin Malitaca795352016-11-16 14:45:34 -050062
63 const SkRect origBounds = SkRect::Make(this->getInfo().bounds());
Florin Malita58cda8f2016-11-23 10:49:20 -050064 const SkRect newBounds = SkRect::Make(img->bounds());
Florin Malitaca795352016-11-16 14:45:34 -050065
66 SkMatrix srcMap = SkMatrix::MakeScale(newBounds.width() / origBounds.width(),
67 newBounds.height() / origBounds.height());
68 srcMap.preTranslate(src.x(), src.y());
69 srcMap.mapRect(&rec->fSrcRect, SkRect::MakeWH(src.width(), src.height()));
70
71 rec->fQuality = kLow_SkFilterQuality;
72
Florin Malita58cda8f2016-11-23 10:49:20 -050073 rec->fReleaseProc = release_proc;
74 rec->fReleaseCtx = SkRef(img.get());
75
Florin Malitaca795352016-11-16 14:45:34 -050076 return true;
77 }
78
79private:
80 static void DrawRings(SkCanvas* c, SkColor color, int lvl = 0) {
81 static constexpr SkScalar kStep = 0.2f;
82
83 SkRect rect = SkRect::MakeWH(1, 1);
84
85 SkPaint p;
86 p.setStyle(SkPaint::kStroke_Style);
87 p.setStrokeWidth(0.02f);
88 p.setAntiAlias(true);
89 p.setColor(color);
90
91 c->concat(SkMatrix::MakeRectToRect(SkRect::MakeWH(1, 1),
92 SkRect::MakeIWH(c->imageInfo().width(),
93 c->imageInfo().height()),
94 SkMatrix::kFill_ScaleToFit));
95 while (!rect.isEmpty()) {
96 c->drawRect(rect, p);
97 rect.inset(kStep, kStep);
98 }
99
100 static constexpr SkScalar kTxtSize = 0.2f;
101 SkASSERT(lvl >= 0 && lvl <= 9);
102 const char label = '0' + lvl;
103 p.setTextSize(kTxtSize);
104 p.setLinearText(true);
105 p.setStyle(SkPaint::kFill_Style);
106 SkRect labelBounds;
107 p.measureText(&label, 1, &labelBounds);
108
109 c->drawText(&label, 1, 0.5f - labelBounds.width() / 2, 0.5f + labelBounds.height() / 2, p);
110 }
111
112 SkMutex fMutex;
113
114 static constexpr int kMaxSize = 512;
115 SkTArray<sk_sp<SkImage>> fMips;
116
117 typedef SkImageGenerator INHERITED;
118};
119
120} // anonymous ns
121
122class ImageGenExternalGM : public skiagm::GM {
123public:
124 explicit ImageGenExternalGM(bool useShader) : fUseShader(useShader) {}
125
126protected:
127 SkString onShortName() override {
128 return SkStringPrintf("ImageGeneratorExternal%s", fUseShader ? "_shader" : "_rect");
129 }
130
131 SkISize onISize() override {
132 return SkISize::Make(800, 800);
133 }
134
135 void onOnceBeforeDraw() override {
136 fImage = SkImage::MakeFromGenerator(new ExternalGenerator(SkISize::Make(kGeneratorSize,
137 kGeneratorSize)));
138 }
139
140 void onDraw(SkCanvas* canvas) override {
141 static const SkRect gSubsets[] = {
142 SkRect::MakeLTRB(0 , 0 , 1 , 1 ),
143 SkRect::MakeLTRB(0 , 0 , 0.5f , 0.5f ),
144 SkRect::MakeLTRB(0.5f , 0 , 1 , 0.5f ),
145 SkRect::MakeLTRB(0.5f , 0.5f , 1 , 1 ),
146 SkRect::MakeLTRB(0 , 0.5f , 0.5f , 1 ),
147 SkRect::MakeLTRB(0.25f, 0.25f, 0.75f, 0.75f),
148 };
149
150 SkPaint p;
151 p.setFilterQuality(kLow_SkFilterQuality);
152
153 for (int i = 1; i <= 4; ++i) {
154 const SkRect dst = SkRect::MakeIWH(kGeneratorSize / i, kGeneratorSize / i);
155
156 canvas->save();
157 for (size_t j = 0; j < SK_ARRAY_COUNT(gSubsets); ++j) {
158 SkRect subset = gSubsets[j];
159 subset.set(kGeneratorSize * subset.left(),
160 kGeneratorSize * subset.top(),
161 kGeneratorSize * subset.right(),
162 kGeneratorSize * subset.bottom());
163 this->drawSubset(canvas, subset, dst, p);
164 canvas->translate(kGeneratorSize * 1.1f, 0);
165 }
166 canvas->restore();
167 canvas->translate(0, dst.height() * 1.2f);
168 }
169 }
170
171private:
172 void drawSubset(SkCanvas* canvas, const SkRect& src, const SkRect& dst,
173 const SkPaint& paint) const {
174 if (fUseShader) {
175 SkPaint p(paint);
176 SkMatrix localMatrix = SkMatrix::MakeRectToRect(src, dst, SkMatrix::kFill_ScaleToFit);
177 p.setShader(fImage->makeShader(SkShader::kClamp_TileMode,
178 SkShader::kClamp_TileMode,
179 &localMatrix));
180 canvas->drawRect(dst, p);
181 } else {
182 canvas->drawImageRect(fImage, src, dst, &paint);
183 }
184 }
185
186 static constexpr int kGeneratorSize = 200;
187 sk_sp<SkImage> fImage;
188 bool fUseShader;
189
190 typedef skiagm::GM INHERITED;
191};
192
193DEF_GM( return new ImageGenExternalGM(false); )
194DEF_GM( return new ImageGenExternalGM(true); )