Source/WebCore/ChangeLog

 12017-12-12 Ryosuke Niwa <rniwa@webkit.org>
 2
 3 Update the SVG use element's shadow trees explicitly before the style recall
 4 https://bugs.webkit.org/show_bug.cgi?id=180729
 5 <rdar://problem/36009806>
 6
 7 Reviewed by NOBODY (OOPS!).
 8
 9 Update the SVG use element's shadow trees before start resolving styles. Document now has a hash set of all
 10 connected SVG use elements with invalidated shadow trees. SVGUseElement adds itself to this set when its
 11 shadow tree gets invalidated, or it gets newly connected to a document with the invalidated shadow tree.
 12 SVGUseElement removes itself from this set when it updates its shadow tree or it gets disconnected from
 13 a document with the invalidated shadow tree.
 14
 15 No new tests. Covered by existing tests.
 16
 17 * dom/Document.cpp:
 18 (WebCore::Document::~Document): Assert that m_svgUseElements has been cleared.
 19 (WebCore::Document::resolveStyle): Update the shadow trees of SVG use elements with invalidated shadow trees.
 20 (WebCore::Document::addSVGUseElement): Added.
 21 (WebCore::Document::removeSVGUseElement): Added.
 22 * dom/Document.h:
 23 (WebCore::Document::svgUseElements const): Added.
 24 * dom/Element.cpp:
 25 (WebCore::Element::cloneElementWithChildren): Removed EventAllowedScope since the SVG use element's shadow
 26 tree is no longer updated when there is a NoEventDispatchAssertion in the stack.
 27 (WebCore::Element::cloneElementWithoutChildren): Ditto.
 28 * svg/SVGUseElement.cpp:
 29 (WebCore::SVGUseElement::insertedIntoAncestor): Add the element to the document's hash set if this use element's
 30 shadow tree needs to be updated (m_shadowTreeNeedsUpdate is set), and it got newly connected.
 31 (WebCore::SVGUseElement::removedFromAncestor): Ditto for removal. We have to check m_shadowTreeNeedsUpdate before
 32 calling SVGGraphicsElement::removedFromAncestor or updateExternalDocument since either function can invoke
 33 m_shadowTreeNeedsUpdate to true.
 34 (WebCore::SVGUseElement::willRecalcStyle): Removed the call to updateShadowTree.
 35 (WebCore::SVGUseElement::updateShadowTree): Remove this element from the document's hah set. We can't clear all
 36 the entries in the map at once in Document::resolveStyle because updating the shadow trees of a SVG use element
 37 can result in a sync IPC in ImageLoader::updateFromElement, which end up executing arbitrary author scripts.
 38 (WebCore::SVGUseElement::cloneTarget const): Removed EventAllowedScope since the SVG use element's shadow tree
 39 is no longer updated when there is a NoEventDispatchAssertion in the stack.
 40 (WebCore::SVGUseElement::expandUseElementsInShadowTree const): Ditto.
 41 (WebCore::SVGUseElement::expandSymbolElementsInShadowTree const): Ditto.
 42 (WebCore::SVGUseElement::invalidateShadowTree): Add the element to the document's hash set if it's connected.
 43 * svg/SVGUseElement.h:
 44
1452017-12-07 Jer Noble <jer.noble@apple.com>
246
347 [EME] Support the 'encrypted' event for FPS encrypted streams

Source/WebCore/dom/Document.cpp

159159#include "SVGNames.h"
160160#include "SVGSVGElement.h"
161161#include "SVGTitleElement.h"
 162#include "SVGUseElement.h"
162163#include "SVGZoomEvent.h"
163164#include "SWClientConnection.h"
164165#include "SchemeRegistry.h"

@@Document::~Document()
628629 if (hasRareData())
629630 clearRareData();
630631
631  ASSERT(m_listsInvalidatedAtDocument.isEmpty());
632  ASSERT(m_collectionsInvalidatedAtDocument.isEmpty());
 632 RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(m_listsInvalidatedAtDocument.isEmpty());
 633 RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(m_collectionsInvalidatedAtDocument.isEmpty());
 634 RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(m_svgUseElements.isEmpty());
633635
634636 for (unsigned count : m_nodeListAndCollectionCounts)
635637 ASSERT_UNUSED(count, !count);

@@void Document::resolveStyle(ResolveStyleType type)
17861788 RenderView::RepaintRegionAccumulator repaintRegionAccumulator(renderView());
17871789 AnimationUpdateBlock animationUpdateBlock(&m_frame->animation());
17881790
 1791 // FIXME: Do this update per tree scope.
 1792 {
 1793 auto elements = copyToVectorOf<RefPtr<SVGUseElement>>(m_svgUseElements);
 1794 // We can't clear m_svgUseElements here because updateShadowTree may end up executing arbitrary scripts
 1795 // which may insert new SVG use elements or remove existing ones inside sync IPC via ImageLoader::updateFromElement.
 1796 for (auto& element : elements)
 1797 element->updateShadowTree();
 1798 }
 1799
