Chromium Code Reviews| 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; |
| } |