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

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: Some small cleanups 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 PassRefPtr<Node> cloneNodeAndAssociate(Node* toClone)
haraken 2014/06/05 05:49:00 PassRefPtrWillBeRawPtr
347 {
pdr. 2014/06/05 04:40:01 Can you assert that toClone is a text or svg node?
348 RefPtr<Node> clone = toClone->cloneNode(false);
haraken 2014/06/05 05:49:00 RefPtrWillBeRawPtr
349 if (clone->isSVGElement()) {
esprehn 2014/06/05 06:29:16 Early return. if (!clone->isSVGElement()) retur
350 SVGElement* svgElement = toSVGElement(toClone);
351 ASSERT(!svgElement->correspondingElement());
352 toSVGElement(clone.get())->setCorrespondingElement(svgElement);
353 if (EventTargetData* data = toClone->eventTargetData())
354 data->eventListenerMap.copyEventListenersNotCreatedFromMarkupToTarge t(svgElement);
pdr. 2014/06/05 04:40:01 What are these events for? I thought that we would
esprehn 2014/06/05 06:29:16 This doesn't look safe, I think you leak access to
355 TrackExceptionState exceptionState;
356 for (Node* n = toClone->firstChild(); n && !exceptionState.hadException( ); n = n->nextSibling())
esprehn 2014/06/05 06:29:16 node =, don't abbreviate.
357 clone->appendChild(cloneNodeAndAssociate(n), exceptionState);
358 }
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 ShadowRoot* shadowTreeRootElement = userAgentShadowRoot();
esprehn 2014/06/05 06:29:16 ShadowRoot& root = ensureUserAgentShadowRoot(); g
383 // The instance tree is accesable from JavaScript, and has to 378 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 379
387 // Build instance tree. Create root SVGElementInstance object for the first sub-tree node. 380 // Set up root SVG element in shadow tree.
388 // 381 RefPtr<Element> newChild = target->cloneElementWithoutChildren();
kouhei (in TOK) 2014/06/05 05:41:37 Oilpan nit: RefPtrWillBeRawPtr
389 // Spec: If the 'use' element references a simple graphics element such as a 'rect', then there is only a 382 m_targetElementInstance = toSVGElement(newChild.get());
390 // single SVGElementInstance object, and the correspondingElement attribute on this SVGElementInstance object 383 shadowTreeRootElement->appendChild(newChild.release());
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 // Clone the target subtree into the shadow tree, not handling <use> and <sy mbol> yet.
395 bool foundProblem = false; 386 bool foundProblem = false;
396 buildInstanceTree(target, m_targetElementInstance.get(), foundProblem, false ); 387 buildShadowTree(target, m_targetElementInstance.get(), foundProblem, false);
397
398 if (instanceTreeIsLoading(m_targetElementInstance.get()))
399 return;
400 388
401 // SVG specification does not say a word about <use> & cycles. My view on th is is: just ignore it! 389 // 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. 390 // Non-appearing <use> content is easier to debug, then half-appearing conte nt.
403 if (foundProblem) { 391 if (foundProblem) {
404 clearResourceReferences(); 392 clearResourceReferences();
405 return; 393 return;
406 } 394 }
407 395
408 // Assure instance tree building was successfull 396 if (instanceTreeIsLoading(m_targetElementInstance.get()))
397 return;
398
399 // Assure shadow tree building was successfull
409 ASSERT(m_targetElementInstance); 400 ASSERT(m_targetElementInstance);
410 ASSERT(!m_targetElementInstance->shadowTreeElement());
411 ASSERT(m_targetElementInstance->correspondingUseElement() == this); 401 ASSERT(m_targetElementInstance->correspondingUseElement() == this);
412 ASSERT(m_targetElementInstance->directUseElement() == this);
413 ASSERT(m_targetElementInstance->correspondingElement() == target); 402 ASSERT(m_targetElementInstance->correspondingElement() == target);
414 403
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. 404 // Expand all <use> elements in the shadow tree.
423 // Expand means: replace the actual <use> element by what it references. 405 // Expand means: replace the actual <use> element by what it references.
424 expandUseElementsInShadowTree(shadowTreeRootElement); 406 foundProblem = false;
425 407 expandUseElementsInShadowTree(m_targetElementInstance.get(), foundProblem);
esprehn 2014/06/05 06:29:16 Use a return value? This foundProblem thing is wei
426 // Expand all <symbol> elements in the shadow tree. 408 if (foundProblem) {
427 // Expand means: replace the actual <symbol> element by the <svg> element.
428 expandSymbolElementsInShadowTree(shadowTreeRootElement);
429
430 // If no shadow tree element is present, this means that the reference root
431 // element was removed, as it is disallowed (ie. <use> on <foreignObject>)
432 // Do NOT leave an inconsistent instance tree around, instead destruct it.
433 Node* shadowTreeTargetNode = shadowTreeRootElement->firstChild();
434 if (!shadowTreeTargetNode) {
435 clearResourceReferences(); 409 clearResourceReferences();
436 return; 410 return;
437 } 411 }
438 412
439 // Now that the shadow tree is completly expanded, we can associate 413 // Expand all <symbol> elements in the shadow tree.
440 // shadow tree elements <-> instances in the instance tree. 414 // Expand means: replace the actual <symbol> element by the <svg> element.
441 associateInstancesWithShadowTreeElements(shadowTreeTargetNode, m_targetEleme ntInstance.get()); 415 expandSymbolElementsInShadowTree(toSVGElement(shadowTreeRootElement->firstCh ild()));
442 416
443 SVGElement* shadowTreeTargetElement = toSVGElement(shadowTreeTargetNode); 417 m_targetElementInstance = toSVGElement(shadowTreeRootElement->firstChild());
444 ASSERT(shadowTreeTargetElement->correspondingElement()); 418 transferUseWidthAndHeightIfNeeded(*this, m_targetElementInstance.get(), *m_t argetElementInstance->correspondingElement());
445 transferUseWidthAndHeightIfNeeded(*this, shadowTreeTargetElement, *shadowTre eTargetElement->correspondingElement());
446 419
447 ASSERT(shadowTreeTargetElement->parentNode() == shadowTreeRootElement); 420 ASSERT(m_targetElementInstance->parentNode() == shadowTreeRootElement);
448
449 // Transfer event listeners assigned to the referenced element to our shadow tree elements.
450 transferEventListenersToShadowTree(shadowTreeTargetElement);
451 421
452 // Update relative length information. 422 // Update relative length information.
453 updateRelativeLengthsInformation(); 423 updateRelativeLengthsInformation();
454 } 424 }
455 425
456 RenderObject* SVGUseElement::createRenderer(RenderStyle*) 426 RenderObject* SVGUseElement::createRenderer(RenderStyle*)
457 { 427 {
458 return new RenderSVGTransformableContainer(this); 428 return new RenderSVGTransformableContainer(this);
459 } 429 }
460 430
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
494 RenderObject* SVGUseElement::rendererClipChild() const 464 RenderObject* SVGUseElement::rendererClipChild() const
495 { 465 {
496 if (Node* n = userAgentShadowRoot()->firstChild()) { 466 if (Node* n = userAgentShadowRoot()->firstChild()) {
497 if (n->isSVGElement() && isDirectReference(*n)) 467 if (n->isSVGElement() && isDirectReference(*n))
498 return toSVGElement(n)->renderer(); 468 return toSVGElement(n)->renderer();
499 } 469 }
500 470
501 return 0; 471 return 0;
502 } 472 }
503 473
504 void SVGUseElement::buildInstanceTree(SVGElement* target, SVGElementInstance* ta rgetInstance, bool& foundProblem, bool foundUse) 474 void SVGUseElement::buildShadowTree(SVGElement* target, SVGElement* targetInstan ce, bool& foundProblem, bool foundUse)
esprehn 2014/06/05 06:29:16 Use a return value, or pass a structure. Don't use
505 { 475 {
506 ASSERT(target); 476 ASSERT(target);
507 ASSERT(targetInstance); 477 ASSERT(targetInstance);
508 478
509 // Spec: If the referenced object is itself a 'use', or if there are 'use' s ubelements within the referenced 479 // 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. 480 // object, the instance tree will contain recursive expansion of the indirec t references to form a complete tree.
511 bool targetIsUseElement = isSVGUseElement(*target); 481 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 482 // We only need to track first degree <use> dependencies. Indirect refer ences are handled
519 // as the invalidation bubbles up the dependency chain. 483 // as the invalidation bubbles up the dependency chain.
520 if (!foundUse) { 484 if (!foundUse) {
521 document().accessSVGExtensions().addElementReferencingTarget(this, t arget); 485 document().accessSVGExtensions().addElementReferencingTarget(this, t arget);
522 foundUse = true; 486 foundUse = true;
523 } 487 }
524 } else if (isDisallowedElement(target)) { 488 } else if (isDisallowedElement(target)) {
525 foundProblem = true; 489 foundProblem = true;
526 return; 490 return;
527 } 491 }
528 492
529 // A general description from the SVG spec, describing what buildInstanceTre e() actually does. 493 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 494
536 for (SVGElement* element = Traversal<SVGElement>::firstChild(*target); eleme nt; element = Traversal<SVGElement>::nextSibling(*element)) { 495 for (RefPtr<Node> child = target->firstChild(); child; child = child->nextSi bling()) {
kouhei (in TOK) 2014/06/05 05:41:37 Can this be Node*? I don't think a strong ref is n
537 // Skip any disallowed element. 496 // Skip any disallowed element.
538 if (isDisallowedElement(element)) 497 if (isDisallowedElement(child.get()))
539 continue; 498 continue;
540 499
541 // Create SVGElementInstance object, for both container/non-container no des. 500 RefPtrWillBeRawPtr<Node> newChild = child->cloneNode(false);
542 RefPtrWillBeRawPtr<SVGElementInstance> instance = SVGElementInstance::cr eate(this, 0, element); 501 Node* instancePtr = newChild.get();
esprehn 2014/06/05 06:29:16 Get rid of this local var, also don't use Ptr.
543 SVGElementInstance* instancePtr = instance.get(); 502 targetInstance->appendChild(newChild.release());
544 targetInstance->appendChild(instance.release()); 503 if (instancePtr->isSVGElement()) {
esprehn 2014/06/05 06:29:16 newChild->isSVGElement()
545 504 // Enter recursion, appending new instance tree nodes to the "instan ce" object.
546 // Enter recursion, appending new instance tree nodes to the "instance" object. 505 buildShadowTree(toSVGElement(child), toSVGElement(instancePtr), foun dProblem, foundUse);
esprehn 2014/06/05 06:29:16 toSVGElement(newChild.get())
547 buildInstanceTree(element, instancePtr, foundProblem, foundUse); 506 if (foundProblem)
esprehn 2014/06/05 06:29:16 I think you want to pass a Context structure that
548 if (foundProblem) 507 return;
549 return; 508 }
550 } 509 }
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 } 510 }
560 511
561 bool SVGUseElement::hasCycleUseReferencing(SVGUseElement* use, SVGElementInstanc e* targetInstance, SVGElement*& newTarget) 512 bool SVGUseElement::hasCycleUseReferencing(SVGUseElement* use, ContainerNode* ta rgetInstance, SVGElement*& newTarget)
562 { 513 {
563 ASSERT(referencedScope()); 514 ASSERT(referencedScope());
564 Element* targetElement = SVGURIReference::targetElementFromIRIString(use->hr efString(), *referencedScope()); 515 Element* targetElement = SVGURIReference::targetElementFromIRIString(use->hr efString(), *referencedScope());
565 newTarget = 0; 516 newTarget = 0;
566 if (targetElement && targetElement->isSVGElement()) 517 if (targetElement && targetElement->isSVGElement())
567 newTarget = toSVGElement(targetElement); 518 newTarget = toSVGElement(targetElement);
568 519
569 if (!newTarget) 520 if (!newTarget)
570 return false; 521 return false;
571 522
572 // Shortcut for self-references 523 // Shortcut for self-references
573 if (newTarget == this) 524 if (newTarget == this)
574 return true; 525 return true;
575 526
576 AtomicString targetId = newTarget->getIdAttribute(); 527 AtomicString targetId = newTarget->getIdAttribute();
577 SVGElementInstance* instance = targetInstance->parentNode(); 528 ContainerNode* instance = targetInstance->parentNode();
578 while (instance) { 529 while (instance && instance->isSVGElement()) {
579 SVGElement* element = instance->correspondingElement(); 530 SVGElement* element = toSVGElement(instance);
580
581 if (element->hasID() && element->getIdAttribute() == targetId && element ->document() == newTarget->document()) 531 if (element->hasID() && element->getIdAttribute() == targetId && element ->document() == newTarget->document())
582 return true; 532 return true;
583 533
584 instance = instance->parentNode(); 534 instance = instance->parentNode();
585 } 535 }
586 return false; 536 return false;
587 } 537 }
588 538
589 static inline void removeDisallowedElementsFromSubtree(Element& subtree) 539 static inline void removeDisallowedElementsFromSubtree(Element& subtree)
590 { 540 {
591 ASSERT(!subtree.inDocument()); 541 ASSERT(!subtree.inDocument());
592 Element* element = ElementTraversal::firstWithin(subtree); 542 Element* element = ElementTraversal::firstWithin(subtree);
593 while (element) { 543 while (element) {
594 if (isDisallowedElement(element)) { 544 if (isDisallowedElement(element)) {
595 Element* next = ElementTraversal::nextSkippingChildren(*element, &su btree); 545 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. 546 // The subtree is not in document so this won't generate events that could mutate the tree.
597 element->parentNode()->removeChild(element); 547 element->parentNode()->removeChild(element);
598 element = next; 548 element = next;
599 } else { 549 } else {
600 element = ElementTraversal::next(*element, &subtree); 550 element = ElementTraversal::next(*element, &subtree);
601 } 551 }
602 } 552 }
603 } 553 }
604 554
605 void SVGUseElement::buildShadowTree(SVGElement* target, SVGElementInstance* targ etInstance, ShadowRoot* shadowTreeRootElement) 555 void SVGUseElement::expandUseElementsInShadowTree(SVGElement* element, bool& fou ndProblem)
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 { 556 {
626 ASSERT(element); 557 ASSERT(element);
627 // Why expand the <use> elements in the shadow tree here, and not just 558 // 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? 559 // do this directly in buildShadowTree, if we encounter a <use> element?
629 // 560 //
630 // Short answer: Because we may miss to expand some elements. For example, i f a <symbol> 561 // 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 562 // 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 563 // actual shadow tree (after the special case modification for svg/symbol) w e have
633 // to walk it completely and expand all <use> elements. 564 // to walk it completely and expand all <use> elements.
634 if (isSVGUseElement(*element)) { 565 if (isSVGUseElement(*element)) {
635 SVGUseElement* use = toSVGUseElement(element); 566 SVGUseElement* use = toSVGUseElement(element);
636 ASSERT(!use->resourceIsStillLoading()); 567 ASSERT(!use->resourceIsStillLoading());
637 568
638 ASSERT(referencedScope());
639 Element* targetElement = SVGURIReference::targetElementFromIRIString(use ->hrefString(), *referencedScope());
640 SVGElement* target = 0; 569 SVGElement* target = 0;
641 if (targetElement && targetElement->isSVGElement()) 570 foundProblem = hasCycleUseReferencing(toSVGUseElement(use->corresponding Element()), use, target);
642 target = toSVGElement(targetElement); 571 if (foundProblem)
572 return;
643 573
574 if (target && isDisallowedElement(target)) {
575 foundProblem = true;
576 return;
577 }
644 // Don't ASSERT(target) here, it may be "pending", too. 578 // Don't ASSERT(target) here, it may be "pending", too.
645 // Setup sub-shadow tree root node 579 // Setup sub-shadow tree root node
646 RefPtrWillBeRawPtr<SVGGElement> cloneParent = SVGGElement::create(refere ncedScope()->document()); 580 RefPtrWillBeRawPtr<SVGGElement> cloneParent = SVGGElement::create(refere ncedScope()->document());
647 use->cloneChildNodes(cloneParent.get()); 581 for (Node* child = use->firstChild(); child;) {
pdr. 2014/06/05 04:40:01 This doesn't look right. I think you just want: f
582 Node* oldChild = child;
583 child = child->nextSibling();
584 cloneParent->appendChild(oldChild);
585 }
586 cloneParent->setCorrespondingElement(use->correspondingElement());
648 587
649 // Spec: In the generated content, the 'use' will be replaced by 'g', wh ere all attributes from the 588 // 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. 589 // 'use' element except for x, y, width, height and xlink:href are trans ferred to the generated 'g' element.
651 transferUseAttributesToReplacedElement(use, cloneParent.get()); 590 transferUseAttributesToReplacedElement(use, cloneParent.get());
652 591
653 if (target && !isDisallowedElement(target)) { 592 if (target) {
654 RefPtrWillBeRawPtr<Element> newChild = target->cloneElementWithChild ren(); 593 RefPtr<Node> newChild = cloneNodeAndAssociate(target);
kouhei (in TOK) 2014/06/05 05:41:37 oilpan: RefPtrWillBeRawPtr
655 ASSERT(newChild->isSVGElement()); 594 ASSERT(newChild->isSVGElement());
656 transferUseWidthAndHeightIfNeeded(*use, toSVGElement(newChild.get()) , *target); 595 transferUseWidthAndHeightIfNeeded(*use, toSVGElement(newChild.get()) , *target);
657 cloneParent->appendChild(newChild.release()); 596 cloneParent->appendChild(newChild.release());
658 } 597 }
659 598
660 // We don't walk the target tree element-by-element, and clone each elem ent, 599 // 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 600 // but instead use cloneElementWithChildren(). This is an optimization f or the common
662 // case where <use> doesn't contain disallowed elements (ie. <foreignObj ect>). 601 // 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. 602 // 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) . 603 // For instance: <use> on <g> containing <foreignObject> (indirect case) .
665 if (subtreeContainsDisallowedElement(cloneParent.get())) 604 if (subtreeContainsDisallowedElement(cloneParent.get()))
666 removeDisallowedElementsFromSubtree(*cloneParent); 605 removeDisallowedElementsFromSubtree(*cloneParent);
667 606
668 RefPtr<Node> replacingElement(cloneParent.get()); 607 RefPtr<SVGElement> replacingElement(cloneParent.get());
haraken 2014/06/05 05:49:00 RefPtrWillBeRawPtr
669 608
670 // Replace <use> with referenced content. 609 // Replace <use> with referenced content.
671 ASSERT(use->parentNode()); 610 ASSERT(use->parentNode());
672 use->parentNode()->replaceChild(cloneParent.release(), use); 611 use->parentNode()->replaceChild(cloneParent.release(), use);
673 612
674 // Expand the siblings because the *element* is replaced and we will 613 // Expand the siblings because the *element* is replaced and we will
675 // lose the sibling chain when we are back from recursion. 614 // lose the sibling chain when we are back from recursion.
676 element = replacingElement.get(); 615 element = replacingElement.get();
677 for (RefPtr<Node> sibling = element->nextSibling(); sibling; sibling = s ibling->nextSibling()) 616 for (RefPtr<SVGElement> sibling = Traversal<SVGElement>::nextSibling(*el ement); sibling; sibling = Traversal<SVGElement>::nextSibling(*sibling)) {
pdr. 2014/06/05 04:40:01 I think you want: RefPtr<SVGElement> sibling = Tra
haraken 2014/06/05 05:49:00 RefPtrWillBeRawPtr
678 expandUseElementsInShadowTree(sibling.get()); 617 expandUseElementsInShadowTree(sibling.get(), foundProblem);
618 if (foundProblem)
619 return;
620 }
679 } 621 }
680 622
681 for (RefPtr<Node> child = element->firstChild(); child; child = child->nextS ibling()) 623 for (RefPtr<SVGElement> child = Traversal<SVGElement>::firstChild(*element); child; child = Traversal<SVGElement>::nextSibling(*child)) {
kouhei (in TOK) 2014/06/05 05:41:37 I think you can also use SVGElement* here. If not,
682 expandUseElementsInShadowTree(child.get()); 624 expandUseElementsInShadowTree(child.get(), foundProblem);
625 if (foundProblem)
626 return;
627 }
683 } 628 }
684 629
685 void SVGUseElement::expandSymbolElementsInShadowTree(Node* element) 630 void SVGUseElement::expandSymbolElementsInShadowTree(SVGElement* element)
686 { 631 {
687 ASSERT(element); 632 ASSERT(element);
688 if (isSVGSymbolElement(*element)) { 633 if (isSVGSymbolElement(*element)) {
689 // Spec: The referenced 'symbol' and its contents are deep-cloned into t he generated tree, 634 // 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 635 // 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 636 // 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 637 // 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 638 // 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. 639 // 'svg' element will use values of 100% for these attributes.
695 ASSERT(referencedScope()); 640 ASSERT(referencedScope());
696 RefPtrWillBeRawPtr<SVGSVGElement> svgElement = SVGSVGElement::create(ref erencedScope()->document()); 641 RefPtrWillBeRawPtr<SVGSVGElement> svgElement = SVGSVGElement::create(ref erencedScope()->document());
697 642
698 // Transfer all data (attributes, etc.) from <symbol> to the new <svg> e lement. 643 // Transfer all data (attributes, etc.) from <symbol> to the new <svg> e lement.
699 svgElement->cloneDataFromElement(*toElement(element)); 644 svgElement->cloneDataFromElement(*element);
645 svgElement->setCorrespondingElement(element->correspondingElement());
700 646
701 // Only clone symbol children, and add them to the new <svg> element 647 // Only clone symbol children, and add them to the new <svg> element
702 for (Node* child = element->firstChild(); child; child = child->nextSibl ing()) { 648 for (Node* child = element->firstChild(); child; ) {
pdr. 2014/06/05 04:40:01 Same issue with this loop as the one above. I don'
703 RefPtr<Node> newChild = child->cloneNode(true); 649 Node* oldChild = child;
704 svgElement->appendChild(newChild.release()); 650 child = child->nextSibling();
651 svgElement->appendChild(oldChild);
705 } 652 }
706 653
707 // We don't walk the target tree element-by-element, and clone each elem ent, 654 // 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 655 // 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>). 656 // 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. 657 // 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) . 658 // For instance: <use> on <g> containing <foreignObject> (indirect case) .
712 if (subtreeContainsDisallowedElement(svgElement.get())) 659 if (subtreeContainsDisallowedElement(svgElement.get()))
713 removeDisallowedElementsFromSubtree(*svgElement); 660 removeDisallowedElementsFromSubtree(*svgElement);
714 661
715 RefPtr<Node> replacingElement(svgElement.get()); 662 RefPtr<SVGElement> replacingElement(svgElement.get());
haraken 2014/06/05 05:49:00 RefPtrWillBeRawPtr
716 663
717 // Replace <symbol> with <svg>. 664 // Replace <symbol> with <svg>.
665 ASSERT(element->parentNode());
718 element->parentNode()->replaceChild(svgElement.release(), element); 666 element->parentNode()->replaceChild(svgElement.release(), element);
719 667
720 // Expand the siblings because the *element* is replaced and we will 668 // Expand the siblings because the *element* is replaced and we will
721 // lose the sibling chain when we are back from recursion. 669 // lose the sibling chain when we are back from recursion.
722 element = replacingElement.get(); 670 element = replacingElement.get();
723 for (RefPtr<Node> sibling = element->nextSibling(); sibling; sibling = s ibling->nextSibling()) 671 for (RefPtr<SVGElement> sibling = Traversal<SVGElement>::nextSibling(*el ement); sibling; sibling = Traversal<SVGElement>::nextSibling(*sibling))
pdr. 2014/06/05 04:40:01 Should the first part of the foor lop be firstChil
kouhei (in TOK) 2014/06/05 05:41:37 Ditto: RefPtr<SVGElement> -> SVGElement*
724 expandSymbolElementsInShadowTree(sibling.get()); 672 expandSymbolElementsInShadowTree(sibling.get());
725 } 673 }
726 674
727 for (RefPtr<Node> child = element->firstChild(); child; child = child->nextS ibling()) 675 for (RefPtr<SVGElement> child = Traversal<SVGElement>::firstChild(*element); child; child = Traversal<SVGElement>::nextSibling(*child))
kouhei (in TOK) 2014/06/05 05:41:37 Ditto.
728 expandSymbolElementsInShadowTree(child.get()); 676 expandSymbolElementsInShadowTree(child.get());
729 } 677 }
730 678
731 void SVGUseElement::transferEventListenersToShadowTree(SVGElement* shadowTreeTar getElement)
732 {
733 if (!shadowTreeTargetElement)
734 return;
735
736 SVGElement* originalElement = shadowTreeTargetElement->correspondingElement( );
737 ASSERT(originalElement);
738 if (EventTargetData* data = originalElement->eventTargetData())
739 data->eventListenerMap.copyEventListenersNotCreatedFromMarkupToTarget(sh adowTreeTargetElement);
740
741 for (SVGElement* child = Traversal<SVGElement>::firstChild(*shadowTreeTarget Element); child; child = Traversal<SVGElement>::nextSibling(*child))
742 transferEventListenersToShadowTree(child);
743 }
744
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() 679 void SVGUseElement::invalidateShadowTree()
778 { 680 {
779 if (!inActiveDocument() || m_needsShadowTreeRecreation) 681 if (!inActiveDocument() || m_needsShadowTreeRecreation)
780 return; 682 return;
781 scheduleShadowTreeRecreation(); 683 scheduleShadowTreeRecreation();
782 invalidateDependentShadowTrees(); 684 invalidateDependentShadowTrees();
783 } 685 }
784 686
785 void SVGUseElement::invalidateDependentShadowTrees() 687 void SVGUseElement::invalidateDependentShadowTrees()
786 { 688 {
(...skipping 26 matching lines...) Expand all
813 { 715 {
814 if (m_x->currentValue()->isRelative() 716 if (m_x->currentValue()->isRelative()
815 || m_y->currentValue()->isRelative() 717 || m_y->currentValue()->isRelative()
816 || m_width->currentValue()->isRelative() 718 || m_width->currentValue()->isRelative()
817 || m_height->currentValue()->isRelative()) 719 || m_height->currentValue()->isRelative())
818 return true; 720 return true;
819 721
820 if (!m_targetElementInstance) 722 if (!m_targetElementInstance)
821 return false; 723 return false;
822 724
823 SVGElement* element = m_targetElementInstance->shadowTreeElement(); 725 return m_targetElementInstance->hasRelativeLengths();
824 if (!element)
825 return false;
826
827 return element->hasRelativeLengths();
828 } 726 }
829 727
830 void SVGUseElement::notifyFinished(Resource* resource) 728 void SVGUseElement::notifyFinished(Resource* resource)
831 { 729 {
832 if (!inDocument()) 730 if (!inDocument())
833 return; 731 return;
834 732
835 invalidateShadowTree(); 733 invalidateShadowTree();
836 if (resource->errorOccurred()) 734 if (resource->errorOccurred())
837 dispatchEvent(Event::create(EventTypeNames::error)); 735 dispatchEvent(Event::create(EventTypeNames::error));
838 else if (!resource->wasCanceled()) { 736 else if (!resource->wasCanceled()) {
839 if (m_haveFiredLoadEvent) 737 if (m_haveFiredLoadEvent)
840 return; 738 return;
841 if (!isStructurallyExternal()) 739 if (!isStructurallyExternal())
842 return; 740 return;
843 ASSERT(!m_haveFiredLoadEvent); 741 ASSERT(!m_haveFiredLoadEvent);
844 m_haveFiredLoadEvent = true; 742 m_haveFiredLoadEvent = true;
845 sendSVGLoadEventIfPossibleAsynchronously(); 743 sendSVGLoadEventIfPossibleAsynchronously();
846 } 744 }
847 } 745 }
848 746
849 bool SVGUseElement::resourceIsStillLoading() 747 bool SVGUseElement::resourceIsStillLoading()
850 { 748 {
851 if (m_resource && m_resource->isLoading()) 749 if (m_resource && m_resource->isLoading())
852 return true; 750 return true;
853 return false; 751 return false;
854 } 752 }
855 753
856 bool SVGUseElement::instanceTreeIsLoading(SVGElementInstance* targetElementInsta nce) 754 bool SVGUseElement::instanceTreeIsLoading(SVGElement* targetInstance)
857 { 755 {
858 for (SVGElementInstance* instance = targetElementInstance->firstChild(); ins tance; instance = instance->nextSibling()) { 756 for (SVGElement* element = Traversal<SVGElement>::firstChild(*targetInstance ); element; element = Traversal<SVGElement>::nextSibling(*element)) {
859 if (SVGUseElement* use = instance->correspondingUseElement()) { 757 if (SVGUseElement* use = element->correspondingUseElement()) {
860 if (use->resourceIsStillLoading()) 758 if (use->resourceIsStillLoading())
861 return true; 759 return true;
862 } 760 }
863 if (instance->hasChildren()) 761 if (element->hasChildren())
864 instanceTreeIsLoading(instance); 762 instanceTreeIsLoading(element);
esprehn 2014/06/05 06:29:16 You're missing a return or something here, this do
865 } 763 }
866 return false; 764 return false;
867 } 765 }
868 766
869 void SVGUseElement::setDocumentResource(ResourcePtr<DocumentResource> resource) 767 void SVGUseElement::setDocumentResource(ResourcePtr<DocumentResource> resource)
870 { 768 {
871 if (m_resource == resource) 769 if (m_resource == resource)
872 return; 770 return;
873 771
874 if (m_resource) 772 if (m_resource)
875 m_resource->removeClient(this); 773 m_resource->removeClient(this);
876 774
877 m_resource = resource; 775 m_resource = resource;
878 if (m_resource) 776 if (m_resource)
879 m_resource->addClient(this); 777 m_resource->addClient(this);
880 } 778 }
881 779
882 void SVGUseElement::trace(Visitor* visitor) 780 void SVGUseElement::trace(Visitor* visitor)
883 { 781 {
884 visitor->trace(m_targetElementInstance); 782 visitor->trace(m_targetElementInstance);
885 SVGGraphicsElement::trace(visitor); 783 SVGGraphicsElement::trace(visitor);
886 } 784 }
887 785
888 } 786 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698