17891800 // FIXME: We should update style on our ancestor chain before proceeding (especially for seamless),
17901801 // however doing so currently causes several tests to crash, as Frame::setDocument calls Document::attach
17911802 // before setting the DOMWindow on the Frame, or the SecurityOrigin on the document. The attach, in turn

@@SVGDocumentExtensions& Document::accessSVGExtensions()
52545265 return *m_svgExtensions;
52555266}
52565267
 5268void Document::addSVGUseElement(SVGUseElement& element)
 5269{
 5270 auto result = m_svgUseElements.add(&element);
 5271 RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(result.isNewEntry);
 5272}
 5273
 5274void Document::removeSVGUseElement(SVGUseElement& element)
 5275{
 5276 bool didRemove = m_svgUseElements.remove(&element);
 5277 RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(didRemove);
 5278}
 5279
52575280bool Document::hasSVGRootNode() const
52585281{
52595282 return documentElement() && documentElement()->hasTagName(SVGNames::svgTag);

Source/WebCore/dom/Document.h

@@class RenderView;
154154class RequestAnimationFrameCallback;
155155class SVGDocumentExtensions;
156156class SVGSVGElement;
 157class SVGUseElement;
157158class SWClientConnection;
158159class ScriptElementData;
159160class ScriptModuleLoader;

@@public:
10771078 WEBCORE_EXPORT const SVGDocumentExtensions* svgExtensions();
10781079 WEBCORE_EXPORT SVGDocumentExtensions& accessSVGExtensions();
10791080
 1081 void addSVGUseElement(SVGUseElement&);
 1082 void removeSVGUseElement(SVGUseElement&);
 1083 HashSet<SVGUseElement*> const svgUseElements() const { return m_svgUseElements; }
 1084
10801085 void initSecurityContext();
10811086 void initContentSecurityPolicy();
10821087

@@private:
16121617 RefPtr<XPathEvaluator> m_xpathEvaluator;
16131618
16141619 std::unique_ptr<SVGDocumentExtensions> m_svgExtensions;
 1620 HashSet<SVGUseElement*> m_svgUseElements;
16151621
16161622#if ENABLE(DASHBOARD_SUPPORT)
16171623 Vector<AnnotatedRegionValue> m_annotatedRegions;

Source/WebCore/dom/Element.cpp

@@Ref<Node> Element::cloneNodeInternal(Document& targetDocument, CloningOperation
349349Ref<Element> Element::cloneElementWithChildren(Document& targetDocument)
350350{
351351 Ref<Element> clone = cloneElementWithoutChildren(targetDocument);
352 
353  // It's safe to dispatch events on the cloned node since author scripts have no access to it yet.
354  // This is needed for SVGUseElement::cloneTarget.
355  NoEventDispatchAssertion::EventAllowedScope allowedScope(clone.get());
356 
357352 cloneChildNodes(clone);
358353 return clone;
359354}

@@Ref<Element> Element::cloneElementWithoutChildren(Document& targetDocument)
362357{
363358 Ref<Element> clone = cloneElementWithoutAttributesAndChildren(targetDocument);
364359
365  // It's safe to dispatch events on the cloned node since author scripts have no access to it yet.
366  // This is needed for SVGUseElement::cloneTarget.
367  NoEventDispatchAssertion::EventAllowedScope allowedScope(clone.get());
368 
369360 // This will catch HTML elements in the wrong namespace that are not correctly copied.
370361 // This is a sanity check as HTML overloads some of the DOM methods.
371362 ASSERT(isHTMLElement() == clone->isHTMLElement());

Source/WebCore/svg/SVGUseElement.cpp

@@Node::InsertedIntoAncestorResult SVGUseElement::insertedIntoAncestor(InsertionTy
108108{
109109 SVGGraphicsElement::insertedIntoAncestor(insertionType, parentOfInsertedTree);
110110 if (insertionType.connectedToDocument) {
 111 if (m_shadowTreeNeedsUpdate)
 112 document().addSVGUseElement(*this);
111113 SVGExternalResourcesRequired::insertedIntoDocument(this);
112114 invalidateShadowTree();
113115 updateExternalDocument();

@@Node::InsertedIntoAncestorResult SVGUseElement::insertedIntoAncestor(InsertionTy
117119
118120void SVGUseElement::removedFromAncestor(RemovalType removalType, ContainerNode& oldParentOfRemovedTree)
119121{
 122 // Check m_shadowTreeNeedsUpdate before calling SVGElement::removedFromAncestor which calls SVGElement::invalidateInstances
 123 // and SVGUseElement::updateExternalDocument which calls invalidateShadowTree().
 124 if (removalType.disconnectedFromDocument) {
 125 if (m_shadowTreeNeedsUpdate)
 126 document().removeSVGUseElement(*this);
 127 }
120128 SVGGraphicsElement::removedFromAncestor(removalType, oldParentOfRemovedTree);
121  clearShadowTree();
122  updateExternalDocument();
 129 if (removalType.disconnectedFromDocument) {
 130 clearShadowTree();
 131 updateExternalDocument();
 132 }
123133}
124134
125135inline Document* SVGUseElement::externalDocument() const

@@void SVGUseElement::svgAttributeChanged(const QualifiedName& attrName)
183193
184194void SVGUseElement::willRecalcStyle(Style::Change change)
185195{
186  // FIXME: Shadow tree should be updated before style recalc.
187  if (m_shadowTreeNeedsUpdate)
188  updateShadowTree();
189196 SVGGraphicsElement::willRecalcStyle(change);
190197}
191198

@@void SVGUseElement::updateShadowTree()
234241 // FIXME: It's expensive to re-clone the entire tree every time. We should find a more efficient way to handle this.
235242 clearShadowTree();
236243
237  if (isInShadowTree() || !isConnected())
 244 if (!isConnected())
 245 return;
 246 document().removeSVGUseElement(*this);
 247
 248 // FIXME: Enable SVG use elements in shadow trees.
 249 if (isInShadowTree())
238250 return;
239251
240252 String targetID;

@@void SVGUseElement::updateShadowTree()
245257 }
246258
247259 {
248  // Safe because the cloned shadow tree has never been exposed to author scripts.
249260 auto& shadowRoot = ensureUserAgentShadowRoot();
250  NoEventDispatchAssertion::EventAllowedScope scope(shadowRoot);
251261 cloneTarget(shadowRoot, *target);
252262 expandUseElementsInShadowTree();
253263 expandSymbolElementsInShadowTree();

@@SVGElement* SVGUseElement::findTarget(String* targetID) const
436446void SVGUseElement::cloneTarget(ContainerNode& container, SVGElement& target) const
437447{
438448 Ref<SVGElement> targetClone = static_cast<SVGElement&>(target.cloneElementWithChildren(document()).get());
439  // Safe because the newy cloned nodes in the shadow tree has not been exposed to author scripts yet.
440  NoEventDispatchAssertion::EventAllowedScope scope(targetClone);
441449 associateClonesWithOriginals(targetClone.get(), target);
442450 removeDisallowedElementsFromSubtree(targetClone.get());
443451 removeSymbolElementsFromSubtree(targetClone.get());

@@void SVGUseElement::expandUseElementsInShadowTree() const
470478 // 'use' element except for x, y, width, height and xlink:href are transferred to the generated 'g' element.
471479
472480 auto replacementClone = SVGGElement::create(document());
473  // Safe because the use element's shadow tree is not exposed to author scripts, and we don't fire synchronous events during layout & DOM layout.
474  NoEventDispatchAssertion::EventAllowedScope scope(replacementClone);
475481
476482 cloneDataAndChildren(replacementClone.get(), originalClone);
477483

@@void SVGUseElement::expandSymbolElementsInShadowTree() const
506512 // 'svg' element will use values of 100% for these attributes.
507513
508514 auto replacementClone = SVGSVGElement::create(document());
509  // Safe because the newly created SVG element and the newly created shadow tree has not been exposed to author scripts yet.
510  NoEventDispatchAssertion::EventAllowedScope scope(replacementClone);
511515 cloneDataAndChildren(replacementClone.get(), originalClone);
512516
513517 originalClone.parentNode()->replaceChild(replacementClone, originalClone);

@@void SVGUseElement::invalidateShadowTree()
533537 m_shadowTreeNeedsUpdate = true;
534538 invalidateStyleAndRenderersForSubtree();
535539 invalidateDependentShadowTrees();
 540 if (isConnected())
 541 document().addSVGUseElement(*this);
536542}
537543
538544void SVGUseElement::invalidateDependentShadowTrees()

Source/WebCore/svg/SVGUseElement.h

@@public:
5050 virtual ~SVGUseElement();
5151
5252 void invalidateShadowTree();
 53 bool shadowTreeNeedsUpdate() const { return m_shadowTreeNeedsUpdate; }
 54 void updateShadowTree();
5355
5456 RenderElement* rendererClipChild() const;
5557

@@private:
8183 void cloneTarget(ContainerNode&, SVGElement& target) const;
8284 RefPtr<SVGElement> targetClone() const;
8385
84  void updateShadowTree();
8586 void expandUseElementsInShadowTree() const;
8687 void expandSymbolElementsInShadowTree() const;
8788 void transferEventListenersToShadowTree() const;