Index: src/pdf/SkPDFDevice.cpp |
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp |
index 43117a2b2fc4d5760d692cb50970070721d71b0c..76dcc2d7b3adcc5e30261c5a5ee6cecd7331f987 100644 |
--- a/src/pdf/SkPDFDevice.cpp |
+++ b/src/pdf/SkPDFDevice.cpp |
@@ -2028,23 +2028,95 @@ int SkPDFDevice::getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID) { |
return resourceIndex; |
} |
-void SkPDFDevice::internalDrawBitmap(const SkMatrix& matrix, |
+static void setup_transparent_bitmap(SkBitmap* bitmap, int width, int height) { |
vandebo (ex-Chrome)
2013/10/16 16:46:41
nit: it seems unlikely that this will get reused.
edisonn
2013/10/16 18:28:52
Done.
|
+ bitmap->setConfig(SkBitmap::kARGB_8888_Config, width, height); |
+ bitmap->allocPixels(); |
+ bitmap->eraseColor(SK_ColorTRANSPARENT); |
+} |
+ |
+void SkPDFDevice::internalDrawBitmap(const SkMatrix& origMatrix, |
const SkClipStack* clipStack, |
- const SkRegion& clipRegion, |
- const SkBitmap& bitmap, |
+ const SkRegion& origClipRegion, |
+ const SkBitmap& origBitmap, |
const SkIRect* srcRect, |
const SkPaint& paint) { |
- // TODO(edisonn): Perspective matrix support implemented here |
+ SkMatrix matrix = origMatrix; |
+ SkRegion perspectiveBounds; |
+ const SkRegion* clipRegion = &origClipRegion; |
+ SkBitmap subsetBitmap; |
+ SkBitmap perspectiveBitmap; |
+ const SkBitmap* bitmap = &origBitmap; |
+ |
+ // Raster the bitmap using perspective in a new bitmap. |
vandebo (ex-Chrome)
2013/10/16 16:46:41
nit: Raster -> Rasterize/Render
edisonn
2013/10/16 18:28:52
Done.
|
+ if (origMatrix.hasPerspective()) { |
+ // TODO(edisonn): testability - add a flag to force this codepath. |
vandebo (ex-Chrome)
2013/10/16 16:46:41
nit: Remove - you could pass a matrix with perspec
edisonn
2013/10/16 18:28:52
Done.
|
+ if (srcRect) { |
+ if (!origBitmap.extractSubset(&subsetBitmap, *srcRect)) { |
+ return; |
+ } |
+ } else { |
+ subsetBitmap = origBitmap; |
vandebo (ex-Chrome)
2013/10/16 16:46:41
nit: this makes a copy. You could move "SkBitmap
edisonn
2013/10/16 18:28:52
Done.
|
+ } |
+ srcRect = NULL; |
+ |
+ // Transform the bitmap in the new space. |
+ SkPath perspectiveOutline; |
+ perspectiveOutline.addRect(SkRect::MakeWH(SkIntToScalar(subsetBitmap.width()), |
+ SkIntToScalar(subsetBitmap.height()))); |
+ perspectiveOutline.transform(origMatrix); |
+ |
+ // Retrieve the bounds of the new shape. |
+ SkRect bounds = perspectiveOutline.getBounds(); |
+ |
+ // TODO(edisonn): add DPI settings. Currently 1 pixel/point, which does not look great, |
+ // but it is not producing large PDFs. |
+ |
+ // TODO(edisonn): A better approach would be to use a bitmap shader (in clamp mode) and |
+ // draw a rect over the entire bounding box. Then intersect perspectiveOutline to the clip. |
+ // That will avoid introducing alpha to the image while still giving good behavior at the |
+ // edge of the image. Avoiding alpha will reduce the pdf size and generation CPU time some. |
+ |
+ // Create transparent bitmap. |
vandebo (ex-Chrome)
2013/10/16 16:46:41
nit: comment is unnecessary
edisonn
2013/10/16 18:28:52
Done.
|
+ setup_transparent_bitmap(&perspectiveBitmap, bounds.width(), bounds.height()); |
+ |
+ SkBitmapDevice device(perspectiveBitmap); |
+ SkCanvas canvas(&device); |
+ |
+ SkScalar deltaX = bounds.left(); |
+ SkScalar deltaY = bounds.top(); |
+ |
+ SkMatrix offsetMatrix = origMatrix; |
+ offsetMatrix.postTranslate(-deltaX, -deltaY); |
+ |
+ // Translate the draw in the new canvas, so we perfectly fit the shape in the bitmap. |
+ canvas.setMatrix(offsetMatrix); |
+ |
+ canvas.drawBitmap(subsetBitmap, SkIntToScalar(0), SkIntToScalar(0)); |
+ |
+ // Make sure the final bits are in the bitmap. |
+ canvas.flush(); |
+ |
+ // In the new space, we use the identity matrix translated. |
+ matrix.setTranslate(deltaX, deltaY); |
+ perspectiveBounds.setRect(SkIRect::MakeXYWH(SkScalarToFixed(bounds.x()), |
+ SkScalarToFixed(bounds.y()), |
+ SkScalarToFixed(bounds.width()), |
+ SkScalarToFixed(bounds.height()))); |
+ clipRegion = &perspectiveBounds; |
+ srcRect = NULL; |
+ bitmap = &perspectiveBitmap; |
+ } |
+ |
SkMatrix scaled; |
// Adjust for origin flip. |
scaled.setScale(SK_Scalar1, -SK_Scalar1); |
scaled.postTranslate(0, SK_Scalar1); |
// Scale the image up from 1x1 to WxH. |
- SkIRect subset = SkIRect::MakeWH(bitmap.width(), bitmap.height()); |
+ SkIRect subset = SkIRect::MakeWH(bitmap->width(), bitmap->height()); |
scaled.postScale(SkIntToScalar(subset.width()), |
SkIntToScalar(subset.height())); |
scaled.postConcat(matrix); |
- ScopedContentEntry content(this, clipStack, clipRegion, scaled, paint); |
+ ScopedContentEntry content(this, clipStack, *clipRegion, scaled, paint); |
if (!content.entry()) { |
return; |
} |
@@ -2053,7 +2125,7 @@ void SkPDFDevice::internalDrawBitmap(const SkMatrix& matrix, |
return; |
} |
- SkPDFImage* image = SkPDFImage::CreateImage(bitmap, subset, fEncoder); |
+ SkPDFImage* image = SkPDFImage::CreateImage(*bitmap, subset, fEncoder); |
if (!image) { |
return; |
} |