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
This commit is contained in:
parent
f361b71439
commit
c3796c7a74
@ -40,4 +40,10 @@ blurrects
|
||||
# New shadow only option in SkDropShadowImageFilter
|
||||
dropshadowimagefilter
|
||||
|
||||
|
||||
# fmalita http://crrev.com/841763005
|
||||
composeshader
|
||||
composeshader_alpha
|
||||
perlinnoise
|
||||
perlinnoise_localmatrix
|
||||
pictureshader
|
||||
pictureshadertile
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user