Chromium Code Reviews| Index: src/pdf/SkPDFShader.cpp |
| diff --git a/src/pdf/SkPDFShader.cpp b/src/pdf/SkPDFShader.cpp |
| index 9394f1b9597c67d25e77a99af74e2bf938fdd4c8..1d8792c1f13c3c8cf0366d054d2ce970699afdaf 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,35 +828,55 @@ 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; |
| } |
| + // Ensure the device bounds include the pattern cell as tiling theoretically |
| + // extends out to infinity. If the device size is too small, the pattern |
| + // cell bitmap will be clipped out, and the shader will look awful. |
| + const SkBitmap* image = &fState.get()->fImage; |
|
vandebo (ex-Chrome)
2013/08/20 17:22:19
I think you don't want to do this for clamp mode.
ducky
2013/08/21 00:44:08
Done.
|
| + SkRect bitmapBounds; |
| + image->getBounds(&bitmapBounds); |
| + 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()); |
| + SkRect patternBBox; |
| + image->getBounds(&patternBBox); |
| + // Translate canvas origin to bitmap origin so all coordinates are > 0 |
| + // (inside device clip bounds). |
| + if (deviceBounds.left() < 0 || deviceBounds.top() < 0) { |
|
vandebo (ex-Chrome)
2013/08/20 17:22:19
Why do this conditionally? What if the pattern is
ducky
2013/08/21 00:44:08
The bitmap origin is at (0, 0), so the joined rect
|
| + 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()); |
| + } |
| + |
| + canvas.drawBitmap(*image, 0, 0); |
| + |
| + SkScalar width = image->width(); |
| + SkScalar height = image->height(); |
| SkShader::TileMode tileModes[2]; |
| tileModes[0] = fState.get()->fImageTileModes[0]; |
| tileModes[1] = fState.get()->fImageTileModes[1]; |
| - canvas.drawBitmap(*image, 0, 0); |
| - SkRect patternBBox = SkRect::MakeXYWH(-surfaceBBox.fLeft, -surfaceBBox.fTop, |
| - width, height); |
| - |
| // Tiling is implied. First we handle mirroring. |
| if (tileModes[0] == SkShader::kMirror_TileMode) { |
| SkMatrix xMirror; |
| @@ -889,28 +909,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 +941,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 +958,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 +973,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 +996,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 +1011,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(); |
| } |
| } |