| Index: src/pdf/SkPDFDevice.cpp
|
| diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
|
| index eda3616a1f7681a1fcd7c2c9895a1c6a8ee74781..410b04992615caabb291ec9952c8c71b265705b7 100644
|
| --- a/src/pdf/SkPDFDevice.cpp
|
| +++ b/src/pdf/SkPDFDevice.cpp
|
| @@ -327,6 +327,96 @@ static void emit_clip(SkPath* clipPath, SkRect* clipRect,
|
| }
|
| }
|
|
|
| +#ifdef SK_PDF_USE_PATHOPS
|
| +/* Calculate an inverted path's equivalent non-inverted path, given the
|
| + * canvas bounds.
|
| + * outPath may alias with invPath (since this is supported by PathOps).
|
| + */
|
| +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);
|
| +}
|
| +
|
| +// Sanity check the numerical values of the SkRegion ops and PathOps ops
|
| +// enums so region_op_to_pathops_op can do a straight passthrough cast.
|
| +// If these are failing, it may be necessary to make region_op_to_pathops_op
|
| +// do more.
|
| +SK_COMPILE_ASSERT(SkRegion::kDifference_Op == (int)kDifference_PathOp,
|
| + region_pathop_mismatch);
|
| +SK_COMPILE_ASSERT(SkRegion::kIntersect_Op == (int)kIntersect_PathOp,
|
| + region_pathop_mismatch);
|
| +SK_COMPILE_ASSERT(SkRegion::kUnion_Op == (int)kUnion_PathOp,
|
| + region_pathop_mismatch);
|
| +SK_COMPILE_ASSERT(SkRegion::kXOR_Op == (int)kXOR_PathOp,
|
| + region_pathop_mismatch);
|
| +SK_COMPILE_ASSERT(SkRegion::kReverseDifference_Op ==
|
| + (int)kReverseDifference_PathOp,
|
| + region_pathop_mismatch);
|
| +
|
| +static SkPathOp region_op_to_pathops_op(SkRegion::Op op) {
|
| + SkASSERT(op >= 0);
|
| + SkASSERT(op <= SkRegion::kReverseDifference_Op);
|
| + return (SkPathOp)op;
|
| +}
|
| +
|
| +/* Uses Path Ops to calculate a vector SkPath clip from a clip stack.
|
| + * Returns true if successful, or false if not successful.
|
| + * If successful, the resulting clip is stored in outClipPath.
|
| + * If not successful, outClipPath is undefined, and a fallback method
|
| + * should be used.
|
| + */
|
| +static bool get_clip_stack_path(const SkMatrix& transform,
|
| + const SkClipStack& clipStack,
|
| + const SkRegion& clipRegion,
|
| + SkPath* outClipPath) {
|
| + outClipPath->reset();
|
| + outClipPath->setFillType(SkPath::kInverseWinding_FillType);
|
| +
|
| + const SkClipStack::Element* clipEntry;
|
| + SkClipStack::Iter iter;
|
| + iter.reset(clipStack, SkClipStack::Iter::kBottom_IterStart);
|
| + for (clipEntry = iter.next(); clipEntry; clipEntry = iter.next()) {
|
| + SkPath entryPath;
|
| + if (SkClipStack::Element::kEmpty_Type == clipEntry->getType()) {
|
| + outClipPath->reset();
|
| + outClipPath->setFillType(SkPath::kInverseWinding_FillType);
|
| + continue;
|
| + } else if (SkClipStack::Element::kRect_Type == clipEntry->getType()) {
|
| + entryPath.addRect(clipEntry->getRect());
|
| + } else if (SkClipStack::Element::kPath_Type == clipEntry->getType()) {
|
| + entryPath = clipEntry->getPath();
|
| + }
|
| + entryPath.transform(transform);
|
| +
|
| + if (SkRegion::kReplace_Op == clipEntry->getOp()) {
|
| + *outClipPath = entryPath;
|
| + } else {
|
| + SkPathOp op = region_op_to_pathops_op(clipEntry->getOp());
|
| + if (!Op(*outClipPath, entryPath, op, outClipPath)) {
|
| + return false;
|
| + }
|
| + }
|
| + }
|
| +
|
| + if (outClipPath->isInverseFillType()) {
|
| + // The bounds are slightly outset to ensure this is correct in the
|
| + // face of floating-point accuracy and possible SkRegion bitmap
|
| + // approximations.
|
| + SkRect clipBounds = SkRect::Make(clipRegion.getBounds());
|
| + clipBounds.outset(SK_Scalar1, SK_Scalar1);
|
| + if (!calculate_inverse_path(clipBounds, *outClipPath, outClipPath)) {
|
| + return false;
|
| + }
|
| + }
|
| + return true;
|
| +}
|
| +#endif
|
| +
|
| // TODO(vandebo): Take advantage of SkClipStack::getSaveCount(), the PDF
|
| // graphic state stack, and the fact that we can know all the clips used
|
| // on the page to optimize this.
|
| @@ -345,6 +435,19 @@ void GraphicStackState::updateClip(const SkClipStack& clipStack,
|
| }
|
| push();
|
|
|
| + currentEntry()->fClipStack = clipStack;
|
| + currentEntry()->fClipRegion = clipRegion;
|
| +
|
| + SkMatrix transform;
|
| + transform.setTranslate(translation.fX, translation.fY);
|
| +
|
| +#ifdef SK_PDF_USE_PATHOPS
|
| + SkPath clipPath;
|
| + if (get_clip_stack_path(transform, clipStack, clipRegion, &clipPath)) {
|
| + emit_clip(&clipPath, NULL, fContentStream);
|
| + return;
|
| + }
|
| +#endif
|
| // gsState->initialEntry()->fClipStack/Region specifies the clip that has
|
| // already been applied. (If this is a top level device, then it specifies
|
| // a clip to the content area. If this is a layer, then it specifies
|
| @@ -373,8 +476,6 @@ void GraphicStackState::updateClip(const SkClipStack& clipStack,
|
| emit_clip(&clipPath, NULL, fContentStream);
|
| } else {
|
| skip_clip_stack_prefix(fEntries[0].fClipStack, clipStack, &iter);
|
| - SkMatrix transform;
|
| - transform.setTranslate(translation.fX, translation.fY);
|
| const SkClipStack::Element* clipEntry;
|
| for (clipEntry = iter.next(); clipEntry; clipEntry = iter.next()) {
|
| SkASSERT(clipEntry->getOp() == SkRegion::kIntersect_Op);
|
| @@ -396,8 +497,6 @@ void GraphicStackState::updateClip(const SkClipStack& clipStack,
|
| }
|
| }
|
| }
|
| - currentEntry()->fClipStack = clipStack;
|
| - currentEntry()->fClipRegion = clipRegion;
|
| }
|
|
|
| void GraphicStackState::updateMatrix(const SkMatrix& matrix) {
|
| @@ -1239,19 +1338,7 @@ 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);
|
| -}
|
| -
|
| +#ifdef SK_PDF_USE_PATHOPS
|
| /* 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,
|
| @@ -1312,6 +1399,7 @@ bool SkPDFDevice::handleInversePath(const SkDraw& d, const SkPath& origPath,
|
| drawPath(d, modifiedPath, noInversePaint, NULL, true);
|
| return true;
|
| }
|
| +#endif
|
|
|
| bool SkPDFDevice::handleRectAnnotation(const SkRect& r, const SkMatrix& matrix,
|
| const SkPaint& p) {
|
|
|