Plumb dst color space in many places, rather than "mode"
[platform/upstream/libSkiaSharp.git] / src / image / SkImageShader.cpp
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 "SkBitmapController.h"
9 #include "SkBitmapProcShader.h"
10 #include "SkBitmapProvider.h"
11 #include "SkColorShader.h"
12 #include "SkColorTable.h"
13 #include "SkEmptyShader.h"
14 #include "SkFixedAlloc.h"
15 #include "SkImage_Base.h"
16 #include "SkImageShader.h"
17 #include "SkImageShaderContext.h"
18 #include "SkPM4fPriv.h"
19 #include "SkReadBuffer.h"
20 #include "SkWriteBuffer.h"
21
22 SkImageShader::SkImageShader(sk_sp<SkImage> img, TileMode tmx, TileMode tmy, const SkMatrix* matrix)
23     : INHERITED(matrix)
24     , fImage(std::move(img))
25     , fTileModeX(tmx)
26     , fTileModeY(tmy)
27 {}
28
29 sk_sp<SkFlattenable> SkImageShader::CreateProc(SkReadBuffer& buffer) {
30     const TileMode tx = (TileMode)buffer.readUInt();
31     const TileMode ty = (TileMode)buffer.readUInt();
32     SkMatrix matrix;
33     buffer.readMatrix(&matrix);
34     sk_sp<SkImage> img = buffer.readImage();
35     if (!img) {
36         return nullptr;
37     }
38     return SkImageShader::Make(std::move(img), tx, ty, &matrix);
39 }
40
41 void SkImageShader::flatten(SkWriteBuffer& buffer) const {
42     buffer.writeUInt(fTileModeX);
43     buffer.writeUInt(fTileModeY);
44     buffer.writeMatrix(this->getLocalMatrix());
45     buffer.writeImage(fImage.get());
46 }
47
48 bool SkImageShader::isOpaque() const {
49     return fImage->isOpaque();
50 }
51
52 size_t SkImageShader::onContextSize(const ContextRec& rec) const {
53     return SkBitmapProcLegacyShader::ContextSize(rec, as_IB(fImage)->onImageInfo());
54 }
55
56 SkShader::Context* SkImageShader::onCreateContext(const ContextRec& rec, void* storage) const {
57     return SkBitmapProcLegacyShader::MakeContext(*this, fTileModeX, fTileModeY,
58                                                  SkBitmapProvider(fImage.get(), rec.fDstColorSpace),
59                                                  rec, storage);
60 }
61
62 SkImage* SkImageShader::onIsAImage(SkMatrix* texM, TileMode xy[]) const {
63     if (texM) {
64         *texM = this->getLocalMatrix();
65     }
66     if (xy) {
67         xy[0] = (TileMode)fTileModeX;
68         xy[1] = (TileMode)fTileModeY;
69     }
70     return const_cast<SkImage*>(fImage.get());
71 }
72
73 #ifdef SK_SUPPORT_LEGACY_SHADER_ISABITMAP
74 bool SkImageShader::onIsABitmap(SkBitmap* texture, SkMatrix* texM, TileMode xy[]) const {
75     const SkBitmap* bm = as_IB(fImage)->onPeekBitmap();
76     if (!bm) {
77         return false;
78     }
79
80     if (texture) {
81         *texture = *bm;
82     }
83     if (texM) {
84         *texM = this->getLocalMatrix();
85     }
86     if (xy) {
87         xy[0] = (TileMode)fTileModeX;
88         xy[1] = (TileMode)fTileModeY;
89     }
90     return true;
91 }
92 #endif
93
94 static bool bitmap_is_too_big(int w, int h) {
95     // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it
96     // communicates between its matrix-proc and its sampler-proc. Until we can
97     // widen that, we have to reject bitmaps that are larger.
98     //
99     static const int kMaxSize = 65535;
100
101     return w > kMaxSize || h > kMaxSize;
102 }
103
104 // returns true and set color if the bitmap can be drawn as a single color
105 // (for efficiency)
106 static bool can_use_color_shader(const SkImage* image, SkColor* color) {
107 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
108     // HWUI does not support color shaders (see b/22390304)
109     return false;
110 #endif
111
112     if (1 != image->width() || 1 != image->height()) {
113         return false;
114     }
115
116     SkPixmap pmap;
117     if (!image->peekPixels(&pmap)) {
118         return false;
119     }
120
121     switch (pmap.colorType()) {
122         case kN32_SkColorType:
123             *color = SkUnPreMultiply::PMColorToColor(*pmap.addr32(0, 0));
124             return true;
125         case kRGB_565_SkColorType:
126             *color = SkPixel16ToColor(*pmap.addr16(0, 0));
127             return true;
128         case kIndex_8_SkColorType: {
129             const SkColorTable& ctable = *pmap.ctable();
130             *color = SkUnPreMultiply::PMColorToColor(ctable[*pmap.addr8(0, 0)]);
131             return true;
132         }
133         default: // just skip the other configs for now
134             break;
135     }
136     return false;
137 }
138
139 sk_sp<SkShader> SkImageShader::Make(sk_sp<SkImage> image, TileMode tx, TileMode ty,
140                                     const SkMatrix* localMatrix,
141                                     SkTBlitterAllocator* allocator) {
142     SkShader* shader;
143     SkColor color;
144     if (!image || bitmap_is_too_big(image->width(), image->height())) {
145         if (nullptr == allocator) {
146             shader = new SkEmptyShader;
147         } else {
148             shader = allocator->createT<SkEmptyShader>();
149         }
150     } else if (can_use_color_shader(image.get(), &color)) {
151         if (nullptr == allocator) {
152             shader = new SkColorShader(color);
153         } else {
154             shader = allocator->createT<SkColorShader>(color);
155         }
156     } else {
157         if (nullptr == allocator) {
158             shader = new SkImageShader(image, tx, ty, localMatrix);
159         } else {
160             shader = allocator->createT<SkImageShader>(image, tx, ty, localMatrix);
161         }
162     }
163     return sk_sp<SkShader>(shader);
164 }
165
166 #ifndef SK_IGNORE_TO_STRING
167 void SkImageShader::toString(SkString* str) const {
168     const char* gTileModeName[SkShader::kTileModeCount] = {
169         "clamp", "repeat", "mirror"
170     };
171
172     str->appendf("ImageShader: ((%s %s) ", gTileModeName[fTileModeX], gTileModeName[fTileModeY]);
173     fImage->toString(str);
174     this->INHERITED::toString(str);
175     str->append(")");
176 }
177 #endif
178
179 ///////////////////////////////////////////////////////////////////////////////////////////////////
180
181 #if SK_SUPPORT_GPU
182
183 #include "SkGr.h"
184 #include "SkGrPriv.h"
185 #include "effects/GrSimpleTextureEffect.h"
186 #include "effects/GrBicubicEffect.h"
187 #include "effects/GrSimpleTextureEffect.h"
188
189 sk_sp<GrFragmentProcessor> SkImageShader::asFragmentProcessor(const AsFPArgs& args) const {
190     SkMatrix matrix;
191     matrix.setIDiv(fImage->width(), fImage->height());
192
193     SkMatrix lmInverse;
194     if (!this->getLocalMatrix().invert(&lmInverse)) {
195         return nullptr;
196     }
197     if (args.fLocalMatrix) {
198         SkMatrix inv;
199         if (!args.fLocalMatrix->invert(&inv)) {
200             return nullptr;
201         }
202         lmInverse.postConcat(inv);
203     }
204     matrix.preConcat(lmInverse);
205
206     SkShader::TileMode tm[] = { fTileModeX, fTileModeY };
207
208     // Must set wrap and filter on the sampler before requesting a texture. In two places below
209     // we check the matrix scale factors to determine how to interpret the filter quality setting.
210     // This completely ignores the complexity of the drawVertices case where explicit local coords
211     // are provided by the caller.
212     bool doBicubic;
213     GrSamplerParams::FilterMode textureFilterMode =
214     GrSkFilterQualityToGrFilterMode(args.fFilterQuality, *args.fViewMatrix, this->getLocalMatrix(),
215                                     &doBicubic);
216     GrSamplerParams params(tm, textureFilterMode);
217     sk_sp<SkColorSpace> texColorSpace;
218     sk_sp<GrTexture> texture(as_IB(fImage)->asTextureRef(args.fContext, params, args.fDstColorSpace,
219                                                          &texColorSpace));
220     if (!texture) {
221         return nullptr;
222     }
223
224     sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(texColorSpace.get(),
225                                                                        args.fDstColorSpace);
226     sk_sp<GrFragmentProcessor> inner;
227     if (doBicubic) {
228         inner = GrBicubicEffect::Make(texture.get(), std::move(colorSpaceXform), matrix, tm);
229     } else {
230         inner = GrSimpleTextureEffect::Make(texture.get(), std::move(colorSpaceXform),
231                                             matrix, params);
232     }
233
234     if (GrPixelConfigIsAlphaOnly(texture->config())) {
235         return inner;
236     }
237     return sk_sp<GrFragmentProcessor>(GrFragmentProcessor::MulOutputByInputAlpha(std::move(inner)));
238 }
239
240 #endif
241
242 ///////////////////////////////////////////////////////////////////////////////////////////////////
243 #include "SkImagePriv.h"
244
245 sk_sp<SkShader> SkMakeBitmapShader(const SkBitmap& src, SkShader::TileMode tmx,
246                                    SkShader::TileMode tmy, const SkMatrix* localMatrix,
247                                    SkCopyPixelsMode cpm, SkTBlitterAllocator* allocator) {
248     // Until we learn otherwise, it seems that any caller that is passing an allocator must be
249     // assuming that the returned shader will have a stack-frame lifetime, so we assert that
250     // they are also asking for kNever_SkCopyPixelsMode. If that proves otherwise, we can remove
251     // or modify this assert.
252     SkASSERT(!allocator || (kNever_SkCopyPixelsMode == cpm));
253
254     return SkImageShader::Make(SkMakeImageFromRasterBitmap(src, cpm, allocator),
255                                tmx, tmy, localMatrix, allocator);
256 }
257
258 static sk_sp<SkFlattenable> SkBitmapProcShader_CreateProc(SkReadBuffer& buffer) {
259     SkMatrix lm;
260     buffer.readMatrix(&lm);
261     sk_sp<SkImage> image = buffer.readBitmapAsImage();
262     SkShader::TileMode mx = (SkShader::TileMode)buffer.readUInt();
263     SkShader::TileMode my = (SkShader::TileMode)buffer.readUInt();
264     return image ? image->makeShader(mx, my, &lm) : nullptr;
265 }
266
267 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkShader)
268 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkImageShader)
269 SkFlattenable::Register("SkBitmapProcShader", SkBitmapProcShader_CreateProc, kSkShader_Type);
270 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
271
272
273 bool SkImageShader::onAppendStages(SkRasterPipeline* p, SkColorSpace* dst, SkFallbackAlloc* scratch,
274                                    const SkMatrix& ctm, const SkPaint& paint) const {
275     auto matrix = SkMatrix::Concat(ctm, this->getLocalMatrix());
276     if (!matrix.invert(&matrix)) {
277         return false;
278     }
279     auto quality = paint.getFilterQuality();
280
281     SkBitmapProvider provider(fImage.get(), dst);
282     SkDefaultBitmapController controller;
283     std::unique_ptr<SkBitmapController::State> state {
284         controller.requestBitmap(provider, matrix, quality)
285     };
286     if (!state) {
287         return false;
288     }
289
290     const SkPixmap& pm = state->pixmap();
291     matrix  = state->invMatrix();
292     quality = state->quality();
293     auto info = pm.info();
294
295     // When the matrix is just an integer translate, bilerp == nearest neighbor.
296     if (matrix.getType() <= SkMatrix::kTranslate_Mask &&
297         matrix.getTranslateX() == (int)matrix.getTranslateX() &&
298         matrix.getTranslateY() == (int)matrix.getTranslateY()) {
299         quality = kNone_SkFilterQuality;
300     }
301
302     // See skia:4649 and the GM image_scale_aligned.
303     if (quality == kNone_SkFilterQuality) {
304         if (matrix.getScaleX() >= 0) {
305             matrix.setTranslateX(nextafterf(matrix.getTranslateX(),
306                                             floorf(matrix.getTranslateX())));
307         }
308         if (matrix.getScaleY() >= 0) {
309             matrix.setTranslateY(nextafterf(matrix.getTranslateY(),
310                                             floorf(matrix.getTranslateY())));
311         }
312     }
313
314     auto ctx = scratch->make<SkImageShaderContext>();
315     ctx->state   = std::move(state);  // Extend lifetime to match the pipeline's.
316     ctx->pixels  = pm.addr();
317     ctx->ctable  = pm.ctable();
318     ctx->color4f = SkColor4f_from_SkColor(paint.getColor(), dst);
319     ctx->stride  = pm.rowBytesAsPixels();
320     ctx->width   = pm.width();
321     ctx->height  = pm.height();
322     if (matrix.asAffine(ctx->matrix)) {
323         p->append(SkRasterPipeline::matrix_2x3, ctx->matrix);
324     } else {
325         matrix.get9(ctx->matrix);
326         p->append(SkRasterPipeline::matrix_perspective, ctx->matrix);
327     }
328
329     auto append_tiling_and_gather = [&] {
330         switch (fTileModeX) {
331             case kClamp_TileMode:  p->append(SkRasterPipeline::clamp_x,  &ctx->width); break;
332             case kMirror_TileMode: p->append(SkRasterPipeline::mirror_x, &ctx->width); break;
333             case kRepeat_TileMode: p->append(SkRasterPipeline::repeat_x, &ctx->width); break;
334         }
335         switch (fTileModeY) {
336             case kClamp_TileMode:  p->append(SkRasterPipeline::clamp_y,  &ctx->height); break;
337             case kMirror_TileMode: p->append(SkRasterPipeline::mirror_y, &ctx->height); break;
338             case kRepeat_TileMode: p->append(SkRasterPipeline::repeat_y, &ctx->height); break;
339         }
340         switch (info.colorType()) {
341             case kAlpha_8_SkColorType:   p->append(SkRasterPipeline::gather_a8,   ctx); break;
342             case kIndex_8_SkColorType:   p->append(SkRasterPipeline::gather_i8,   ctx); break;
343             case kGray_8_SkColorType:    p->append(SkRasterPipeline::gather_g8,   ctx); break;
344             case kRGB_565_SkColorType:   p->append(SkRasterPipeline::gather_565,  ctx); break;
345             case kARGB_4444_SkColorType: p->append(SkRasterPipeline::gather_4444, ctx); break;
346             case kRGBA_8888_SkColorType:
347             case kBGRA_8888_SkColorType: p->append(SkRasterPipeline::gather_8888, ctx); break;
348             case kRGBA_F16_SkColorType:  p->append(SkRasterPipeline::gather_f16,  ctx); break;
349             default: SkASSERT(false);
350         }
351         if (info.gammaCloseToSRGB() && dst != nullptr) {
352             p->append(SkRasterPipeline::from_srgb);
353         }
354     };
355
356     auto sample = [&](SkRasterPipeline::StockStage sampler) {
357         p->append(sampler, ctx);
358         append_tiling_and_gather();
359         p->append(SkRasterPipeline::accumulate, ctx);
360     };
361
362     if (quality == kNone_SkFilterQuality) {
363         append_tiling_and_gather();
364     } else {
365         p->append(SkRasterPipeline::save_xy, ctx);
366         sample(SkRasterPipeline::bilinear_nn);
367         sample(SkRasterPipeline::bilinear_np);
368         sample(SkRasterPipeline::bilinear_pn);
369         sample(SkRasterPipeline::bilinear_pp);
370         p->append(SkRasterPipeline::move_dst_src);
371     }
372
373     auto effective_color_type = [](SkColorType ct) {
374         return ct == kIndex_8_SkColorType ? kN32_SkColorType : ct;
375     };
376
377     if (effective_color_type(info.colorType()) == kBGRA_8888_SkColorType) {
378         p->append(SkRasterPipeline::swap_rb);
379     }
380     if (info.colorType() == kAlpha_8_SkColorType) {
381         p->append(SkRasterPipeline::set_rgb, &ctx->color4f);
382     }
383     if (info.colorType() == kAlpha_8_SkColorType || info.alphaType() == kUnpremul_SkAlphaType) {
384         p->append(SkRasterPipeline::premul);
385     }
386     return append_gamut_transform(p, scratch, info.colorSpace(), dst);
387 }