OLD | NEW |
---|---|
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 1002 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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; | 1155 // FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME |
tomhudson
2015/09/30 16:10:30
Not ready to land?
hal.canary
2015/10/01 01:24:55
Done.
| |
1067 | 1156 |
1068 // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if | 1157 // 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. | 1158 // needed (if the src was clipped). No check needed if src==null. |
1159 SkAutoTUnref<const SkImage> autoImageUnref; | |
1070 if (src) { | 1160 if (src) { |
1071 if (!bitmapBounds.contains(*src)) { | 1161 if (!imageBounds.contains(*src)) { |
1072 if (!tmpSrc.intersect(bitmapBounds)) { | 1162 if (!tmpSrc.intersect(imageBounds)) { |
1073 return; // nothing to draw | 1163 return; // nothing to draw |
1074 } | 1164 } |
1075 // recompute dst, based on the smaller tmpSrc | 1165 // recompute dst, based on the smaller tmpSrc |
1076 matrix.mapRect(&tmpDst, tmpSrc); | 1166 matrix.mapRect(&tmpDst, tmpSrc); |
1077 } | 1167 } |
1078 | 1168 |
1079 // since we may need to clamp to the borders of the src rect within | 1169 // since we may need to clamp to the borders of the src rect within |
1080 // the bitmap, we extract a subset. | 1170 // the bitmap, we extract a subset. |
1081 // TODO: make sure this is handled in drawBitmap and remove from here. | 1171 // TODO: make sure this is handled in drawBitmap and remove from here. |
1082 SkIRect srcIR; | 1172 SkIRect srcIR; |
1083 tmpSrc.roundOut(&srcIR); | 1173 tmpSrc.roundOut(&srcIR); |
1084 if (!bitmap.extractSubset(&tmpBitmap, srcIR)) { | 1174 |
1175 autoImageUnref.reset(image->newSubset(srcIR)); | |
1176 if (!autoImageUnref) { | |
1085 return; | 1177 return; |
1086 } | 1178 } |
1087 bitmapPtr = &tmpBitmap; | 1179 image = autoImageUnref; |
1088 | |
1089 // Since we did an extract, we need to adjust the matrix accordingly | 1180 // Since we did an extract, we need to adjust the matrix accordingly |
1090 SkScalar dx = 0, dy = 0; | 1181 SkScalar dx = 0, dy = 0; |
1091 if (srcIR.fLeft > 0) { | 1182 if (srcIR.fLeft > 0) { |
1092 dx = SkIntToScalar(srcIR.fLeft); | 1183 dx = SkIntToScalar(srcIR.fLeft); |
1093 } | 1184 } |
1094 if (srcIR.fTop > 0) { | 1185 if (srcIR.fTop > 0) { |
1095 dy = SkIntToScalar(srcIR.fTop); | 1186 dy = SkIntToScalar(srcIR.fTop); |
1096 } | 1187 } |
1097 if (dx || dy) { | 1188 if (dx || dy) { |
1098 matrix.preTranslate(dx, dy); | 1189 matrix.preTranslate(dx, dy); |
1099 } | 1190 } |
1100 } | 1191 } |
1101 this->drawBitmap(draw, *bitmapPtr, matrix, paint); | 1192 matrix.postConcat(*draw.fMatrix); |
1102 } | 1193 this->internalDrawImage(matrix, draw.fClipStack, *draw.fClip, image, |
1103 | 1194 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 } | 1195 } |
1137 | 1196 |
1138 // Create a PDF string. Maximum length (in bytes) is 65,535. | 1197 // Create a PDF string. Maximum length (in bytes) is 65,535. |
1139 // @param input A string value. | 1198 // @param input A string value. |
1140 // @param len The length of the input array. | 1199 // @param len The length of the input array. |
1141 // @param wideChars True iff the upper byte in each uint16_t is | 1200 // @param wideChars True iff the upper byte in each uint16_t is |
1142 // significant and should be encoded and not | 1201 // significant and should be encoded and not |
1143 // discarded. If true, the upper byte is encoded | 1202 // discarded. If true, the upper byte is encoded |
1144 // first. Otherwise, we assert the upper byte is | 1203 // first. Otherwise, we assert the upper byte is |
1145 // zero. | 1204 // zero. |
(...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1428 mediaBox->appendInt(0); | 1487 mediaBox->appendInt(0); |
1429 mediaBox->appendInt(0); | 1488 mediaBox->appendInt(0); |
1430 mediaBox->appendInt(fPageSize.fWidth); | 1489 mediaBox->appendInt(fPageSize.fWidth); |
1431 mediaBox->appendInt(fPageSize.fHeight); | 1490 mediaBox->appendInt(fPageSize.fHeight); |
1432 return mediaBox.detach(); | 1491 return mediaBox.detach(); |
1433 } | 1492 } |
1434 | 1493 |
1435 SkStreamAsset* SkPDFDevice::content() const { | 1494 SkStreamAsset* SkPDFDevice::content() const { |
1436 SkDynamicMemoryWStream buffer; | 1495 SkDynamicMemoryWStream buffer; |
1437 this->writeContent(&buffer); | 1496 this->writeContent(&buffer); |
1438 return buffer.detachAsStream(); | 1497 return buffer.bytesWritten() > 0 |
1498 ? buffer.detachAsStream() | |
1499 : new SkMemoryStream; | |
1439 } | 1500 } |
1440 | 1501 |
1441 void SkPDFDevice::copyContentEntriesToData(ContentEntry* entry, | 1502 void SkPDFDevice::copyContentEntriesToData(ContentEntry* entry, |
1442 SkWStream* data) const { | 1503 SkWStream* data) const { |
1443 // TODO(ctguil): For margins, I'm not sure fExistingClipStack/Region is the | 1504 // TODO(ctguil): For margins, I'm not sure fExistingClipStack/Region is the |
1444 // right thing to pass here. | 1505 // right thing to pass here. |
1445 GraphicStackState gsState(fExistingClipStack, fExistingClipRegion, data); | 1506 GraphicStackState gsState(fExistingClipStack, fExistingClipRegion, data); |
1446 while (entry != nullptr) { | 1507 while (entry != nullptr) { |
1447 SkPoint translation; | 1508 SkPoint translation; |
1448 translation.iset(this->getOrigin()); | 1509 translation.iset(this->getOrigin()); |
(...skipping 614 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2063 SkPDFFont::GetFontResource(fCanon, typeface, glyphID)); | 2124 SkPDFFont::GetFontResource(fCanon, typeface, glyphID)); |
2064 int resourceIndex = fFontResources.find(newFont.get()); | 2125 int resourceIndex = fFontResources.find(newFont.get()); |
2065 if (resourceIndex < 0) { | 2126 if (resourceIndex < 0) { |
2066 resourceIndex = fFontResources.count(); | 2127 resourceIndex = fFontResources.count(); |
2067 fFontResources.push(newFont.get()); | 2128 fFontResources.push(newFont.get()); |
2068 newFont.get()->ref(); | 2129 newFont.get()->ref(); |
2069 } | 2130 } |
2070 return resourceIndex; | 2131 return resourceIndex; |
2071 } | 2132 } |
2072 | 2133 |
2073 void SkPDFDevice::internalDrawBitmap(const SkMatrix& origMatrix, | 2134 static SkSize rect_to_size(const SkRect& r) { |
2074 const SkClipStack* clipStack, | 2135 return SkSize::Make(r.width(), r.height()); |
2075 const SkRegion& origClipRegion, | 2136 } |
2076 const SkBitmap& origBitmap, | 2137 |
2077 const SkIRect* srcRect, | 2138 static const SkImage* color_filter(const SkImage* image, |
2078 const SkPaint& paint) { | 2139 SkColorFilter* colorFilter) { |
2140 SkAutoTUnref<SkSurface> surface(SkSurface::NewRaster( | |
2141 SkImageInfo::MakeN32Premul(image->dimensions()))); | |
2142 if (!surface) { | |
2143 return image; | |
2144 } | |
2145 SkCanvas* canvas = surface->getCanvas(); | |
2146 canvas->clear(SK_ColorTRANSPARENT); | |
2147 SkPaint paint; | |
2148 paint.setColorFilter(colorFilter); | |
2149 canvas->drawImage(image, 0, 0, &paint); | |
2150 canvas->flush(); | |
2151 return surface->newImageSnapshot(); | |
2152 } | |
2153 | |
2154 //////////////////////////////////////////////////////////////////////////////// | |
2155 void SkPDFDevice::internalDrawImage(const SkMatrix& origMatrix, | |
2156 const SkClipStack* clipStack, | |
2157 const SkRegion& origClipRegion, | |
2158 const SkImage* image, | |
2159 const SkIRect* srcRect, | |
2160 const SkPaint& paint) { | |
2161 SkASSERT(image); | |
2162 #ifdef SK_PDF_IMAGE_STATS | |
2163 gDrawImageCalls.fetch_add(1); | |
2164 #endif | |
2079 SkMatrix matrix = origMatrix; | 2165 SkMatrix matrix = origMatrix; |
2080 SkRegion perspectiveBounds; | 2166 SkRegion perspectiveBounds; |
2081 const SkRegion* clipRegion = &origClipRegion; | 2167 const SkRegion* clipRegion = &origClipRegion; |
2082 SkBitmap perspectiveBitmap; | 2168 SkAutoTUnref<const SkImage> autoImageUnref; |
2083 const SkBitmap* bitmap = &origBitmap; | |
2084 SkBitmap tmpSubsetBitmap; | |
2085 | 2169 |
2170 if (srcRect) { | |
2171 autoImageUnref.reset(image->newSubset(*srcRect)); | |
2172 if (!autoImageUnref) { | |
2173 return; | |
2174 } | |
2175 image = autoImageUnref; | |
2176 } | |
2086 // Rasterize the bitmap using perspective in a new bitmap. | 2177 // Rasterize the bitmap using perspective in a new bitmap. |
2087 if (origMatrix.hasPerspective()) { | 2178 if (origMatrix.hasPerspective()) { |
2088 if (fRasterDpi == 0) { | 2179 if (fRasterDpi == 0) { |
2089 return; | 2180 return; |
2090 } | 2181 } |
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 | 2182 // Transform the bitmap in the new space, without taking into |
2104 // account the initial transform. | 2183 // account the initial transform. |
2105 SkPath perspectiveOutline; | 2184 SkPath perspectiveOutline; |
2106 perspectiveOutline.addRect( | 2185 SkRect imageBounds = SkRect::Make(image->bounds()); |
2107 SkRect::MakeWH(SkIntToScalar(subsetBitmap->width()), | 2186 perspectiveOutline.addRect(imageBounds); |
2108 SkIntToScalar(subsetBitmap->height()))); | |
2109 perspectiveOutline.transform(origMatrix); | 2187 perspectiveOutline.transform(origMatrix); |
2110 | 2188 |
2111 // TODO(edisonn): perf - use current clip too. | 2189 // TODO(edisonn): perf - use current clip too. |
2112 // Retrieve the bounds of the new shape. | 2190 // Retrieve the bounds of the new shape. |
2113 SkRect bounds = perspectiveOutline.getBounds(); | 2191 SkRect bounds = perspectiveOutline.getBounds(); |
2114 | 2192 |
2115 // Transform the bitmap in the new space, taking into | 2193 // Transform the bitmap in the new space, taking into |
2116 // account the initial transform. | 2194 // account the initial transform. |
2117 SkMatrix total = origMatrix; | 2195 SkMatrix total = origMatrix; |
2118 total.postConcat(fInitialTransform); | 2196 total.postConcat(fInitialTransform); |
2119 total.postScale(SkIntToScalar(fRasterDpi) / | 2197 SkScalar dpiScale = SkIntToScalar(fRasterDpi) / |
2120 SkIntToScalar(DPI_FOR_RASTER_SCALE_ONE), | 2198 SkIntToScalar(DPI_FOR_RASTER_SCALE_ONE); |
2121 SkIntToScalar(fRasterDpi) / | 2199 total.postScale(dpiScale, dpiScale); |
2122 SkIntToScalar(DPI_FOR_RASTER_SCALE_ONE)); | 2200 |
2123 SkPath physicalPerspectiveOutline; | 2201 SkPath physicalPerspectiveOutline; |
2124 physicalPerspectiveOutline.addRect( | 2202 physicalPerspectiveOutline.addRect(imageBounds); |
2125 SkRect::MakeWH(SkIntToScalar(subsetBitmap->width()), | |
2126 SkIntToScalar(subsetBitmap->height()))); | |
2127 physicalPerspectiveOutline.transform(total); | 2203 physicalPerspectiveOutline.transform(total); |
2128 | 2204 |
2129 SkScalar scaleX = physicalPerspectiveOutline.getBounds().width() / | 2205 SkRect physicalPerspectiveBounds = |
2130 bounds.width(); | 2206 physicalPerspectiveOutline.getBounds(); |
2131 SkScalar scaleY = physicalPerspectiveOutline.getBounds().height() / | 2207 SkScalar scaleX = physicalPerspectiveBounds.width() / bounds.width(); |
2132 bounds.height(); | 2208 SkScalar scaleY = physicalPerspectiveBounds.height() / bounds.height(); |
2133 | 2209 |
2134 // TODO(edisonn): A better approach would be to use a bitmap shader | 2210 // 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 | 2211 // (in clamp mode) and draw a rect over the entire bounding box. Then |
2136 // intersect perspectiveOutline to the clip. That will avoid introducing | 2212 // intersect perspectiveOutline to the clip. That will avoid introducing |
2137 // alpha to the image while still giving good behavior at the edge of | 2213 // 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 | 2214 // the image. Avoiding alpha will reduce the pdf size and generation |
2139 // CPU time some. | 2215 // CPU time some. |
2140 | 2216 |
2141 const int w = SkScalarCeilToInt(physicalPerspectiveOutline.getBounds().w idth()); | 2217 SkISize wh = rect_to_size(physicalPerspectiveBounds).toCeil(); |
2142 const int h = SkScalarCeilToInt(physicalPerspectiveOutline.getBounds().h eight()); | 2218 |
2143 if (!perspectiveBitmap.tryAllocN32Pixels(w, h)) { | 2219 SkAutoTUnref<SkSurface> surface( |
2220 SkSurface::NewRaster(SkImageInfo::MakeN32Premul(wh))); | |
2221 if (!surface) { | |
2144 return; | 2222 return; |
2145 } | 2223 } |
2146 perspectiveBitmap.eraseColor(SK_ColorTRANSPARENT); | 2224 SkCanvas* canvas = surface->getCanvas(); |
2147 | 2225 canvas->clear(SK_ColorTRANSPARENT); |
2148 SkCanvas canvas(perspectiveBitmap); | |
2149 | 2226 |
2150 SkScalar deltaX = bounds.left(); | 2227 SkScalar deltaX = bounds.left(); |
2151 SkScalar deltaY = bounds.top(); | 2228 SkScalar deltaY = bounds.top(); |
2152 | 2229 |
2153 SkMatrix offsetMatrix = origMatrix; | 2230 SkMatrix offsetMatrix = origMatrix; |
2154 offsetMatrix.postTranslate(-deltaX, -deltaY); | 2231 offsetMatrix.postTranslate(-deltaX, -deltaY); |
2155 offsetMatrix.postScale(scaleX, scaleY); | 2232 offsetMatrix.postScale(scaleX, scaleY); |
2156 | 2233 |
2157 // Translate the draw in the new canvas, so we perfectly fit the | 2234 // Translate the draw in the new canvas, so we perfectly fit the |
2158 // shape in the bitmap. | 2235 // shape in the bitmap. |
2159 canvas.setMatrix(offsetMatrix); | 2236 canvas->setMatrix(offsetMatrix); |
2160 | 2237 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. | 2238 // Make sure the final bits are in the bitmap. |
2164 canvas.flush(); | 2239 canvas->flush(); |
2165 | 2240 |
2166 // In the new space, we use the identity matrix translated | 2241 // In the new space, we use the identity matrix translated |
2167 // and scaled to reflect DPI. | 2242 // and scaled to reflect DPI. |
2168 matrix.setScale(1 / scaleX, 1 / scaleY); | 2243 matrix.setScale(1 / scaleX, 1 / scaleY); |
2169 matrix.postTranslate(deltaX, deltaY); | 2244 matrix.postTranslate(deltaX, deltaY); |
2170 | 2245 |
2171 perspectiveBounds.setRect( | 2246 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; | 2247 clipRegion = &perspectiveBounds; |
2177 srcRect = nullptr; | 2248 srcRect = nullptr; |
2178 bitmap = &perspectiveBitmap; | 2249 |
2250 autoImageUnref.reset(surface->newImageSnapshot()); | |
2251 image = autoImageUnref; | |
2179 } | 2252 } |
2180 | 2253 |
2181 SkMatrix scaled; | 2254 SkMatrix scaled; |
2182 // Adjust for origin flip. | 2255 // Adjust for origin flip. |
2183 scaled.setScale(SK_Scalar1, -SK_Scalar1); | 2256 scaled.setScale(SK_Scalar1, -SK_Scalar1); |
2184 scaled.postTranslate(0, SK_Scalar1); | 2257 scaled.postTranslate(0, SK_Scalar1); |
2185 // Scale the image up from 1x1 to WxH. | 2258 // Scale the image up from 1x1 to WxH. |
2186 SkIRect subset = bitmap->bounds(); | 2259 SkIRect subset = image->bounds(); |
2187 scaled.postScale(SkIntToScalar(subset.width()), | 2260 scaled.postScale(SkIntToScalar(image->width()), |
2188 SkIntToScalar(subset.height())); | 2261 SkIntToScalar(image->height())); |
2189 scaled.postConcat(matrix); | 2262 scaled.postConcat(matrix); |
2190 ScopedContentEntry content(this, clipStack, *clipRegion, scaled, paint); | 2263 ScopedContentEntry content(this, clipStack, *clipRegion, scaled, paint); |
2191 if (!content.entry() || (srcRect && !subset.intersect(*srcRect))) { | 2264 if (!content.entry() || (srcRect && !subset.intersect(*srcRect))) { |
2192 return; | 2265 return; |
2193 } | 2266 } |
2194 if (content.needShape()) { | 2267 if (content.needShape()) { |
2195 SkPath shape; | 2268 SkPath shape; |
2196 shape.addRect(SkRect::MakeWH(SkIntToScalar(subset.width()), | 2269 shape.addRect(SkRect::Make(subset)); |
2197 SkIntToScalar(subset.height()))); | |
2198 shape.transform(matrix); | 2270 shape.transform(matrix); |
2199 content.setShape(shape); | 2271 content.setShape(shape); |
2200 } | 2272 } |
2201 if (!content.needSource()) { | 2273 if (!content.needSource()) { |
2202 return; | 2274 return; |
2203 } | 2275 } |
2204 | 2276 |
2205 SkBitmap subsetBitmap; | |
2206 if (!bitmap->extractSubset(&subsetBitmap, subset)) { | |
2207 return; | |
2208 } | |
2209 if (SkColorFilter* colorFilter = paint.getColorFilter()) { | 2277 if (SkColorFilter* colorFilter = paint.getColorFilter()) { |
2210 // TODO(http://skbug.com/4378): implement colorfilter on other | 2278 // TODO(http://skbug.com/4378): implement colorfilter on other |
2211 // draw calls. This code here works for all drawBitmap*() | 2279 // draw calls. This code here works for all |
2212 // calls amd ImageFilters (which rasterize a layer on this | 2280 // drawBitmap*()/drawImage*() calls amd ImageFilters (which |
2213 // backend). Fortuanely, this seems to be how Chromium | 2281 // rasterize a layer on this backend). Fortuanely, this seems |
2214 // impements most color-filters. | 2282 // to be how Chromium impements most color-filters. |
2215 SkBitmap tmp; | 2283 autoImageUnref.reset(color_filter(image, colorFilter)); |
2216 if (subsetBitmap.copyTo(&tmp, kN32_SkColorType)) { | 2284 image = autoImageUnref; |
2217 SkAutoLockPixels autoLockPixelsTmp(tmp); | 2285 // TODO(halcanary): de-dupe this by caching filtered images. |
2218 for (int y = 0; y < tmp.height(); ++y) { | 2286 // (maybe in the resource cache?) |
2219 SkPMColor* pixels = tmp.getAddr32(0, y); | 2287 } |
2220 colorFilter->filterSpan(pixels, tmp.width(), pixels); | 2288 SkAutoTUnref<SkPDFObject> pdfimage(fCanon->findPDFBitmap(image)); |
2221 } | 2289 if (!pdfimage) { |
2222 tmp.setImmutable(); | 2290 pdfimage.reset(SkPDFCreateBitmapObject(image)); |
2223 subsetBitmap = tmp; | 2291 if (!pdfimage) { |
2292 return; | |
2224 } | 2293 } |
2294 fCanon->addPDFBitmap(image->uniqueID(), pdfimage); | |
2225 } | 2295 } |
2226 SkAutoTUnref<SkPDFObject> image(SkPDFBitmap::Create(fCanon, subsetBitmap)); | 2296 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); | 2297 &content.entry()->fContent); |
2233 } | 2298 } |
OLD | NEW |