Index: src/image/SkImageShader.cpp |
diff --git a/src/image/SkImageShader.cpp b/src/image/SkImageShader.cpp |
index 12caa7a3d2862024907e710a6bfae6a6a081ea65..a486f71dfde21365f54db34b6619be9b2508ebaf 100644 |
--- a/src/image/SkImageShader.cpp |
+++ b/src/image/SkImageShader.cpp |
@@ -7,6 +7,9 @@ |
#include "SkBitmapProcShader.h" |
#include "SkBitmapProvider.h" |
+#include "SkColorShader.h" |
+#include "SkColorTable.h" |
+#include "SkEmptyShader.h" |
#include "SkImage_Base.h" |
#include "SkImageShader.h" |
#include "SkReadBuffer.h" |
@@ -43,11 +46,11 @@ bool SkImageShader::isOpaque() const { |
} |
size_t SkImageShader::onContextSize(const ContextRec& rec) const { |
- return SkBitmapProcShader::ContextSize(rec, SkBitmapProvider(fImage).info()); |
+ return SkBitmapProcLegacyShader::ContextSize(rec, SkBitmapProvider(fImage).info()); |
} |
SkShader::Context* SkImageShader::onCreateContext(const ContextRec& rec, void* storage) const { |
- return SkBitmapProcShader::MakeContext(*this, fTileModeX, fTileModeY, |
+ return SkBitmapProcLegacyShader::MakeContext(*this, fTileModeX, fTileModeY, |
SkBitmapProvider(fImage), rec, storage); |
} |
@@ -81,12 +84,76 @@ bool SkImageShader::onIsABitmap(SkBitmap* texture, SkMatrix* texM, TileMode xy[] |
return true; |
} |
+static bool bitmap_is_too_big(int w, int h) { |
+ // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it |
+ // communicates between its matrix-proc and its sampler-proc. Until we can |
+ // widen that, we have to reject bitmaps that are larger. |
+ // |
+ static const int kMaxSize = 65535; |
+ |
+ return w > kMaxSize || h > kMaxSize; |
+} |
+ |
+// returns true and set color if the bitmap can be drawn as a single color |
+// (for efficiency) |
+static bool can_use_color_shader(const SkImage* image, SkColor* color) { |
+#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK |
+ // HWUI does not support color shaders (see b/22390304) |
+ return false; |
+#endif |
+ |
+ if (1 != image->width() || 1 != image->height()) { |
+ return false; |
+ } |
+ |
+ SkPixmap pmap; |
+ if (!image->peekPixels(&pmap)) { |
+ return false; |
+ } |
+ |
+ switch (pmap.colorType()) { |
+ case kN32_SkColorType: |
+ *color = SkUnPreMultiply::PMColorToColor(*pmap.addr32(0, 0)); |
+ return true; |
+ case kRGB_565_SkColorType: |
+ *color = SkPixel16ToColor(*pmap.addr16(0, 0)); |
+ return true; |
+ case kIndex_8_SkColorType: { |
+ const SkColorTable& ctable = *pmap.ctable(); |
+ *color = SkUnPreMultiply::PMColorToColor(ctable[*pmap.addr8(0, 0)]); |
+ return true; |
+ } |
+ default: // just skip the other configs for now |
+ break; |
+ } |
+ return false; |
+} |
+ |
sk_sp<SkShader> SkImageShader::Make(const SkImage* image, TileMode tx, TileMode ty, |
- const SkMatrix* localMatrix) { |
- if (!image) { |
- return nullptr; |
+ const SkMatrix* localMatrix, |
+ SkTBlitterAllocator* allocator) { |
+ SkShader* shader; |
+ SkColor color; |
+ if (!image || bitmap_is_too_big(image->width(), image->height())) { |
+ if (nullptr == allocator) { |
+ shader = new SkEmptyShader; |
+ } else { |
+ shader = allocator->createT<SkEmptyShader>(); |
+ } |
+ } else if (can_use_color_shader(image, &color)) { |
+ if (nullptr == allocator) { |
+ shader = new SkColorShader(color); |
+ } else { |
+ shader = allocator->createT<SkColorShader>(color); |
+ } |
+ } else { |
+ if (nullptr == allocator) { |
+ shader = new SkImageShader(image, tx, ty, localMatrix); |
+ } else { |
+ shader = allocator->createT<SkImageShader>(image, tx, ty, localMatrix); |
+ } |
} |
- return sk_sp<SkShader>(new SkImageShader(image, tx, ty, localMatrix)); |
+ return sk_sp<SkShader>(shader); |
} |
#ifndef SK_IGNORE_TO_STRING |
@@ -161,3 +228,33 @@ sk_sp<GrFragmentProcessor> SkImageShader::asFragmentProcessor(const AsFPArgs& ar |
} |
#endif |
+ |
+/////////////////////////////////////////////////////////////////////////////////////////////////// |
+#include "SkImagePriv.h" |
+ |
+sk_sp<SkShader> SkMakeBitmapShader(const SkBitmap& src, SkShader::TileMode tmx, |
+ SkShader::TileMode tmy, const SkMatrix* localMatrix, |
+ SkTBlitterAllocator* allocator) { |
+ ForceCopyMode mode = allocator ? kNever_ForceCopyMode : kNo_ForceCopyMode; |
+ return SkImageShader::Make(SkMakeImageFromRasterBitmap(src, mode).get(), |
+ tmx, tmy, localMatrix, allocator); |
+} |
+ |
+static sk_sp<SkFlattenable> SkBitmapProcShader_CreateProc(SkReadBuffer& buffer) { |
+ SkMatrix lm; |
+ buffer.readMatrix(&lm); |
+ SkBitmap bm; |
+ if (!buffer.readBitmap(&bm)) { |
+ return nullptr; |
+ } |
+ bm.setImmutable(); |
+ SkShader::TileMode mx = (SkShader::TileMode)buffer.readUInt(); |
+ SkShader::TileMode my = (SkShader::TileMode)buffer.readUInt(); |
+ return SkShader::MakeBitmapShader(bm, mx, my, &lm); |
+} |
+ |
+SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkShader) |
+SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkImageShader) |
+SkFlattenable::Register("SkBitmapProcShader", SkBitmapProcShader_CreateProc, kSkShader_Type); |
+SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END |
+ |