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>
This commit is contained in:
parent
bd04be76ad
commit
d00ef06619
@ -283,6 +283,78 @@ bool apply_clip(SkClipOp op, const SkPath& u, const SkPath& v, SkPath* r) {
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
*dst = currentClip;
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
SkPath clipBoundsPath;
|
||||
clipBoundsPath.addRect(outsetBounds);
|
||||
|
||||
if (Op(clipPath, clipBoundsPath, kIntersect_SkPathOp, &clipPath)) {
|
||||
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) {
|
||||
wStream->writeText("W* n\n");
|
||||
} else {
|
||||
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.
|
||||
@ -301,29 +373,7 @@ void GraphicStackState::updateClip(const SkClipStack& clipStack,
|
||||
push();
|
||||
|
||||
currentEntry()->fClipStack = clipStack;
|
||||
|
||||
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)));
|
||||
|
||||
if (Op(clipPath, clipBoundsPath, kIntersect_SkPathOp, &clipPath)) {
|
||||
SkPDFUtils::EmitPath(clipPath, SkPaint::kFill_Style, fContentStream);
|
||||
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");
|
||||
} else {
|
||||
fContentStream->writeText("W n\n");
|
||||
}
|
||||
}
|
||||
// If Op() fails (pathological case; e.g. input values are
|
||||
// extremely large or NaN), emit no clip at all.
|
||||
append_clip(clipStack, bounds, fContentStream);
|
||||
}
|
||||
|
||||
void GraphicStackState::updateMatrix(const SkMatrix& matrix) {
|
||||
|
Loading…
Reference in New Issue
Block a user