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

Side by Side Diff: src/pdf/SkPDFDevice.cpp

Issue 1372783003: SkPDF: Implement drawImage*() properly (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: 2015-09-30 (Wednesday) 21:22:24 EDT Created 5 years, 2 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 unified diff | Download patch
« no previous file with comments | « src/pdf/SkPDFDevice.h ('k') | src/pdf/SkPDFTypes.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2011 Google Inc. 2 * Copyright 2011 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "SkPDFDevice.h" 8 #include "SkPDFDevice.h"
9 9
10 #include "SkAnnotation.h" 10 #include "SkAnnotation.h"
11 #include "SkColor.h" 11 #include "SkColor.h"
12 #include "SkColorFilter.h" 12 #include "SkColorFilter.h"
13 #include "SkClipStack.h" 13 #include "SkClipStack.h"
14 #include "SkData.h" 14 #include "SkData.h"
15 #include "SkDraw.h" 15 #include "SkDraw.h"
16 #include "SkGlyphCache.h" 16 #include "SkGlyphCache.h"
17 #include "SkPaint.h" 17 #include "SkPaint.h"
18 #include "SkPath.h" 18 #include "SkPath.h"
19 #include "SkPathOps.h" 19 #include "SkPathOps.h"
20 #include "SkPDFBitmap.h" 20 #include "SkPDFBitmap.h"
21 #include "SkPDFCanon.h"
21 #include "SkPDFFont.h" 22 #include "SkPDFFont.h"
22 #include "SkPDFFormXObject.h" 23 #include "SkPDFFormXObject.h"
23 #include "SkPDFGraphicState.h" 24 #include "SkPDFGraphicState.h"
24 #include "SkPDFResourceDict.h" 25 #include "SkPDFResourceDict.h"
25 #include "SkPDFShader.h" 26 #include "SkPDFShader.h"
26 #include "SkPDFStream.h" 27 #include "SkPDFStream.h"
27 #include "SkPDFTypes.h" 28 #include "SkPDFTypes.h"
28 #include "SkPDFUtils.h" 29 #include "SkPDFUtils.h"
29 #include "SkRasterClip.h" 30 #include "SkRasterClip.h"
30 #include "SkRect.h" 31 #include "SkRect.h"
(...skipping 532 matching lines...) Expand 10 before | Expand all | Expand 10 after
563 fContentStream->writeText(" Tr\n"); 564 fContentStream->writeText(" Tr\n");
564 currentEntry()->fTextFill = state.fTextFill; 565 currentEntry()->fTextFill = state.fTextFill;
565 } 566 }
566 } 567 }
567 } 568 }
568 569
569 static bool not_supported_for_layers(const SkPaint& layerPaint) { 570 static bool not_supported_for_layers(const SkPaint& layerPaint) {
570 // PDF does not support image filters, so render them on CPU. 571 // PDF does not support image filters, so render them on CPU.
571 // Note that this rendering is done at "screen" resolution (100dpi), not 572 // Note that this rendering is done at "screen" resolution (100dpi), not
572 // printer resolution. 573 // printer resolution.
573 // FIXME: It may be possible to express some filters natively using PDF 574 // TODO: It may be possible to express some filters natively using PDF
574 // to improve quality and file size (http://skbug.com/3043) 575 // to improve quality and file size (http://skbug.com/3043)
575 576
576 // TODO: should we return true if there is a colorfilter? 577 // TODO: should we return true if there is a colorfilter?
577 return layerPaint.getImageFilter() != nullptr; 578 return layerPaint.getImageFilter() != nullptr;
578 } 579 }
579 580
580 SkBaseDevice* SkPDFDevice::onCreateDevice(const CreateInfo& cinfo, const SkPaint * layerPaint) { 581 SkBaseDevice* SkPDFDevice::onCreateDevice(const CreateInfo& cinfo, const SkPaint * layerPaint) {
581 if (cinfo.fForImageFilter || 582 if (cinfo.fForImageFilter ||
582 (layerPaint && not_supported_for_layers(*layerPaint))) { 583 (layerPaint && not_supported_for_layers(*layerPaint))) {
583 return nullptr; 584 return nullptr;
(...skipping 449 matching lines...) Expand 10 before | Expand all | Expand 10 after
1033 ScopedContentEntry content(this, d.fClipStack, *d.fClip, matrix, paint); 1034 ScopedContentEntry content(this, d.fClipStack, *d.fClip, matrix, paint);
1034 if (!content.entry()) { 1035 if (!content.entry()) {
1035 return; 1036 return;
1036 } 1037 }
1037 SkPDFUtils::EmitPath(*pathPtr, paint.getStyle(), 1038 SkPDFUtils::EmitPath(*pathPtr, paint.getStyle(),
1038 &content.entry()->fContent); 1039 &content.entry()->fContent);
1039 SkPDFUtils::PaintPath(paint.getStyle(), pathPtr->getFillType(), 1040 SkPDFUtils::PaintPath(paint.getStyle(), pathPtr->getFillType(),
1040 &content.entry()->fContent); 1041 &content.entry()->fContent);
1041 } 1042 }
1042 1043
1043 void SkPDFDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, 1044 void SkPDFDevice::drawBitmapRect(const SkDraw& draw,
1044 const SkRect* src, const SkRect& dst, 1045 const SkBitmap& bitmap,
1045 const SkPaint& srcPaint, SkCanvas::SrcRectConst raint constraint) { 1046 const SkRect* src,
1047 const SkRect& dst,
1048 const SkPaint& srcPaint,
1049 SkCanvas::SrcRectConstraint constraint) {
1050 const SkImage* image = fCanon->bitmapToImage(bitmap);
1051 if (!image) {
1052 return;
1053 }
1054 // ownership of this image is retained by the canon.
1055 this->drawImageRect(draw, image, src, dst, srcPaint, constraint);
1056 }
1057
1058 void SkPDFDevice::drawBitmap(const SkDraw& d,
1059 const SkBitmap& bitmap,
1060 const SkMatrix& matrix,
1061 const SkPaint& srcPaint) {
1046 SkPaint paint = srcPaint; 1062 SkPaint paint = srcPaint;
1047 if (bitmap.isOpaque()) { 1063 if (bitmap.isOpaque()) {
1048 replace_srcmode_on_opaque_paint(&paint); 1064 replace_srcmode_on_opaque_paint(&paint);
1049 } 1065 }
1050 1066
1067 if (d.fClip->isEmpty()) {
1068 return;
1069 }
1070
1071 SkMatrix transform = matrix;
1072 transform.postConcat(*d.fMatrix);
1073 const SkImage* image = fCanon->bitmapToImage(bitmap);
1074 if (!image) {
1075 return;
1076 }
1077 this->internalDrawImage(transform, d.fClipStack, *d.fClip, image, nullptr,
1078 paint);
1079 }
1080
1081 void SkPDFDevice::drawSprite(const SkDraw& d,
1082 const SkBitmap& bitmap,
1083 int x,
1084 int y,
1085 const SkPaint& srcPaint) {
1086 SkPaint paint = srcPaint;
1087 if (bitmap.isOpaque()) {
1088 replace_srcmode_on_opaque_paint(&paint);
1089 }
1090
1091 if (d.fClip->isEmpty()) {
1092 return;
1093 }
1094
1095 SkMatrix matrix;
1096 matrix.setTranslate(SkIntToScalar(x), SkIntToScalar(y));
1097 const SkImage* image = fCanon->bitmapToImage(bitmap);
1098 if (!image) {
1099 return;
1100 }
1101 this->internalDrawImage(matrix, d.fClipStack, *d.fClip, image, nullptr,
1102 paint);
1103 }
1104
1105 void SkPDFDevice::drawImage(const SkDraw& draw,
1106 const SkImage* image,
1107 SkScalar x,
1108 SkScalar y,
1109 const SkPaint& srcPaint) {
1110 SkPaint paint = srcPaint;
1111 if (!image) {
1112 return;
1113 }
1114 if (image->isOpaque()) {
1115 replace_srcmode_on_opaque_paint(&paint);
1116 }
1117 if (draw.fClip->isEmpty()) {
1118 return;
1119 }
1120 SkMatrix transform = SkMatrix::MakeTrans(x, y);
1121 transform.postConcat(*draw.fMatrix);
1122 this->internalDrawImage(transform, draw.fClipStack, *draw.fClip, image,
1123 nullptr, paint);
1124 }
1125
1126 void SkPDFDevice::drawImageRect(const SkDraw& draw,
1127 const SkImage* image,
1128 const SkRect* src,
1129 const SkRect& dst,
1130 const SkPaint& srcPaint,
1131 SkCanvas::SrcRectConstraint constraint) {
1132 if (!image) {
1133 return;
1134 }
1135 if (draw.fClip->isEmpty()) {
1136 return;
1137 }
1138 SkPaint paint = srcPaint;
1139 if (image->isOpaque()) {
1140 replace_srcmode_on_opaque_paint(&paint);
1141 }
1051 // TODO: this code path must be updated to respect the flags parameter 1142 // TODO: this code path must be updated to respect the flags parameter
1052 SkMatrix matrix; 1143 SkMatrix matrix;
1053 SkRect bitmapBounds, tmpSrc, tmpDst; 1144 SkRect tmpSrc, tmpDst;
1054 SkBitmap tmpBitmap; 1145 SkRect imageBounds = SkRect::Make(image->bounds());
1055
1056 bitmapBounds.isetWH(bitmap.width(), bitmap.height());
1057 1146
1058 // Compute matrix from the two rectangles 1147 // Compute matrix from the two rectangles
1059 if (src) { 1148 if (src) {
1060 tmpSrc = *src; 1149 tmpSrc = *src;
1061 } else { 1150 } else {
1062 tmpSrc = bitmapBounds; 1151 tmpSrc = imageBounds;
1063 } 1152 }
1064 matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit); 1153 matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
1065 1154
1066 const SkBitmap* bitmapPtr = &bitmap;
1067
1068 // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if 1155 // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if
1069 // needed (if the src was clipped). No check needed if src==null. 1156 // needed (if the src was clipped). No check needed if src==null.
1157 SkAutoTUnref<const SkImage> autoImageUnref;
1070 if (src) { 1158 if (src) {
1071 if (!bitmapBounds.contains(*src)) { 1159 if (!imageBounds.contains(*src)) {
1072 if (!tmpSrc.intersect(bitmapBounds)) { 1160 if (!tmpSrc.intersect(imageBounds)) {
1073 return; // nothing to draw 1161 return; // nothing to draw
1074 } 1162 }
1075 // recompute dst, based on the smaller tmpSrc 1163 // recompute dst, based on the smaller tmpSrc
1076 matrix.mapRect(&tmpDst, tmpSrc); 1164 matrix.mapRect(&tmpDst, tmpSrc);
1077 } 1165 }
1078 1166
1079 // since we may need to clamp to the borders of the src rect within 1167 // since we may need to clamp to the borders of the src rect within
1080 // the bitmap, we extract a subset. 1168 // the bitmap, we extract a subset.
1081 // TODO: make sure this is handled in drawBitmap and remove from here.
1082 SkIRect srcIR; 1169 SkIRect srcIR;
1083 tmpSrc.roundOut(&srcIR); 1170 tmpSrc.roundOut(&srcIR);
1084 if (!bitmap.extractSubset(&tmpBitmap, srcIR)) { 1171
1172 autoImageUnref.reset(image->newSubset(srcIR));
1173 if (!autoImageUnref) {
1085 return; 1174 return;
1086 } 1175 }
1087 bitmapPtr = &tmpBitmap; 1176 image = autoImageUnref;
1088
1089 // Since we did an extract, we need to adjust the matrix accordingly 1177 // Since we did an extract, we need to adjust the matrix accordingly
1090 SkScalar dx = 0, dy = 0; 1178 SkScalar dx = 0, dy = 0;
1091 if (srcIR.fLeft > 0) { 1179 if (srcIR.fLeft > 0) {
1092 dx = SkIntToScalar(srcIR.fLeft); 1180 dx = SkIntToScalar(srcIR.fLeft);
1093 } 1181 }
1094 if (srcIR.fTop > 0) { 1182 if (srcIR.fTop > 0) {
1095 dy = SkIntToScalar(srcIR.fTop); 1183 dy = SkIntToScalar(srcIR.fTop);
1096 } 1184 }
1097 if (dx || dy) { 1185 if (dx || dy) {
1098 matrix.preTranslate(dx, dy); 1186 matrix.preTranslate(dx, dy);
1099 } 1187 }
1100 } 1188 }
1101 this->drawBitmap(draw, *bitmapPtr, matrix, paint); 1189 matrix.postConcat(*draw.fMatrix);
1102 } 1190 this->internalDrawImage(matrix, draw.fClipStack, *draw.fClip, image,
1103 1191 nullptr, paint);
1104 void SkPDFDevice::drawBitmap(const SkDraw& d, const SkBitmap& bitmap,
1105 const SkMatrix& matrix, const SkPaint& srcPaint) {
1106 SkPaint paint = srcPaint;
1107 if (bitmap.isOpaque()) {
1108 replace_srcmode_on_opaque_paint(&paint);
1109 }
1110
1111 if (d.fClip->isEmpty()) {
1112 return;
1113 }
1114
1115 SkMatrix transform = matrix;
1116 transform.postConcat(*d.fMatrix);
1117 this->internalDrawBitmap(transform, d.fClipStack, *d.fClip, bitmap, nullptr,
1118 paint);
1119 }
1120
1121 void SkPDFDevice::drawSprite(const SkDraw& d, const SkBitmap& bitmap,
1122 int x, int y, const SkPaint& srcPaint) {
1123 SkPaint paint = srcPaint;
1124 if (bitmap.isOpaque()) {
1125 replace_srcmode_on_opaque_paint(&paint);
1126 }
1127
1128 if (d.fClip->isEmpty()) {
1129 return;
1130 }
1131
1132 SkMatrix matrix;
1133 matrix.setTranslate(SkIntToScalar(x), SkIntToScalar(y));
1134 this->internalDrawBitmap(matrix, d.fClipStack, *d.fClip, bitmap, nullptr,
1135 paint);
1136 } 1192 }
1137 1193
1138 // Create a PDF string. Maximum length (in bytes) is 65,535. 1194 // Create a PDF string. Maximum length (in bytes) is 65,535.
1139 // @param input A string value. 1195 // @param input A string value.
1140 // @param len The length of the input array. 1196 // @param len The length of the input array.
1141 // @param wideChars True iff the upper byte in each uint16_t is 1197 // @param wideChars True iff the upper byte in each uint16_t is
1142 // significant and should be encoded and not 1198 // significant and should be encoded and not
1143 // discarded. If true, the upper byte is encoded 1199 // discarded. If true, the upper byte is encoded
1144 // first. Otherwise, we assert the upper byte is 1200 // first. Otherwise, we assert the upper byte is
1145 // zero. 1201 // zero.
(...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after
1428 mediaBox->appendInt(0); 1484 mediaBox->appendInt(0);
1429 mediaBox->appendInt(0); 1485 mediaBox->appendInt(0);
1430 mediaBox->appendInt(fPageSize.fWidth); 1486 mediaBox->appendInt(fPageSize.fWidth);
1431 mediaBox->appendInt(fPageSize.fHeight); 1487 mediaBox->appendInt(fPageSize.fHeight);
1432 return mediaBox.detach(); 1488 return mediaBox.detach();
1433 } 1489 }
1434 1490
1435 SkStreamAsset* SkPDFDevice::content() const { 1491 SkStreamAsset* SkPDFDevice::content() const {
1436 SkDynamicMemoryWStream buffer; 1492 SkDynamicMemoryWStream buffer;
1437 this->writeContent(&buffer); 1493 this->writeContent(&buffer);
1438 return buffer.detachAsStream(); 1494 return buffer.bytesWritten() > 0
1495 ? buffer.detachAsStream()
1496 : new SkMemoryStream;
1439 } 1497 }
1440 1498
1441 void SkPDFDevice::copyContentEntriesToData(ContentEntry* entry, 1499 void SkPDFDevice::copyContentEntriesToData(ContentEntry* entry,
1442 SkWStream* data) const { 1500 SkWStream* data) const {
1443 // TODO(ctguil): For margins, I'm not sure fExistingClipStack/Region is the 1501 // TODO(ctguil): For margins, I'm not sure fExistingClipStack/Region is the
1444 // right thing to pass here. 1502 // right thing to pass here.
1445 GraphicStackState gsState(fExistingClipStack, fExistingClipRegion, data); 1503 GraphicStackState gsState(fExistingClipStack, fExistingClipRegion, data);
1446 while (entry != nullptr) { 1504 while (entry != nullptr) {
1447 SkPoint translation; 1505 SkPoint translation;
1448 translation.iset(this->getOrigin()); 1506 translation.iset(this->getOrigin());
(...skipping 614 matching lines...) Expand 10 before | Expand all | Expand 10 after
2063 SkPDFFont::GetFontResource(fCanon, typeface, glyphID)); 2121 SkPDFFont::GetFontResource(fCanon, typeface, glyphID));
2064 int resourceIndex = fFontResources.find(newFont.get()); 2122 int resourceIndex = fFontResources.find(newFont.get());
2065 if (resourceIndex < 0) { 2123 if (resourceIndex < 0) {
2066 resourceIndex = fFontResources.count(); 2124 resourceIndex = fFontResources.count();
2067 fFontResources.push(newFont.get()); 2125 fFontResources.push(newFont.get());
2068 newFont.get()->ref(); 2126 newFont.get()->ref();
2069 } 2127 }
2070 return resourceIndex; 2128 return resourceIndex;
2071 } 2129 }
2072 2130
2073 void SkPDFDevice::internalDrawBitmap(const SkMatrix& origMatrix, 2131 static SkSize rect_to_size(const SkRect& r) {
2074 const SkClipStack* clipStack, 2132 return SkSize::Make(r.width(), r.height());
2075 const SkRegion& origClipRegion, 2133 }
2076 const SkBitmap& origBitmap, 2134
2077 const SkIRect* srcRect, 2135 static const SkImage* color_filter(const SkImage* image,
2078 const SkPaint& paint) { 2136 SkColorFilter* colorFilter) {
2137 SkAutoTUnref<SkSurface> surface(SkSurface::NewRaster(
2138 SkImageInfo::MakeN32Premul(image->dimensions())));
2139 if (!surface) {
2140 return image;
2141 }
2142 SkCanvas* canvas = surface->getCanvas();
2143 canvas->clear(SK_ColorTRANSPARENT);
2144 SkPaint paint;
2145 paint.setColorFilter(colorFilter);
2146 canvas->drawImage(image, 0, 0, &paint);
2147 canvas->flush();
2148 return surface->newImageSnapshot();
2149 }
2150
2151 ////////////////////////////////////////////////////////////////////////////////
2152 void SkPDFDevice::internalDrawImage(const SkMatrix& origMatrix,
2153 const SkClipStack* clipStack,
2154 const SkRegion& origClipRegion,
2155 const SkImage* image,
2156 const SkIRect* srcRect,
2157 const SkPaint& paint) {
2158 SkASSERT(image);
2159 #ifdef SK_PDF_IMAGE_STATS
2160 gDrawImageCalls.fetch_add(1);
2161 #endif
2079 SkMatrix matrix = origMatrix; 2162 SkMatrix matrix = origMatrix;
2080 SkRegion perspectiveBounds; 2163 SkRegion perspectiveBounds;
2081 const SkRegion* clipRegion = &origClipRegion; 2164 const SkRegion* clipRegion = &origClipRegion;
2082 SkBitmap perspectiveBitmap; 2165 SkAutoTUnref<const SkImage> autoImageUnref;
2083 const SkBitmap* bitmap = &origBitmap;
2084 SkBitmap tmpSubsetBitmap;
2085 2166
2167 if (srcRect) {
2168 autoImageUnref.reset(image->newSubset(*srcRect));
2169 if (!autoImageUnref) {
2170 return;
2171 }
2172 image = autoImageUnref;
2173 }
2086 // Rasterize the bitmap using perspective in a new bitmap. 2174 // Rasterize the bitmap using perspective in a new bitmap.
2087 if (origMatrix.hasPerspective()) { 2175 if (origMatrix.hasPerspective()) {
2088 if (fRasterDpi == 0) { 2176 if (fRasterDpi == 0) {
2089 return; 2177 return;
2090 } 2178 }
2091 SkBitmap* subsetBitmap;
2092 if (srcRect) {
2093 if (!origBitmap.extractSubset(&tmpSubsetBitmap, *srcRect)) {
2094 return;
2095 }
2096 subsetBitmap = &tmpSubsetBitmap;
2097 } else {
2098 subsetBitmap = &tmpSubsetBitmap;
2099 *subsetBitmap = origBitmap;
2100 }
2101 srcRect = nullptr;
2102
2103 // Transform the bitmap in the new space, without taking into 2179 // Transform the bitmap in the new space, without taking into
2104 // account the initial transform. 2180 // account the initial transform.
2105 SkPath perspectiveOutline; 2181 SkPath perspectiveOutline;
2106 perspectiveOutline.addRect( 2182 SkRect imageBounds = SkRect::Make(image->bounds());
2107 SkRect::MakeWH(SkIntToScalar(subsetBitmap->width()), 2183 perspectiveOutline.addRect(imageBounds);
2108 SkIntToScalar(subsetBitmap->height())));
2109 perspectiveOutline.transform(origMatrix); 2184 perspectiveOutline.transform(origMatrix);
2110 2185
2111 // TODO(edisonn): perf - use current clip too. 2186 // TODO(edisonn): perf - use current clip too.
2112 // Retrieve the bounds of the new shape. 2187 // Retrieve the bounds of the new shape.
2113 SkRect bounds = perspectiveOutline.getBounds(); 2188 SkRect bounds = perspectiveOutline.getBounds();
2114 2189
2115 // Transform the bitmap in the new space, taking into 2190 // Transform the bitmap in the new space, taking into
2116 // account the initial transform. 2191 // account the initial transform.
2117 SkMatrix total = origMatrix; 2192 SkMatrix total = origMatrix;
2118 total.postConcat(fInitialTransform); 2193 total.postConcat(fInitialTransform);
2119 total.postScale(SkIntToScalar(fRasterDpi) / 2194 SkScalar dpiScale = SkIntToScalar(fRasterDpi) /
2120 SkIntToScalar(DPI_FOR_RASTER_SCALE_ONE), 2195 SkIntToScalar(DPI_FOR_RASTER_SCALE_ONE);
2121 SkIntToScalar(fRasterDpi) / 2196 total.postScale(dpiScale, dpiScale);
2122 SkIntToScalar(DPI_FOR_RASTER_SCALE_ONE)); 2197
2123 SkPath physicalPerspectiveOutline; 2198 SkPath physicalPerspectiveOutline;
2124 physicalPerspectiveOutline.addRect( 2199 physicalPerspectiveOutline.addRect(imageBounds);
2125 SkRect::MakeWH(SkIntToScalar(subsetBitmap->width()),
2126 SkIntToScalar(subsetBitmap->height())));
2127 physicalPerspectiveOutline.transform(total); 2200 physicalPerspectiveOutline.transform(total);
2128 2201
2129 SkScalar scaleX = physicalPerspectiveOutline.getBounds().width() / 2202 SkRect physicalPerspectiveBounds =
2130 bounds.width(); 2203 physicalPerspectiveOutline.getBounds();
2131 SkScalar scaleY = physicalPerspectiveOutline.getBounds().height() / 2204 SkScalar scaleX = physicalPerspectiveBounds.width() / bounds.width();
2132 bounds.height(); 2205 SkScalar scaleY = physicalPerspectiveBounds.height() / bounds.height();
2133 2206
2134 // TODO(edisonn): A better approach would be to use a bitmap shader 2207 // TODO(edisonn): A better approach would be to use a bitmap shader
2135 // (in clamp mode) and draw a rect over the entire bounding box. Then 2208 // (in clamp mode) and draw a rect over the entire bounding box. Then
2136 // intersect perspectiveOutline to the clip. That will avoid introducing 2209 // intersect perspectiveOutline to the clip. That will avoid introducing
2137 // alpha to the image while still giving good behavior at the edge of 2210 // alpha to the image while still giving good behavior at the edge of
2138 // the image. Avoiding alpha will reduce the pdf size and generation 2211 // the image. Avoiding alpha will reduce the pdf size and generation
2139 // CPU time some. 2212 // CPU time some.
2140 2213
2141 const int w = SkScalarCeilToInt(physicalPerspectiveOutline.getBounds().w idth()); 2214 SkISize wh = rect_to_size(physicalPerspectiveBounds).toCeil();
2142 const int h = SkScalarCeilToInt(physicalPerspectiveOutline.getBounds().h eight()); 2215
2143 if (!perspectiveBitmap.tryAllocN32Pixels(w, h)) { 2216 SkAutoTUnref<SkSurface> surface(
2217 SkSurface::NewRaster(SkImageInfo::MakeN32Premul(wh)));
2218 if (!surface) {
2144 return; 2219 return;
2145 } 2220 }
2146 perspectiveBitmap.eraseColor(SK_ColorTRANSPARENT); 2221 SkCanvas* canvas = surface->getCanvas();
2147 2222 canvas->clear(SK_ColorTRANSPARENT);
2148 SkCanvas canvas(perspectiveBitmap);
2149 2223
2150 SkScalar deltaX = bounds.left(); 2224 SkScalar deltaX = bounds.left();
2151 SkScalar deltaY = bounds.top(); 2225 SkScalar deltaY = bounds.top();
2152 2226
2153 SkMatrix offsetMatrix = origMatrix; 2227 SkMatrix offsetMatrix = origMatrix;
2154 offsetMatrix.postTranslate(-deltaX, -deltaY); 2228 offsetMatrix.postTranslate(-deltaX, -deltaY);
2155 offsetMatrix.postScale(scaleX, scaleY); 2229 offsetMatrix.postScale(scaleX, scaleY);
2156 2230
2157 // Translate the draw in the new canvas, so we perfectly fit the 2231 // Translate the draw in the new canvas, so we perfectly fit the
2158 // shape in the bitmap. 2232 // shape in the bitmap.
2159 canvas.setMatrix(offsetMatrix); 2233 canvas->setMatrix(offsetMatrix);
2160 2234 canvas->drawImage(image, 0, 0, nullptr);
2161 canvas.drawBitmap(*subsetBitmap, SkIntToScalar(0), SkIntToScalar(0));
2162
2163 // Make sure the final bits are in the bitmap. 2235 // Make sure the final bits are in the bitmap.
2164 canvas.flush(); 2236 canvas->flush();
2165 2237
2166 // In the new space, we use the identity matrix translated 2238 // In the new space, we use the identity matrix translated
2167 // and scaled to reflect DPI. 2239 // and scaled to reflect DPI.
2168 matrix.setScale(1 / scaleX, 1 / scaleY); 2240 matrix.setScale(1 / scaleX, 1 / scaleY);
2169 matrix.postTranslate(deltaX, deltaY); 2241 matrix.postTranslate(deltaX, deltaY);
2170 2242
2171 perspectiveBounds.setRect( 2243 perspectiveBounds.setRect(bounds.roundOut());
2172 SkIRect::MakeXYWH(SkScalarFloorToInt(bounds.x()),
2173 SkScalarFloorToInt(bounds.y()),
2174 SkScalarCeilToInt(bounds.width()),
2175 SkScalarCeilToInt(bounds.height())));
2176 clipRegion = &perspectiveBounds; 2244 clipRegion = &perspectiveBounds;
2177 srcRect = nullptr; 2245 srcRect = nullptr;
2178 bitmap = &perspectiveBitmap; 2246
2247 autoImageUnref.reset(surface->newImageSnapshot());
2248 image = autoImageUnref;
2179 } 2249 }
2180 2250
2181 SkMatrix scaled; 2251 SkMatrix scaled;
2182 // Adjust for origin flip. 2252 // Adjust for origin flip.
2183 scaled.setScale(SK_Scalar1, -SK_Scalar1); 2253 scaled.setScale(SK_Scalar1, -SK_Scalar1);
2184 scaled.postTranslate(0, SK_Scalar1); 2254 scaled.postTranslate(0, SK_Scalar1);
2185 // Scale the image up from 1x1 to WxH. 2255 // Scale the image up from 1x1 to WxH.
2186 SkIRect subset = bitmap->bounds(); 2256 SkIRect subset = image->bounds();
2187 scaled.postScale(SkIntToScalar(subset.width()), 2257 scaled.postScale(SkIntToScalar(image->width()),
2188 SkIntToScalar(subset.height())); 2258 SkIntToScalar(image->height()));
2189 scaled.postConcat(matrix); 2259 scaled.postConcat(matrix);
2190 ScopedContentEntry content(this, clipStack, *clipRegion, scaled, paint); 2260 ScopedContentEntry content(this, clipStack, *clipRegion, scaled, paint);
2191 if (!content.entry() || (srcRect && !subset.intersect(*srcRect))) { 2261 if (!content.entry() || (srcRect && !subset.intersect(*srcRect))) {
2192 return; 2262 return;
2193 } 2263 }
2194 if (content.needShape()) { 2264 if (content.needShape()) {
2195 SkPath shape; 2265 SkPath shape;
2196 shape.addRect(SkRect::MakeWH(SkIntToScalar(subset.width()), 2266 shape.addRect(SkRect::Make(subset));
2197 SkIntToScalar(subset.height())));
2198 shape.transform(matrix); 2267 shape.transform(matrix);
2199 content.setShape(shape); 2268 content.setShape(shape);
2200 } 2269 }
2201 if (!content.needSource()) { 2270 if (!content.needSource()) {
2202 return; 2271 return;
2203 } 2272 }
2204 2273
2205 SkBitmap subsetBitmap;
2206 if (!bitmap->extractSubset(&subsetBitmap, subset)) {
2207 return;
2208 }
2209 if (SkColorFilter* colorFilter = paint.getColorFilter()) { 2274 if (SkColorFilter* colorFilter = paint.getColorFilter()) {
2210 // TODO(http://skbug.com/4378): implement colorfilter on other 2275 // TODO(http://skbug.com/4378): implement colorfilter on other
2211 // draw calls. This code here works for all drawBitmap*() 2276 // draw calls. This code here works for all
2212 // calls amd ImageFilters (which rasterize a layer on this 2277 // drawBitmap*()/drawImage*() calls amd ImageFilters (which
2213 // backend). Fortuanely, this seems to be how Chromium 2278 // rasterize a layer on this backend). Fortuanely, this seems
2214 // impements most color-filters. 2279 // to be how Chromium impements most color-filters.
2215 SkBitmap tmp; 2280 autoImageUnref.reset(color_filter(image, colorFilter));
2216 if (subsetBitmap.copyTo(&tmp, kN32_SkColorType)) { 2281 image = autoImageUnref;
2217 SkAutoLockPixels autoLockPixelsTmp(tmp); 2282 // TODO(halcanary): de-dupe this by caching filtered images.
2218 for (int y = 0; y < tmp.height(); ++y) { 2283 // (maybe in the resource cache?)
2219 SkPMColor* pixels = tmp.getAddr32(0, y); 2284 }
2220 colorFilter->filterSpan(pixels, tmp.width(), pixels); 2285 SkAutoTUnref<SkPDFObject> pdfimage(fCanon->findPDFBitmap(image));
2221 } 2286 if (!pdfimage) {
2222 tmp.setImmutable(); 2287 pdfimage.reset(SkPDFCreateBitmapObject(image));
2223 subsetBitmap = tmp; 2288 if (!pdfimage) {
2289 return;
2224 } 2290 }
2291 fCanon->addPDFBitmap(image->uniqueID(), pdfimage);
2225 } 2292 }
2226 SkAutoTUnref<SkPDFObject> image(SkPDFBitmap::Create(fCanon, subsetBitmap)); 2293 SkPDFUtils::DrawFormXObject(this->addXObjectResource(SkRef(pdfimage.get())),
2227 if (!image) {
2228 return;
2229 }
2230
2231 SkPDFUtils::DrawFormXObject(this->addXObjectResource(image.get()),
2232 &content.entry()->fContent); 2294 &content.entry()->fContent);
2233 } 2295 }
OLDNEW
« no previous file with comments | « src/pdf/SkPDFDevice.h ('k') | src/pdf/SkPDFTypes.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698