| Index: src/pdf/SkPDFShader.cpp
|
| diff --git a/src/pdf/SkPDFShader.cpp b/src/pdf/SkPDFShader.cpp
|
| index 9394f1b9597c67d25e77a99af74e2bf938fdd4c8..fa0587fc5001465dda81c2e1c99dba68dd41b2ca 100644
|
| --- a/src/pdf/SkPDFShader.cpp
|
| +++ b/src/pdf/SkPDFShader.cpp
|
| @@ -24,7 +24,7 @@
|
| #include "SkTSet.h"
|
| #include "SkTypes.h"
|
|
|
| -static bool transformBBox(const SkMatrix& matrix, SkRect* bbox) {
|
| +static bool inverseTransformBBox(const SkMatrix& matrix, SkRect* bbox) {
|
| SkMatrix inverse;
|
| if (!matrix.invert(&inverse)) {
|
| return false;
|
| @@ -780,7 +780,7 @@ SkPDFFunctionShader::SkPDFFunctionShader(SkPDFShader::State* state)
|
|
|
| SkRect bbox;
|
| bbox.set(fState.get()->fBBox);
|
| - if (!transformBBox(finalMatrix, &bbox)) {
|
| + if (!inverseTransformBBox(finalMatrix, &bbox)) {
|
| return;
|
| }
|
|
|
| @@ -828,34 +828,60 @@ SkPDFFunctionShader::SkPDFFunctionShader(SkPDFShader::State* state)
|
| SkPDFImageShader::SkPDFImageShader(SkPDFShader::State* state) : fState(state) {
|
| fState.get()->fImage.lockPixels();
|
|
|
| + // The image shader pattern cell will be drawn into a separate device
|
| + // in pattern cell space (no scaling on the bitmap, though there may be
|
| + // translations so that all content is in the device, coordinates > 0).
|
| +
|
| + // Map clip bounds to shader space to ensure the device is large enough
|
| + // to handle fake clamping.
|
| SkMatrix finalMatrix = fState.get()->fCanvasTransform;
|
| finalMatrix.preConcat(fState.get()->fShaderTransform);
|
| - SkRect surfaceBBox;
|
| - surfaceBBox.set(fState.get()->fBBox);
|
| - if (!transformBBox(finalMatrix, &surfaceBBox)) {
|
| + SkRect deviceBounds;
|
| + deviceBounds.set(fState.get()->fBBox);
|
| + if (!inverseTransformBBox(finalMatrix, &deviceBounds)) {
|
| return;
|
| }
|
|
|
| + const SkBitmap* image = &fState.get()->fImage;
|
| + SkRect bitmapBounds;
|
| + image->getBounds(&bitmapBounds);
|
| +
|
| + // For tiling modes, the bounds should be extended to include the bitmap,
|
| + // otherwise the bitmap gets clipped out and the shader is empty and awful.
|
| + // For clamp modes, we're only interested in the clip region, whether
|
| + // or not the main bitmap is in it.
|
| + SkShader::TileMode tileModes[2];
|
| + tileModes[0] = fState.get()->fImageTileModes[0];
|
| + tileModes[1] = fState.get()->fImageTileModes[1];
|
| + if (tileModes[0] != SkShader::kClamp_TileMode ||
|
| + tileModes[1] != SkShader::kClamp_TileMode) {
|
| + deviceBounds.join(bitmapBounds);
|
| + }
|
| +
|
| SkMatrix unflip;
|
| - unflip.setTranslate(0, SkScalarRoundToScalar(surfaceBBox.height()));
|
| + unflip.setTranslate(0, SkScalarRoundToScalar(deviceBounds.height()));
|
| unflip.preScale(SK_Scalar1, -SK_Scalar1);
|
| - SkISize size = SkISize::Make(SkScalarRound(surfaceBBox.width()),
|
| - SkScalarRound(surfaceBBox.height()));
|
| + SkISize size = SkISize::Make(SkScalarRound(deviceBounds.width()),
|
| + SkScalarRound(deviceBounds.height()));
|
| SkPDFDevice pattern(size, size, unflip);
|
| SkCanvas canvas(&pattern);
|
| - canvas.translate(-surfaceBBox.fLeft, -surfaceBBox.fTop);
|
| - finalMatrix.preTranslate(surfaceBBox.fLeft, surfaceBBox.fTop);
|
|
|
| - const SkBitmap* image = &fState.get()->fImage;
|
| - SkScalar width = SkIntToScalar(image->width());
|
| - SkScalar height = SkIntToScalar(image->height());
|
| - SkShader::TileMode tileModes[2];
|
| - tileModes[0] = fState.get()->fImageTileModes[0];
|
| - tileModes[1] = fState.get()->fImageTileModes[1];
|
| + SkRect patternBBox;
|
| + image->getBounds(&patternBBox);
|
|
|
| + // Translate the canvas so that the bitmap origin is at (0, 0).
|
| + canvas.translate(-deviceBounds.left(), -deviceBounds.top());
|
| + patternBBox.offset(-deviceBounds.left(), -deviceBounds.top());
|
| + // Undo the translation in the final matrix
|
| + finalMatrix.preTranslate(deviceBounds.left(), deviceBounds.top());
|
| +
|
| + // If the bitmap is out of bounds (i.e. clamp mode where we only see the
|
| + // stretched sides), canvas will clip this out and the extraneous data
|
| + // won't be saved to the PDF.
|
| canvas.drawBitmap(*image, 0, 0);
|
| - SkRect patternBBox = SkRect::MakeXYWH(-surfaceBBox.fLeft, -surfaceBBox.fTop,
|
| - width, height);
|
| +
|
| + SkScalar width = SkIntToScalar(image->width());
|
| + SkScalar height = SkIntToScalar(image->height());
|
|
|
| // Tiling is implied. First we handle mirroring.
|
| if (tileModes[0] == SkShader::kMirror_TileMode) {
|
| @@ -889,28 +915,29 @@ SkPDFImageShader::SkPDFImageShader(SkPDFShader::State* state) : fState(state) {
|
| tileModes[1] == SkShader::kClamp_TileMode) {
|
| SkPaint paint;
|
| SkRect rect;
|
| - rect = SkRect::MakeLTRB(surfaceBBox.fLeft, surfaceBBox.fTop, 0, 0);
|
| + rect = SkRect::MakeLTRB(deviceBounds.left(), deviceBounds.top(), 0, 0);
|
| if (!rect.isEmpty()) {
|
| paint.setColor(image->getColor(0, 0));
|
| canvas.drawRect(rect, paint);
|
| }
|
|
|
| - rect = SkRect::MakeLTRB(width, surfaceBBox.fTop, surfaceBBox.fRight, 0);
|
| + rect = SkRect::MakeLTRB(width, deviceBounds.top(),
|
| + deviceBounds.right(), 0);
|
| if (!rect.isEmpty()) {
|
| paint.setColor(image->getColor(image->width() - 1, 0));
|
| canvas.drawRect(rect, paint);
|
| }
|
|
|
| - rect = SkRect::MakeLTRB(width, height, surfaceBBox.fRight,
|
| - surfaceBBox.fBottom);
|
| + rect = SkRect::MakeLTRB(width, height,
|
| + deviceBounds.right(), deviceBounds.bottom());
|
| if (!rect.isEmpty()) {
|
| paint.setColor(image->getColor(image->width() - 1,
|
| image->height() - 1));
|
| canvas.drawRect(rect, paint);
|
| }
|
|
|
| - rect = SkRect::MakeLTRB(surfaceBBox.fLeft, height, 0,
|
| - surfaceBBox.fBottom);
|
| + rect = SkRect::MakeLTRB(deviceBounds.left(), height,
|
| + 0, deviceBounds.bottom());
|
| if (!rect.isEmpty()) {
|
| paint.setColor(image->getColor(0, image->height() - 1));
|
| canvas.drawRect(rect, paint);
|
| @@ -920,13 +947,13 @@ SkPDFImageShader::SkPDFImageShader(SkPDFShader::State* state) : fState(state) {
|
| // Then expand the left, right, top, then bottom.
|
| if (tileModes[0] == SkShader::kClamp_TileMode) {
|
| SkIRect subset = SkIRect::MakeXYWH(0, 0, 1, image->height());
|
| - if (surfaceBBox.fLeft < 0) {
|
| + if (deviceBounds.left() < 0) {
|
| SkBitmap left;
|
| SkAssertResult(image->extractSubset(&left, subset));
|
|
|
| SkMatrix leftMatrix;
|
| - leftMatrix.setScale(-surfaceBBox.fLeft, 1);
|
| - leftMatrix.postTranslate(surfaceBBox.fLeft, 0);
|
| + leftMatrix.setScale(-deviceBounds.left(), 1);
|
| + leftMatrix.postTranslate(deviceBounds.left(), 0);
|
| canvas.drawBitmapMatrix(left, leftMatrix);
|
|
|
| if (tileModes[1] == SkShader::kMirror_TileMode) {
|
| @@ -937,13 +964,13 @@ SkPDFImageShader::SkPDFImageShader(SkPDFShader::State* state) : fState(state) {
|
| patternBBox.fLeft = 0;
|
| }
|
|
|
| - if (surfaceBBox.fRight > width) {
|
| + if (deviceBounds.right() > width) {
|
| SkBitmap right;
|
| subset.offset(image->width() - 1, 0);
|
| SkAssertResult(image->extractSubset(&right, subset));
|
|
|
| SkMatrix rightMatrix;
|
| - rightMatrix.setScale(surfaceBBox.fRight - width, 1);
|
| + rightMatrix.setScale(deviceBounds.right() - width, 1);
|
| rightMatrix.postTranslate(width, 0);
|
| canvas.drawBitmapMatrix(right, rightMatrix);
|
|
|
| @@ -952,19 +979,19 @@ SkPDFImageShader::SkPDFImageShader(SkPDFShader::State* state) : fState(state) {
|
| rightMatrix.postTranslate(0, 2 * height);
|
| canvas.drawBitmapMatrix(right, rightMatrix);
|
| }
|
| - patternBBox.fRight = surfaceBBox.width();
|
| + patternBBox.fRight = deviceBounds.width();
|
| }
|
| }
|
|
|
| if (tileModes[1] == SkShader::kClamp_TileMode) {
|
| SkIRect subset = SkIRect::MakeXYWH(0, 0, image->width(), 1);
|
| - if (surfaceBBox.fTop < 0) {
|
| + if (deviceBounds.top() < 0) {
|
| SkBitmap top;
|
| SkAssertResult(image->extractSubset(&top, subset));
|
|
|
| SkMatrix topMatrix;
|
| - topMatrix.setScale(SK_Scalar1, -surfaceBBox.fTop);
|
| - topMatrix.postTranslate(0, surfaceBBox.fTop);
|
| + topMatrix.setScale(SK_Scalar1, -deviceBounds.top());
|
| + topMatrix.postTranslate(0, deviceBounds.top());
|
| canvas.drawBitmapMatrix(top, topMatrix);
|
|
|
| if (tileModes[0] == SkShader::kMirror_TileMode) {
|
| @@ -975,13 +1002,13 @@ SkPDFImageShader::SkPDFImageShader(SkPDFShader::State* state) : fState(state) {
|
| patternBBox.fTop = 0;
|
| }
|
|
|
| - if (surfaceBBox.fBottom > height) {
|
| + if (deviceBounds.bottom() > height) {
|
| SkBitmap bottom;
|
| subset.offset(0, image->height() - 1);
|
| SkAssertResult(image->extractSubset(&bottom, subset));
|
|
|
| SkMatrix bottomMatrix;
|
| - bottomMatrix.setScale(SK_Scalar1, surfaceBBox.fBottom - height);
|
| + bottomMatrix.setScale(SK_Scalar1, deviceBounds.bottom() - height);
|
| bottomMatrix.postTranslate(0, height);
|
| canvas.drawBitmapMatrix(bottom, bottomMatrix);
|
|
|
| @@ -990,7 +1017,7 @@ SkPDFImageShader::SkPDFImageShader(SkPDFShader::State* state) : fState(state) {
|
| bottomMatrix.postTranslate(2 * width, 0);
|
| canvas.drawBitmapMatrix(bottom, bottomMatrix);
|
| }
|
| - patternBBox.fBottom = surfaceBBox.height();
|
| + patternBBox.fBottom = deviceBounds.height();
|
| }
|
| }
|
|
|
|
|