Index: src/pdf/SkPDFShader.cpp |
diff --git a/src/pdf/SkPDFShader.cpp b/src/pdf/SkPDFShader.cpp |
index 40f7d93f8907b30ab5c9ae191c449c60fa292879..890bf447d5c46a8b0e4943ab0704bfef233195d7 100644 |
--- a/src/pdf/SkPDFShader.cpp |
+++ b/src/pdf/SkPDFShader.cpp |
@@ -489,7 +489,7 @@ public: |
SkShader::TileMode fImageTileModes[2]; |
State(const SkShader& shader, const SkMatrix& canvasTransform, |
- const SkIRect& bbox); |
+ const SkIRect& bbox, SkScalar rasterScale); |
bool operator==(const State& b) const; |
@@ -657,10 +657,11 @@ void SkPDFShader::RemoveShader(SkPDFObject* shader) { |
// static |
SkPDFObject* SkPDFShader::GetPDFShader(const SkShader& shader, |
const SkMatrix& matrix, |
- const SkIRect& surfaceBBox) { |
+ const SkIRect& surfaceBBox, |
+ SkScalar rasterScale) { |
SkAutoMutexAcquire lock(CanonicalShadersMutex()); |
return GetPDFShaderByState( |
- SkNEW_ARGS(State, (shader, matrix, surfaceBBox))); |
+ SkNEW_ARGS(State, (shader, matrix, surfaceBBox, rasterScale))); |
} |
// static |
@@ -1239,8 +1240,8 @@ bool SkPDFShader::State::operator==(const SkPDFShader::State& b) const { |
return true; |
} |
-SkPDFShader::State::State(const SkShader& shader, |
- const SkMatrix& canvasTransform, const SkIRect& bbox) |
+SkPDFShader::State::State(const SkShader& shader, const SkMatrix& canvasTransform, |
+ const SkIRect& bbox, SkScalar rasterScale) |
: fCanvasTransform(canvasTransform), |
fBBox(bbox), |
fPixelGeneration(0) { |
@@ -1257,10 +1258,39 @@ SkPDFShader::State::State(const SkShader& shader, |
SkMatrix matrix; |
bitmapType = shader.asABitmap(&fImage, &matrix, fImageTileModes); |
if (bitmapType != SkShader::kDefault_BitmapType) { |
- fImage.reset(); |
- return; |
+ // Generic fallback for unsupported shaders: |
+ // * allocate a bbox-sized bitmap |
+ // * shade the whole area |
+ // * use the result as a bitmap shader |
+ |
+ // Clamp the bitmap size to about 1M pixels |
+ static const SkScalar kMaxBitmapArea = 1024 * 1024; |
+ SkScalar bitmapArea = rasterScale * bbox.width() * rasterScale * bbox.height(); |
+ if (bitmapArea > kMaxBitmapArea) { |
+ rasterScale *= SkScalarSqrt(SkScalarDiv(kMaxBitmapArea, bitmapArea)); |
+ } |
+ |
+ SkISize size = SkISize::Make(SkScalarRoundToInt(rasterScale * bbox.width()), |
+ SkScalarRoundToInt(rasterScale * bbox.height())); |
+ SkSize scale = SkSize::Make(SkIntToScalar(size.width()) / SkIntToScalar(bbox.width()), |
+ SkIntToScalar(size.height()) / SkIntToScalar(bbox.height())); |
+ |
+ fImage.allocN32Pixels(size.width(), size.height()); |
+ fImage.eraseColor(SK_ColorTRANSPARENT); |
+ |
+ SkPaint p; |
+ p.setShader(const_cast<SkShader*>(&shader)); |
+ |
+ SkCanvas canvas(fImage); |
+ canvas.scale(scale.width(), scale.height()); |
+ canvas.translate(-SkIntToScalar(bbox.x()), -SkIntToScalar(bbox.y())); |
+ canvas.drawPaint(p); |
+ |
+ fShaderTransform.setTranslate(SkIntToScalar(bbox.x()), SkIntToScalar(bbox.y())); |
+ fShaderTransform.preScale(1 / scale.width(), 1 / scale.height()); |
+ } else { |
+ SkASSERT(matrix.isIdentity()); |
} |
- SkASSERT(matrix.isIdentity()); |
fPixelGeneration = fImage.getGenerationID(); |
} else { |
AllocateGradientInfoStorage(); |