diff options
author | 2015-01-13 08:06:11 -0800 | |
---|---|---|
committer | 2015-01-13 08:06:11 -0800 | |
commit | c3796c7a74e103d9b367ad9449fcdacfa20d83e1 (patch) | |
tree | 4c6f2f7a5c023fca5dbf0a2ee69f7aecd6503ba5 /src | |
parent | f361b714390422a5c2a8b1dacb8e67502d0e40bb (diff) |
Generic PDF shader fallback
Instead of ignoring unsupported shaders (and essentially filling with
solid black), convert them to bitmap shaders using on-the-fly
rasterization.
BUG=skia:3299
R=reed@google.com,halcanary@google.com
Review URL: https://codereview.chromium.org/841763005
Diffstat (limited to 'src')
-rw-r--r-- | src/pdf/SkPDFDevice.cpp | 3 | ||||
-rw-r--r-- | src/pdf/SkPDFShader.cpp | 46 | ||||
-rw-r--r-- | src/pdf/SkPDFShader.h | 14 |
3 files changed, 48 insertions, 15 deletions
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp index e9a38a0e9b..c3ee262db3 100644 --- a/src/pdf/SkPDFDevice.cpp +++ b/src/pdf/SkPDFDevice.cpp @@ -1950,7 +1950,8 @@ void SkPDFDevice::populateGraphicStateEntryFromPaint( fInitialTransform.mapRect(&boundsTemp); boundsTemp.roundOut(&bounds); - pdfShader.reset(SkPDFShader::GetPDFShader(*shader, transform, bounds)); + pdfShader.reset(SkPDFShader::GetPDFShader(*shader, transform, bounds, + SkIntToScalar(fRasterDpi) / DPI_FOR_RASTER_SCALE_ONE)); if (pdfShader.get()) { // pdfShader has been canonicalized so we can directly compare diff --git a/src/pdf/SkPDFShader.cpp b/src/pdf/SkPDFShader.cpp index 40f7d93f89..890bf447d5 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(); diff --git a/src/pdf/SkPDFShader.h b/src/pdf/SkPDFShader.h index 0b292e932a..9c92d77d92 100644 --- a/src/pdf/SkPDFShader.h +++ b/src/pdf/SkPDFShader.h @@ -33,15 +33,17 @@ public: * unreference it when done. This is needed to accommodate the weak * reference pattern used when the returned object is new and has no * other references. - * @param shader The SkShader to emulate. - * @param matrix The current transform. (PDF shaders are absolutely - * positioned, relative to where the page is drawn.) - * @param surfceBBox The bounding box of the drawing surface (with matrix - * already applied). + * @param shader The SkShader to emulate. + * @param matrix The current transform. (PDF shaders are absolutely + * positioned, relative to where the page is drawn.) + * @param surfceBBox The bounding box of the drawing surface (with matrix + * already applied). + * @param rasterScale Additional scale to be applied for early rasterization. */ static SkPDFObject* GetPDFShader(const SkShader& shader, const SkMatrix& matrix, - const SkIRect& surfaceBBox); + const SkIRect& surfaceBBox, + SkScalar rasterScale); protected: class State; |