aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar fmalita <fmalita@chromium.org>2015-01-13 08:06:11 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2015-01-13 08:06:11 -0800
commitc3796c7a74e103d9b367ad9449fcdacfa20d83e1 (patch)
tree4c6f2f7a5c023fca5dbf0a2ee69f7aecd6503ba5 /src
parentf361b714390422a5c2a8b1dacb8e67502d0e40bb (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.cpp3
-rw-r--r--src/pdf/SkPDFShader.cpp46
-rw-r--r--src/pdf/SkPDFShader.h14
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;