Index: src/pdf/SkPDFDevice.cpp |
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp |
index 387bfe836148b7715c3be37189e3d8e7e64dc670..eda3616a1f7681a1fcd7c2c9895a1c6a8ee74781 100644 |
--- a/src/pdf/SkPDFDevice.cpp |
+++ b/src/pdf/SkPDFDevice.cpp |
@@ -16,6 +16,7 @@ |
#include "SkGlyphCache.h" |
#include "SkPaint.h" |
#include "SkPath.h" |
+#include "SkPathOps.h" |
#include "SkPDFFont.h" |
#include "SkPDFFormXObject.h" |
#include "SkPDFGraphicState.h" |
@@ -842,6 +843,12 @@ void SkPDFDevice::drawPath(const SkDraw& d, const SkPath& origPath, |
return; |
} |
+#ifdef SK_PDF_USE_PATHOPS |
+ if (handleInversePath(d, origPath, paint, pathIsMutable)) { |
+ return; |
+ } |
+#endif |
+ |
if (handleRectAnnotation(pathPtr->getBounds(), *d.fMatrix, paint)) { |
return; |
} |
@@ -1232,6 +1239,80 @@ SkData* SkPDFDevice::copyContentToData() const { |
return data.copyToData(); |
} |
+/* Calculate an inverted path's equivalent non-inverted path, given the |
+ * canvas bounds. |
+ */ |
+static bool calculate_inverse_path(const SkRect& bounds, const SkPath& invPath, |
+ SkPath* outPath) { |
+ SkASSERT(invPath.isInverseFillType()); |
+ |
+ SkPath clipPath; |
+ clipPath.addRect(bounds); |
+ |
+ return Op(clipPath, invPath, kIntersect_PathOp, outPath); |
+} |
+ |
+/* Draws an inverse filled path by using Path Ops to compute the positive |
+ * inverse using the current clip as the inverse bounds. |
+ * Return true if this was an inverse path and was properly handled, |
+ * otherwise returns false and the normal drawing routine should continue, |
+ * either as a (incorrect) fallback or because the path was not inverse |
+ * in the first place. |
+ */ |
+bool SkPDFDevice::handleInversePath(const SkDraw& d, const SkPath& origPath, |
+ const SkPaint& paint, bool pathIsMutable) { |
+ if (!origPath.isInverseFillType()) { |
+ return false; |
+ } |
+ |
+ if (d.fClip->isEmpty()) { |
+ return false; |
+ } |
+ |
+ SkPath modifiedPath; |
+ SkPath* pathPtr = const_cast<SkPath*>(&origPath); |
+ SkPaint noInversePaint(paint); |
+ |
+ // Merge stroking operations into final path. |
+ if (SkPaint::kStroke_Style == paint.getStyle() || |
+ SkPaint::kStrokeAndFill_Style == paint.getStyle()) { |
+ bool doFillPath = paint.getFillPath(origPath, &modifiedPath); |
+ if (doFillPath) { |
+ noInversePaint.setStyle(SkPaint::kFill_Style); |
+ noInversePaint.setStrokeWidth(0); |
+ pathPtr = &modifiedPath; |
+ } else { |
+ // To be consistent with the raster output, hairline strokes |
+ // are rendered as non-inverted. |
+ modifiedPath.toggleInverseFillType(); |
+ drawPath(d, modifiedPath, paint, NULL, true); |
+ return true; |
+ } |
+ } |
+ |
+ // Get bounds of clip in current transform space |
+ // (clip bounds are given in device space). |
+ SkRect bounds; |
+ SkMatrix transformInverse; |
+ if (!d.fMatrix->invert(&transformInverse)) { |
+ return false; |
+ } |
+ bounds.set(d.fClip->getBounds()); |
+ transformInverse.mapRect(&bounds); |
+ |
+ // Extend the bounds by the line width (plus some padding) |
+ // so the edge doesn't cause a visible stroke. |
+ bounds.outset(paint.getStrokeWidth() + SK_Scalar1, |
+ paint.getStrokeWidth() + SK_Scalar1); |
+ |
+ if (!calculate_inverse_path(bounds, *pathPtr, &modifiedPath)) { |
+ return false; |
+ } |
+ |
+ drawPath(d, modifiedPath, noInversePaint, NULL, true); |
+ return true; |
+} |
+ |
bool SkPDFDevice::handleRectAnnotation(const SkRect& r, const SkMatrix& matrix, |
const SkPaint& p) { |
SkAnnotation* annotationInfo = p.getAnnotation(); |