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

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: Fix TestExpectations 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 void cloneChildrenAndAssociate(Node* toClone, PassRefPtr<Node> clone);
347
348 static PassRefPtr<Node> cloneNodeAndAssociate(Node* toClone)
349 {
350 RefPtr<Node> clone = toClone->cloneNode(false);
351 if (toClone->isSVGElement())
352 if (SVGElement* svgElement = toSVGElement(toClone))
353 toSVGElement(clone.get())->setCorrespondingElement(svgElement->corre spondingElement() ? svgElement->correspondingElement() : svgElement);
354 cloneChildrenAndAssociate(toClone, clone);
355 return clone.release();
356 }
357
358 static void cloneChildrenAndAssociate(Node* toClone, PassRefPtr<Node> clone)
359 {
360 TrackExceptionState exceptionState;
361 for (Node* n = toClone->firstChild(); n && !exceptionState.hadException(); n = n->nextSibling())
362 clone->appendChild(cloneNodeAndAssociate(n), exceptionState);
363 }
364
367 void SVGUseElement::buildShadowAndInstanceTree(SVGElement* target) 365 void SVGUseElement::buildShadowAndInstanceTree(SVGElement* target)
368 { 366 {
369 ASSERT(!m_targetElementInstance); 367 ASSERT(!m_targetElementInstance);
370 368
371 // <use> creates a "user agent" shadow root. Do not build the shadow/instanc e tree for <use> 369 // <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 370 // elements living in a user agent shadow tree because they will get expande d in a second
373 // pass -- see expandUseElementsInShadowTree(). 371 // pass -- see expandUseElementsInShadowTree().
374 if (inUseShadowTree()) 372 if (inUseShadowTree())
375 return; 373 return;
376 374
377 // Do not allow self-referencing. 375 // Do not allow self-referencing.
378 // 'target' may be null, if it's a non SVG namespaced element. 376 // 'target' may be null, if it's a non SVG namespaced element.
379 if (!target || target == this) 377 if (!target || target == this)
380 return; 378 return;
381 379
382 // Why a seperated instance/shadow tree? SVG demands it: 380 ShadowRoot* shadowTreeRootElement = userAgentShadowRoot();
383 // The instance tree is accesable from JavaScript, and has to 381 ASSERT(shadowTreeRootElement);
384 // expose a 1:1 copy of the referenced tree, whereas internally we need
385 // to alter the tree for correct "use-on-symbol", "use-on-svg" support.
386 382
387 // Build instance tree. Create root SVGElementInstance object for the first sub-tree node. 383 // Set up root SVG element in shadow tree.
388 // 384 RefPtr<Element> newChild = target->cloneElementWithoutChildren();
389 // Spec: If the 'use' element references a simple graphics element such as a 'rect', then there is only a 385 m_targetElementInstance = toSVGElement(newChild.get());
390 // single SVGElementInstance object, and the correspondingElement attribute on this SVGElementInstance object 386 shadowTreeRootElement->appendChild(newChild.release());
391 // is the SVGRectElement that corresponds to the referenced 'rect' element.
392 m_targetElementInstance = SVGElementInstance::create(this, this, target);
393 387
394 // Eventually enter recursion to build SVGElementInstance objects for the su b-tree children 388 // Clone the target subtree into the shadow tree, not handling <use> and <sy mbol> yet.
395 bool foundProblem = false; 389 bool foundProblem = false;
396 buildInstanceTree(target, m_targetElementInstance.get(), foundProblem, false ); 390 buildShadowTree(target, m_targetElementInstance.get(), foundProblem, false);
397
398 if (instanceTreeIsLoading(m_targetElementInstance.get()))
399 return;
400 391
401 // SVG specification does not say a word about <use> & cycles. My view on th is is: just ignore it! 392 // SVG specification does not say a word about <use> & cycles. My view on th is is: just ignore it!
402 // Non-appearing <use> content is easier to debug, then half-appearing conte nt. 393 // Non-appearing <use> content is easier to debug, then half-appearing conte nt.
403 if (foundProblem) { 394 if (foundProblem) {
404 clearResourceReferences(); 395 clearResourceReferences();
405 return; 396 return;
406 } 397 }
407 398
408 // Assure instance tree building was successfull 399 if (instanceTreeIsLoading(m_targetElementInstance.get()))
400 return;
401
402 // Assure shadow tree building was successfull
409 ASSERT(m_targetElementInstance); 403 ASSERT(m_targetElementInstance);
410 ASSERT(!m_targetElementInstance->shadowTreeElement());
411 ASSERT(m_targetElementInstance->correspondingUseElement() == this); 404 ASSERT(m_targetElementInstance->correspondingUseElement() == this);
412 ASSERT(m_targetElementInstance->directUseElement() == this);
413 ASSERT(m_targetElementInstance->correspondingElement() == target); 405 ASSERT(m_targetElementInstance->correspondingElement() == target);
414 406
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. 407 // Expand all <use> elements in the shadow tree.
423 // Expand means: replace the actual <use> element by what it references. 408 // Expand means: replace the actual <use> element by what it references.
424 expandUseElementsInShadowTree(shadowTreeRootElement); 409 foundProblem = false;
410 expandUseElementsInShadowTree(shadowTreeRootElement, foundProblem);
411 if (foundProblem) {
412 clearResourceReferences();
413 return;
414 }
425 415
426 // Expand all <symbol> elements in the shadow tree. 416 // Expand all <symbol> elements in the shadow tree.
427 // Expand means: replace the actual <symbol> element by the <svg> element. 417 // Expand means: replace the actual <symbol> element by the <svg> element.
428 expandSymbolElementsInShadowTree(shadowTreeRootElement); 418 expandSymbolElementsInShadowTree(shadowTreeRootElement);
429 419
430 // If no shadow tree element is present, this means that the reference root 420 m_targetElementInstance = toSVGElement(shadowTreeRootElement->firstChild());
431 // element was removed, as it is disallowed (ie. <use> on <foreignObject>) 421 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 422
439 // Now that the shadow tree is completly expanded, we can associate 423 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 424
449 // Transfer event listeners assigned to the referenced element to our shadow tree elements. 425 // Transfer event listeners assigned to the referenced element to our shadow tree elements.
450 transferEventListenersToShadowTree(shadowTreeTargetElement); 426 transferEventListenersToShadowTree(m_targetElementInstance.get());
451 427
452 // Update relative length information. 428 // Update relative length information.
453 updateRelativeLengthsInformation(); 429 updateRelativeLengthsInformation();
454 } 430 }
455 431
456 RenderObject* SVGUseElement::createRenderer(RenderStyle*) 432 RenderObject* SVGUseElement::createRenderer(RenderStyle*)
457 { 433 {
458 return new RenderSVGTransformableContainer(this); 434 return new RenderSVGTransformableContainer(this);
459 } 435 }
460 436
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
494 RenderObject* SVGUseElement::rendererClipChild() const 470 RenderObject* SVGUseElement::rendererClipChild() const
495 { 471 {
496 if (Node* n = userAgentShadowRoot()->firstChild()) { 472 if (Node* n = userAgentShadowRoot()->firstChild()) {
497 if (n->isSVGElement() && isDirectReference(*n)) 473 if (n->isSVGElement() && isDirectReference(*n))
498 return toSVGElement(n)->renderer(); 474 return toSVGElement(n)->renderer();
499 } 475 }
500 476
501 return 0; 477 return 0;
502 } 478 }
503 479
504 void SVGUseElement::buildInstanceTree(SVGElement* target, SVGElementInstance* ta rgetInstance, bool& foundProblem, bool foundUse) 480 void SVGUseElement::buildShadowTree(SVGElement* target, SVGElement* targetInstan ce, bool& foundProblem, bool foundUse)
505 { 481 {
506 ASSERT(target); 482 ASSERT(target);
507 ASSERT(targetInstance); 483 ASSERT(targetInstance);
508 484
509 // Spec: If the referenced object is itself a 'use', or if there are 'use' s ubelements within the referenced 485 // 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. 486 // object, the instance tree will contain recursive expansion of the indirec t references to form a complete tree.
511 bool targetIsUseElement = isSVGUseElement(*target); 487 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 488 // We only need to track first degree <use> dependencies. Indirect refer ences are handled
519 // as the invalidation bubbles up the dependency chain. 489 // as the invalidation bubbles up the dependency chain.
520 if (!foundUse) { 490 if (!foundUse) {
521 document().accessSVGExtensions().addElementReferencingTarget(this, t arget); 491 document().accessSVGExtensions().addElementReferencingTarget(this, t arget);
522 foundUse = true; 492 foundUse = true;
523 } 493 }
524 } else if (isDisallowedElement(target)) { 494 } else if (isDisallowedElement(target)) {
525 foundProblem = true; 495 foundProblem = true;
526 return; 496 return;
527 } 497 }
528 498
499 targetInstance->setCorrespondingElement(target);
500
529 // A general description from the SVG spec, describing what buildInstanceTre e() actually does. 501 // A general description from the SVG spec, describing what buildInstanceTre e() actually does.
530 // 502 //
531 // Spec: If the 'use' element references a 'g' which contains two 'rect' ele ments, then the instance tree 503 // 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 504 // 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 505 // 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. 506 // its correspondingElement that is an SVGRectElement object.
535 507 for (RefPtr<Node> child = target->firstChild(); child; child = child->nextSi bling()) {
536 for (SVGElement* element = Traversal<SVGElement>::firstChild(*target); eleme nt; element = Traversal<SVGElement>::nextSibling(*element)) {
537 // Skip any disallowed element. 508 // Skip any disallowed element.
538 if (isDisallowedElement(element)) 509 if (isDisallowedElement(child.get()))
539 continue; 510 continue;
540 511
541 // Create SVGElementInstance object, for both container/non-container no des. 512 RefPtrWillBeRawPtr<Node> newChild = child->cloneNode(false);
542 RefPtrWillBeRawPtr<SVGElementInstance> instance = SVGElementInstance::cr eate(this, 0, element); 513 Node* instancePtr = newChild.get();
543 SVGElementInstance* instancePtr = instance.get(); 514 targetInstance->appendChild(newChild.release());
544 targetInstance->appendChild(instance.release()); 515 if (instancePtr->isSVGElement()) {
545 516 // Enter recursion, appending new instance tree nodes to the "instan ce" object.
546 // Enter recursion, appending new instance tree nodes to the "instance" object. 517 buildShadowTree(toSVGElement(child), toSVGElement(instancePtr), foun dProblem, foundUse);
547 buildInstanceTree(element, instancePtr, foundProblem, foundUse); 518 if (foundProblem)
548 if (foundProblem) 519 return;
549 return; 520 }
550 } 521 }
551
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 } 522 }
560 523
561 bool SVGUseElement::hasCycleUseReferencing(SVGUseElement* use, SVGElementInstanc e* targetInstance, SVGElement*& newTarget) 524 bool SVGUseElement::hasCycleUseReferencing(SVGUseElement* use, ContainerNode* ta rgetInstance, SVGElement*& newTarget)
562 { 525 {
563 ASSERT(referencedScope()); 526 ASSERT(referencedScope());
564 Element* targetElement = SVGURIReference::targetElementFromIRIString(use->hr efString(), *referencedScope()); 527 Element* targetElement = SVGURIReference::targetElementFromIRIString(use->hr efString(), *referencedScope());
565 newTarget = 0; 528 newTarget = 0;
566 if (targetElement && targetElement->isSVGElement()) 529 if (targetElement && targetElement->isSVGElement())
567 newTarget = toSVGElement(targetElement); 530 newTarget = toSVGElement(targetElement);
568 531
569 if (!newTarget) 532 if (!newTarget)
570 return false; 533 return false;
571 534
572 // Shortcut for self-references 535 // Shortcut for self-references
573 if (newTarget == this) 536 if (newTarget == this)
574 return true; 537 return true;
575 538
576 AtomicString targetId = newTarget->getIdAttribute(); 539 AtomicString targetId = newTarget->getIdAttribute();
577 SVGElementInstance* instance = targetInstance->parentNode(); 540 ContainerNode* instance = targetInstance->parentNode();
578 while (instance) { 541 while (instance && instance->isSVGElement()) {
579 SVGElement* element = instance->correspondingElement(); 542 SVGElement* element = toSVGElement(instance);
580
581 if (element->hasID() && element->getIdAttribute() == targetId && element ->document() == newTarget->document()) 543 if (element->hasID() && element->getIdAttribute() == targetId && element ->document() == newTarget->document())
582 return true; 544 return true;
583 545
584 instance = instance->parentNode(); 546 instance = instance->parentNode();
585 } 547 }
586 return false; 548 return false;
587 } 549 }
588 550
589 static inline void removeDisallowedElementsFromSubtree(Element& subtree) 551 static inline void removeDisallowedElementsFromSubtree(Element& subtree)
590 { 552 {
591 ASSERT(!subtree.inDocument()); 553 ASSERT(!subtree.inDocument());
592 Element* element = ElementTraversal::firstWithin(subtree); 554 Element* element = ElementTraversal::firstWithin(subtree);
593 while (element) { 555 while (element) {
594 if (isDisallowedElement(element)) { 556 if (isDisallowedElement(element)) {
595 Element* next = ElementTraversal::nextSkippingChildren(*element, &su btree); 557 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. 558 // The subtree is not in document so this won't generate events that could mutate the tree.
597 element->parentNode()->removeChild(element); 559 element->parentNode()->removeChild(element);
598 element = next; 560 element = next;
599 } else { 561 } else {
600 element = ElementTraversal::next(*element, &subtree); 562 element = ElementTraversal::next(*element, &subtree);
601 } 563 }
602 } 564 }
603 } 565 }
604 566
605 void SVGUseElement::buildShadowTree(SVGElement* target, SVGElementInstance* targ etInstance, ShadowRoot* shadowTreeRootElement) 567 void SVGUseElement::expandUseElementsInShadowTree(Node* element, bool& foundProb lem)
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 { 568 {
626 ASSERT(element); 569 ASSERT(element);
627 // Why expand the <use> elements in the shadow tree here, and not just 570 // 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? 571 // do this directly in buildShadowTree, if we encounter a <use> element?
629 // 572 //
630 // Short answer: Because we may miss to expand some elements. For example, i f a <symbol> 573 // 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 574 // 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 575 // actual shadow tree (after the special case modification for svg/symbol) w e have
633 // to walk it completely and expand all <use> elements. 576 // to walk it completely and expand all <use> elements.
634 if (isSVGUseElement(*element)) { 577 if (isSVGUseElement(*element)) {
635 SVGUseElement* use = toSVGUseElement(element); 578 SVGUseElement* use = toSVGUseElement(element);
636 ASSERT(!use->resourceIsStillLoading()); 579 ASSERT(!use->resourceIsStillLoading());
637 580
638 ASSERT(referencedScope());
639 Element* targetElement = SVGURIReference::targetElementFromIRIString(use ->hrefString(), *referencedScope());
640 SVGElement* target = 0; 581 SVGElement* target = 0;
641 if (targetElement && targetElement->isSVGElement()) 582 foundProblem = hasCycleUseReferencing(toSVGUseElement(use->corresponding Element()), use, target);
642 target = toSVGElement(targetElement); 583 if (foundProblem)
584 return;
643 585
586 if (target && isDisallowedElement(target)) {
587 foundProblem = true;
588 return;
589 }
644 // Don't ASSERT(target) here, it may be "pending", too. 590 // Don't ASSERT(target) here, it may be "pending", too.
645 // Setup sub-shadow tree root node 591 // Setup sub-shadow tree root node
646 RefPtrWillBeRawPtr<SVGGElement> cloneParent = SVGGElement::create(refere ncedScope()->document()); 592 RefPtrWillBeRawPtr<SVGGElement> cloneParent = SVGGElement::create(refere ncedScope()->document());
647 use->cloneChildNodes(cloneParent.get()); 593 cloneChildrenAndAssociate(use, cloneParent.get());
594 cloneParent->setCorrespondingElement(use->correspondingElement());
648 595
649 // Spec: In the generated content, the 'use' will be replaced by 'g', wh ere all attributes from the 596 // 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. 597 // 'use' element except for x, y, width, height and xlink:href are trans ferred to the generated 'g' element.
651 transferUseAttributesToReplacedElement(use, cloneParent.get()); 598 transferUseAttributesToReplacedElement(use, cloneParent.get());
652 599
653 if (target && !isDisallowedElement(target)) { 600 if (target) {
654 RefPtrWillBeRawPtr<Element> newChild = target->cloneElementWithChild ren(); 601 RefPtrWillBeRawPtr<Node> newChild = cloneNodeAndAssociate(target);
655 ASSERT(newChild->isSVGElement()); 602 ASSERT(newChild->isSVGElement());
656 transferUseWidthAndHeightIfNeeded(*use, toSVGElement(newChild.get()) , *target); 603 transferUseWidthAndHeightIfNeeded(*use, toSVGElement(newChild.get()) , *target);
657 cloneParent->appendChild(newChild.release()); 604 cloneParent->appendChild(newChild.release());
658 } 605 }
659 606
660 // We don't walk the target tree element-by-element, and clone each elem ent, 607 // 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 608 // but instead use cloneElementWithChildren(). This is an optimization f or the common
662 // case where <use> doesn't contain disallowed elements (ie. <foreignObj ect>). 609 // 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. 610 // 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) . 611 // For instance: <use> on <g> containing <foreignObject> (indirect case) .
665 if (subtreeContainsDisallowedElement(cloneParent.get())) 612 if (subtreeContainsDisallowedElement(cloneParent.get()))
666 removeDisallowedElementsFromSubtree(*cloneParent); 613 removeDisallowedElementsFromSubtree(*cloneParent);
667 614
668 RefPtr<Node> replacingElement(cloneParent.get()); 615 RefPtr<Node> replacingElement(cloneParent.get());
669 616
670 // Replace <use> with referenced content. 617 // Replace <use> with referenced content.
671 ASSERT(use->parentNode()); 618 ASSERT(use->parentNode());
672 use->parentNode()->replaceChild(cloneParent.release(), use); 619 use->parentNode()->replaceChild(cloneParent.release(), use);
620 use->setCorrespondingElement(0);
673 621
674 // Expand the siblings because the *element* is replaced and we will 622 // Expand the siblings because the *element* is replaced and we will
675 // lose the sibling chain when we are back from recursion. 623 // lose the sibling chain when we are back from recursion.
676 element = replacingElement.get(); 624 element = replacingElement.get();
677 for (RefPtr<Node> sibling = element->nextSibling(); sibling; sibling = s ibling->nextSibling()) 625 for (RefPtr<Node> sibling = element->nextSibling(); sibling; sibling = s ibling->nextSibling()) {
678 expandUseElementsInShadowTree(sibling.get()); 626 expandUseElementsInShadowTree(sibling.get(), foundProblem);
627 if (foundProblem)
628 return;
629 }
679 } 630 }
680 631
681 for (RefPtr<Node> child = element->firstChild(); child; child = child->nextS ibling()) 632 for (RefPtr<Node> child = element->firstChild(); child; child = child->nextS ibling()) {
682 expandUseElementsInShadowTree(child.get()); 633 expandUseElementsInShadowTree(child.get(), foundProblem);
634 if (foundProblem)
635 return;
636 }
683 } 637 }
684 638
685 void SVGUseElement::expandSymbolElementsInShadowTree(Node* element) 639 void SVGUseElement::expandSymbolElementsInShadowTree(Node* element)
686 { 640 {
687 ASSERT(element); 641 ASSERT(element);
688 if (isSVGSymbolElement(*element)) { 642 if (isSVGSymbolElement(*element)) {
689 // Spec: The referenced 'symbol' and its contents are deep-cloned into t he generated tree, 643 // 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 644 // 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 645 // 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 646 // 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 647 // 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. 648 // 'svg' element will use values of 100% for these attributes.
695 ASSERT(referencedScope()); 649 ASSERT(referencedScope());
696 RefPtrWillBeRawPtr<SVGSVGElement> svgElement = SVGSVGElement::create(ref erencedScope()->document()); 650 RefPtrWillBeRawPtr<SVGSVGElement> svgElement = SVGSVGElement::create(ref erencedScope()->document());
697 651
698 // Transfer all data (attributes, etc.) from <symbol> to the new <svg> e lement. 652 // Transfer all data (attributes, etc.) from <symbol> to the new <svg> e lement.
699 svgElement->cloneDataFromElement(*toElement(element)); 653 svgElement->cloneDataFromElement(*toElement(element));
654 svgElement->setCorrespondingElement(toSVGElement(element)->corresponding Element());
700 655
701 // Only clone symbol children, and add them to the new <svg> element 656 // Only clone symbol children, and add them to the new <svg> element
702 for (Node* child = element->firstChild(); child; child = child->nextSibl ing()) { 657 for (Node* child = toSVGElement(element)->firstChild(); child; child = c hild->nextSibling()) {
703 RefPtr<Node> newChild = child->cloneNode(true); 658 RefPtr<Node> newChild = cloneNodeAndAssociate(child);
704 svgElement->appendChild(newChild.release()); 659 svgElement->appendChild(newChild.release());
705 } 660 }
706 661
707 // We don't walk the target tree element-by-element, and clone each elem ent, 662 // We don't walk the target tree element-by-element, and clone each elem ent,
708 // but instead use cloneNode(deep=true). This is an optimization for the common 663 // but instead use cloneNode(deep=true). This is an optimization for the common
709 // case where <use> doesn't contain disallowed elements (ie. <foreignObj ect>). 664 // case where <use> doesn't contain disallowed elements (ie. <foreignObj ect>).
710 // Though if there are disallowed elements in the subtree, we have to re move them. 665 // Though if there are disallowed elements in the subtree, we have to re move them.
711 // For instance: <use> on <g> containing <foreignObject> (indirect case) . 666 // For instance: <use> on <g> containing <foreignObject> (indirect case) .
712 if (subtreeContainsDisallowedElement(svgElement.get())) 667 if (subtreeContainsDisallowedElement(svgElement.get()))
713 removeDisallowedElementsFromSubtree(*svgElement); 668 removeDisallowedElementsFromSubtree(*svgElement);
(...skipping 14 matching lines...) Expand all
728 expandSymbolElementsInShadowTree(child.get()); 683 expandSymbolElementsInShadowTree(child.get());
729 } 684 }
730 685
731 void SVGUseElement::transferEventListenersToShadowTree(SVGElement* shadowTreeTar getElement) 686 void SVGUseElement::transferEventListenersToShadowTree(SVGElement* shadowTreeTar getElement)
732 { 687 {
733 if (!shadowTreeTargetElement) 688 if (!shadowTreeTargetElement)
734 return; 689 return;
735 690
736 SVGElement* originalElement = shadowTreeTargetElement->correspondingElement( ); 691 SVGElement* originalElement = shadowTreeTargetElement->correspondingElement( );
737 ASSERT(originalElement); 692 ASSERT(originalElement);
693 originalElement->mapInstanceToElement(shadowTreeTargetElement);
694
738 if (EventTargetData* data = originalElement->eventTargetData()) 695 if (EventTargetData* data = originalElement->eventTargetData())
739 data->eventListenerMap.copyEventListenersNotCreatedFromMarkupToTarget(sh adowTreeTargetElement); 696 data->eventListenerMap.copyEventListenersNotCreatedFromMarkupToTarget(sh adowTreeTargetElement);
740 697
741 for (SVGElement* child = Traversal<SVGElement>::firstChild(*shadowTreeTarget Element); child; child = Traversal<SVGElement>::nextSibling(*child)) 698 for (SVGElement* child = Traversal<SVGElement>::firstChild(*shadowTreeTarget Element); child; child = Traversal<SVGElement>::nextSibling(*child))
742 transferEventListenersToShadowTree(child); 699 transferEventListenersToShadowTree(child);
743 } 700 }
744 701
745 void SVGUseElement::associateInstancesWithShadowTreeElements(Node* target, SVGEl ementInstance* targetInstance)
746 {
747 if (!target || !targetInstance)
748 return;
749
750 SVGElement* originalElement = targetInstance->correspondingElement();
751 ASSERT(originalElement);
752 if (isSVGUseElement(*originalElement)) {
753 // <use> gets replaced by <g>
754 ASSERT(AtomicString(target->nodeName()) == SVGNames::gTag);
755 } else if (isSVGSymbolElement(*originalElement)) {
756 // <symbol> gets replaced by <svg>
757 ASSERT(AtomicString(target->nodeName()) == SVGNames::svgTag);
758 } else {
759 ASSERT(AtomicString(target->nodeName()) == originalElement->nodeName());
760 }
761
762 SVGElement* element = 0;
763 if (target->isSVGElement())
764 element = toSVGElement(target);
765
766 ASSERT(!targetInstance->shadowTreeElement());
767 targetInstance->setShadowTreeElement(element);
768 element->setCorrespondingElement(originalElement);
769
770 SVGElement* child = Traversal<SVGElement>::firstChild(*target);
771 for (SVGElementInstance* instance = targetInstance->firstChild(); child && i nstance; instance = instance->nextSibling()) {
772 associateInstancesWithShadowTreeElements(child, instance);
773 child = Traversal<SVGElement>::nextSibling(*child);
774 }
775 }
776
777 void SVGUseElement::invalidateShadowTree() 702 void SVGUseElement::invalidateShadowTree()
778 { 703 {
779 if (!inActiveDocument() || m_needsShadowTreeRecreation) 704 if (!inActiveDocument() || m_needsShadowTreeRecreation)
780 return; 705 return;
781 scheduleShadowTreeRecreation(); 706 scheduleShadowTreeRecreation();
782 invalidateDependentShadowTrees(); 707 invalidateDependentShadowTrees();
783 } 708 }
784 709
785 void SVGUseElement::invalidateDependentShadowTrees() 710 void SVGUseElement::invalidateDependentShadowTrees()
786 { 711 {
(...skipping 26 matching lines...) Expand all
813 { 738 {
814 if (m_x->currentValue()->isRelative() 739 if (m_x->currentValue()->isRelative()
815 || m_y->currentValue()->isRelative() 740 || m_y->currentValue()->isRelative()
816 || m_width->currentValue()->isRelative() 741 || m_width->currentValue()->isRelative()
817 || m_height->currentValue()->isRelative()) 742 || m_height->currentValue()->isRelative())
818 return true; 743 return true;
819 744
820 if (!m_targetElementInstance) 745 if (!m_targetElementInstance)
821 return false; 746 return false;
822 747
823 SVGElement* element = m_targetElementInstance->shadowTreeElement(); 748 return m_targetElementInstance->hasRelativeLengths();
824 if (!element)
825 return false;
826
827 return element->hasRelativeLengths();
828 } 749 }
829 750
830 void SVGUseElement::notifyFinished(Resource* resource) 751 void SVGUseElement::notifyFinished(Resource* resource)
831 { 752 {
832 if (!inDocument()) 753 if (!inDocument())
833 return; 754 return;
834 755
835 invalidateShadowTree(); 756 invalidateShadowTree();
836 if (resource->errorOccurred()) 757 if (resource->errorOccurred())
837 dispatchEvent(Event::create(EventTypeNames::error)); 758 dispatchEvent(Event::create(EventTypeNames::error));
838 else if (!resource->wasCanceled()) { 759 else if (!resource->wasCanceled()) {
839 if (m_haveFiredLoadEvent) 760 if (m_haveFiredLoadEvent)
840 return; 761 return;
841 if (!isStructurallyExternal()) 762 if (!isStructurallyExternal())
842 return; 763 return;
843 ASSERT(!m_haveFiredLoadEvent); 764 ASSERT(!m_haveFiredLoadEvent);
844 m_haveFiredLoadEvent = true; 765 m_haveFiredLoadEvent = true;
845 sendSVGLoadEventIfPossibleAsynchronously(); 766 sendSVGLoadEventIfPossibleAsynchronously();
846 } 767 }
847 } 768 }
848 769
849 bool SVGUseElement::resourceIsStillLoading() 770 bool SVGUseElement::resourceIsStillLoading()
850 { 771 {
851 if (m_resource && m_resource->isLoading()) 772 if (m_resource && m_resource->isLoading())
852 return true; 773 return true;
853 return false; 774 return false;
854 } 775 }
855 776
856 bool SVGUseElement::instanceTreeIsLoading(SVGElementInstance* targetElementInsta nce) 777 bool SVGUseElement::instanceTreeIsLoading(SVGElement* targetInstance)
857 { 778 {
858 for (SVGElementInstance* instance = targetElementInstance->firstChild(); ins tance; instance = instance->nextSibling()) { 779 for (SVGElement* element = Traversal<SVGElement>::firstChild(*targetInstance ); element; element = Traversal<SVGElement>::nextSibling(*element)) {
859 if (SVGUseElement* use = instance->correspondingUseElement()) { 780 if (SVGUseElement* use = element->correspondingUseElement()) {
860 if (use->resourceIsStillLoading()) 781 if (use->resourceIsStillLoading())
861 return true; 782 return true;
862 } 783 }
863 if (instance->hasChildren()) 784 if (element->hasChildren())
864 instanceTreeIsLoading(instance); 785 instanceTreeIsLoading(element);
865 } 786 }
866 return false; 787 return false;
867 } 788 }
868 789
869 void SVGUseElement::setDocumentResource(ResourcePtr<DocumentResource> resource) 790 void SVGUseElement::setDocumentResource(ResourcePtr<DocumentResource> resource)
870 { 791 {
871 if (m_resource == resource) 792 if (m_resource == resource)
872 return; 793 return;
873 794
874 if (m_resource) 795 if (m_resource)
875 m_resource->removeClient(this); 796 m_resource->removeClient(this);
876 797
877 m_resource = resource; 798 m_resource = resource;
878 if (m_resource) 799 if (m_resource)
879 m_resource->addClient(this); 800 m_resource->addClient(this);
880 } 801 }
881 802
882 void SVGUseElement::trace(Visitor* visitor) 803 void SVGUseElement::trace(Visitor* visitor)
883 { 804 {
884 visitor->trace(m_targetElementInstance); 805 visitor->trace(m_targetElementInstance);
885 SVGGraphicsElement::trace(visitor); 806 SVGGraphicsElement::trace(visitor);
886 } 807 }
887 808
888 } 809 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698