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 * Copyright (C) 2014 Google, Inc. |
5 * | 6 * |
6 * This library is free software; you can redistribute it and/or | 7 * This library is free software; you can redistribute it and/or |
7 * modify it under the terms of the GNU Library General Public | 8 * modify it under the terms of the GNU Library General Public |
8 * License as published by the Free Software Foundation; either | 9 * License as published by the Free Software Foundation; either |
9 * version 2 of the License, or (at your option) any later version. | 10 * version 2 of the License, or (at your option) any later version. |
10 * | 11 * |
11 * This library is distributed in the hope that it will be useful, | 12 * This library is distributed in the hope that it will be useful, |
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 * Library General Public License for more details. | 15 * Library General Public License for more details. |
(...skipping 307 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
322 if (updateRelativeLengthsOrViewBox | 323 if (updateRelativeLengthsOrViewBox |
323 || SVGZoomAndPan::isKnownAttribute(attrName)) { | 324 || SVGZoomAndPan::isKnownAttribute(attrName)) { |
324 if (renderer()) | 325 if (renderer()) |
325 RenderSVGResource::markForLayoutAndParentResourceInvalidation(render
er()); | 326 RenderSVGResource::markForLayoutAndParentResourceInvalidation(render
er()); |
326 return; | 327 return; |
327 } | 328 } |
328 | 329 |
329 SVGGraphicsElement::svgAttributeChanged(attrName); | 330 SVGGraphicsElement::svgAttributeChanged(attrName); |
330 } | 331 } |
331 | 332 |
332 PassRefPtr<NodeList> SVGSVGElement::collectIntersectionOrEnclosureList(const Flo
atRect& rect, SVGElement* referenceElement, CollectIntersectionOrEnclosure colle
ct) const | 333 // FloatRect::intersects does not consider horizontal or vertical lines (because
of isEmpty()). |
| 334 static bool intersectsAllowingEmpty(const FloatRect& r1, const FloatRect& r2) |
| 335 { |
| 336 if (r1.width() < 0 || r1.height() < 0 || r2.width() < 0 || r2.height() < 0) |
| 337 return false; |
| 338 |
| 339 return r1.x() < r2.maxX() && r2.x() < r1.maxX() |
| 340 && r1.y() < r2.maxY() && r2.y() < r1.maxY(); |
| 341 } |
| 342 |
| 343 // One of the element types that can cause graphics to be drawn onto the target
canvas. |
| 344 // Specifically: circle, ellipse, image, line, path, polygon, polyline, rect, te
xt and use. |
| 345 static bool isIntersectionOrEnclosureTarget(RenderObject* renderer) |
| 346 { |
| 347 return renderer->isSVGShape() |
| 348 || renderer->isSVGText() |
| 349 || renderer->isSVGImage() |
| 350 || renderer->node()->hasTagName(SVGNames::useTag); |
| 351 } |
| 352 |
| 353 bool SVGSVGElement::checkIntersectionOrEnclosure(const SVGElement& element, cons
t FloatRect& rect, |
| 354 CheckIntersectionOrEnclosure mode) const |
| 355 { |
| 356 RenderObject* renderer = element.renderer(); |
| 357 ASSERT(!renderer || renderer->style()); |
| 358 if (!renderer || renderer->style()->pointerEvents() == PE_NONE) |
| 359 return false; |
| 360 |
| 361 if (!isIntersectionOrEnclosureTarget(renderer)) |
| 362 return false; |
| 363 |
| 364 AffineTransform ctm = toSVGGraphicsElement(element).computeCTM(AncestorScope
, DisallowStyleUpdate, this); |
| 365 FloatRect mappedRepaintRect = ctm.mapRect(renderer->repaintRectInLocalCoordi
nates()); |
| 366 |
| 367 bool result = false; |
| 368 switch (mode) { |
| 369 case CheckIntersection: |
| 370 result = intersectsAllowingEmpty(rect, mappedRepaintRect); |
| 371 break; |
| 372 case CheckEnclosure: |
| 373 result = rect.contains(mappedRepaintRect); |
| 374 break; |
| 375 default: |
| 376 ASSERT_NOT_REACHED(); |
| 377 break; |
| 378 } |
| 379 |
| 380 return result; |
| 381 } |
| 382 |
| 383 PassRefPtr<NodeList> SVGSVGElement::collectIntersectionOrEnclosureList(const Flo
atRect& rect, |
| 384 SVGElement* referenceElement, CheckIntersectionOrEnclosure mode) const |
333 { | 385 { |
334 Vector<RefPtr<Node> > nodes; | 386 Vector<RefPtr<Node> > nodes; |
335 Element* element = ElementTraversal::next(*(referenceElement ? referenceElem
ent : this)); | 387 |
336 while (element) { | 388 const SVGElement* root = this; |
337 if (element->isSVGElement()) { | 389 if (referenceElement) { |
338 SVGElement* svgElement = toSVGElement(element); | 390 // Only the common subtree needs to be traversed. |
339 if (collect == CollectIntersectionList) { | 391 if (contains(referenceElement)) { |
340 if (RenderSVGModelObject::checkIntersection(svgElement->renderer
(), rect)) | 392 root = referenceElement; |
341 nodes.append(element); | 393 } else if (!isDescendantOf(referenceElement)) { |
342 } else { | 394 // No common subtree. |
343 if (RenderSVGModelObject::checkEnclosure(svgElement->renderer(),
rect)) | 395 return StaticNodeList::adopt(nodes); |
344 nodes.append(element); | |
345 } | |
346 } | 396 } |
| 397 } |
347 | 398 |
348 element = ElementTraversal::next(*element, referenceElement ? referenceE
lement : this); | 399 for (Element* element = ElementTraversal::firstWithin(*root); element; |
| 400 element = ElementTraversal::next(*element, root)) { |
| 401 |
| 402 if (!WebCore::isSVGGraphicsElement(*element)) |
| 403 continue; |
| 404 |
| 405 SVGElement* svgElement = toSVGElement(element); |
| 406 if (checkIntersectionOrEnclosure(*svgElement, rect, mode)) |
| 407 nodes.append(element); |
349 } | 408 } |
| 409 |
350 return StaticNodeList::adopt(nodes); | 410 return StaticNodeList::adopt(nodes); |
351 } | 411 } |
352 | 412 |
353 PassRefPtr<NodeList> SVGSVGElement::getIntersectionList(PassRefPtr<SVGRectTearOf
f> passRect, SVGElement* referenceElement) const | 413 PassRefPtr<NodeList> SVGSVGElement::getIntersectionList(PassRefPtr<SVGRectTearOf
f> rect, SVGElement* referenceElement) const |
354 { | 414 { |
355 RefPtr<SVGRectTearOff> rect = passRect; | 415 document().updateLayoutIgnorePendingStylesheets(); |
356 return collectIntersectionOrEnclosureList(rect->target()->value(), reference
Element, CollectIntersectionList); | 416 |
| 417 return collectIntersectionOrEnclosureList(rect->target()->value(), reference
Element, CheckIntersection); |
357 } | 418 } |
358 | 419 |
359 PassRefPtr<NodeList> SVGSVGElement::getEnclosureList(PassRefPtr<SVGRectTearOff>
passRect, SVGElement* referenceElement) const | 420 PassRefPtr<NodeList> SVGSVGElement::getEnclosureList(PassRefPtr<SVGRectTearOff>
rect, SVGElement* referenceElement) const |
360 { | 421 { |
361 RefPtr<SVGRectTearOff> rect = passRect; | 422 document().updateLayoutIgnorePendingStylesheets(); |
362 return collectIntersectionOrEnclosureList(rect->target()->value(), reference
Element, CollectEnclosureList); | 423 |
| 424 return collectIntersectionOrEnclosureList(rect->target()->value(), reference
Element, CheckEnclosure); |
363 } | 425 } |
364 | 426 |
365 bool SVGSVGElement::checkIntersection(SVGElement* element, PassRefPtr<SVGRectTea
rOff> passRect) const | 427 bool SVGSVGElement::checkIntersection(SVGElement* element, PassRefPtr<SVGRectTea
rOff> rect) const |
366 { | 428 { |
367 RefPtr<SVGRectTearOff> rect = passRect; | 429 ASSERT(element); |
368 return RenderSVGModelObject::checkIntersection(element->renderer(), rect->ta
rget()->value()); | 430 document().updateLayoutIgnorePendingStylesheets(); |
| 431 |
| 432 return checkIntersectionOrEnclosure(*element, rect->target()->value(), Check
Intersection); |
369 } | 433 } |
370 | 434 |
371 bool SVGSVGElement::checkEnclosure(SVGElement* element, PassRefPtr<SVGRectTearOf
f> passRect) const | 435 bool SVGSVGElement::checkEnclosure(SVGElement* element, PassRefPtr<SVGRectTearOf
f> rect) const |
372 { | 436 { |
373 RefPtr<SVGRectTearOff> rect = passRect; | 437 ASSERT(element); |
374 return RenderSVGModelObject::checkEnclosure(element->renderer(), rect->targe
t()->value()); | 438 document().updateLayoutIgnorePendingStylesheets(); |
| 439 |
| 440 return checkIntersectionOrEnclosure(*element, rect->target()->value(), Check
Enclosure); |
375 } | 441 } |
376 | 442 |
377 void SVGSVGElement::deselectAll() | 443 void SVGSVGElement::deselectAll() |
378 { | 444 { |
379 if (LocalFrame* frame = document().frame()) | 445 if (LocalFrame* frame = document().frame()) |
380 frame->selection().clear(); | 446 frame->selection().clear(); |
381 } | 447 } |
382 | 448 |
383 PassRefPtr<SVGNumberTearOff> SVGSVGElement::createSVGNumber() | 449 PassRefPtr<SVGNumberTearOff> SVGSVGElement::createSVGNumber() |
384 { | 450 { |
(...skipping 395 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
780 Vector<Element*>::const_iterator end = elements.end(); | 846 Vector<Element*>::const_iterator end = elements.end(); |
781 for (Vector<Element*>::const_iterator it = elements.begin(); it != end; ++it
) { | 847 for (Vector<Element*>::const_iterator it = elements.begin(); it != end; ++it
) { |
782 if ((*it)->isDescendantOf(this)) | 848 if ((*it)->isDescendantOf(this)) |
783 return *it; | 849 return *it; |
784 } | 850 } |
785 | 851 |
786 return 0; | 852 return 0; |
787 } | 853 } |
788 | 854 |
789 } | 855 } |
OLD | NEW |