Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(387)

Side by Side Diff: Source/core/svg/SVGUseElement.cpp

Issue 272523002: Remove SVGElementInstance (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Remove foundProblem mechanism Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Nikolas Zimmermann <zimmermann@kde .org> 2 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Nikolas Zimmermann <zimmermann@kde .org>
3 * Copyright (C) 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org> 3 * Copyright (C) 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org>
4 * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved. 4 * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
5 * Copyright (C) 2011 Torch Mobile (Beijing) Co. Ltd. All rights reserved. 5 * Copyright (C) 2011 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
6 * Copyright (C) 2012 University of Szeged 6 * Copyright (C) 2012 University of Szeged
7 * Copyright (C) 2012 Renata Hodovan <reni@webkit.org> 7 * Copyright (C) 2012 Renata Hodovan <reni@webkit.org>
8 * 8 *
9 * This library is free software; you can redistribute it and/or 9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public 10 * modify it under the terms of the GNU Library General Public
(...skipping 19 matching lines...) Expand all
30 #include "bindings/v8/ExceptionStatePlaceholder.h" 30 #include "bindings/v8/ExceptionStatePlaceholder.h"
31 #include "core/dom/Document.h" 31 #include "core/dom/Document.h"
32 #include "core/dom/ElementTraversal.h" 32 #include "core/dom/ElementTraversal.h"
33 #include "core/events/Event.h" 33 #include "core/events/Event.h"
34 #include "core/dom/shadow/ElementShadow.h" 34 #include "core/dom/shadow/ElementShadow.h"
35 #include "core/dom/shadow/ShadowRoot.h" 35 #include "core/dom/shadow/ShadowRoot.h"
36 #include "core/fetch/FetchRequest.h" 36 #include "core/fetch/FetchRequest.h"
37 #include "core/fetch/ResourceFetcher.h" 37 #include "core/fetch/ResourceFetcher.h"
38 #include "core/rendering/svg/RenderSVGResource.h" 38 #include "core/rendering/svg/RenderSVGResource.h"
39 #include "core/rendering/svg/RenderSVGTransformableContainer.h" 39 #include "core/rendering/svg/RenderSVGTransformableContainer.h"
40 #include "core/svg/SVGElementInstance.h"
41 #include "core/svg/SVGGElement.h" 40 #include "core/svg/SVGGElement.h"
42 #include "core/svg/SVGLengthContext.h" 41 #include "core/svg/SVGLengthContext.h"
43 #include "core/svg/SVGSVGElement.h" 42 #include "core/svg/SVGSVGElement.h"
44 #include "core/xml/parser/XMLDocumentParser.h" 43 #include "core/xml/parser/XMLDocumentParser.h"
45 44
46 namespace WebCore { 45 namespace WebCore {
47 46
48 inline SVGUseElement::SVGUseElement(Document& document) 47 inline SVGUseElement::SVGUseElement(Document& document)
49 : SVGGraphicsElement(SVGNames::useTag, document) 48 : SVGGraphicsElement(SVGNames::useTag, document)
50 , SVGURIReference(this) 49 , SVGURIReference(this)
(...skipping 23 matching lines...) Expand all
74 } 73 }
75 74
76 SVGUseElement::~SVGUseElement() 75 SVGUseElement::~SVGUseElement()
77 { 76 {
78 setDocumentResource(0); 77 setDocumentResource(0);
79 #if !ENABLE(OILPAN) 78 #if !ENABLE(OILPAN)
80 clearResourceReferences(); 79 clearResourceReferences();
81 #endif 80 #endif
82 } 81 }
83 82
84 SVGElementInstance* SVGUseElement::instanceRoot()
85 {
86 // If there is no element instance tree, force immediate SVGElementInstance tree
87 // creation by asking the document to invoke our recalcStyle function - as w e can't
88 // wait for the lazy creation to happen if e.g. JS wants to access the insta nceRoot
89 // object right after creating the element on-the-fly
90 if (!m_targetElementInstance)
91 document().updateRenderTreeIfNeeded();
92
93 return m_targetElementInstance.get();
94 }
95
96 SVGElementInstance* SVGUseElement::animatedInstanceRoot() const
97 {
98 // FIXME: Implement me.
99 return 0;
100 }
101
102 bool SVGUseElement::isSupportedAttribute(const QualifiedName& attrName) 83 bool SVGUseElement::isSupportedAttribute(const QualifiedName& attrName)
103 { 84 {
104 DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ()); 85 DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ());
105 if (supportedAttributes.isEmpty()) { 86 if (supportedAttributes.isEmpty()) {
106 SVGURIReference::addSupportedAttributes(supportedAttributes); 87 SVGURIReference::addSupportedAttributes(supportedAttributes);
107 supportedAttributes.add(SVGNames::xAttr); 88 supportedAttributes.add(SVGNames::xAttr);
108 supportedAttributes.add(SVGNames::yAttr); 89 supportedAttributes.add(SVGNames::yAttr);
109 supportedAttributes.add(SVGNames::widthAttr); 90 supportedAttributes.add(SVGNames::widthAttr);
110 supportedAttributes.add(SVGNames::heightAttr); 91 supportedAttributes.add(SVGNames::heightAttr);
111 } 92 }
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
217 SVGElement::InvalidationGuard invalidationGuard(this); 198 SVGElement::InvalidationGuard invalidationGuard(this);
218 199
219 RenderObject* renderer = this->renderer(); 200 RenderObject* renderer = this->renderer();
220 if (attrName == SVGNames::xAttr 201 if (attrName == SVGNames::xAttr
221 || attrName == SVGNames::yAttr 202 || attrName == SVGNames::yAttr
222 || attrName == SVGNames::widthAttr 203 || attrName == SVGNames::widthAttr
223 || attrName == SVGNames::heightAttr) { 204 || attrName == SVGNames::heightAttr) {
224 updateRelativeLengthsInformation(); 205 updateRelativeLengthsInformation();
225 if (m_targetElementInstance) { 206 if (m_targetElementInstance) {
226 ASSERT(m_targetElementInstance->correspondingElement()); 207 ASSERT(m_targetElementInstance->correspondingElement());
227 transferUseWidthAndHeightIfNeeded(*this, m_targetElementInstance->sh adowTreeElement(), *m_targetElementInstance->correspondingElement()); 208 transferUseWidthAndHeightIfNeeded(*this, m_targetElementInstance.get (), *m_targetElementInstance->correspondingElement());
228 } 209 }
229 if (renderer) 210 if (renderer)
230 RenderSVGResource::markForLayoutAndParentResourceInvalidation(render er); 211 RenderSVGResource::markForLayoutAndParentResourceInvalidation(render er);
231 return; 212 return;
232 } 213 }
233 214
234 if (SVGURIReference::isKnownAttribute(attrName)) { 215 if (SVGURIReference::isKnownAttribute(attrName)) {
235 bool isExternalReference = isExternalURIReference(hrefString(), document ()); 216 bool isExternalReference = isExternalURIReference(hrefString(), document ());
236 if (isExternalReference) { 217 if (isExternalReference) {
237 KURL url = document().completeURL(hrefString()); 218 KURL url = document().completeURL(hrefString());
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
311 void SVGUseElement::scheduleShadowTreeRecreation() 292 void SVGUseElement::scheduleShadowTreeRecreation()
312 { 293 {
313 if (!referencedScope() || inUseShadowTree()) 294 if (!referencedScope() || inUseShadowTree())
314 return; 295 return;
315 m_needsShadowTreeRecreation = true; 296 m_needsShadowTreeRecreation = true;
316 document().scheduleUseShadowTreeUpdate(*this); 297 document().scheduleUseShadowTreeUpdate(*this);
317 } 298 }
318 299
319 void SVGUseElement::clearResourceReferences() 300 void SVGUseElement::clearResourceReferences()
320 { 301 {
321 if (m_targetElementInstance) { 302 if (m_targetElementInstance)
322 m_targetElementInstance->detach();
323 m_targetElementInstance = nullptr; 303 m_targetElementInstance = nullptr;
324 }
325 304
326 // FIXME: We should try to optimize this, to at least allow partial reclones . 305 // FIXME: We should try to optimize this, to at least allow partial reclones .
327 if (ShadowRoot* shadowTreeRootElement = userAgentShadowRoot()) 306 if (ShadowRoot* shadowTreeRootElement = userAgentShadowRoot())
328 shadowTreeRootElement->removeChildren(); 307 shadowTreeRootElement->removeChildren();
329 308
330 m_needsShadowTreeRecreation = false; 309 m_needsShadowTreeRecreation = false;
331 document().unscheduleUseShadowTreeUpdate(*this); 310 document().unscheduleUseShadowTreeUpdate(*this);
332 311
333 document().accessSVGExtensions().removeAllTargetReferencesForElement(this); 312 document().accessSVGExtensions().removeAllTargetReferencesForElement(this);
334 } 313 }
(...skipping 22 matching lines...) Expand all
357 } 336 }
358 337
359 if (target->isSVGElement()) { 338 if (target->isSVGElement()) {
360 buildShadowAndInstanceTree(toSVGElement(target)); 339 buildShadowAndInstanceTree(toSVGElement(target));
361 invalidateDependentShadowTrees(); 340 invalidateDependentShadowTrees();
362 } 341 }
363 342
364 ASSERT(!m_needsShadowTreeRecreation); 343 ASSERT(!m_needsShadowTreeRecreation);
365 } 344 }
366 345
346 static PassRefPtrWillBeRawPtr<Node> cloneNodeAndAssociate(Node* toClone)
esprehn 2014/06/05 20:57:25 toClone should be a reference.
347 {
348 ASSERT(toClone);
349 RefPtrWillBeRawPtr<Node> clone = toClone->cloneNode(false);
350 if (!clone->isSVGElement())
351 return clone.release();
352
353 SVGElement* svgElement = toSVGElement(toClone);
354 ASSERT(!svgElement->correspondingElement());
355 toSVGElement(clone.get())->setCorrespondingElement(svgElement);
356 TrackExceptionState exceptionState;
357 for (Node* node = toClone->firstChild(); node && !exceptionState.hadExceptio n(); node = node->nextSibling())
358 clone->appendChild(cloneNodeAndAssociate(node), exceptionState);
359 return clone.release();
360 }
361
367 void SVGUseElement::buildShadowAndInstanceTree(SVGElement* target) 362 void SVGUseElement::buildShadowAndInstanceTree(SVGElement* target)
368 { 363 {
369 ASSERT(!m_targetElementInstance); 364 ASSERT(!m_targetElementInstance);
370 365
371 // <use> creates a "user agent" shadow root. Do not build the shadow/instanc e tree for <use> 366 // <use> creates a "user agent" shadow root. Do not build the shadow/instanc e tree for <use>
372 // elements living in a user agent shadow tree because they will get expande d in a second 367 // elements living in a user agent shadow tree because they will get expande d in a second
373 // pass -- see expandUseElementsInShadowTree(). 368 // pass -- see expandUseElementsInShadowTree().
374 if (inUseShadowTree()) 369 if (inUseShadowTree())
375 return; 370 return;
376 371
377 // Do not allow self-referencing. 372 // Do not allow self-referencing.
378 // 'target' may be null, if it's a non SVG namespaced element. 373 // 'target' may be null, if it's a non SVG namespaced element.
379 if (!target || target == this) 374 if (!target || target == this)
380 return; 375 return;
381 376
382 // Why a seperated instance/shadow tree? SVG demands it: 377 // Set up root SVG element in shadow tree.
383 // The instance tree is accesable from JavaScript, and has to 378 RefPtrWillBeRawPtr<Element> newChild = target->cloneElementWithoutChildren() ;
384 // expose a 1:1 copy of the referenced tree, whereas internally we need 379 m_targetElementInstance = toSVGElement(newChild.get());
385 // to alter the tree for correct "use-on-symbol", "use-on-svg" support. 380 ShadowRoot* shadowTreeRootElement = userAgentShadowRoot();
381 shadowTreeRootElement->appendChild(newChild.release());
386 382
387 // Build instance tree. Create root SVGElementInstance object for the first sub-tree node. 383 // Clone the target subtree into the shadow tree, not handling <use> and <sy mbol> yet.
388 //
389 // Spec: If the 'use' element references a simple graphics element such as a 'rect', then there is only a
390 // single SVGElementInstance object, and the correspondingElement attribute on this SVGElementInstance object
391 // is the SVGRectElement that corresponds to the referenced 'rect' element.
392 m_targetElementInstance = SVGElementInstance::create(this, this, target);
393 384
394 // Eventually enter recursion to build SVGElementInstance objects for the su b-tree children 385 // SVG specification does not say a word about <use> & cycles. My view on th is is: just ignore it!
395 bool foundProblem = false; 386 // Non-appearing <use> content is easier to debug, then half-appearing conte nt.
396 buildInstanceTree(target, m_targetElementInstance.get(), foundProblem, false ); 387 if (!buildShadowTree(target, m_targetElementInstance.get(), false)) {
388 clearResourceReferences();
389 return;
390 }
397 391
398 if (instanceTreeIsLoading(m_targetElementInstance.get())) 392 if (instanceTreeIsLoading(m_targetElementInstance.get()))
399 return; 393 return;
400 394
401 // SVG specification does not say a word about <use> & cycles. My view on th is is: just ignore it! 395 // Assure shadow tree building was successfull
402 // Non-appearing <use> content is easier to debug, then half-appearing conte nt. 396 ASSERT(m_targetElementInstance);
403 if (foundProblem) { 397 ASSERT(m_targetElementInstance->correspondingUseElement() == this);
398 ASSERT(m_targetElementInstance->correspondingElement() == target);
399
400 // Expand all <use> elements in the shadow tree.
401 // Expand means: replace the actual <use> element by what it references.
402 if (!expandUseElementsInShadowTree(m_targetElementInstance.get())) {
404 clearResourceReferences(); 403 clearResourceReferences();
405 return; 404 return;
406 } 405 }
407 406
408 // Assure instance tree building was successfull
409 ASSERT(m_targetElementInstance);
410 ASSERT(!m_targetElementInstance->shadowTreeElement());
411 ASSERT(m_targetElementInstance->correspondingUseElement() == this);
412 ASSERT(m_targetElementInstance->directUseElement() == this);
413 ASSERT(m_targetElementInstance->correspondingElement() == target);
414
415 ShadowRoot* shadowTreeRootElement = userAgentShadowRoot();
416 ASSERT(shadowTreeRootElement);
417
418 // Build shadow tree from instance tree
419 // This also handles the special cases: <use> on <symbol>, <use> on <svg>.
420 buildShadowTree(target, m_targetElementInstance.get(), shadowTreeRootElement );
421
422 // Expand all <use> elements in the shadow tree.
423 // Expand means: replace the actual <use> element by what it references.
424 expandUseElementsInShadowTree(shadowTreeRootElement);
425
426 // Expand all <symbol> elements in the shadow tree. 407 // Expand all <symbol> elements in the shadow tree.
427 // Expand means: replace the actual <symbol> element by the <svg> element. 408 // Expand means: replace the actual <symbol> element by the <svg> element.
428 expandSymbolElementsInShadowTree(shadowTreeRootElement); 409 expandSymbolElementsInShadowTree(toSVGElement(shadowTreeRootElement->firstCh ild()));
429 410
430 // If no shadow tree element is present, this means that the reference root 411 m_targetElementInstance = toSVGElement(shadowTreeRootElement->firstChild());
431 // element was removed, as it is disallowed (ie. <use> on <foreignObject>) 412 transferUseWidthAndHeightIfNeeded(*this, m_targetElementInstance.get(), *m_t argetElementInstance->correspondingElement());
432 // Do NOT leave an inconsistent instance tree around, instead destruct it.
433 Node* shadowTreeTargetNode = shadowTreeRootElement->firstChild();
434 if (!shadowTreeTargetNode) {
435 clearResourceReferences();
436 return;
437 }
438 413
439 // Now that the shadow tree is completly expanded, we can associate 414 ASSERT(m_targetElementInstance->parentNode() == shadowTreeRootElement);
440 // shadow tree elements <-> instances in the instance tree.
441 associateInstancesWithShadowTreeElements(shadowTreeTargetNode, m_targetEleme ntInstance.get());
442
443 SVGElement* shadowTreeTargetElement = toSVGElement(shadowTreeTargetNode);
444 ASSERT(shadowTreeTargetElement->correspondingElement());
445 transferUseWidthAndHeightIfNeeded(*this, shadowTreeTargetElement, *shadowTre eTargetElement->correspondingElement());
446
447 ASSERT(shadowTreeTargetElement->parentNode() == shadowTreeRootElement);
448
449 // Transfer event listeners assigned to the referenced element to our shadow tree elements.
450 transferEventListenersToShadowTree(shadowTreeTargetElement);
451 415
452 // Update relative length information. 416 // Update relative length information.
453 updateRelativeLengthsInformation(); 417 updateRelativeLengthsInformation();
454 } 418 }
455 419
456 RenderObject* SVGUseElement::createRenderer(RenderStyle*) 420 RenderObject* SVGUseElement::createRenderer(RenderStyle*)
457 { 421 {
458 return new RenderSVGTransformableContainer(this); 422 return new RenderSVGTransformableContainer(this);
459 } 423 }
460 424
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
494 RenderObject* SVGUseElement::rendererClipChild() const 458 RenderObject* SVGUseElement::rendererClipChild() const
495 { 459 {
496 if (Node* n = userAgentShadowRoot()->firstChild()) { 460 if (Node* n = userAgentShadowRoot()->firstChild()) {
497 if (n->isSVGElement() && isDirectReference(*n)) 461 if (n->isSVGElement() && isDirectReference(*n))
498 return toSVGElement(n)->renderer(); 462 return toSVGElement(n)->renderer();
499 } 463 }
500 464
501 return 0; 465 return 0;
502 } 466 }
503 467
504 void SVGUseElement::buildInstanceTree(SVGElement* target, SVGElementInstance* ta rgetInstance, bool& foundProblem, bool foundUse) 468 bool SVGUseElement::buildShadowTree(SVGElement* target, SVGElement* targetInstan ce, bool foundUse)
505 { 469 {
506 ASSERT(target); 470 ASSERT(target);
507 ASSERT(targetInstance); 471 ASSERT(targetInstance);
508 472
509 // Spec: If the referenced object is itself a 'use', or if there are 'use' s ubelements within the referenced 473 // Spec: If the referenced object is itself a 'use', or if there are 'use' s ubelements within the referenced
510 // object, the instance tree will contain recursive expansion of the indirec t references to form a complete tree. 474 // object, the instance tree will contain recursive expansion of the indirec t references to form a complete tree.
511 bool targetIsUseElement = isSVGUseElement(*target); 475 if (isSVGUseElement(*target)) {
512 SVGElement* newTarget = 0;
513 if (targetIsUseElement) {
514 foundProblem = hasCycleUseReferencing(toSVGUseElement(target), targetIns tance, newTarget);
515 if (foundProblem)
516 return;
517
518 // We only need to track first degree <use> dependencies. Indirect refer ences are handled 476 // We only need to track first degree <use> dependencies. Indirect refer ences are handled
519 // as the invalidation bubbles up the dependency chain. 477 // as the invalidation bubbles up the dependency chain.
520 if (!foundUse) { 478 if (!foundUse) {
521 document().accessSVGExtensions().addElementReferencingTarget(this, t arget); 479 document().accessSVGExtensions().addElementReferencingTarget(this, t arget);
522 foundUse = true; 480 foundUse = true;
523 } 481 }
524 } else if (isDisallowedElement(target)) { 482 } else if (isDisallowedElement(target)) {
525 foundProblem = true; 483 return false;
526 return;
527 } 484 }
528 485
529 // A general description from the SVG spec, describing what buildInstanceTre e() actually does. 486 targetInstance->setCorrespondingElement(target);
530 //
531 // Spec: If the 'use' element references a 'g' which contains two 'rect' ele ments, then the instance tree
532 // contains three SVGElementInstance objects, a root SVGElementInstance obje ct whose correspondingElement
533 // is the SVGGElement object for the 'g', and then two child SVGElementInsta nce objects, each of which has
534 // its correspondingElement that is an SVGRectElement object.
535 487
536 for (SVGElement* element = Traversal<SVGElement>::firstChild(*target); eleme nt; element = Traversal<SVGElement>::nextSibling(*element)) { 488 for (Node* child = target->firstChild(); child; child = child->nextSibling() ) {
537 // Skip any disallowed element. 489 // Skip any disallowed element.
538 if (isDisallowedElement(element)) 490 if (isDisallowedElement(child))
539 continue; 491 continue;
540 492
541 // Create SVGElementInstance object, for both container/non-container no des. 493 RefPtrWillBeRawPtr<Node> newChild = child->cloneNode(false);
542 RefPtrWillBeRawPtr<SVGElementInstance> instance = SVGElementInstance::cr eate(this, 0, element); 494 targetInstance->appendChild(newChild.get());
543 SVGElementInstance* instancePtr = instance.get(); 495 if (newChild->isSVGElement()) {
544 targetInstance->appendChild(instance.release()); 496 // Enter recursion, appending new instance tree nodes to the "instan ce" object.
545 497 if (!buildShadowTree(toSVGElement(child), toSVGElement(newChild), fo undUse))
546 // Enter recursion, appending new instance tree nodes to the "instance" object. 498 return false;
547 buildInstanceTree(element, instancePtr, foundProblem, foundUse); 499 }
548 if (foundProblem)
549 return;
550 } 500 }
551 501 return true;
552 if (!targetIsUseElement || !newTarget)
553 return;
554
555 RefPtrWillBeRawPtr<SVGElementInstance> newInstance = SVGElementInstance::cre ate(this, toSVGUseElement(target), newTarget);
556 SVGElementInstance* newInstancePtr = newInstance.get();
557 targetInstance->appendChild(newInstance.release());
558 buildInstanceTree(newTarget, newInstancePtr, foundProblem, foundUse);
559 } 502 }
560 503
561 bool SVGUseElement::hasCycleUseReferencing(SVGUseElement* use, SVGElementInstanc e* targetInstance, SVGElement*& newTarget) 504 bool SVGUseElement::hasCycleUseReferencing(SVGUseElement* use, ContainerNode* ta rgetInstance, SVGElement*& newTarget)
562 { 505 {
563 ASSERT(referencedScope()); 506 ASSERT(referencedScope());
564 Element* targetElement = SVGURIReference::targetElementFromIRIString(use->hr efString(), *referencedScope()); 507 Element* targetElement = SVGURIReference::targetElementFromIRIString(use->hr efString(), *referencedScope());
565 newTarget = 0; 508 newTarget = 0;
566 if (targetElement && targetElement->isSVGElement()) 509 if (targetElement && targetElement->isSVGElement())
567 newTarget = toSVGElement(targetElement); 510 newTarget = toSVGElement(targetElement);
568 511
569 if (!newTarget) 512 if (!newTarget)
570 return false; 513 return false;
571 514
572 // Shortcut for self-references 515 // Shortcut for self-references
573 if (newTarget == this) 516 if (newTarget == this)
574 return true; 517 return true;
575 518
576 AtomicString targetId = newTarget->getIdAttribute(); 519 AtomicString targetId = newTarget->getIdAttribute();
577 SVGElementInstance* instance = targetInstance->parentNode(); 520 ContainerNode* instance = targetInstance->parentNode();
578 while (instance) { 521 while (instance && instance->isSVGElement()) {
579 SVGElement* element = instance->correspondingElement(); 522 SVGElement* element = toSVGElement(instance);
580
581 if (element->hasID() && element->getIdAttribute() == targetId && element ->document() == newTarget->document()) 523 if (element->hasID() && element->getIdAttribute() == targetId && element ->document() == newTarget->document())
582 return true; 524 return true;
583 525
584 instance = instance->parentNode(); 526 instance = instance->parentNode();
585 } 527 }
586 return false; 528 return false;
587 } 529 }
588 530
589 static inline void removeDisallowedElementsFromSubtree(Element& subtree) 531 static inline void removeDisallowedElementsFromSubtree(Element& subtree)
590 { 532 {
591 ASSERT(!subtree.inDocument()); 533 ASSERT(!subtree.inDocument());
592 Element* element = ElementTraversal::firstWithin(subtree); 534 Element* element = ElementTraversal::firstWithin(subtree);
593 while (element) { 535 while (element) {
594 if (isDisallowedElement(element)) { 536 if (isDisallowedElement(element)) {
595 Element* next = ElementTraversal::nextSkippingChildren(*element, &su btree); 537 Element* next = ElementTraversal::nextSkippingChildren(*element, &su btree);
596 // The subtree is not in document so this won't generate events that could mutate the tree. 538 // The subtree is not in document so this won't generate events that could mutate the tree.
597 element->parentNode()->removeChild(element); 539 element->parentNode()->removeChild(element);
598 element = next; 540 element = next;
599 } else { 541 } else {
600 element = ElementTraversal::next(*element, &subtree); 542 element = ElementTraversal::next(*element, &subtree);
601 } 543 }
602 } 544 }
603 } 545 }
604 546
605 void SVGUseElement::buildShadowTree(SVGElement* target, SVGElementInstance* targ etInstance, ShadowRoot* shadowTreeRootElement) 547 bool SVGUseElement::expandUseElementsInShadowTree(SVGElement* element)
606 {
607 // For instance <use> on <foreignObject> (direct case).
608 if (isDisallowedElement(target))
609 return;
610
611 RefPtrWillBeRawPtr<Element> newChild = targetInstance->correspondingElement( )->cloneElementWithChildren();
612
613 // We don't walk the target tree element-by-element, and clone each element,
614 // but instead use cloneElementWithChildren(). This is an optimization for t he common
615 // case where <use> doesn't contain disallowed elements (ie. <foreignObject> ).
616 // Though if there are disallowed elements in the subtree, we have to remove them.
617 // For instance: <use> on <g> containing <foreignObject> (indirect case).
618 if (subtreeContainsDisallowedElement(newChild.get()))
619 removeDisallowedElementsFromSubtree(*newChild);
620
621 shadowTreeRootElement->appendChild(newChild.release());
622 }
623
624 void SVGUseElement::expandUseElementsInShadowTree(Node* element)
625 { 548 {
626 ASSERT(element); 549 ASSERT(element);
627 // Why expand the <use> elements in the shadow tree here, and not just 550 // Why expand the <use> elements in the shadow tree here, and not just
628 // do this directly in buildShadowTree, if we encounter a <use> element? 551 // do this directly in buildShadowTree, if we encounter a <use> element?
629 // 552 //
630 // Short answer: Because we may miss to expand some elements. For example, i f a <symbol> 553 // Short answer: Because we may miss to expand some elements. For example, i f a <symbol>
631 // contains <use> tags, we'd miss them. So once we're done with setting up t he 554 // contains <use> tags, we'd miss them. So once we're done with setting up t he
632 // actual shadow tree (after the special case modification for svg/symbol) w e have 555 // actual shadow tree (after the special case modification for svg/symbol) w e have
633 // to walk it completely and expand all <use> elements. 556 // to walk it completely and expand all <use> elements.
634 if (isSVGUseElement(*element)) { 557 if (isSVGUseElement(*element)) {
635 SVGUseElement* use = toSVGUseElement(element); 558 SVGUseElement* use = toSVGUseElement(element);
636 ASSERT(!use->resourceIsStillLoading()); 559 ASSERT(!use->resourceIsStillLoading());
637 560
638 ASSERT(referencedScope());
639 Element* targetElement = SVGURIReference::targetElementFromIRIString(use ->hrefString(), *referencedScope());
640 SVGElement* target = 0; 561 SVGElement* target = 0;
641 if (targetElement && targetElement->isSVGElement()) 562 if (hasCycleUseReferencing(toSVGUseElement(use->correspondingElement()), use, target))
642 target = toSVGElement(targetElement); 563 return false;
643 564
565 if (target && isDisallowedElement(target))
566 return false;
644 // Don't ASSERT(target) here, it may be "pending", too. 567 // Don't ASSERT(target) here, it may be "pending", too.
645 // Setup sub-shadow tree root node 568 // Setup sub-shadow tree root node
646 RefPtrWillBeRawPtr<SVGGElement> cloneParent = SVGGElement::create(refere ncedScope()->document()); 569 RefPtrWillBeRawPtr<SVGGElement> cloneParent = SVGGElement::create(refere ncedScope()->document());
647 use->cloneChildNodes(cloneParent.get()); 570 cloneParent->setCorrespondingElement(use->correspondingElement());
571
572 // Move already cloned elements to the new <g> element
573 for (Node* child = use->firstChild(); child; ) {
574 Node* nextChild = child->nextSibling();
575 cloneParent->appendChild(child);
576 child = nextChild;
577 }
648 578
649 // Spec: In the generated content, the 'use' will be replaced by 'g', wh ere all attributes from the 579 // Spec: In the generated content, the 'use' will be replaced by 'g', wh ere all attributes from the
650 // 'use' element except for x, y, width, height and xlink:href are trans ferred to the generated 'g' element. 580 // 'use' element except for x, y, width, height and xlink:href are trans ferred to the generated 'g' element.
651 transferUseAttributesToReplacedElement(use, cloneParent.get()); 581 transferUseAttributesToReplacedElement(use, cloneParent.get());
652 582
653 if (target && !isDisallowedElement(target)) { 583 if (target) {
654 RefPtrWillBeRawPtr<Element> newChild = target->cloneElementWithChild ren(); 584 RefPtrWillBeRawPtr<Node> newChild = cloneNodeAndAssociate(target);
655 ASSERT(newChild->isSVGElement()); 585 ASSERT(newChild->isSVGElement());
656 transferUseWidthAndHeightIfNeeded(*use, toSVGElement(newChild.get()) , *target); 586 transferUseWidthAndHeightIfNeeded(*use, toSVGElement(newChild.get()) , *target);
657 cloneParent->appendChild(newChild.release()); 587 cloneParent->appendChild(newChild.release());
658 } 588 }
659 589
660 // We don't walk the target tree element-by-element, and clone each elem ent, 590 // We don't walk the target tree element-by-element, and clone each elem ent,
661 // but instead use cloneElementWithChildren(). This is an optimization f or the common 591 // but instead use cloneElementWithChildren(). This is an optimization f or the common
662 // case where <use> doesn't contain disallowed elements (ie. <foreignObj ect>). 592 // case where <use> doesn't contain disallowed elements (ie. <foreignObj ect>).
663 // Though if there are disallowed elements in the subtree, we have to re move them. 593 // Though if there are disallowed elements in the subtree, we have to re move them.
664 // For instance: <use> on <g> containing <foreignObject> (indirect case) . 594 // For instance: <use> on <g> containing <foreignObject> (indirect case) .
665 if (subtreeContainsDisallowedElement(cloneParent.get())) 595 if (subtreeContainsDisallowedElement(cloneParent.get()))
666 removeDisallowedElementsFromSubtree(*cloneParent); 596 removeDisallowedElementsFromSubtree(*cloneParent);
667 597
668 RefPtrWillBeRawPtr<Node> replacingElement(cloneParent.get()); 598 RefPtrWillBeRawPtr<SVGElement> replacingElement(cloneParent.get());
669 599
670 // Replace <use> with referenced content. 600 // Replace <use> with referenced content.
671 ASSERT(use->parentNode()); 601 ASSERT(use->parentNode());
672 use->parentNode()->replaceChild(cloneParent.release(), use); 602 use->parentNode()->replaceChild(cloneParent.release(), use);
673 603
674 // Expand the siblings because the *element* is replaced and we will 604 // Expand the siblings because the *element* is replaced and we will
675 // lose the sibling chain when we are back from recursion. 605 // lose the sibling chain when we are back from recursion.
676 element = replacingElement.get(); 606 element = replacingElement.get();
677 for (RefPtrWillBeRawPtr<Node> sibling = element->nextSibling(); sibling; sibling = sibling->nextSibling()) 607 for (RefPtrWillBeRawPtr<SVGElement> sibling = Traversal<SVGElement>::nex tSibling(*element); sibling; sibling = Traversal<SVGElement>::nextSibling(*sibli ng)) {
678 expandUseElementsInShadowTree(sibling.get()); 608 if (!expandUseElementsInShadowTree(sibling.get()))
609 return false;
610 }
679 } 611 }
680 612
681 for (RefPtrWillBeRawPtr<Node> child = element->firstChild(); child; child = child->nextSibling()) 613 for (RefPtrWillBeRawPtr<SVGElement> child = Traversal<SVGElement>::firstChil d(*element); child; child = Traversal<SVGElement>::nextSibling(*child)) {
682 expandUseElementsInShadowTree(child.get()); 614 if (!expandUseElementsInShadowTree(child.get()))
615 return false;
616 }
617 return true;
683 } 618 }
684 619
685 void SVGUseElement::expandSymbolElementsInShadowTree(Node* element) 620 void SVGUseElement::expandSymbolElementsInShadowTree(SVGElement* element)
686 { 621 {
687 ASSERT(element); 622 ASSERT(element);
688 if (isSVGSymbolElement(*element)) { 623 if (isSVGSymbolElement(*element)) {
689 // Spec: The referenced 'symbol' and its contents are deep-cloned into t he generated tree, 624 // Spec: The referenced 'symbol' and its contents are deep-cloned into t he generated tree,
690 // with the exception that the 'symbol' is replaced by an 'svg'. This ge nerated 'svg' will 625 // with the exception that the 'symbol' is replaced by an 'svg'. This ge nerated 'svg' will
691 // always have explicit values for attributes width and height. If attri butes width and/or 626 // always have explicit values for attributes width and height. If attri butes width and/or
692 // height are provided on the 'use' element, then these attributes will be transferred to 627 // height are provided on the 'use' element, then these attributes will be transferred to
693 // the generated 'svg'. If attributes width and/or height are not specif ied, the generated 628 // the generated 'svg'. If attributes width and/or height are not specif ied, the generated
694 // 'svg' element will use values of 100% for these attributes. 629 // 'svg' element will use values of 100% for these attributes.
695 ASSERT(referencedScope()); 630 ASSERT(referencedScope());
696 RefPtrWillBeRawPtr<SVGSVGElement> svgElement = SVGSVGElement::create(ref erencedScope()->document()); 631 RefPtrWillBeRawPtr<SVGSVGElement> svgElement = SVGSVGElement::create(ref erencedScope()->document());
632 // Transfer all data (attributes, etc.) from <symbol> to the new <svg> e lement.
633 svgElement->cloneDataFromElement(*element);
634 svgElement->setCorrespondingElement(element->correspondingElement());
697 635
698 // Transfer all data (attributes, etc.) from <symbol> to the new <svg> e lement. 636 // Move already cloned elements to the new <svg> element
699 svgElement->cloneDataFromElement(*toElement(element)); 637 for (Node* child = element->firstChild(); child; ) {
700 638 Node* nextChild = child->nextSibling();
701 // Only clone symbol children, and add them to the new <svg> element 639 svgElement->appendChild(child);
702 for (Node* child = element->firstChild(); child; child = child->nextSibl ing()) 640 child = nextChild;
703 svgElement->appendChild(child->cloneNode(true)); 641 }
704 642
705 // We don't walk the target tree element-by-element, and clone each elem ent, 643 // We don't walk the target tree element-by-element, and clone each elem ent,
706 // but instead use cloneNode(deep=true). This is an optimization for the common 644 // but instead use cloneNode(deep=true). This is an optimization for the common
707 // case where <use> doesn't contain disallowed elements (ie. <foreignObj ect>). 645 // case where <use> doesn't contain disallowed elements (ie. <foreignObj ect>).
708 // Though if there are disallowed elements in the subtree, we have to re move them. 646 // Though if there are disallowed elements in the subtree, we have to re move them.
709 // For instance: <use> on <g> containing <foreignObject> (indirect case) . 647 // For instance: <use> on <g> containing <foreignObject> (indirect case) .
710 if (subtreeContainsDisallowedElement(svgElement.get())) 648 if (subtreeContainsDisallowedElement(svgElement.get()))
711 removeDisallowedElementsFromSubtree(*svgElement); 649 removeDisallowedElementsFromSubtree(*svgElement);
712 650
713 RefPtrWillBeRawPtr<Node> replacingElement(svgElement.get()); 651 RefPtrWillBeRawPtr<SVGElement> replacingElement(svgElement.get());
714 652
715 // Replace <symbol> with <svg>. 653 // Replace <symbol> with <svg>.
654 ASSERT(element->parentNode());
716 element->parentNode()->replaceChild(svgElement.release(), element); 655 element->parentNode()->replaceChild(svgElement.release(), element);
717 656
718 // Expand the siblings because the *element* is replaced and we will 657 // Expand the siblings because the *element* is replaced and we will
719 // lose the sibling chain when we are back from recursion. 658 // lose the sibling chain when we are back from recursion.
720 element = replacingElement.get(); 659 element = replacingElement.get();
721 for (RefPtrWillBeRawPtr<Node> sibling = element->nextSibling(); sibling; sibling = sibling->nextSibling())
722 expandSymbolElementsInShadowTree(sibling.get());
723 } 660 }
724 661
725 for (RefPtrWillBeRawPtr<Node> child = element->firstChild(); child; child = child->nextSibling()) 662 for (RefPtrWillBeRawPtr<SVGElement> child = Traversal<SVGElement>::firstChil d(*element); child; child = Traversal<SVGElement>::nextSibling(*child))
726 expandSymbolElementsInShadowTree(child.get()); 663 expandSymbolElementsInShadowTree(child.get());
727 } 664 }
728 665
729 void SVGUseElement::transferEventListenersToShadowTree(SVGElement* shadowTreeTar getElement)
730 {
731 if (!shadowTreeTargetElement)
732 return;
733
734 SVGElement* originalElement = shadowTreeTargetElement->correspondingElement( );
735 ASSERT(originalElement);
736 if (EventTargetData* data = originalElement->eventTargetData())
737 data->eventListenerMap.copyEventListenersNotCreatedFromMarkupToTarget(sh adowTreeTargetElement);
738
739 for (SVGElement* child = Traversal<SVGElement>::firstChild(*shadowTreeTarget Element); child; child = Traversal<SVGElement>::nextSibling(*child))
740 transferEventListenersToShadowTree(child);
741 }
742
743 void SVGUseElement::associateInstancesWithShadowTreeElements(Node* target, SVGEl ementInstance* targetInstance)
744 {
745 if (!target || !targetInstance)
746 return;
747
748 SVGElement* originalElement = targetInstance->correspondingElement();
749 ASSERT(originalElement);
750 if (isSVGUseElement(*originalElement)) {
751 // <use> gets replaced by <g>
752 ASSERT(AtomicString(target->nodeName()) == SVGNames::gTag);
753 } else if (isSVGSymbolElement(*originalElement)) {
754 // <symbol> gets replaced by <svg>
755 ASSERT(AtomicString(target->nodeName()) == SVGNames::svgTag);
756 } else {
757 ASSERT(AtomicString(target->nodeName()) == originalElement->nodeName());
758 }
759
760 SVGElement* element = 0;
761 if (target->isSVGElement())
762 element = toSVGElement(target);
763
764 ASSERT(!targetInstance->shadowTreeElement());
765 targetInstance->setShadowTreeElement(element);
766 element->setCorrespondingElement(originalElement);
767
768 SVGElement* child = Traversal<SVGElement>::firstChild(*target);
769 for (SVGElementInstance* instance = targetInstance->firstChild(); child && i nstance; instance = instance->nextSibling()) {
770 associateInstancesWithShadowTreeElements(child, instance);
771 child = Traversal<SVGElement>::nextSibling(*child);
772 }
773 }
774
775 void SVGUseElement::invalidateShadowTree() 666 void SVGUseElement::invalidateShadowTree()
776 { 667 {
777 if (!inActiveDocument() || m_needsShadowTreeRecreation) 668 if (!inActiveDocument() || m_needsShadowTreeRecreation)
778 return; 669 return;
779 scheduleShadowTreeRecreation(); 670 scheduleShadowTreeRecreation();
780 invalidateDependentShadowTrees(); 671 invalidateDependentShadowTrees();
781 } 672 }
782 673
783 void SVGUseElement::invalidateDependentShadowTrees() 674 void SVGUseElement::invalidateDependentShadowTrees()
784 { 675 {
(...skipping 26 matching lines...) Expand all
811 { 702 {
812 if (m_x->currentValue()->isRelative() 703 if (m_x->currentValue()->isRelative()
813 || m_y->currentValue()->isRelative() 704 || m_y->currentValue()->isRelative()
814 || m_width->currentValue()->isRelative() 705 || m_width->currentValue()->isRelative()
815 || m_height->currentValue()->isRelative()) 706 || m_height->currentValue()->isRelative())
816 return true; 707 return true;
817 708
818 if (!m_targetElementInstance) 709 if (!m_targetElementInstance)
819 return false; 710 return false;
820 711
821 SVGElement* element = m_targetElementInstance->shadowTreeElement(); 712 return m_targetElementInstance->hasRelativeLengths();
822 if (!element)
823 return false;
824
825 return element->hasRelativeLengths();
826 } 713 }
827 714
828 void SVGUseElement::notifyFinished(Resource* resource) 715 void SVGUseElement::notifyFinished(Resource* resource)
829 { 716 {
830 if (!inDocument()) 717 if (!inDocument())
831 return; 718 return;
832 719
833 invalidateShadowTree(); 720 invalidateShadowTree();
834 if (resource->errorOccurred()) 721 if (resource->errorOccurred())
835 dispatchEvent(Event::create(EventTypeNames::error)); 722 dispatchEvent(Event::create(EventTypeNames::error));
836 else if (!resource->wasCanceled()) { 723 else if (!resource->wasCanceled()) {
837 if (m_haveFiredLoadEvent) 724 if (m_haveFiredLoadEvent)
838 return; 725 return;
839 if (!isStructurallyExternal()) 726 if (!isStructurallyExternal())
840 return; 727 return;
841 ASSERT(!m_haveFiredLoadEvent); 728 ASSERT(!m_haveFiredLoadEvent);
842 m_haveFiredLoadEvent = true; 729 m_haveFiredLoadEvent = true;
843 sendSVGLoadEventIfPossibleAsynchronously(); 730 sendSVGLoadEventIfPossibleAsynchronously();
844 } 731 }
845 } 732 }
846 733
847 bool SVGUseElement::resourceIsStillLoading() 734 bool SVGUseElement::resourceIsStillLoading()
848 { 735 {
849 if (m_resource && m_resource->isLoading()) 736 if (m_resource && m_resource->isLoading())
850 return true; 737 return true;
851 return false; 738 return false;
852 } 739 }
853 740
854 bool SVGUseElement::instanceTreeIsLoading(SVGElementInstance* targetElementInsta nce) 741 bool SVGUseElement::instanceTreeIsLoading(SVGElement* targetInstance)
855 { 742 {
856 for (SVGElementInstance* instance = targetElementInstance->firstChild(); ins tance; instance = instance->nextSibling()) { 743 for (SVGElement* element = Traversal<SVGElement>::firstChild(*targetInstance ); element; element = Traversal<SVGElement>::nextSibling(*element)) {
857 if (SVGUseElement* use = instance->correspondingUseElement()) { 744 if (SVGUseElement* use = element->correspondingUseElement()) {
858 if (use->resourceIsStillLoading()) 745 if (use->resourceIsStillLoading())
859 return true; 746 return true;
860 } 747 }
861 if (instance->hasChildren()) 748 if (element->hasChildren() && instanceTreeIsLoading(element))
esprehn 2014/06/05 20:57:25 We should probably write a test for this, but it's
862 instanceTreeIsLoading(instance); 749 return true;
863 } 750 }
864 return false; 751 return false;
865 } 752 }
866 753
867 void SVGUseElement::setDocumentResource(ResourcePtr<DocumentResource> resource) 754 void SVGUseElement::setDocumentResource(ResourcePtr<DocumentResource> resource)
868 { 755 {
869 if (m_resource == resource) 756 if (m_resource == resource)
870 return; 757 return;
871 758
872 if (m_resource) 759 if (m_resource)
873 m_resource->removeClient(this); 760 m_resource->removeClient(this);
874 761
875 m_resource = resource; 762 m_resource = resource;
876 if (m_resource) 763 if (m_resource)
877 m_resource->addClient(this); 764 m_resource->addClient(this);
878 } 765 }
879 766
880 void SVGUseElement::trace(Visitor* visitor) 767 void SVGUseElement::trace(Visitor* visitor)
881 { 768 {
882 visitor->trace(m_targetElementInstance); 769 visitor->trace(m_targetElementInstance);
883 SVGGraphicsElement::trace(visitor); 770 SVGGraphicsElement::trace(visitor);
884 } 771 }
885 772
886 } 773 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698