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. staticbool 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: returnfalse;
} if (element->isReplaceOp()) {
currentClip = rect_intersect(bounds, elementRect);
} elseif (element->getOp() == SkClipOp::kIntersect) {
currentClip = rect_intersect(currentClip, elementRect);
} else { returnfalse;
}
}
*dst = currentClip; returntrue;
}
// TODO: When there's no expanding clip ops, this function may not be necessary anymore. staticbool is_complex_clip(const SkClipStack& stack) {
SkClipStack::Iter iter(stack, SkClipStack::Iter::kBottom_IterStart); while (const SkClipStack::Element* element = iter.next()) { if (element->isReplaceOp()) { returntrue;
}
} returnfalse;
}
template <typename F> staticvoid apply_clip(const SkClipStack& stack, const SkRect& outerBounds, F fn) { // assumes clipstack is not complex.
constexpr SkRect kHuge{-30000, -30000, 30000, 30000};
SkClipStack::Iter iter(stack, SkClipStack::Iter::kBottom_IterStart);
SkRect bounds = outerBounds; while (const SkClipStack::Element* element = iter.next()) {
SkPath operand;
element->asDeviceSpacePath(&operand);
SkPathOp op; switch (element->getOp()) { case SkClipOp::kDifference: op = kDifference_SkPathOp; break; case SkClipOp::kIntersect: op = kIntersect_SkPathOp; break;
} if (op == kDifference_SkPathOp ||
operand.isInverseFillType() ||
!kHuge.contains(operand.getBounds()))
{
Op(SkPath::Rect(bounds), operand, op, &operand);
}
SkASSERT(!operand.isInverseFillType());
fn(operand); if (!bounds.intersect(operand.getBounds())) { return; // return early;
}
}
}
staticvoid 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));
if (is_complex_clip(clipStack)) {
SkPath clipPath;
SkClipStack_AsPath(clipStack, &clipPath); if (Op(clipPath, SkPath::Rect(outsetBounds), kIntersect_SkPathOp, &clipPath)) {
append_clip_path(clipPath, wStream);
} // If Op() fails (pathological case; e.g. input values are // extremely large or NaN), emit no clip at all.
} else {
apply_clip(clipStack, outsetBounds, [wStream](const SkPath& path) {
append_clip_path(path, wStream);
});
}
}
void SkPDFGraphicStackState::updateDrawingState(const SkPDFGraphicStackState::Entry& state) { // PDF treats a shader as a color, so we only set one or the other. if (state.fShaderIndex >= 0) { if (state.fShaderIndex != currentEntry()->fShaderIndex) {
SkPDFUtils::ApplyPattern(state.fShaderIndex, fContentStream);
currentEntry()->fShaderIndex = state.fShaderIndex;
}
} elseif (state.fColor != currentEntry()->fColor || currentEntry()->fShaderIndex >= 0) {
emit_pdf_color(state.fColor, fContentStream);
fContentStream->writeText("RG ");
emit_pdf_color(state.fColor, fContentStream);
fContentStream->writeText("rg\n");
currentEntry()->fColor = state.fColor;
currentEntry()->fShaderIndex = -1;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.