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

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: Use attach/detach 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);
pdr. 2014/06/04 04:07:52 I'm not sure this is needed (see comments in expan
347
348 static PassRefPtr<Node> cloneNodeAndAssociate(Node* toClone)
349 {
350 RefPtr<Node> clone = toClone->cloneNode(false);
351 if (toClone->isSVGElement())
pdr. 2014/06/04 04:07:52 ForeignObject isn't allowed with <use>. Do we even
352 if (SVGElement* svgElement = toSVGElement(toClone))
353 toSVGElement(clone.get())->setCorrespondingElement(svgElement->corre spondingElement() ? svgElement->correspondingElement() : svgElement);
pdr. 2014/06/04 04:07:52 I'm afraid I don't understand this line. We're set
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());
pdr. 2014/06/04 04:07:52 Is this still needed?
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
529 // A general description from the SVG spec, describing what buildInstanceTre e() actually does. 499 targetInstance->setCorrespondingElement(target);
pdr. 2014/06/04 04:07:52 I think this comment was useful. Could we update i
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 500
536 for (SVGElement* element = Traversal<SVGElement>::firstChild(*target); eleme nt; element = Traversal<SVGElement>::nextSibling(*element)) { 501 for (RefPtr<Node> child = target->firstChild(); child; child = child->nextSi bling()) {
pdr. 2014/06/04 04:07:52 Why doesn't the SVGElement traversal work here?
537 // Skip any disallowed element. 502 // Skip any disallowed element.
538 if (isDisallowedElement(element)) 503 if (isDisallowedElement(child.get()))
539 continue; 504 continue;
540 505
541 // Create SVGElementInstance object, for both container/non-container no des. 506 RefPtrWillBeRawPtr<Node> newChild = child->cloneNode(false);
542 RefPtrWillBeRawPtr<SVGElementInstance> instance = SVGElementInstance::cr eate(this, 0, element); 507 Node* instancePtr = newChild.get();
543 SVGElementInstance* instancePtr = instance.get(); 508 targetInstance->appendChild(newChild.release());
544 targetInstance->appendChild(instance.release()); 509 if (instancePtr->isSVGElement()) {
kouhei (in TOK) 2014/06/04 04:28:44 Why do we need this if condition?
545 510 // Enter recursion, appending new instance tree nodes to the "instan ce" object.
546 // Enter recursion, appending new instance tree nodes to the "instance" object. 511 buildShadowTree(toSVGElement(child), toSVGElement(instancePtr), foun dProblem, foundUse);
547 buildInstanceTree(element, instancePtr, foundProblem, foundUse); 512 if (foundProblem)
548 if (foundProblem) 513 return;
549 return; 514 }
550 } 515 }
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 } 516 }
560 517
561 bool SVGUseElement::hasCycleUseReferencing(SVGUseElement* use, SVGElementInstanc e* targetInstance, SVGElement*& newTarget) 518 bool SVGUseElement::hasCycleUseReferencing(SVGUseElement* use, ContainerNode* ta rgetInstance, SVGElement*& newTarget)
562 { 519 {
563 ASSERT(referencedScope()); 520 ASSERT(referencedScope());
564 Element* targetElement = SVGURIReference::targetElementFromIRIString(use->hr efString(), *referencedScope()); 521 Element* targetElement = SVGURIReference::targetElementFromIRIString(use->hr efString(), *referencedScope());
565 newTarget = 0; 522 newTarget = 0;
566 if (targetElement && targetElement->isSVGElement()) 523 if (targetElement && targetElement->isSVGElement())
567 newTarget = toSVGElement(targetElement); 524 newTarget = toSVGElement(targetElement);
568 525
569 if (!newTarget) 526 if (!newTarget)
570 return false; 527 return false;
571 528
572 // Shortcut for self-references 529 // Shortcut for self-references
573 if (newTarget == this) 530 if (newTarget == this)
574 return true; 531 return true;
575 532
576 AtomicString targetId = newTarget->getIdAttribute(); 533 AtomicString targetId = newTarget->getIdAttribute();
577 SVGElementInstance* instance = targetInstance->parentNode(); 534 ContainerNode* instance = targetInstance->parentNode();
578 while (instance) { 535 while (instance && instance->isSVGElement()) {
579 SVGElement* element = instance->correspondingElement(); 536 SVGElement* element = toSVGElement(instance);
580
581 if (element->hasID() && element->getIdAttribute() == targetId && element ->document() == newTarget->document()) 537 if (element->hasID() && element->getIdAttribute() == targetId && element ->document() == newTarget->document())
582 return true; 538 return true;
583 539
584 instance = instance->parentNode(); 540 instance = instance->parentNode();
585 } 541 }
586 return false; 542 return false;
587 } 543 }
588 544
589 static inline void removeDisallowedElementsFromSubtree(Element& subtree) 545 static inline void removeDisallowedElementsFromSubtree(Element& subtree)
590 { 546 {
591 ASSERT(!subtree.inDocument()); 547 ASSERT(!subtree.inDocument());
592 Element* element = ElementTraversal::firstWithin(subtree); 548 Element* element = ElementTraversal::firstWithin(subtree);
593 while (element) { 549 while (element) {
594 if (isDisallowedElement(element)) { 550 if (isDisallowedElement(element)) {
595 Element* next = ElementTraversal::nextSkippingChildren(*element, &su btree); 551 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. 552 // The subtree is not in document so this won't generate events that could mutate the tree.
597 element->parentNode()->removeChild(element); 553 element->parentNode()->removeChild(element);
598 element = next; 554 element = next;
599 } else { 555 } else {
600 element = ElementTraversal::next(*element, &subtree); 556 element = ElementTraversal::next(*element, &subtree);
601 } 557 }
602 } 558 }
603 } 559 }
604 560
605 void SVGUseElement::buildShadowTree(SVGElement* target, SVGElementInstance* targ etInstance, ShadowRoot* shadowTreeRootElement) 561 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 { 562 {
626 ASSERT(element); 563 ASSERT(element);
627 // Why expand the <use> elements in the shadow tree here, and not just 564 // 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? 565 // do this directly in buildShadowTree, if we encounter a <use> element?
629 // 566 //
630 // Short answer: Because we may miss to expand some elements. For example, i f a <symbol> 567 // 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 568 // 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 569 // actual shadow tree (after the special case modification for svg/symbol) w e have
633 // to walk it completely and expand all <use> elements. 570 // to walk it completely and expand all <use> elements.
634 if (isSVGUseElement(*element)) { 571 if (isSVGUseElement(*element)) {
635 SVGUseElement* use = toSVGUseElement(element); 572 SVGUseElement* use = toSVGUseElement(element);
636 ASSERT(!use->resourceIsStillLoading()); 573 ASSERT(!use->resourceIsStillLoading());
637 574
638 ASSERT(referencedScope());
639 Element* targetElement = SVGURIReference::targetElementFromIRIString(use ->hrefString(), *referencedScope());
640 SVGElement* target = 0; 575 SVGElement* target = 0;
641 if (targetElement && targetElement->isSVGElement()) 576 foundProblem = hasCycleUseReferencing(toSVGUseElement(use->corresponding Element()), use, target);
642 target = toSVGElement(targetElement); 577 if (foundProblem)
578 return;
643 579
580 if (target && isDisallowedElement(target)) {
581 foundProblem = true;
582 return;
583 }
644 // Don't ASSERT(target) here, it may be "pending", too. 584 // Don't ASSERT(target) here, it may be "pending", too.
645 // Setup sub-shadow tree root node 585 // Setup sub-shadow tree root node
646 RefPtrWillBeRawPtr<SVGGElement> cloneParent = SVGGElement::create(refere ncedScope()->document()); 586 RefPtrWillBeRawPtr<SVGGElement> cloneParent = SVGGElement::create(refere ncedScope()->document());
647 use->cloneChildNodes(cloneParent.get()); 587 cloneChildrenAndAssociate(use, cloneParent.get());
pdr. 2014/06/04 04:07:52 expandUseElementsInShadowTree already handles recu
588 cloneParent->setCorrespondingElement(use->correspondingElement());
648 589
649 // Spec: In the generated content, the 'use' will be replaced by 'g', wh ere all attributes from the 590 // 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. 591 // 'use' element except for x, y, width, height and xlink:href are trans ferred to the generated 'g' element.
651 transferUseAttributesToReplacedElement(use, cloneParent.get()); 592 transferUseAttributesToReplacedElement(use, cloneParent.get());
652 593
653 if (target && !isDisallowedElement(target)) { 594 if (target) {
654 RefPtrWillBeRawPtr<Element> newChild = target->cloneElementWithChild ren(); 595 RefPtrWillBeRawPtr<Node> newChild = cloneNodeAndAssociate(target);
655 ASSERT(newChild->isSVGElement()); 596 ASSERT(newChild->isSVGElement());
656 transferUseWidthAndHeightIfNeeded(*use, toSVGElement(newChild.get()) , *target); 597 transferUseWidthAndHeightIfNeeded(*use, toSVGElement(newChild.get()) , *target);
657 cloneParent->appendChild(newChild.release()); 598 cloneParent->appendChild(newChild.release());
658 } 599 }
659 600
660 // We don't walk the target tree element-by-element, and clone each elem ent, 601 // 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 602 // but instead use cloneElementWithChildren(). This is an optimization f or the common
662 // case where <use> doesn't contain disallowed elements (ie. <foreignObj ect>). 603 // 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. 604 // 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) . 605 // For instance: <use> on <g> containing <foreignObject> (indirect case) .
665 if (subtreeContainsDisallowedElement(cloneParent.get())) 606 if (subtreeContainsDisallowedElement(cloneParent.get()))
666 removeDisallowedElementsFromSubtree(*cloneParent); 607 removeDisallowedElementsFromSubtree(*cloneParent);
667 608
668 RefPtr<Node> replacingElement(cloneParent.get()); 609 RefPtr<Node> replacingElement(cloneParent.get());
669 610
670 // Replace <use> with referenced content. 611 // Replace <use> with referenced content.
671 ASSERT(use->parentNode()); 612 ASSERT(use->parentNode());
672 use->parentNode()->replaceChild(cloneParent.release(), use); 613 use->parentNode()->replaceChild(cloneParent.release(), use);
673 614
674 // Expand the siblings because the *element* is replaced and we will 615 // Expand the siblings because the *element* is replaced and we will
675 // lose the sibling chain when we are back from recursion. 616 // lose the sibling chain when we are back from recursion.
676 element = replacingElement.get(); 617 element = replacingElement.get();
677 for (RefPtr<Node> sibling = element->nextSibling(); sibling; sibling = s ibling->nextSibling()) 618 for (RefPtr<Node> sibling = element->nextSibling(); sibling; sibling = s ibling->nextSibling()) {
678 expandUseElementsInShadowTree(sibling.get()); 619 expandUseElementsInShadowTree(sibling.get(), foundProblem);
620 if (foundProblem)
621 return;
622 }
679 } 623 }
680 624
681 for (RefPtr<Node> child = element->firstChild(); child; child = child->nextS ibling()) 625 for (RefPtr<Node> child = element->firstChild(); child; child = child->nextS ibling()) {
682 expandUseElementsInShadowTree(child.get()); 626 expandUseElementsInShadowTree(child.get(), foundProblem);
627 if (foundProblem)
628 return;
629 }
683 } 630 }
684 631
685 void SVGUseElement::expandSymbolElementsInShadowTree(Node* element) 632 void SVGUseElement::expandSymbolElementsInShadowTree(Node* element)
686 { 633 {
687 ASSERT(element); 634 ASSERT(element);
688 if (isSVGSymbolElement(*element)) { 635 if (isSVGSymbolElement(*element)) {
689 // Spec: The referenced 'symbol' and its contents are deep-cloned into t he generated tree, 636 // 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 637 // 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 638 // 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 639 // 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 640 // 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. 641 // 'svg' element will use values of 100% for these attributes.
695 ASSERT(referencedScope()); 642 ASSERT(referencedScope());
696 RefPtrWillBeRawPtr<SVGSVGElement> svgElement = SVGSVGElement::create(ref erencedScope()->document()); 643 RefPtrWillBeRawPtr<SVGSVGElement> svgElement = SVGSVGElement::create(ref erencedScope()->document());
697 644
698 // Transfer all data (attributes, etc.) from <symbol> to the new <svg> e lement. 645 // Transfer all data (attributes, etc.) from <symbol> to the new <svg> e lement.
699 svgElement->cloneDataFromElement(*toElement(element)); 646 svgElement->cloneDataFromElement(*toElement(element));
647 svgElement->setCorrespondingElement(toSVGElement(element)->corresponding Element());
700 648
701 // Only clone symbol children, and add them to the new <svg> element 649 // Only clone symbol children, and add them to the new <svg> element
702 for (Node* child = element->firstChild(); child; child = child->nextSibl ing()) { 650 for (Node* child = toSVGElement(element)->firstChild(); child; child = c hild->nextSibling()) {
703 RefPtr<Node> newChild = child->cloneNode(true); 651 RefPtr<Node> newChild = cloneNodeAndAssociate(child);
704 svgElement->appendChild(newChild.release()); 652 svgElement->appendChild(newChild.release());
705 } 653 }
706 654
707 // We don't walk the target tree element-by-element, and clone each elem ent, 655 // 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 656 // 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>). 657 // 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. 658 // 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) . 659 // For instance: <use> on <g> containing <foreignObject> (indirect case) .
712 if (subtreeContainsDisallowedElement(svgElement.get())) 660 if (subtreeContainsDisallowedElement(svgElement.get()))
713 removeDisallowedElementsFromSubtree(*svgElement); 661 removeDisallowedElementsFromSubtree(*svgElement);
(...skipping 14 matching lines...) Expand all
728 expandSymbolElementsInShadowTree(child.get()); 676 expandSymbolElementsInShadowTree(child.get());
729 } 677 }
730 678
731 void SVGUseElement::transferEventListenersToShadowTree(SVGElement* shadowTreeTar getElement) 679 void SVGUseElement::transferEventListenersToShadowTree(SVGElement* shadowTreeTar getElement)
732 { 680 {
733 if (!shadowTreeTargetElement) 681 if (!shadowTreeTargetElement)
734 return; 682 return;
735 683
736 SVGElement* originalElement = shadowTreeTargetElement->correspondingElement( ); 684 SVGElement* originalElement = shadowTreeTargetElement->correspondingElement( );
737 ASSERT(originalElement); 685 ASSERT(originalElement);
686
738 if (EventTargetData* data = originalElement->eventTargetData()) 687 if (EventTargetData* data = originalElement->eventTargetData())
739 data->eventListenerMap.copyEventListenersNotCreatedFromMarkupToTarget(sh adowTreeTargetElement); 688 data->eventListenerMap.copyEventListenersNotCreatedFromMarkupToTarget(sh adowTreeTargetElement);
740 689
741 for (SVGElement* child = Traversal<SVGElement>::firstChild(*shadowTreeTarget Element); child; child = Traversal<SVGElement>::nextSibling(*child)) 690 for (SVGElement* child = Traversal<SVGElement>::firstChild(*shadowTreeTarget Element); child; child = Traversal<SVGElement>::nextSibling(*child))
742 transferEventListenersToShadowTree(child); 691 transferEventListenersToShadowTree(child);
743 } 692 }
744 693
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() 694 void SVGUseElement::invalidateShadowTree()
778 { 695 {
779 if (!inActiveDocument() || m_needsShadowTreeRecreation) 696 if (!inActiveDocument() || m_needsShadowTreeRecreation)
780 return; 697 return;
781 scheduleShadowTreeRecreation(); 698 scheduleShadowTreeRecreation();
782 invalidateDependentShadowTrees(); 699 invalidateDependentShadowTrees();
783 } 700 }
784 701
785 void SVGUseElement::invalidateDependentShadowTrees() 702 void SVGUseElement::invalidateDependentShadowTrees()
786 { 703 {
(...skipping 26 matching lines...) Expand all
813 { 730 {
814 if (m_x->currentValue()->isRelative() 731 if (m_x->currentValue()->isRelative()
815 || m_y->currentValue()->isRelative() 732 || m_y->currentValue()->isRelative()
816 || m_width->currentValue()->isRelative() 733 || m_width->currentValue()->isRelative()
817 || m_height->currentValue()->isRelative()) 734 || m_height->currentValue()->isRelative())
818 return true; 735 return true;
819 736
820 if (!m_targetElementInstance) 737 if (!m_targetElementInstance)
821 return false; 738 return false;
822 739
823 SVGElement* element = m_targetElementInstance->shadowTreeElement(); 740 return m_targetElementInstance->hasRelativeLengths();
824 if (!element)
825 return false;
826
827 return element->hasRelativeLengths();
828 } 741 }
829 742
830 void SVGUseElement::notifyFinished(Resource* resource) 743 void SVGUseElement::notifyFinished(Resource* resource)
831 { 744 {
832 if (!inDocument()) 745 if (!inDocument())
833 return; 746 return;
834 747
835 invalidateShadowTree(); 748 invalidateShadowTree();
836 if (resource->errorOccurred()) 749 if (resource->errorOccurred())
837 dispatchEvent(Event::create(EventTypeNames::error)); 750 dispatchEvent(Event::create(EventTypeNames::error));
838 else if (!resource->wasCanceled()) { 751 else if (!resource->wasCanceled()) {
839 if (m_haveFiredLoadEvent) 752 if (m_haveFiredLoadEvent)
840 return; 753 return;
841 if (!isStructurallyExternal()) 754 if (!isStructurallyExternal())
842 return; 755 return;
843 ASSERT(!m_haveFiredLoadEvent); 756 ASSERT(!m_haveFiredLoadEvent);
844 m_haveFiredLoadEvent = true; 757 m_haveFiredLoadEvent = true;
845 sendSVGLoadEventIfPossibleAsynchronously(); 758 sendSVGLoadEventIfPossibleAsynchronously();
846 } 759 }
847 } 760 }
848 761
849 bool SVGUseElement::resourceIsStillLoading() 762 bool SVGUseElement::resourceIsStillLoading()
850 { 763 {
851 if (m_resource && m_resource->isLoading()) 764 if (m_resource && m_resource->isLoading())
852 return true; 765 return true;
853 return false; 766 return false;
854 } 767 }
855 768
856 bool SVGUseElement::instanceTreeIsLoading(SVGElementInstance* targetElementInsta nce) 769 bool SVGUseElement::instanceTreeIsLoading(SVGElement* targetInstance)
857 { 770 {
858 for (SVGElementInstance* instance = targetElementInstance->firstChild(); ins tance; instance = instance->nextSibling()) { 771 for (SVGElement* element = Traversal<SVGElement>::firstChild(*targetInstance ); element; element = Traversal<SVGElement>::nextSibling(*element)) {
859 if (SVGUseElement* use = instance->correspondingUseElement()) { 772 if (SVGUseElement* use = element->correspondingUseElement()) {
860 if (use->resourceIsStillLoading()) 773 if (use->resourceIsStillLoading())
861 return true; 774 return true;
862 } 775 }
863 if (instance->hasChildren()) 776 if (element->hasChildren())
864 instanceTreeIsLoading(instance); 777 instanceTreeIsLoading(element);
865 } 778 }
866 return false; 779 return false;
867 } 780 }
868 781
869 void SVGUseElement::setDocumentResource(ResourcePtr<DocumentResource> resource) 782 void SVGUseElement::setDocumentResource(ResourcePtr<DocumentResource> resource)
870 { 783 {
871 if (m_resource == resource) 784 if (m_resource == resource)
872 return; 785 return;
873 786
874 if (m_resource) 787 if (m_resource)
875 m_resource->removeClient(this); 788 m_resource->removeClient(this);
876 789
877 m_resource = resource; 790 m_resource = resource;
878 if (m_resource) 791 if (m_resource)
879 m_resource->addClient(this); 792 m_resource->addClient(this);
880 } 793 }
881 794
882 void SVGUseElement::trace(Visitor* visitor) 795 void SVGUseElement::trace(Visitor* visitor)
883 { 796 {
884 visitor->trace(m_targetElementInstance); 797 visitor->trace(m_targetElementInstance);
885 SVGGraphicsElement::trace(visitor); 798 SVGGraphicsElement::trace(visitor);
886 } 799 }
887 800
888 } 801 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698