Chromium Code Reviews| Index: Source/core/svg/SVGSVGElement.cpp |
| diff --git a/Source/core/svg/SVGSVGElement.cpp b/Source/core/svg/SVGSVGElement.cpp |
| index af5a33658f00b7a24f4ceec4348df4e23b319193..264b87839fc221f12573ea42e41faa684652f807 100644 |
| --- a/Source/core/svg/SVGSVGElement.cpp |
| +++ b/Source/core/svg/SVGSVGElement.cpp |
| @@ -329,49 +329,121 @@ void SVGSVGElement::svgAttributeChanged(const QualifiedName& attrName) |
| SVGGraphicsElement::svgAttributeChanged(attrName); |
| } |
| -PassRefPtr<NodeList> SVGSVGElement::collectIntersectionOrEnclosureList(const FloatRect& rect, SVGElement* referenceElement, CollectIntersectionOrEnclosure collect) const |
| +// FloatRect::intersects does not consider horizontal or vertical lines (because of isEmpty()). |
| +// So special-case handling of such lines. |
| +static bool intersectsAllowingEmpty(const FloatRect& r, const FloatRect& other) |
|
Stephen Chennney
2014/03/03 13:00:22
Either this is much simpler to implement, or I'm n
f(malita)
2014/03/03 14:12:18
TBH I haven't looked beyond the comments when movi
|
| +{ |
| + if (r.isEmpty() && other.isEmpty()) |
|
fs
2014/03/03 10:44:32
This function had me wondering...
Since isEmpty()
|
| + return false; |
| + if (r.isEmpty() && !other.isEmpty()) { |
| + return (other.contains(r.x(), r.y()) && !other.contains(r.maxX(), r.maxY())) |
| + || (!other.contains(r.x(), r.y()) && other.contains(r.maxX(), r.maxY())); |
| + } |
| + if (other.isEmpty() && !r.isEmpty()) |
| + return intersectsAllowingEmpty(other, r); |
|
fs
2014/03/03 10:44:32
Might make sense to just make the code in the abov
|
| + return r.intersects(other); |
| +} |
| + |
| +// One of the element types that can cause graphics to be drawn onto the target canvas. |
| +// Specifically: circle, ellipse, image, line, path, polygon, polyline, rect, text and use. |
| +static bool isIntersectionOrEnclosureTarget(RenderObject* renderer) |
| +{ |
| + return renderer->isSVGShape() |
| + || renderer->isSVGText() |
| + || renderer->isSVGImage() |
| + || renderer->node()->hasTagName(SVGNames::useTag); |
| +} |
| + |
| +bool SVGSVGElement::checkIntersectionOrEnclosure(const SVGElement& element, const FloatRect& rect, |
| + CheckIntersectionOrEnclosure mode) const |
| +{ |
| + RenderObject* renderer = element.renderer(); |
| + ASSERT(!renderer || renderer->style()); |
| + if (!renderer || renderer->style()->pointerEvents() == PE_NONE) |
| + return false; |
| + |
| + if (!isIntersectionOrEnclosureTarget(renderer)) |
| + return false; |
| + |
| + ASSERT(WebCore::isSVGGraphicsElement(element)); |
| + AffineTransform ctm = toSVGGraphicsElement(element).computeCTM(AncestorScope, DisallowStyleUpdate, this); |
| + FloatRect mappedRepaintRect = ctm.mapRect(renderer->repaintRectInLocalCoordinates()); |
| + |
| + bool result = false; |
| + switch (mode) { |
| + case CheckIntersection: |
| + result = intersectsAllowingEmpty(rect, mappedRepaintRect); |
| + break; |
| + case CheckEnclosure: |
| + result = rect.contains(mappedRepaintRect); |
| + break; |
| + default: |
| + ASSERT_NOT_REACHED(); |
| + break; |
| + } |
| + |
| + return result; |
| +} |
| + |
| +PassRefPtr<NodeList> SVGSVGElement::collectIntersectionOrEnclosureList(const FloatRect& rect, |
| + SVGElement* referenceElement, CheckIntersectionOrEnclosure mode) const |
| { |
| Vector<RefPtr<Node> > nodes; |
| - Element* element = ElementTraversal::next(*(referenceElement ? referenceElement : this)); |
| - while (element) { |
| - if (element->isSVGElement()) { |
| - SVGElement* svgElement = toSVGElement(element); |
| - if (collect == CollectIntersectionList) { |
| - if (RenderSVGModelObject::checkIntersection(svgElement->renderer(), rect)) |
| - nodes.append(element); |
| - } else { |
| - if (RenderSVGModelObject::checkEnclosure(svgElement->renderer(), rect)) |
| - nodes.append(element); |
| - } |
| + |
| + const SVGElement* root = this; |
| + if (referenceElement) { |
|
fs
2014/03/03 10:44:32
Some test(s) for this case would be nice - but I'm
f(malita)
2014/03/03 14:12:18
I'll add some willingly :)
|
| + // Only the common subtree needs to be traversed. |
| + if (contains(referenceElement)) { |
| + root = referenceElement; |
| + } else if (!isDescendantOf(referenceElement)) { |
| + // No common subtree: the spec is not clear about this case - should we bend over backwards |
|
fs
2014/03/03 10:44:32
I think this is in line with the spec wording, so
f(malita)
2014/03/03 14:12:18
Awesome, I'll remove the comment then.
|
| + // to find a common ancestor and map everything in its space? |
| + return StaticNodeList::adopt(nodes); |
| } |
| + } |
| - element = ElementTraversal::next(*element, referenceElement ? referenceElement : this); |
| + for (Element* element = ElementTraversal::firstWithin(*root); element; |
| + element = ElementTraversal::next(*element, root)) { |
| + |
| + if (!WebCore::isSVGGraphicsElement(*element)) |
| + continue; |
| + |
| + SVGElement* svgElement = toSVGElement(element); |
| + if (checkIntersectionOrEnclosure(*svgElement, rect, mode)) |
| + nodes.append(element); |
| } |
| + |
| return StaticNodeList::adopt(nodes); |
| } |
| -PassRefPtr<NodeList> SVGSVGElement::getIntersectionList(PassRefPtr<SVGRectTearOff> passRect, SVGElement* referenceElement) const |
| +PassRefPtr<NodeList> SVGSVGElement::getIntersectionList(PassRefPtr<SVGRectTearOff> rect, SVGElement* referenceElement) const |
| { |
| - RefPtr<SVGRectTearOff> rect = passRect; |
| - return collectIntersectionOrEnclosureList(rect->target()->value(), referenceElement, CollectIntersectionList); |
| + document().updateLayoutIgnorePendingStylesheets(); |
| + |
| + return collectIntersectionOrEnclosureList(rect->target()->value(), referenceElement, CheckIntersection); |
| } |
| -PassRefPtr<NodeList> SVGSVGElement::getEnclosureList(PassRefPtr<SVGRectTearOff> passRect, SVGElement* referenceElement) const |
| +PassRefPtr<NodeList> SVGSVGElement::getEnclosureList(PassRefPtr<SVGRectTearOff> rect, SVGElement* referenceElement) const |
| { |
| - RefPtr<SVGRectTearOff> rect = passRect; |
| - return collectIntersectionOrEnclosureList(rect->target()->value(), referenceElement, CollectEnclosureList); |
| + document().updateLayoutIgnorePendingStylesheets(); |
| + |
| + return collectIntersectionOrEnclosureList(rect->target()->value(), referenceElement, CheckEnclosure); |
| } |
| -bool SVGSVGElement::checkIntersection(SVGElement* element, PassRefPtr<SVGRectTearOff> passRect) const |
| +bool SVGSVGElement::checkIntersection(SVGElement* element, PassRefPtr<SVGRectTearOff> rect) const |
| { |
| - RefPtr<SVGRectTearOff> rect = passRect; |
| - return RenderSVGModelObject::checkIntersection(element->renderer(), rect->target()->value()); |
| + ASSERT(element); |
| + document().updateLayoutIgnorePendingStylesheets(); |
| + |
| + return checkIntersectionOrEnclosure(*element, rect->target()->value(), CheckIntersection); |
| } |
| -bool SVGSVGElement::checkEnclosure(SVGElement* element, PassRefPtr<SVGRectTearOff> passRect) const |
| +bool SVGSVGElement::checkEnclosure(SVGElement* element, PassRefPtr<SVGRectTearOff> rect) const |
| { |
| - RefPtr<SVGRectTearOff> rect = passRect; |
| - return RenderSVGModelObject::checkEnclosure(element->renderer(), rect->target()->value()); |
| + ASSERT(element); |
| + document().updateLayoutIgnorePendingStylesheets(); |
| + |
| + return checkIntersectionOrEnclosure(*element, rect->target()->value(), CheckEnclosure); |
| } |
| void SVGSVGElement::deselectAll() |