| 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 |
| 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 this->internalDrawImage(matrix, draw.fClipStack, *draw.fClip, image, |
| 1102 } | 1193 nullptr, paint); |
| 1103 | |
| 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 } | 1194 } |
| 1137 | 1195 |
| 1138 // Create a PDF string. Maximum length (in bytes) is 65,535. | 1196 // Create a PDF string. Maximum length (in bytes) is 65,535. |
| 1139 // @param input A string value. | 1197 // @param input A string value. |
| 1140 // @param len The length of the input array. | 1198 // @param len The length of the input array. |
| 1141 // @param wideChars True iff the upper byte in each uint16_t is | 1199 // @param wideChars True iff the upper byte in each uint16_t is |
| 1142 // significant and should be encoded and not | 1200 // significant and should be encoded and not |
| 1143 // discarded. If true, the upper byte is encoded | 1201 // discarded. If true, the upper byte is encoded |
| 1144 // first. Otherwise, we assert the upper byte is | 1202 // first. Otherwise, we assert the upper byte is |
| 1145 // zero. | 1203 // zero. |
| (...skipping 917 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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); |
| 2079 SkMatrix matrix = origMatrix; | 2159 SkMatrix matrix = origMatrix; |
| 2080 SkRegion perspectiveBounds; | 2160 SkRegion perspectiveBounds; |
| 2081 const SkRegion* clipRegion = &origClipRegion; | 2161 const SkRegion* clipRegion = &origClipRegion; |
| 2082 SkBitmap perspectiveBitmap; | 2162 SkAutoTUnref<const SkImage> autoImageUnref; |
| 2083 const SkBitmap* bitmap = &origBitmap; | |
| 2084 SkBitmap tmpSubsetBitmap; | |
| 2085 | 2163 |
| 2164 if (srcRect) { |
| 2165 autoImageUnref.reset(image->newSubset(*srcRect)); |
| 2166 if (!autoImageUnref) { |
| 2167 return; |
| 2168 } |
| 2169 image = autoImageUnref; |
| 2170 } |
| 2086 // Rasterize the bitmap using perspective in a new bitmap. | 2171 // Rasterize the bitmap using perspective in a new bitmap. |
| 2087 if (origMatrix.hasPerspective()) { | 2172 if (origMatrix.hasPerspective()) { |
| 2088 if (fRasterDpi == 0) { | 2173 if (fRasterDpi == 0) { |
| 2089 return; | 2174 return; |
| 2090 } | 2175 } |
| 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 | 2176 // Transform the bitmap in the new space, without taking into |
| 2104 // account the initial transform. | 2177 // account the initial transform. |
| 2105 SkPath perspectiveOutline; | 2178 SkPath perspectiveOutline; |
| 2106 perspectiveOutline.addRect( | 2179 SkRect imageBounds = SkRect::Make(image->bounds()); |
| 2107 SkRect::MakeWH(SkIntToScalar(subsetBitmap->width()), | 2180 perspectiveOutline.addRect(imageBounds); |
| 2108 SkIntToScalar(subsetBitmap->height()))); | |
| 2109 perspectiveOutline.transform(origMatrix); | 2181 perspectiveOutline.transform(origMatrix); |
| 2110 | 2182 |
| 2111 // TODO(edisonn): perf - use current clip too. | 2183 // TODO(edisonn): perf - use current clip too. |
| 2112 // Retrieve the bounds of the new shape. | 2184 // Retrieve the bounds of the new shape. |
| 2113 SkRect bounds = perspectiveOutline.getBounds(); | 2185 SkRect bounds = perspectiveOutline.getBounds(); |
| 2114 | 2186 |
| 2115 // Transform the bitmap in the new space, taking into | 2187 // Transform the bitmap in the new space, taking into |
| 2116 // account the initial transform. | 2188 // account the initial transform. |
| 2117 SkMatrix total = origMatrix; | 2189 SkMatrix total = origMatrix; |
| 2118 total.postConcat(fInitialTransform); | 2190 total.postConcat(fInitialTransform); |
| 2119 total.postScale(SkIntToScalar(fRasterDpi) / | 2191 SkScalar dpiScale = SkIntToScalar(fRasterDpi) / |
| 2120 SkIntToScalar(DPI_FOR_RASTER_SCALE_ONE), | 2192 SkIntToScalar(DPI_FOR_RASTER_SCALE_ONE); |
| 2121 SkIntToScalar(fRasterDpi) / | 2193 total.postScale(dpiScale, dpiScale); |
| 2122 SkIntToScalar(DPI_FOR_RASTER_SCALE_ONE)); | 2194 |
| 2123 SkPath physicalPerspectiveOutline; | 2195 SkPath physicalPerspectiveOutline; |
| 2124 physicalPerspectiveOutline.addRect( | 2196 physicalPerspectiveOutline.addRect(imageBounds); |
| 2125 SkRect::MakeWH(SkIntToScalar(subsetBitmap->width()), | |
| 2126 SkIntToScalar(subsetBitmap->height()))); | |
| 2127 physicalPerspectiveOutline.transform(total); | 2197 physicalPerspectiveOutline.transform(total); |
| 2128 | 2198 |
| 2129 SkScalar scaleX = physicalPerspectiveOutline.getBounds().width() / | 2199 SkRect physicalPerspectiveBounds = |
| 2130 bounds.width(); | 2200 physicalPerspectiveOutline.getBounds(); |
| 2131 SkScalar scaleY = physicalPerspectiveOutline.getBounds().height() / | 2201 SkScalar scaleX = physicalPerspectiveBounds.width() / bounds.width(); |
| 2132 bounds.height(); | 2202 SkScalar scaleY = physicalPerspectiveBounds.height() / bounds.height(); |
| 2133 | 2203 |
| 2134 // TODO(edisonn): A better approach would be to use a bitmap shader | 2204 // 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 | 2205 // (in clamp mode) and draw a rect over the entire bounding box. Then |
| 2136 // intersect perspectiveOutline to the clip. That will avoid introducing | 2206 // intersect perspectiveOutline to the clip. That will avoid introducing |
| 2137 // alpha to the image while still giving good behavior at the edge of | 2207 // 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 | 2208 // the image. Avoiding alpha will reduce the pdf size and generation |
| 2139 // CPU time some. | 2209 // CPU time some. |
| 2140 | 2210 |
| 2141 const int w = SkScalarCeilToInt(physicalPerspectiveOutline.getBounds().w
idth()); | 2211 SkISize wh = rect_to_size(physicalPerspectiveBounds).toCeil(); |
| 2142 const int h = SkScalarCeilToInt(physicalPerspectiveOutline.getBounds().h
eight()); | 2212 |
| 2143 if (!perspectiveBitmap.tryAllocN32Pixels(w, h)) { | 2213 SkAutoTUnref<SkSurface> surface( |
| 2214 SkSurface::NewRaster(SkImageInfo::MakeN32Premul(wh))); |
| 2215 if (!surface) { |
| 2144 return; | 2216 return; |
| 2145 } | 2217 } |
| 2146 perspectiveBitmap.eraseColor(SK_ColorTRANSPARENT); | 2218 SkCanvas* canvas = surface->getCanvas(); |
| 2147 | 2219 canvas->clear(SK_ColorTRANSPARENT); |
| 2148 SkCanvas canvas(perspectiveBitmap); | |
| 2149 | 2220 |
| 2150 SkScalar deltaX = bounds.left(); | 2221 SkScalar deltaX = bounds.left(); |
| 2151 SkScalar deltaY = bounds.top(); | 2222 SkScalar deltaY = bounds.top(); |
| 2152 | 2223 |
| 2153 SkMatrix offsetMatrix = origMatrix; | 2224 SkMatrix offsetMatrix = origMatrix; |
| 2154 offsetMatrix.postTranslate(-deltaX, -deltaY); | 2225 offsetMatrix.postTranslate(-deltaX, -deltaY); |
| 2155 offsetMatrix.postScale(scaleX, scaleY); | 2226 offsetMatrix.postScale(scaleX, scaleY); |
| 2156 | 2227 |
| 2157 // Translate the draw in the new canvas, so we perfectly fit the | 2228 // Translate the draw in the new canvas, so we perfectly fit the |
| 2158 // shape in the bitmap. | 2229 // shape in the bitmap. |
| 2159 canvas.setMatrix(offsetMatrix); | 2230 canvas->setMatrix(offsetMatrix); |
| 2160 | 2231 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. | 2232 // Make sure the final bits are in the bitmap. |
| 2164 canvas.flush(); | 2233 canvas->flush(); |
| 2165 | 2234 |
| 2166 // In the new space, we use the identity matrix translated | 2235 // In the new space, we use the identity matrix translated |
| 2167 // and scaled to reflect DPI. | 2236 // and scaled to reflect DPI. |
| 2168 matrix.setScale(1 / scaleX, 1 / scaleY); | 2237 matrix.setScale(1 / scaleX, 1 / scaleY); |
| 2169 matrix.postTranslate(deltaX, deltaY); | 2238 matrix.postTranslate(deltaX, deltaY); |
| 2170 | 2239 |
| 2171 perspectiveBounds.setRect( | 2240 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; | 2241 clipRegion = &perspectiveBounds; |
| 2177 srcRect = nullptr; | 2242 srcRect = nullptr; |
| 2178 bitmap = &perspectiveBitmap; | 2243 |
| 2244 autoImageUnref.reset(surface->newImageSnapshot()); |
| 2245 image = autoImageUnref; |
| 2179 } | 2246 } |
| 2180 | 2247 |
| 2181 SkMatrix scaled; | 2248 SkMatrix scaled; |
| 2182 // Adjust for origin flip. | 2249 // Adjust for origin flip. |
| 2183 scaled.setScale(SK_Scalar1, -SK_Scalar1); | 2250 scaled.setScale(SK_Scalar1, -SK_Scalar1); |
| 2184 scaled.postTranslate(0, SK_Scalar1); | 2251 scaled.postTranslate(0, SK_Scalar1); |
| 2185 // Scale the image up from 1x1 to WxH. | 2252 // Scale the image up from 1x1 to WxH. |
| 2186 SkIRect subset = bitmap->bounds(); | 2253 SkIRect subset = image->bounds(); |
| 2187 scaled.postScale(SkIntToScalar(subset.width()), | 2254 scaled.postScale(SkIntToScalar(image->width()), |
| 2188 SkIntToScalar(subset.height())); | 2255 SkIntToScalar(image->height())); |
| 2189 scaled.postConcat(matrix); | 2256 scaled.postConcat(matrix); |
| 2190 ScopedContentEntry content(this, clipStack, *clipRegion, scaled, paint); | 2257 ScopedContentEntry content(this, clipStack, *clipRegion, scaled, paint); |
| 2191 if (!content.entry() || (srcRect && !subset.intersect(*srcRect))) { | 2258 if (!content.entry() || (srcRect && !subset.intersect(*srcRect))) { |
| 2192 return; | 2259 return; |
| 2193 } | 2260 } |
| 2194 if (content.needShape()) { | 2261 if (content.needShape()) { |
| 2195 SkPath shape; | 2262 SkPath shape; |
| 2196 shape.addRect(SkRect::MakeWH(SkIntToScalar(subset.width()), | 2263 shape.addRect(SkRect::Make(subset)); |
| 2197 SkIntToScalar(subset.height()))); | |
| 2198 shape.transform(matrix); | 2264 shape.transform(matrix); |
| 2199 content.setShape(shape); | 2265 content.setShape(shape); |
| 2200 } | 2266 } |
| 2201 if (!content.needSource()) { | 2267 if (!content.needSource()) { |
| 2202 return; | 2268 return; |
| 2203 } | 2269 } |
| 2204 | 2270 |
| 2205 SkBitmap subsetBitmap; | |
| 2206 if (!bitmap->extractSubset(&subsetBitmap, subset)) { | |
| 2207 return; | |
| 2208 } | |
| 2209 if (SkColorFilter* colorFilter = paint.getColorFilter()) { | 2271 if (SkColorFilter* colorFilter = paint.getColorFilter()) { |
| 2210 // TODO(http://skbug.com/4378): implement colorfilter on other | 2272 // TODO(http://skbug.com/4378): implement colorfilter on other |
| 2211 // draw calls. This code here works for all drawBitmap*() | 2273 // draw calls. This code here works for all |
| 2212 // calls amd ImageFilters (which rasterize a layer on this | 2274 // drawBitmap*()/drawImage*() calls amd ImageFilters (which |
| 2213 // backend). Fortuanely, this seems to be how Chromium | 2275 // rasterize a layer on this backend). Fortuanely, this seems |
| 2214 // impements most color-filters. | 2276 // to be how Chromium impements most color-filters. |
| 2215 SkBitmap tmp; | 2277 autoImageUnref.reset(color_filter(image, colorFilter)); |
| 2216 if (subsetBitmap.copyTo(&tmp, kN32_SkColorType)) { | 2278 image = autoImageUnref; |
| 2217 SkAutoLockPixels autoLockPixelsTmp(tmp); | 2279 // TODO(halcanary): de-dupe this by caching filtered images. |
| 2218 for (int y = 0; y < tmp.height(); ++y) { | 2280 // (maybe in the resource cache?) |
| 2219 SkPMColor* pixels = tmp.getAddr32(0, y); | 2281 } |
| 2220 colorFilter->filterSpan(pixels, tmp.width(), pixels); | 2282 SkAutoTUnref<SkPDFObject> pdfimage(fCanon->findPDFBitmap(image)); |
| 2221 } | 2283 if (!pdfimage) { |
| 2222 tmp.setImmutable(); | 2284 pdfimage.reset(SkPDFCreateBitmapObject(image)); |
| 2223 subsetBitmap = tmp; | 2285 if (!pdfimage) { |
| 2286 return; |
| 2224 } | 2287 } |
| 2288 fCanon->addPDFBitmap(image->uniqueID(), pdfimage); |
| 2225 } | 2289 } |
| 2226 SkAutoTUnref<SkPDFObject> image(SkPDFBitmap::Create(fCanon, subsetBitmap)); | 2290 SkPDFUtils::DrawFormXObject(this->addXObjectResource(pdfimage.get()), |
| 2227 if (!image) { | |
| 2228 return; | |
| 2229 } | |
| 2230 | |
| 2231 SkPDFUtils::DrawFormXObject(this->addXObjectResource(image.get()), | |
| 2232 &content.entry()->fContent); | 2291 &content.entry()->fContent); |
| 2233 } | 2292 } |
| OLD | NEW |