SkPDFShader::State::State(const SkShader& shader, const SkMatrix& canvasTransform, const SkIRect& bbox, SkScalar rasterScale) : fCanvasTransform(canvasTransform), fBBox(bbox), fPixelGeneration(0) { fInfo.fColorCount = 0; fInfo.fColors = NULL; fInfo.fColorOffsets = NULL; fShaderTransform = shader.getLocalMatrix(); fImageTileModes[0] = fImageTileModes[1] = SkShader::kClamp_TileMode; fType = shader.asAGradient(&fInfo); if (fType == SkShader::kNone_GradientType) { SkMatrix matrix; if (shader.isABitmap(&fImage, &matrix, fImageTileModes)) { SkASSERT(matrix.isIdentity()); } else { // Generic fallback for unsupported shaders: // * allocate a bbox-sized bitmap // * shade the whole area // * use the result as a bitmap shader // bbox is in device space. While that's exactly what we want for sizing our bitmap, // we need to map it into shader space for adjustments (to match // SkPDFImageShader::Create's behavior). SkRect shaderRect = SkRect::Make(bbox); if (!inverse_transform_bbox(canvasTransform, &shaderRect)) { fImage.reset(); return; } // 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(kMaxBitmapArea / bitmapArea); } SkISize size = SkISize::Make(SkScalarRoundToInt(rasterScale * bbox.width()), SkScalarRoundToInt(rasterScale * bbox.height())); SkSize scale = SkSize::Make(SkIntToScalar(size.width()) / shaderRect.width(), SkIntToScalar(size.height()) / shaderRect.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(-shaderRect.x(), -shaderRect.y()); canvas.drawPaint(p); fShaderTransform.setTranslate(shaderRect.x(), shaderRect.y()); fShaderTransform.preScale(1 / scale.width(), 1 / scale.height()); } fPixelGeneration = fImage.getGenerationID(); } else { AllocateGradientInfoStorage(); shader.asAGradient(&fInfo); } }