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 "SkClipStack.h" | 12 #include "SkClipStack.h" |
13 #include "SkData.h" | 13 #include "SkData.h" |
14 #include "SkDraw.h" | 14 #include "SkDraw.h" |
15 #include "SkFontHost.h" | 15 #include "SkFontHost.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 "SkPDFFont.h" | 20 #include "SkPDFFont.h" |
20 #include "SkPDFFormXObject.h" | 21 #include "SkPDFFormXObject.h" |
21 #include "SkPDFGraphicState.h" | 22 #include "SkPDFGraphicState.h" |
22 #include "SkPDFImage.h" | 23 #include "SkPDFImage.h" |
23 #include "SkPDFResourceDict.h" | 24 #include "SkPDFResourceDict.h" |
24 #include "SkPDFShader.h" | 25 #include "SkPDFShader.h" |
25 #include "SkPDFStream.h" | 26 #include "SkPDFStream.h" |
26 #include "SkPDFTypes.h" | 27 #include "SkPDFTypes.h" |
27 #include "SkPDFUtils.h" | 28 #include "SkPDFUtils.h" |
28 #include "SkRect.h" | 29 #include "SkRect.h" |
(...skipping 806 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
835 if (fill) { | 836 if (fill) { |
836 noEffectPaint.setStyle(SkPaint::kFill_Style); | 837 noEffectPaint.setStyle(SkPaint::kFill_Style); |
837 } else { | 838 } else { |
838 noEffectPaint.setStyle(SkPaint::kStroke_Style); | 839 noEffectPaint.setStyle(SkPaint::kStroke_Style); |
839 noEffectPaint.setStrokeWidth(0); | 840 noEffectPaint.setStrokeWidth(0); |
840 } | 841 } |
841 drawPath(d, *pathPtr, noEffectPaint, NULL, true); | 842 drawPath(d, *pathPtr, noEffectPaint, NULL, true); |
842 return; | 843 return; |
843 } | 844 } |
844 | 845 |
| 846 #ifdef SK_PDF_USE_PATHOPS |
| 847 if (handleInversePath(d, origPath, paint, pathIsMutable)) { |
| 848 return; |
| 849 } |
| 850 #endif |
| 851 |
845 if (handleRectAnnotation(pathPtr->getBounds(), *d.fMatrix, paint)) { | 852 if (handleRectAnnotation(pathPtr->getBounds(), *d.fMatrix, paint)) { |
846 return; | 853 return; |
847 } | 854 } |
848 | 855 |
849 ScopedContentEntry content(this, d, paint); | 856 ScopedContentEntry content(this, d, paint); |
850 if (!content.entry()) { | 857 if (!content.entry()) { |
851 return; | 858 return; |
852 } | 859 } |
853 SkPDFUtils::EmitPath(*pathPtr, paint.getStyle(), | 860 SkPDFUtils::EmitPath(*pathPtr, paint.getStyle(), |
854 &content.entry()->fContent); | 861 &content.entry()->fContent); |
(...skipping 370 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1225 emit_clip(NULL, &r, &data); | 1232 emit_clip(NULL, &r, &data); |
1226 } | 1233 } |
1227 | 1234 |
1228 SkPDFDevice::copyContentEntriesToData(fContentEntries.get(), &data); | 1235 SkPDFDevice::copyContentEntriesToData(fContentEntries.get(), &data); |
1229 | 1236 |
1230 // potentially we could cache this SkData, and only rebuild it if we | 1237 // potentially we could cache this SkData, and only rebuild it if we |
1231 // see that our state has changed. | 1238 // see that our state has changed. |
1232 return data.copyToData(); | 1239 return data.copyToData(); |
1233 } | 1240 } |
1234 | 1241 |
| 1242 /* Calculate an inverted path's equivalent non-inverted path, given the |
| 1243 * canvas bounds. |
| 1244 */ |
| 1245 static bool calculate_inverse_path(const SkRect& bounds, const SkPath& invPath, |
| 1246 SkPath* outPath) { |
| 1247 SkASSERT(invPath.isInverseFillType()); |
| 1248 |
| 1249 SkPath clipPath; |
| 1250 clipPath.addRect(bounds); |
| 1251 |
| 1252 return Op(clipPath, invPath, kIntersect_PathOp, outPath); |
| 1253 } |
| 1254 |
| 1255 /* Draws an inverse filled path by using Path Ops to compute the positive |
| 1256 * inverse using the current clip as the inverse bounds. |
| 1257 * Return true if this was an inverse path and was properly handled, |
| 1258 * otherwise returns false and the normal drawing routine should continue, |
| 1259 * either as a (incorrect) fallback or because the path was not inverse |
| 1260 * in the first place. |
| 1261 */ |
| 1262 bool SkPDFDevice::handleInversePath(const SkDraw& d, const SkPath& origPath, |
| 1263 const SkPaint& paint, bool pathIsMutable) { |
| 1264 if (!origPath.isInverseFillType()) { |
| 1265 return false; |
| 1266 } |
| 1267 |
| 1268 if (d.fClip->isEmpty()) { |
| 1269 return false; |
| 1270 } |
| 1271 |
| 1272 SkPath modifiedPath; |
| 1273 SkPath* pathPtr = const_cast<SkPath*>(&origPath); |
| 1274 SkPaint noInversePaint(paint); |
| 1275 |
| 1276 // Merge stroking operations into final path. |
| 1277 if (SkPaint::kStroke_Style == paint.getStyle() || |
| 1278 SkPaint::kStrokeAndFill_Style == paint.getStyle()) { |
| 1279 bool doFillPath = paint.getFillPath(origPath, &modifiedPath); |
| 1280 if (doFillPath) { |
| 1281 noInversePaint.setStyle(SkPaint::kFill_Style); |
| 1282 noInversePaint.setStrokeWidth(0); |
| 1283 pathPtr = &modifiedPath; |
| 1284 } else { |
| 1285 // To be consistent with the raster output, hairline strokes |
| 1286 // are rendered as non-inverted. |
| 1287 modifiedPath.toggleInverseFillType(); |
| 1288 drawPath(d, modifiedPath, paint, NULL, true); |
| 1289 return true; |
| 1290 } |
| 1291 } |
| 1292 |
| 1293 // Get bounds of clip in current transform space |
| 1294 // (clip bounds are given in device space). |
| 1295 SkRect bounds; |
| 1296 SkMatrix transformInverse; |
| 1297 if (!d.fMatrix->invert(&transformInverse)) { |
| 1298 return false; |
| 1299 } |
| 1300 bounds.set(d.fClip->getBounds()); |
| 1301 transformInverse.mapRect(&bounds); |
| 1302 |
| 1303 // Extend the bounds by the line width (plus some padding) |
| 1304 // so the edge doesn't cause a visible stroke. |
| 1305 bounds.outset(paint.getStrokeWidth() + SK_Scalar1, |
| 1306 paint.getStrokeWidth() + SK_Scalar1); |
| 1307 |
| 1308 if (!calculate_inverse_path(bounds, *pathPtr, &modifiedPath)) { |
| 1309 return false; |
| 1310 } |
| 1311 |
| 1312 drawPath(d, modifiedPath, noInversePaint, NULL, true); |
| 1313 return true; |
| 1314 } |
| 1315 |
1235 bool SkPDFDevice::handleRectAnnotation(const SkRect& r, const SkMatrix& matrix, | 1316 bool SkPDFDevice::handleRectAnnotation(const SkRect& r, const SkMatrix& matrix, |
1236 const SkPaint& p) { | 1317 const SkPaint& p) { |
1237 SkAnnotation* annotationInfo = p.getAnnotation(); | 1318 SkAnnotation* annotationInfo = p.getAnnotation(); |
1238 if (!annotationInfo) { | 1319 if (!annotationInfo) { |
1239 return false; | 1320 return false; |
1240 } | 1321 } |
1241 SkData* urlData = annotationInfo->find(SkAnnotationKeys::URL_Key()); | 1322 SkData* urlData = annotationInfo->find(SkAnnotationKeys::URL_Key()); |
1242 if (urlData) { | 1323 if (urlData) { |
1243 handleLinkToURL(urlData, r, matrix); | 1324 handleLinkToURL(urlData, r, matrix); |
1244 return p.isNoDrawAnnotation(); | 1325 return p.isNoDrawAnnotation(); |
(...skipping 506 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1751 } | 1832 } |
1752 | 1833 |
1753 bool SkPDFDevice::onReadPixels(const SkBitmap& bitmap, int x, int y, | 1834 bool SkPDFDevice::onReadPixels(const SkBitmap& bitmap, int x, int y, |
1754 SkCanvas::Config8888) { | 1835 SkCanvas::Config8888) { |
1755 return false; | 1836 return false; |
1756 } | 1837 } |
1757 | 1838 |
1758 bool SkPDFDevice::allowImageFilter(SkImageFilter*) { | 1839 bool SkPDFDevice::allowImageFilter(SkImageFilter*) { |
1759 return false; | 1840 return false; |
1760 } | 1841 } |
OLD | NEW |