forked from mirrors/gecko-dev
		
	Bug 1483882 - Teach IDTracker about Shadow DOM. r=smaug
Differential Revision: https://phabricator.services.mozilla.com/D3533
This commit is contained in:
		
							parent
							
								
									bb47a9554c
								
							
						
					
					
						commit
						66b986e252
					
				
					 19 changed files with 282 additions and 90 deletions
				
			
		|  | @ -349,6 +349,18 @@ DocumentOrShadowRoot::RemoveIDTargetObserver(nsAtom* aID, | |||
|   entry->RemoveContentChangeCallback(aObserver, aData, aForImage); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| Element* | ||||
| DocumentOrShadowRoot::LookupImageElement(const nsAString& aId) | ||||
| { | ||||
|   if (aId.IsEmpty()) { | ||||
|     return nullptr; | ||||
|   } | ||||
| 
 | ||||
|   nsIdentifierMapEntry* entry = mIdentifierMap.GetEntry(aId); | ||||
|   return entry ? entry->GetImageIdElement() : nullptr; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| DocumentOrShadowRoot::ReportEmptyGetElementByIdArg() | ||||
| { | ||||
|  |  | |||
|  | @ -160,6 +160,15 @@ public: | |||
|   void RemoveIDTargetObserver(nsAtom* aID, IDTargetObserver aObserver, | ||||
|                               void* aData, bool aForImage); | ||||
| 
 | ||||
|   /**
 | ||||
|    * Lookup an image element using its associated ID, which is usually provided | ||||
|    * by |-moz-element()|. Similar to GetElementById, with the difference that | ||||
|    * elements set using mozSetImageElement have higher priority. | ||||
|    * @param aId the ID associated the element we want to lookup | ||||
|    * @return the element associated with |aId| | ||||
|    */ | ||||
|   Element* LookupImageElement(const nsAString& aElementId); | ||||
| 
 | ||||
|   /**
 | ||||
|    * Check that aId is not empty and log a message to the console | ||||
|    * service if it is. | ||||
|  |  | |||
|  | @ -1464,10 +1464,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(FragmentOrElement) | |||
|     unbind the child nodes. | ||||
|   } */ | ||||
| 
 | ||||
|   // Clear flag here because unlinking slots will clear the
 | ||||
|   // containing shadow root pointer.
 | ||||
|   tmp->UnsetFlags(NODE_IS_IN_SHADOW_TREE); | ||||
| 
 | ||||
|   if (ShadowRoot* shadowRoot = tmp->GetShadowRoot()) { | ||||
|     for (nsIContent* child = shadowRoot->GetFirstChild(); | ||||
|          child; | ||||
|  |  | |||
|  | @ -17,9 +17,28 @@ | |||
| namespace mozilla { | ||||
| namespace dom { | ||||
| 
 | ||||
| static DocumentOrShadowRoot* | ||||
| DocOrShadowFromContent(nsIContent& aContent) | ||||
| { | ||||
|   ShadowRoot* shadow = aContent.GetContainingShadow(); | ||||
| 
 | ||||
|   // We never look in <svg:use> shadow trees, for backwards compat.
 | ||||
|   while (shadow && shadow->Host()->IsSVGElement(nsGkAtoms::use)) { | ||||
|     shadow = shadow->Host()->GetContainingShadow(); | ||||
|   } | ||||
| 
 | ||||
|   if (shadow) { | ||||
|     return shadow; | ||||
|   } | ||||
| 
 | ||||
|   return aContent.OwnerDoc(); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| IDTracker::Reset(nsIContent* aFromContent, nsIURI* aURI, | ||||
|                  bool aWatch, bool aReferenceImage) | ||||
| IDTracker::Reset(nsIContent* aFromContent, | ||||
|                  nsIURI* aURI, | ||||
|                  bool aWatch, | ||||
|                  bool aReferenceImage) | ||||
| { | ||||
|   MOZ_ASSERT(aFromContent, "Reset() expects non-null content pointer"); | ||||
| 
 | ||||
|  | @ -34,13 +53,11 @@ IDTracker::Reset(nsIContent* aFromContent, nsIURI* aURI, | |||
|   // document charset, hopefully...
 | ||||
|   NS_UnescapeURL(refPart); | ||||
| 
 | ||||
|   // Get the current document
 | ||||
|   nsIDocument *doc = aFromContent->OwnerDoc(); | ||||
|   if (!doc) { | ||||
|     return; | ||||
|   } | ||||
| 
 | ||||
|   // Get the thing to observe changes to.
 | ||||
|   nsIDocument* doc = aFromContent->OwnerDoc(); | ||||
|   DocumentOrShadowRoot* docOrShadow = DocOrShadowFromContent(*aFromContent); | ||||
|   auto encoding = doc->GetDocumentCharacterSet(); | ||||
| 
 | ||||
|   nsAutoString ref; | ||||
|   nsresult rv = encoding->DecodeWithoutBOMHandling(refPart, ref); | ||||
|   if (NS_FAILED(rv) || ref.IsEmpty()) { | ||||
|  | @ -49,7 +66,7 @@ IDTracker::Reset(nsIContent* aFromContent, nsIURI* aURI, | |||
|   rv = NS_OK; | ||||
| 
 | ||||
|   nsIContent* bindingParent = aFromContent->GetBindingParent(); | ||||
|   if (bindingParent) { | ||||
|   if (bindingParent && !aFromContent->IsInShadowTree()) { | ||||
|     nsXBLBinding* binding = bindingParent->GetXBLBinding(); | ||||
|     if (!binding) { | ||||
|       // This happens, for example, if aFromContent is part of the content
 | ||||
|  | @ -100,6 +117,7 @@ IDTracker::Reset(nsIContent* aFromContent, nsIURI* aURI, | |||
|     RefPtr<nsIDocument::ExternalResourceLoad> load; | ||||
|     doc = doc->RequestExternalResource(aURI, aFromContent, | ||||
|                                        getter_AddRefs(load)); | ||||
|     docOrShadow = doc; | ||||
|     if (!doc) { | ||||
|       if (!load || !aWatch) { | ||||
|         // Nothing will ever happen here
 | ||||
|  | @ -109,9 +127,7 @@ IDTracker::Reset(nsIContent* aFromContent, nsIURI* aURI, | |||
|       DocumentLoadNotification* observer = | ||||
|         new DocumentLoadNotification(this, ref); | ||||
|       mPendingNotification = observer; | ||||
|       if (observer) { | ||||
|       load->AddObserver(observer); | ||||
|       } | ||||
|       // Keep going so we set up our watching stuff a bit
 | ||||
|     } | ||||
|   } | ||||
|  | @ -124,51 +140,49 @@ IDTracker::Reset(nsIContent* aFromContent, nsIURI* aURI, | |||
|   } | ||||
| 
 | ||||
|   mReferencingImage = aReferenceImage; | ||||
| 
 | ||||
|   HaveNewDocument(doc, aWatch, ref); | ||||
|   HaveNewDocumentOrShadowRoot(docOrShadow, aWatch, ref); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| IDTracker::ResetWithID(nsIContent* aFromContent, const nsString& aID, | ||||
| IDTracker::ResetWithID(nsIContent* aFromContent, | ||||
|                        nsAtom* aID, | ||||
|                        bool aWatch) | ||||
| { | ||||
|   nsIDocument *doc = aFromContent->OwnerDoc(); | ||||
|   if (!doc) | ||||
|     return; | ||||
| 
 | ||||
|   // XXX Need to take care of XBL/XBL2
 | ||||
|   MOZ_ASSERT(aFromContent); | ||||
|   MOZ_ASSERT(aID); | ||||
| 
 | ||||
|   if (aWatch) { | ||||
|     RefPtr<nsAtom> atom = NS_Atomize(aID); | ||||
|     if (!atom) | ||||
|       return; | ||||
|     RefPtr<nsAtom> atom = aID; | ||||
|     atom.swap(mWatchID); | ||||
|   } | ||||
| 
 | ||||
|   mReferencingImage = false; | ||||
| 
 | ||||
|   HaveNewDocument(doc, aWatch, aID); | ||||
|   DocumentOrShadowRoot* docOrShadow = DocOrShadowFromContent(*aFromContent); | ||||
|   HaveNewDocumentOrShadowRoot(docOrShadow, aWatch, nsDependentAtomString(aID)); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| IDTracker::HaveNewDocument(nsIDocument* aDocument, bool aWatch, | ||||
| IDTracker::HaveNewDocumentOrShadowRoot( | ||||
|   DocumentOrShadowRoot* aDocOrShadow, | ||||
|   bool aWatch, | ||||
|   const nsString& aRef) | ||||
| { | ||||
|   if (aWatch) { | ||||
|     mWatchDocument = aDocument; | ||||
|     if (mWatchDocument) { | ||||
|       mElement = mWatchDocument->AddIDTargetObserver(mWatchID, Observe, this, | ||||
|                                                      mReferencingImage); | ||||
|     mWatchDocumentOrShadowRoot = nullptr; | ||||
|     if (aDocOrShadow) { | ||||
|       mWatchDocumentOrShadowRoot = &aDocOrShadow->AsNode(); | ||||
|       mElement = aDocOrShadow->AddIDTargetObserver(mWatchID, Observe, this, mReferencingImage); | ||||
|     } | ||||
|     return; | ||||
|   } | ||||
| 
 | ||||
|   if (!aDocument) { | ||||
|   if (!aDocOrShadow) { | ||||
|     return; | ||||
|   } | ||||
| 
 | ||||
|   Element *e = mReferencingImage ? aDocument->LookupImageElement(aRef) : | ||||
|                                    aDocument->GetElementById(aRef); | ||||
|   Element* e = mReferencingImage ? aDocOrShadow->LookupImageElement(aRef) | ||||
|                                  : aDocOrShadow->GetElementById(aRef); | ||||
|   if (e) { | ||||
|     mElement = e; | ||||
|   } | ||||
|  | @ -177,32 +191,33 @@ IDTracker::HaveNewDocument(nsIDocument* aDocument, bool aWatch, | |||
| void | ||||
| IDTracker::Traverse(nsCycleCollectionTraversalCallback* aCB) | ||||
| { | ||||
|   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCB, "mWatchDocument"); | ||||
|   aCB->NoteXPCOMChild(mWatchDocument); | ||||
|   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCB, "mContent"); | ||||
|   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCB, "mWatchDocumentOrShadowRoot"); | ||||
|   aCB->NoteXPCOMChild(mWatchDocumentOrShadowRoot); | ||||
|   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCB, "mElement"); | ||||
|   aCB->NoteXPCOMChild(mElement); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| IDTracker::Unlink() | ||||
| { | ||||
|   if (mWatchDocument && mWatchID) { | ||||
|     mWatchDocument->RemoveIDTargetObserver(mWatchID, Observe, this, | ||||
|                                            mReferencingImage); | ||||
|   if (mWatchID) { | ||||
|     if (DocumentOrShadowRoot* docOrShadow = GetWatchDocOrShadowRoot()) { | ||||
|       docOrShadow->RemoveIDTargetObserver( | ||||
|         mWatchID, Observe, this, mReferencingImage); | ||||
|     } | ||||
|   } | ||||
|   if (mPendingNotification) { | ||||
|     mPendingNotification->Clear(); | ||||
|     mPendingNotification = nullptr; | ||||
|   } | ||||
|   mWatchDocument = nullptr; | ||||
|   mWatchDocumentOrShadowRoot = nullptr; | ||||
|   mWatchID = nullptr; | ||||
|   mElement = nullptr; | ||||
|   mReferencingImage = false; | ||||
| } | ||||
| 
 | ||||
| bool | ||||
| IDTracker::Observe(Element* aOldElement, | ||||
|                    Element* aNewElement, void* aData) | ||||
| IDTracker::Observe(Element* aOldElement, Element* aNewElement, void* aData) | ||||
| { | ||||
|   IDTracker* p = static_cast<IDTracker*>(aData); | ||||
|   if (p->mPendingNotification) { | ||||
|  | @ -216,17 +231,14 @@ IDTracker::Observe(Element* aOldElement, | |||
|   } | ||||
|   bool keepTracking = p->IsPersistent(); | ||||
|   if (!keepTracking) { | ||||
|     p->mWatchDocument = nullptr; | ||||
|     p->mWatchDocumentOrShadowRoot = nullptr; | ||||
|     p->mWatchID = nullptr; | ||||
|   } | ||||
|   return keepTracking; | ||||
| } | ||||
| 
 | ||||
| NS_IMPL_ISUPPORTS_INHERITED0(IDTracker::ChangeNotification, | ||||
|                              mozilla::Runnable) | ||||
| 
 | ||||
| NS_IMPL_ISUPPORTS(IDTracker::DocumentLoadNotification, | ||||
|                   nsIObserver) | ||||
| NS_IMPL_ISUPPORTS_INHERITED0(IDTracker::ChangeNotification, mozilla::Runnable) | ||||
| NS_IMPL_ISUPPORTS(IDTracker::DocumentLoadNotification, nsIObserver) | ||||
| 
 | ||||
| NS_IMETHODIMP | ||||
| IDTracker::DocumentLoadNotification::Observe(nsISupports* aSubject, | ||||
|  | @ -241,7 +253,7 @@ IDTracker::DocumentLoadNotification::Observe(nsISupports* aSubject, | |||
|     NS_ASSERTION(!mTarget->mElement, "Why do we have content here?"); | ||||
|     // If we got here, that means we had Reset() called with aWatch ==
 | ||||
|     // true.  So keep watching if IsPersistent().
 | ||||
|     mTarget->HaveNewDocument(doc, mTarget->IsPersistent(), mRef); | ||||
|     mTarget->HaveNewDocumentOrShadowRoot(doc, mTarget->IsPersistent(), mRef); | ||||
|     mTarget->ElementChanged(nullptr, mTarget->mElement); | ||||
|   } | ||||
|   return NS_OK; | ||||
|  |  | |||
|  | @ -9,6 +9,7 @@ | |||
| 
 | ||||
| #include "mozilla/Attributes.h" | ||||
| #include "mozilla/dom/Element.h" | ||||
| #include "mozilla/dom/ShadowRoot.h" | ||||
| #include "nsAtom.h" | ||||
| #include "nsIDocument.h" | ||||
| #include "nsThreadUtils.h" | ||||
|  | @ -39,10 +40,10 @@ class IDTracker { | |||
| public: | ||||
|   typedef mozilla::dom::Element Element; | ||||
| 
 | ||||
|   IDTracker() | ||||
|     : mReferencingImage(false) | ||||
|   {} | ||||
|   ~IDTracker() { | ||||
|   IDTracker() = default; | ||||
| 
 | ||||
|   ~IDTracker() | ||||
|   { | ||||
|     Unlink(); | ||||
|   } | ||||
| 
 | ||||
|  | @ -63,7 +64,9 @@ public: | |||
|    * @param aReferenceImage whether the ID references image elements which are | ||||
|    * subject to the document's mozSetImageElement overriding mechanism. | ||||
|    */ | ||||
|   void Reset(nsIContent* aFrom, nsIURI* aURI, bool aWatch = true, | ||||
|   void Reset(nsIContent* aFrom, | ||||
|              nsIURI* aURI, | ||||
|              bool aWatch = true, | ||||
|              bool aReferenceImage = false); | ||||
| 
 | ||||
|   /**
 | ||||
|  | @ -75,8 +78,7 @@ public: | |||
|    * changes, so ElementChanged won't fire and get() will always return the same | ||||
|    * value, the current element for the ID. | ||||
|    */ | ||||
|   void ResetWithID(nsIContent* aFrom, const nsString& aID, | ||||
|                    bool aWatch = true); | ||||
|   void ResetWithID(nsIContent* aFrom, nsAtom* aID, bool aWatch = true); | ||||
| 
 | ||||
|   /**
 | ||||
|    * Clears the reference. ElementChanged is not triggered. get() will return | ||||
|  | @ -92,7 +94,8 @@ protected: | |||
|    * to call this superclass method to change mElement. This is called | ||||
|    * at script-runnable time. | ||||
|    */ | ||||
|   virtual void ElementChanged(Element* aFrom, Element* aTo) { | ||||
|   virtual void ElementChanged(Element* aFrom, Element* aTo) | ||||
|   { | ||||
|     mElement = aTo; | ||||
|   } | ||||
| 
 | ||||
|  | @ -106,7 +109,8 @@ protected: | |||
|    * Set ourselves up with our new document.  Note that aDocument might be | ||||
|    * null.  Either aWatch must be false or aRef must be empty. | ||||
|    */ | ||||
|   void HaveNewDocument(nsIDocument* aDocument, bool aWatch, | ||||
|   void HaveNewDocumentOrShadowRoot(DocumentOrShadowRoot*, | ||||
|                                    bool aWatch, | ||||
|                                    const nsString& aRef); | ||||
| 
 | ||||
| private: | ||||
|  | @ -167,9 +171,8 @@ private: | |||
|                                    public nsIObserver | ||||
|   { | ||||
|   public: | ||||
|     DocumentLoadNotification(IDTracker* aTarget, | ||||
|                              const nsString& aRef) : | ||||
|       Notification(aTarget) | ||||
|     DocumentLoadNotification(IDTracker* aTarget, const nsString& aRef) | ||||
|       : Notification(aTarget) | ||||
|     { | ||||
|       if (!mTarget->IsPersistent()) { | ||||
|         mRef = aRef; | ||||
|  | @ -187,11 +190,24 @@ private: | |||
|   }; | ||||
|   friend class DocumentLoadNotification; | ||||
| 
 | ||||
|   DocumentOrShadowRoot* GetWatchDocOrShadowRoot() const | ||||
|   { | ||||
|     if (!mWatchDocumentOrShadowRoot) { | ||||
|       return nullptr; | ||||
|     } | ||||
|     MOZ_ASSERT(mWatchDocumentOrShadowRoot->IsDocument() || | ||||
|                mWatchDocumentOrShadowRoot->IsShadowRoot()); | ||||
|     if (ShadowRoot* shadow = ShadowRoot::FromNode(*mWatchDocumentOrShadowRoot)) { | ||||
|       return shadow; | ||||
|     } | ||||
|     return mWatchDocumentOrShadowRoot->AsDocument(); | ||||
|   } | ||||
| 
 | ||||
|   RefPtr<nsAtom> mWatchID; | ||||
|   nsCOMPtr<nsIDocument>  mWatchDocument; | ||||
|   nsCOMPtr<nsINode> mWatchDocumentOrShadowRoot; // Always a `DocumentOrShadowRoot`.
 | ||||
|   RefPtr<Element> mElement; | ||||
|   RefPtr<Notification> mPendingNotification; | ||||
|   bool                   mReferencingImage; | ||||
|   bool mReferencingImage = false; | ||||
| }; | ||||
| 
 | ||||
| inline void | ||||
|  |  | |||
|  | @ -4953,16 +4953,6 @@ nsIDocument::MozSetImageElement(const nsAString& aImageElementId, | |||
|   } | ||||
| } | ||||
| 
 | ||||
| Element* | ||||
| nsIDocument::LookupImageElement(const nsAString& aId) | ||||
| { | ||||
|   if (aId.IsEmpty()) | ||||
|     return nullptr; | ||||
| 
 | ||||
|   nsIdentifierMapEntry* entry = mIdentifierMap.GetEntry(aId); | ||||
|   return entry ? entry->GetImageIdElement() : nullptr; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| nsIDocument::DispatchContentLoadedEvents() | ||||
| { | ||||
|  |  | |||
|  | @ -2844,15 +2844,6 @@ public: | |||
|   using mozilla::dom::DocumentOrShadowRoot::GetElementsByTagNameNS; | ||||
|   using mozilla::dom::DocumentOrShadowRoot::GetElementsByClassName; | ||||
| 
 | ||||
|   /**
 | ||||
|    * Lookup an image element using its associated ID, which is usually provided | ||||
|    * by |-moz-element()|. Similar to GetElementById, with the difference that | ||||
|    * elements set using mozSetImageElement have higher priority. | ||||
|    * @param aId the ID associated the element we want to lookup | ||||
|    * @return the element associated with |aId| | ||||
|    */ | ||||
|   Element* LookupImageElement(const nsAString& aElementId); | ||||
| 
 | ||||
|   mozilla::dom::DocumentTimeline* Timeline(); | ||||
|   mozilla::LinkedList<mozilla::dom::DocumentTimeline>& Timelines() | ||||
|   { | ||||
|  |  | |||
|  | @ -105,8 +105,7 @@ nsSMILTimeValueSpec::ResolveReferences(nsIContent* aContextNode) | |||
|   RefPtr<Element> oldReferencedElement = mReferencedElement.get(); | ||||
| 
 | ||||
|   if (mParams.mDependentElemID) { | ||||
|     mReferencedElement.ResetWithID(aContextNode, | ||||
|         nsDependentAtomString(mParams.mDependentElemID)); | ||||
|     mReferencedElement.ResetWithID(aContextNode, mParams.mDependentElemID); | ||||
|   } else if (mParams.mType == nsSMILTimeValueSpecParams::EVENT) { | ||||
|     Element* target = mOwner->GetTargetElement(); | ||||
|     mReferencedElement.ResetWithElement(target); | ||||
|  |  | |||
							
								
								
									
										22
									
								
								layout/reftests/svg/fragid-shadow-1.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								layout/reftests/svg/fragid-shadow-1.html
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,22 @@ | |||
| <!doctype html> | ||||
| <svg style="position: absolute; width: 0; height: 0"> | ||||
|   <defs> | ||||
|     <pattern id="rect" width="100" height="100"> | ||||
|       <rect fill="red" width="100" height="100" /> | ||||
|     </pattern> | ||||
|   </defs> | ||||
| </svg> | ||||
| <div id="host"></div> | ||||
| <script> | ||||
|   // Should peek the pattern from the shadow root (green), not from the document (red). | ||||
|   host.attachShadow({ mode: "open" }).innerHTML = ` | ||||
|     <svg width="100" height="100"> | ||||
|       <defs> | ||||
|         <pattern id="rect" width="100" height="100"> | ||||
|           <rect fill="lime" width="100" height="100" /> | ||||
|         </pattern> | ||||
|       </defs> | ||||
|       <rect fill="url(#rect)" width="100" height="100" /> | ||||
|     </svg> | ||||
|   `; | ||||
| </script> | ||||
							
								
								
									
										17
									
								
								layout/reftests/svg/fragid-shadow-2.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								layout/reftests/svg/fragid-shadow-2.html
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,17 @@ | |||
| <!doctype html> | ||||
| <div id="host"></div> | ||||
| <script> | ||||
|   // Test dynamic id changes inside the shadow root. | ||||
|   host.attachShadow({ mode: "open" }).innerHTML = ` | ||||
|     <svg width="100" height="100"> | ||||
|       <defs> | ||||
|         <pattern id="rect1" width="100" height="100"> | ||||
|           <rect fill="lime" width="100" height="100" /> | ||||
|         </pattern> | ||||
|       </defs> | ||||
|       <rect fill="url(#rect)" width="100" height="100" /> | ||||
|     </svg> | ||||
|   `; | ||||
|   document.body.offsetTop; | ||||
|   host.shadowRoot.getElementById("rect1").id = "rect"; | ||||
| </script> | ||||
							
								
								
									
										14
									
								
								layout/reftests/svg/fragid-shadow-3.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								layout/reftests/svg/fragid-shadow-3.html
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | |||
| <!doctype html> | ||||
| <div id="host"></div> | ||||
| <svg height="0"> | ||||
|   <!-- use an empty g to force fragid-shadow-resource.svg to load before onload --> | ||||
|   <use href="fragid-shadow-resource.svg#empty"> | ||||
| </svg> | ||||
| <script> | ||||
|   // Test that external resource URIs resolve properly inside shadow trees. | ||||
|   host.attachShadow({ mode: "open" }).innerHTML = ` | ||||
|     <svg width="100" height="100"> | ||||
|       <rect fill="url(fragid-shadow-resource.svg#rect)" width="100" height="100" /> | ||||
|     </svg> | ||||
|   `; | ||||
| </script> | ||||
							
								
								
									
										13
									
								
								layout/reftests/svg/fragid-shadow-4.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								layout/reftests/svg/fragid-shadow-4.html
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,13 @@ | |||
| <!doctype html> | ||||
| <div id="host"></div> | ||||
| <script> | ||||
|   // Test references in <svg:use> work properly. | ||||
|   host.attachShadow({ mode: "open" }).innerHTML = ` | ||||
|     <svg width="100" height="100"> | ||||
|       <defs> | ||||
|         <rect fill="lime" id="rect-4" width="100" height="100"> | ||||
|       </defs> | ||||
|       <use href="#rect-4" /> | ||||
|     </svg> | ||||
|   `; | ||||
| </script> | ||||
							
								
								
									
										13
									
								
								layout/reftests/svg/fragid-shadow-5.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								layout/reftests/svg/fragid-shadow-5.html
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,13 @@ | |||
| <!doctype html> | ||||
| <div id="host"></div> | ||||
| <script> | ||||
|   // Test absolute URIs inside shadow trees, which behave the same way as just the fragment id. | ||||
|   host.attachShadow({ mode: "open" }).innerHTML = ` | ||||
|     <svg width="100" height="100"> | ||||
|       <defs> | ||||
|         <rect fill="lime" id="rect-5" width="100" height="100"> | ||||
|       </defs> | ||||
|       <use href="${location.href}#rect-5" /> | ||||
|     </svg> | ||||
|   `; | ||||
| </script> | ||||
							
								
								
									
										23
									
								
								layout/reftests/svg/fragid-shadow-6.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								layout/reftests/svg/fragid-shadow-6.html
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,23 @@ | |||
| <!doctype html> | ||||
| <svg style="position: absolute; width: 0; height: 0"> | ||||
|   <defs> | ||||
|     <pattern id="rect" width="100" height="100"> | ||||
|       <rect fill="red" width="100" height="100" /> | ||||
|     </pattern> | ||||
|   </defs> | ||||
| </svg> | ||||
| <div id="host"></div> | ||||
| <script> | ||||
|   // Should peek the pattern from the shadow root (green), not from the document (red), | ||||
|   // even though the uri is absolute. | ||||
|   host.attachShadow({ mode: "open" }).innerHTML = ` | ||||
|     <svg width="100" height="100"> | ||||
|       <defs> | ||||
|         <pattern id="rect" width="100" height="100"> | ||||
|           <rect fill="lime" width="100" height="100" /> | ||||
|         </pattern> | ||||
|       </defs> | ||||
|       <rect fill="url(${location.href}#rect)" width="100" height="100" /> | ||||
|     </svg> | ||||
|   `; | ||||
| </script> | ||||
							
								
								
									
										28
									
								
								layout/reftests/svg/fragid-shadow-7.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								layout/reftests/svg/fragid-shadow-7.html
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,28 @@ | |||
| <!doctype html> | ||||
| <svg style="position: absolute; width: 0; height: 0"> | ||||
|   <defs> | ||||
|     <pattern id="rect" width="100" height="100"> | ||||
|       <rect fill="red" width="100" height="100" /> | ||||
|     </pattern> | ||||
|   </defs> | ||||
| </svg> | ||||
| <div id="host"></div> | ||||
| <script> | ||||
|   // Test references from a <svg:use> subtree. | ||||
|   host.attachShadow({ mode: "open" }).innerHTML = ` | ||||
|     <svg width="100" height="100"> | ||||
|       <defs> | ||||
|         <pattern id="rect" width="100" height="100"> | ||||
|           <rect fill="lime" width="100" height="100" /> | ||||
|         </pattern> | ||||
|         <symbol id="useme"> | ||||
|           <pattern id="rect" width="100" height="100"> | ||||
|             <rect fill="red" width="100" height="100" /> | ||||
|           </pattern> | ||||
|           <rect fill="url(#rect)" width="100" height="100" /> | ||||
|         </symbol> | ||||
|       </defs> | ||||
|       <use href="#useme" /> | ||||
|     </svg> | ||||
|   `; | ||||
| </script> | ||||
							
								
								
									
										15
									
								
								layout/reftests/svg/fragid-shadow-8.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								layout/reftests/svg/fragid-shadow-8.html
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,15 @@ | |||
| <!doctype html> | ||||
| <svg width="100" height="100"> | ||||
|   <defs> | ||||
|     <pattern id="rect" width="100" height="100"> | ||||
|       <rect fill="lime" width="100" height="100" /> | ||||
|     </pattern> | ||||
|     <symbol id="useme"> | ||||
|       <pattern id="rect" width="100" height="100"> | ||||
|         <rect fill="red" width="100" height="100" /> | ||||
|       </pattern> | ||||
|       <rect fill="url(#rect)" width="100" height="100" /> | ||||
|     </symbol> | ||||
|   </defs> | ||||
|   <use href="#useme" /> | ||||
| </svg> | ||||
							
								
								
									
										4
									
								
								layout/reftests/svg/fragid-shadow-ref.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								layout/reftests/svg/fragid-shadow-ref.html
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,4 @@ | |||
| <!doctype html> | ||||
| <svg width="100" height="100"> | ||||
|   <rect fill="lime" width="100" height="100" /> | ||||
| </svg> | ||||
							
								
								
									
										8
									
								
								layout/reftests/svg/fragid-shadow-resource.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								layout/reftests/svg/fragid-shadow-resource.svg
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,8 @@ | |||
| <svg xmlns="http://www.w3.org/2000/svg"> | ||||
|   <defs> | ||||
|     <g id="empty" /> | ||||
|     <pattern id="rect" width="100" height="100"> | ||||
|       <rect fill="lime" width="100" height="100" /> | ||||
|     </pattern> | ||||
|   </defs> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 204 B | 
|  | @ -552,3 +552,13 @@ fuzzy-if(skiaContent,0-1,0-100) == tspan-xy-anchor-end-01.svg tspan-xy-anchor-en | |||
| == currentColor-override-flood.svg pass.svg | ||||
| == currentColor-override-lighting.svg currentColor-override-lighting-ref.svg | ||||
| == currentColor-override-stop.svg pass.svg | ||||
| 
 | ||||
| # Shadow DOM id tracking. | ||||
| pref(dom.webcomponents.shadowdom.enabled,true) == fragid-shadow-1.html fragid-shadow-ref.html | ||||
| pref(dom.webcomponents.shadowdom.enabled,true) == fragid-shadow-2.html fragid-shadow-ref.html | ||||
| pref(dom.webcomponents.shadowdom.enabled,true) == fragid-shadow-3.html fragid-shadow-ref.html | ||||
| pref(dom.webcomponents.shadowdom.enabled,true) == fragid-shadow-4.html fragid-shadow-ref.html | ||||
| pref(dom.webcomponents.shadowdom.enabled,true) == fragid-shadow-5.html fragid-shadow-ref.html | ||||
| pref(dom.webcomponents.shadowdom.enabled,true) == fragid-shadow-6.html fragid-shadow-ref.html | ||||
| pref(dom.webcomponents.shadowdom.enabled,true) == fragid-shadow-7.html fragid-shadow-ref.html | ||||
| pref(dom.webcomponents.shadowdom.enabled,true) == fragid-shadow-8.html fragid-shadow-ref.html | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Emilio Cobos Álvarez
						Emilio Cobos Álvarez