Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(608)

Unified Diff: src/pdf/SkPDFShader.cpp

Issue 22884013: Support tiling bitmaps outside clip bounds in SkPDFImageShader (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: Fix GM slide nits Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « gyp/gmslides.gypi ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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();
}
}
« no previous file with comments | « gyp/gmslides.gypi ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698