OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (C) 2004, 2005, 2006 Nikolas Zimmermann <zimmermann@kde.org> | 2 * Copyright (C) 2004, 2005, 2006 Nikolas Zimmermann <zimmermann@kde.org> |
3 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010 Rob Buis <buis@kde.org> | 3 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010 Rob Buis <buis@kde.org> |
4 * Copyright (C) 2007 Apple Inc. All rights reserved. | 4 * Copyright (C) 2007 Apple Inc. All rights reserved. |
5 * | 5 * |
6 * This library is free software; you can redistribute it and/or | 6 * This library is free software; you can redistribute it and/or |
7 * modify it under the terms of the GNU Library General Public | 7 * modify it under the terms of the GNU Library General Public |
8 * License as published by the Free Software Foundation; either | 8 * License as published by the Free Software Foundation; either |
9 * version 2 of the License, or (at your option) any later version. | 9 * version 2 of the License, or (at your option) any later version. |
10 * | 10 * |
(...skipping 311 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
322 if (updateRelativeLengthsOrViewBox | 322 if (updateRelativeLengthsOrViewBox |
323 || SVGZoomAndPan::isKnownAttribute(attrName)) { | 323 || SVGZoomAndPan::isKnownAttribute(attrName)) { |
324 if (renderer()) | 324 if (renderer()) |
325 RenderSVGResource::markForLayoutAndParentResourceInvalidation(render er()); | 325 RenderSVGResource::markForLayoutAndParentResourceInvalidation(render er()); |
326 return; | 326 return; |
327 } | 327 } |
328 | 328 |
329 SVGGraphicsElement::svgAttributeChanged(attrName); | 329 SVGGraphicsElement::svgAttributeChanged(attrName); |
330 } | 330 } |
331 | 331 |
332 PassRefPtr<NodeList> SVGSVGElement::collectIntersectionOrEnclosureList(const Flo atRect& rect, SVGElement* referenceElement, CollectIntersectionOrEnclosure colle ct) const | 332 // FloatRect::intersects does not consider horizontal or vertical lines (because of isEmpty()). |
333 // So special-case handling of such lines. | |
334 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
| |
335 { | |
336 if (r.isEmpty() && other.isEmpty()) | |
fs
2014/03/03 10:44:32
This function had me wondering...
Since isEmpty()
| |
337 return false; | |
338 if (r.isEmpty() && !other.isEmpty()) { | |
339 return (other.contains(r.x(), r.y()) && !other.contains(r.maxX(), r.maxY ())) | |
340 || (!other.contains(r.x(), r.y()) && other.contains(r.maxX(), r.maxY ())); | |
341 } | |
342 if (other.isEmpty() && !r.isEmpty()) | |
343 return intersectsAllowingEmpty(other, r); | |
fs
2014/03/03 10:44:32
Might make sense to just make the code in the abov
| |
344 return r.intersects(other); | |
345 } | |
346 | |
347 // One of the element types that can cause graphics to be drawn onto the target canvas. | |
348 // Specifically: circle, ellipse, image, line, path, polygon, polyline, rect, te xt and use. | |
349 static bool isIntersectionOrEnclosureTarget(RenderObject* renderer) | |
350 { | |
351 return renderer->isSVGShape() | |
352 || renderer->isSVGText() | |
353 || renderer->isSVGImage() | |
354 || renderer->node()->hasTagName(SVGNames::useTag); | |
355 } | |
356 | |
357 bool SVGSVGElement::checkIntersectionOrEnclosure(const SVGElement& element, cons t FloatRect& rect, | |
358 CheckIntersectionOrEnclosure mode) const | |
359 { | |
360 RenderObject* renderer = element.renderer(); | |
361 ASSERT(!renderer || renderer->style()); | |
362 if (!renderer || renderer->style()->pointerEvents() == PE_NONE) | |
363 return false; | |
364 | |
365 if (!isIntersectionOrEnclosureTarget(renderer)) | |
366 return false; | |
367 | |
368 ASSERT(WebCore::isSVGGraphicsElement(element)); | |
369 AffineTransform ctm = toSVGGraphicsElement(element).computeCTM(AncestorScope , DisallowStyleUpdate, this); | |
370 FloatRect mappedRepaintRect = ctm.mapRect(renderer->repaintRectInLocalCoordi nates()); | |
371 | |
372 bool result = false; | |
373 switch (mode) { | |
374 case CheckIntersection: | |
375 result = intersectsAllowingEmpty(rect, mappedRepaintRect); | |
376 break; | |
377 case CheckEnclosure: | |
378 result = rect.contains(mappedRepaintRect); | |
379 break; | |
380 default: | |
381 ASSERT_NOT_REACHED(); | |
382 break; | |
383 } | |
384 | |
385 return result; | |
386 } | |
387 | |
388 PassRefPtr<NodeList> SVGSVGElement::collectIntersectionOrEnclosureList(const Flo atRect& rect, | |
389 SVGElement* referenceElement, CheckIntersectionOrEnclosure mode) const | |
333 { | 390 { |
334 Vector<RefPtr<Node> > nodes; | 391 Vector<RefPtr<Node> > nodes; |
335 Element* element = ElementTraversal::next(*(referenceElement ? referenceElem ent : this)); | 392 |
336 while (element) { | 393 const SVGElement* root = this; |
337 if (element->isSVGElement()) { | 394 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 :)
| |
338 SVGElement* svgElement = toSVGElement(element); | 395 // Only the common subtree needs to be traversed. |
339 if (collect == CollectIntersectionList) { | 396 if (contains(referenceElement)) { |
340 if (RenderSVGModelObject::checkIntersection(svgElement->renderer (), rect)) | 397 root = referenceElement; |
341 nodes.append(element); | 398 } else if (!isDescendantOf(referenceElement)) { |
342 } else { | 399 // 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.
| |
343 if (RenderSVGModelObject::checkEnclosure(svgElement->renderer(), rect)) | 400 // to find a common ancestor and map everything in its space? |
344 nodes.append(element); | 401 return StaticNodeList::adopt(nodes); |
345 } | |
346 } | 402 } |
403 } | |
347 | 404 |
348 element = ElementTraversal::next(*element, referenceElement ? referenceE lement : this); | 405 for (Element* element = ElementTraversal::firstWithin(*root); element; |
406 element = ElementTraversal::next(*element, root)) { | |
407 | |
408 if (!WebCore::isSVGGraphicsElement(*element)) | |
409 continue; | |
410 | |
411 SVGElement* svgElement = toSVGElement(element); | |
412 if (checkIntersectionOrEnclosure(*svgElement, rect, mode)) | |
413 nodes.append(element); | |
349 } | 414 } |
415 | |
350 return StaticNodeList::adopt(nodes); | 416 return StaticNodeList::adopt(nodes); |
351 } | 417 } |
352 | 418 |
353 PassRefPtr<NodeList> SVGSVGElement::getIntersectionList(PassRefPtr<SVGRectTearOf f> passRect, SVGElement* referenceElement) const | 419 PassRefPtr<NodeList> SVGSVGElement::getIntersectionList(PassRefPtr<SVGRectTearOf f> rect, SVGElement* referenceElement) const |
354 { | 420 { |
355 RefPtr<SVGRectTearOff> rect = passRect; | 421 document().updateLayoutIgnorePendingStylesheets(); |
356 return collectIntersectionOrEnclosureList(rect->target()->value(), reference Element, CollectIntersectionList); | 422 |
423 return collectIntersectionOrEnclosureList(rect->target()->value(), reference Element, CheckIntersection); | |
357 } | 424 } |
358 | 425 |
359 PassRefPtr<NodeList> SVGSVGElement::getEnclosureList(PassRefPtr<SVGRectTearOff> passRect, SVGElement* referenceElement) const | 426 PassRefPtr<NodeList> SVGSVGElement::getEnclosureList(PassRefPtr<SVGRectTearOff> rect, SVGElement* referenceElement) const |
360 { | 427 { |
361 RefPtr<SVGRectTearOff> rect = passRect; | 428 document().updateLayoutIgnorePendingStylesheets(); |
362 return collectIntersectionOrEnclosureList(rect->target()->value(), reference Element, CollectEnclosureList); | 429 |
430 return collectIntersectionOrEnclosureList(rect->target()->value(), reference Element, CheckEnclosure); | |
363 } | 431 } |
364 | 432 |
365 bool SVGSVGElement::checkIntersection(SVGElement* element, PassRefPtr<SVGRectTea rOff> passRect) const | 433 bool SVGSVGElement::checkIntersection(SVGElement* element, PassRefPtr<SVGRectTea rOff> rect) const |
366 { | 434 { |
367 RefPtr<SVGRectTearOff> rect = passRect; | 435 ASSERT(element); |
368 return RenderSVGModelObject::checkIntersection(element->renderer(), rect->ta rget()->value()); | 436 document().updateLayoutIgnorePendingStylesheets(); |
437 | |
438 return checkIntersectionOrEnclosure(*element, rect->target()->value(), Check Intersection); | |
369 } | 439 } |
370 | 440 |
371 bool SVGSVGElement::checkEnclosure(SVGElement* element, PassRefPtr<SVGRectTearOf f> passRect) const | 441 bool SVGSVGElement::checkEnclosure(SVGElement* element, PassRefPtr<SVGRectTearOf f> rect) const |
372 { | 442 { |
373 RefPtr<SVGRectTearOff> rect = passRect; | 443 ASSERT(element); |
374 return RenderSVGModelObject::checkEnclosure(element->renderer(), rect->targe t()->value()); | 444 document().updateLayoutIgnorePendingStylesheets(); |
445 | |
446 return checkIntersectionOrEnclosure(*element, rect->target()->value(), Check Enclosure); | |
375 } | 447 } |
376 | 448 |
377 void SVGSVGElement::deselectAll() | 449 void SVGSVGElement::deselectAll() |
378 { | 450 { |
379 if (LocalFrame* frame = document().frame()) | 451 if (LocalFrame* frame = document().frame()) |
380 frame->selection().clear(); | 452 frame->selection().clear(); |
381 } | 453 } |
382 | 454 |
383 PassRefPtr<SVGNumberTearOff> SVGSVGElement::createSVGNumber() | 455 PassRefPtr<SVGNumberTearOff> SVGSVGElement::createSVGNumber() |
384 { | 456 { |
(...skipping 395 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
780 Vector<Element*>::const_iterator end = elements.end(); | 852 Vector<Element*>::const_iterator end = elements.end(); |
781 for (Vector<Element*>::const_iterator it = elements.begin(); it != end; ++it ) { | 853 for (Vector<Element*>::const_iterator it = elements.begin(); it != end; ++it ) { |
782 if ((*it)->isDescendantOf(this)) | 854 if ((*it)->isDescendantOf(this)) |
783 return *it; | 855 return *it; |
784 } | 856 } |
785 | 857 |
786 return 0; | 858 return 0; |
787 } | 859 } |
788 | 860 |
789 } | 861 } |
OLD | NEW |