blob: f58228c56c131799176d55239cc57759a5888975 [file] [log] [blame]
reed856e9d92015-09-30 12:21:45 -07001/*
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 "SkBitmapProcShader.h"
9#include "SkBitmapProvider.h"
reed320a40d2016-08-02 06:12:06 -070010#include "SkColorShader.h"
11#include "SkColorTable.h"
12#include "SkEmptyShader.h"
reed856e9d92015-09-30 12:21:45 -070013#include "SkImage_Base.h"
14#include "SkImageShader.h"
15#include "SkReadBuffer.h"
16#include "SkWriteBuffer.h"
17
reed6b2d7ac2016-08-11 06:42:26 -070018SkImageShader::SkImageShader(sk_sp<SkImage> img, TileMode tmx, TileMode tmy, const SkMatrix* matrix)
reed856e9d92015-09-30 12:21:45 -070019 : INHERITED(matrix)
reed6b2d7ac2016-08-11 06:42:26 -070020 , fImage(std::move(img))
reed856e9d92015-09-30 12:21:45 -070021 , fTileModeX(tmx)
22 , fTileModeY(tmy)
23{}
24
reed60c9b582016-04-03 09:11:13 -070025sk_sp<SkFlattenable> SkImageShader::CreateProc(SkReadBuffer& buffer) {
reed856e9d92015-09-30 12:21:45 -070026 const TileMode tx = (TileMode)buffer.readUInt();
27 const TileMode ty = (TileMode)buffer.readUInt();
28 SkMatrix matrix;
29 buffer.readMatrix(&matrix);
reeda9ca05c2016-08-11 03:55:15 -070030 sk_sp<SkImage> img = buffer.readImage();
reed856e9d92015-09-30 12:21:45 -070031 if (!img) {
32 return nullptr;
33 }
reed6b2d7ac2016-08-11 06:42:26 -070034 return SkImageShader::Make(std::move(img), tx, ty, &matrix);
reed856e9d92015-09-30 12:21:45 -070035}
36
37void SkImageShader::flatten(SkWriteBuffer& buffer) const {
38 buffer.writeUInt(fTileModeX);
39 buffer.writeUInt(fTileModeY);
40 buffer.writeMatrix(this->getLocalMatrix());
reed6b2d7ac2016-08-11 06:42:26 -070041 buffer.writeImage(fImage.get());
reed856e9d92015-09-30 12:21:45 -070042}
43
44bool SkImageShader::isOpaque() const {
45 return fImage->isOpaque();
46}
47
reed773ceda2016-03-03 18:18:25 -080048size_t SkImageShader::onContextSize(const ContextRec& rec) const {
fmalitadc87a7d2016-10-17 06:09:26 -070049 return SkBitmapProcLegacyShader::ContextSize(rec, as_IB(fImage)->onImageInfo());
reed856e9d92015-09-30 12:21:45 -070050}
51
52SkShader::Context* SkImageShader::onCreateContext(const ContextRec& rec, void* storage) const {
reed320a40d2016-08-02 06:12:06 -070053 return SkBitmapProcLegacyShader::MakeContext(*this, fTileModeX, fTileModeY,
reed6b2d7ac2016-08-11 06:42:26 -070054 SkBitmapProvider(fImage.get()), rec, storage);
reed856e9d92015-09-30 12:21:45 -070055}
56
reedf1ac1822016-08-01 11:24:14 -070057SkImage* SkImageShader::onIsAImage(SkMatrix* texM, TileMode xy[]) const {
58 if (texM) {
59 *texM = this->getLocalMatrix();
60 }
61 if (xy) {
62 xy[0] = (TileMode)fTileModeX;
63 xy[1] = (TileMode)fTileModeY;
64 }
65 return const_cast<SkImage*>(fImage.get());
66}
67
Mike Reed627778d2016-09-28 17:13:38 -040068#ifdef SK_SUPPORT_LEGACY_SHADER_ISABITMAP
reedf1ac1822016-08-01 11:24:14 -070069bool SkImageShader::onIsABitmap(SkBitmap* texture, SkMatrix* texM, TileMode xy[]) const {
70 const SkBitmap* bm = as_IB(fImage)->onPeekBitmap();
71 if (!bm) {
72 return false;
73 }
74
75 if (texture) {
76 *texture = *bm;
77 }
78 if (texM) {
79 *texM = this->getLocalMatrix();
80 }
81 if (xy) {
82 xy[0] = (TileMode)fTileModeX;
83 xy[1] = (TileMode)fTileModeY;
84 }
85 return true;
86}
Mike Reed627778d2016-09-28 17:13:38 -040087#endif
reedf1ac1822016-08-01 11:24:14 -070088
reed320a40d2016-08-02 06:12:06 -070089static bool bitmap_is_too_big(int w, int h) {
90 // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it
91 // communicates between its matrix-proc and its sampler-proc. Until we can
92 // widen that, we have to reject bitmaps that are larger.
93 //
94 static const int kMaxSize = 65535;
95
96 return w > kMaxSize || h > kMaxSize;
97}
98
99// returns true and set color if the bitmap can be drawn as a single color
100// (for efficiency)
101static bool can_use_color_shader(const SkImage* image, SkColor* color) {
102#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
103 // HWUI does not support color shaders (see b/22390304)
104 return false;
105#endif
106
107 if (1 != image->width() || 1 != image->height()) {
108 return false;
reed856e9d92015-09-30 12:21:45 -0700109 }
reed320a40d2016-08-02 06:12:06 -0700110
111 SkPixmap pmap;
112 if (!image->peekPixels(&pmap)) {
113 return false;
114 }
115
116 switch (pmap.colorType()) {
117 case kN32_SkColorType:
118 *color = SkUnPreMultiply::PMColorToColor(*pmap.addr32(0, 0));
119 return true;
120 case kRGB_565_SkColorType:
121 *color = SkPixel16ToColor(*pmap.addr16(0, 0));
122 return true;
123 case kIndex_8_SkColorType: {
124 const SkColorTable& ctable = *pmap.ctable();
125 *color = SkUnPreMultiply::PMColorToColor(ctable[*pmap.addr8(0, 0)]);
126 return true;
127 }
128 default: // just skip the other configs for now
129 break;
130 }
131 return false;
132}
133
reed6b2d7ac2016-08-11 06:42:26 -0700134sk_sp<SkShader> SkImageShader::Make(sk_sp<SkImage> image, TileMode tx, TileMode ty,
reed320a40d2016-08-02 06:12:06 -0700135 const SkMatrix* localMatrix,
136 SkTBlitterAllocator* allocator) {
137 SkShader* shader;
138 SkColor color;
139 if (!image || bitmap_is_too_big(image->width(), image->height())) {
140 if (nullptr == allocator) {
141 shader = new SkEmptyShader;
142 } else {
143 shader = allocator->createT<SkEmptyShader>();
144 }
reed6b2d7ac2016-08-11 06:42:26 -0700145 } else if (can_use_color_shader(image.get(), &color)) {
reed320a40d2016-08-02 06:12:06 -0700146 if (nullptr == allocator) {
147 shader = new SkColorShader(color);
148 } else {
149 shader = allocator->createT<SkColorShader>(color);
150 }
151 } else {
152 if (nullptr == allocator) {
153 shader = new SkImageShader(image, tx, ty, localMatrix);
154 } else {
155 shader = allocator->createT<SkImageShader>(image, tx, ty, localMatrix);
156 }
157 }
158 return sk_sp<SkShader>(shader);
reed856e9d92015-09-30 12:21:45 -0700159}
160
161#ifndef SK_IGNORE_TO_STRING
162void SkImageShader::toString(SkString* str) const {
163 const char* gTileModeName[SkShader::kTileModeCount] = {
164 "clamp", "repeat", "mirror"
165 };
166
167 str->appendf("ImageShader: ((%s %s) ", gTileModeName[fTileModeX], gTileModeName[fTileModeY]);
168 fImage->toString(str);
169 this->INHERITED::toString(str);
170 str->append(")");
171}
172#endif
173
174///////////////////////////////////////////////////////////////////////////////////////////////////
175
176#if SK_SUPPORT_GPU
177
178#include "GrTextureAccess.h"
179#include "SkGr.h"
bsalomonf276ac52015-10-09 13:36:42 -0700180#include "SkGrPriv.h"
reed856e9d92015-09-30 12:21:45 -0700181#include "effects/GrSimpleTextureEffect.h"
182#include "effects/GrBicubicEffect.h"
183#include "effects/GrSimpleTextureEffect.h"
184
brianosman839345d2016-07-22 11:04:53 -0700185sk_sp<GrFragmentProcessor> SkImageShader::asFragmentProcessor(const AsFPArgs& args) const {
reed856e9d92015-09-30 12:21:45 -0700186 SkMatrix matrix;
187 matrix.setIDiv(fImage->width(), fImage->height());
188
189 SkMatrix lmInverse;
190 if (!this->getLocalMatrix().invert(&lmInverse)) {
191 return nullptr;
192 }
brianosman839345d2016-07-22 11:04:53 -0700193 if (args.fLocalMatrix) {
reed856e9d92015-09-30 12:21:45 -0700194 SkMatrix inv;
brianosman839345d2016-07-22 11:04:53 -0700195 if (!args.fLocalMatrix->invert(&inv)) {
reed856e9d92015-09-30 12:21:45 -0700196 return nullptr;
197 }
198 lmInverse.postConcat(inv);
199 }
200 matrix.preConcat(lmInverse);
201
202 SkShader::TileMode tm[] = { fTileModeX, fTileModeY };
203
204 // Must set wrap and filter on the sampler before requesting a texture. In two places below
205 // we check the matrix scale factors to determine how to interpret the filter quality setting.
206 // This completely ignores the complexity of the drawVertices case where explicit local coords
207 // are provided by the caller.
208 bool doBicubic;
209 GrTextureParams::FilterMode textureFilterMode =
brianosman839345d2016-07-22 11:04:53 -0700210 GrSkFilterQualityToGrFilterMode(args.fFilterQuality, *args.fViewMatrix, this->getLocalMatrix(),
211 &doBicubic);
reed856e9d92015-09-30 12:21:45 -0700212 GrTextureParams params(tm, textureFilterMode);
Hal Canary67b39de2016-11-07 11:47:44 -0500213 sk_sp<GrTexture> texture(as_IB(fImage)->asTextureRef(args.fContext, params,
214 args.fGammaTreatment));
reed856e9d92015-09-30 12:21:45 -0700215 if (!texture) {
216 return nullptr;
217 }
218
brianosman77320db2016-09-07 08:09:10 -0700219 SkImageInfo info = as_IB(fImage)->onImageInfo();
220 sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(info.colorSpace(),
brianosman51924752016-09-12 08:50:19 -0700221 args.fDstColorSpace);
bungeman06ca8ec2016-06-09 08:01:03 -0700222 sk_sp<GrFragmentProcessor> inner;
reed856e9d92015-09-30 12:21:45 -0700223 if (doBicubic) {
Hal Canary67b39de2016-11-07 11:47:44 -0500224 inner = GrBicubicEffect::Make(texture.get(), std::move(colorSpaceXform), matrix, tm);
reed856e9d92015-09-30 12:21:45 -0700225 } else {
Hal Canary67b39de2016-11-07 11:47:44 -0500226 inner = GrSimpleTextureEffect::Make(texture.get(), std::move(colorSpaceXform),
227 matrix, params);
reed856e9d92015-09-30 12:21:45 -0700228 }
229
230 if (GrPixelConfigIsAlphaOnly(texture->config())) {
bungeman06ca8ec2016-06-09 08:01:03 -0700231 return inner;
reed856e9d92015-09-30 12:21:45 -0700232 }
bungeman06ca8ec2016-06-09 08:01:03 -0700233 return sk_sp<GrFragmentProcessor>(GrFragmentProcessor::MulOutputByInputAlpha(std::move(inner)));
reed856e9d92015-09-30 12:21:45 -0700234}
235
236#endif
reed320a40d2016-08-02 06:12:06 -0700237
238///////////////////////////////////////////////////////////////////////////////////////////////////
239#include "SkImagePriv.h"
240
241sk_sp<SkShader> SkMakeBitmapShader(const SkBitmap& src, SkShader::TileMode tmx,
242 SkShader::TileMode tmy, const SkMatrix* localMatrix,
reed1ec04d92016-08-05 12:07:41 -0700243 SkCopyPixelsMode cpm, SkTBlitterAllocator* allocator) {
244 // Until we learn otherwise, it seems that any caller that is passing an allocator must be
245 // assuming that the returned shader will have a stack-frame lifetime, so we assert that
246 // they are also asking for kNever_SkCopyPixelsMode. If that proves otherwise, we can remove
247 // or modify this assert.
248 SkASSERT(!allocator || (kNever_SkCopyPixelsMode == cpm));
249
reed6b2d7ac2016-08-11 06:42:26 -0700250 return SkImageShader::Make(SkMakeImageFromRasterBitmap(src, cpm, allocator),
reed320a40d2016-08-02 06:12:06 -0700251 tmx, tmy, localMatrix, allocator);
252}
253
254static sk_sp<SkFlattenable> SkBitmapProcShader_CreateProc(SkReadBuffer& buffer) {
255 SkMatrix lm;
256 buffer.readMatrix(&lm);
reeda9ca05c2016-08-11 03:55:15 -0700257 sk_sp<SkImage> image = buffer.readBitmapAsImage();
reed320a40d2016-08-02 06:12:06 -0700258 SkShader::TileMode mx = (SkShader::TileMode)buffer.readUInt();
259 SkShader::TileMode my = (SkShader::TileMode)buffer.readUInt();
reeda9ca05c2016-08-11 03:55:15 -0700260 return image ? image->makeShader(mx, my, &lm) : nullptr;
reed320a40d2016-08-02 06:12:06 -0700261}
262
263SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkShader)
264SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkImageShader)
265SkFlattenable::Register("SkBitmapProcShader", SkBitmapProcShader_CreateProc, kSkShader_Type);
266SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
267