aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/pdf
diff options
context:
space:
mode:
authorGravatar Hal Canary <halcanary@google.com>2018-06-05 11:53:58 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-06-05 17:36:29 +0000
commitd00ef066198b40aa0b02603fe4766b31996eb835 (patch)
tree62e884f91ae914ed20335c9657ef13a713c653d5 /src/pdf
parentbd04be76ad9739dd1b67aca6a8a3ef4cf6d1c228 (diff)
SkPDF: Fastpath for clipstack flattening
BUG: chromium:837279 Change-Id: I79a675e7d9e713617711948e491e28babe06b1a2 Reviewed-on: https://skia-review.googlesource.com/132092 Auto-Submit: Hal Canary <halcanary@google.com> Commit-Queue: Ben Wagner <bungeman@google.com> Reviewed-by: Ben Wagner <bungeman@google.com>
Diffstat (limited to 'src/pdf')
-rw-r--r--src/pdf/SkPDFDevice.cpp94
1 files changed, 72 insertions, 22 deletions
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
index ced94ce9a9..1cf649c1a1 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -283,49 +283,99 @@ bool apply_clip(SkClipOp op, const SkPath& u, const SkPath& v, SkPath* r) {
}
}
-// 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.
-void GraphicStackState::updateClip(const SkClipStack& clipStack,
- const SkIRect& bounds) {
- if (clipStack == currentEntry()->fClipStack) {
- return;
- }
-
- while (fStackDepth > 0) {
- pop();
- if (clipStack == currentEntry()->fClipStack) {
- return;
+static SkRect rect_intersect(SkRect u, SkRect v) {
+ if (u.isEmpty() || v.isEmpty()) { return {0, 0, 0, 0}; }
+ return u.intersect(v) ? u : SkRect{0, 0, 0, 0};
+}
+
+// Test to see if the clipstack is a simple rect, If so, we can avoid all PathOps code
+// and speed thing up.
+static bool is_rect(const SkClipStack& clipStack, const SkRect& bounds, SkRect* dst) {
+ SkRect currentClip = bounds;
+ SkClipStack::Iter iter(clipStack, SkClipStack::Iter::kBottom_IterStart);
+ while (const SkClipStack::Element* element = iter.next()) {
+ SkRect elementRect{0, 0, 0, 0};
+ switch (element->getDeviceSpaceType()) {
+ case SkClipStack::Element::DeviceSpaceType::kEmpty:
+ break;
+ case SkClipStack::Element::DeviceSpaceType::kRect:
+ elementRect = element->getDeviceSpaceRect();
+ break;
+ default:
+ return false;
+ }
+ switch (element->getOp()) {
+ case kReplace_SkClipOp:
+ currentClip = rect_intersect(bounds, elementRect);
+ break;
+ case SkClipOp::kIntersect:
+ currentClip = rect_intersect(currentClip, elementRect);
+ break;
+ default:
+ return false;
}
}
- push();
+ *dst = currentClip;
+ return true;
+}
- currentEntry()->fClipStack = clipStack;
+static void append_clip(const SkClipStack& clipStack,
+ const SkIRect& bounds,
+ SkWStream* wStream) {
+ // The bounds are slightly outset to ensure this is correct in the
+ // face of floating-point accuracy and possible SkRegion bitmap
+ // approximations.
+ SkRect outsetBounds = SkRect::Make(bounds.makeOutset(1, 1));
+
+ SkRect clipStackRect;
+ if (is_rect(clipStack, outsetBounds, &clipStackRect)) {
+ SkPDFUtils::AppendRectangle(clipStackRect, wStream);
+ wStream->writeText("W* n\n");
+ return;
+ }
SkPath clipPath;
(void)clipStack.asPath(&clipPath);
- // The bounds are slightly outset to ensure this is correct in the
- // face of floating-point accuracy and possible SkRegion bitmap
- // approximations.
SkPath clipBoundsPath;
- clipBoundsPath.addRect(SkRect::Make(bounds.makeOutset(1, 1)));
+ clipBoundsPath.addRect(outsetBounds);
if (Op(clipPath, clipBoundsPath, kIntersect_SkPathOp, &clipPath)) {
- SkPDFUtils::EmitPath(clipPath, SkPaint::kFill_Style, fContentStream);
+ SkPDFUtils::EmitPath(clipPath, SkPaint::kFill_Style, wStream);
SkPath::FillType clipFill = clipPath.getFillType();
NOT_IMPLEMENTED(clipFill == SkPath::kInverseEvenOdd_FillType, false);
NOT_IMPLEMENTED(clipFill == SkPath::kInverseWinding_FillType, false);
if (clipFill == SkPath::kEvenOdd_FillType) {
- fContentStream->writeText("W* n\n");
+ wStream->writeText("W* n\n");
} else {
- fContentStream->writeText("W n\n");
+ wStream->writeText("W n\n");
}
}
// If Op() fails (pathological case; e.g. input values are
// extremely large or NaN), emit no clip at all.
}
+// 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.
+void GraphicStackState::updateClip(const SkClipStack& clipStack,
+ const SkIRect& bounds) {
+ if (clipStack == currentEntry()->fClipStack) {
+ return;
+ }
+
+ while (fStackDepth > 0) {
+ pop();
+ if (clipStack == currentEntry()->fClipStack) {
+ return;
+ }
+ }
+ push();
+
+ currentEntry()->fClipStack = clipStack;
+ append_clip(clipStack, bounds, fContentStream);
+}
+
void GraphicStackState::updateMatrix(const SkMatrix& matrix) {
if (matrix == currentEntry()->fMatrix) {
return;