Bug 1413834 - part 4: Limit frame traversal inside scope owned by document root when shadow host has no frame , r=smaug, emilio
authorben.tian@gmail.com
Fri, 26 Jan 2018 17:49:47 +0200
changeset 400992 bf9cdce5d0b7de4dad26291c37ab8070a25ceb70
parent 400991 f988728a10ae96c05281648ca5424ea7d633ffa6
child 400993 5cbdc4e31b0f42029113f1f4bde8d8a6d31a6475
push id99276
push useropettay@mozilla.com
push dateFri, 26 Jan 2018 20:41:03 +0000
treeherdermozilla-inbound@bf9cdce5d0b7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug, emilio
bugs1413834
milestone60.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1413834 - part 4: Limit frame traversal inside scope owned by document root when shadow host has no frame , r=smaug, emilio
layout/base/nsFrameTraversal.cpp
--- a/layout/base/nsFrameTraversal.cpp
+++ b/layout/base/nsFrameTraversal.cpp
@@ -24,17 +24,17 @@ public:
   virtual nsIFrame* CurrentItem() override;
   virtual bool IsDone() override;
 
   virtual void Last() override;
   virtual void Prev() override;
 
   nsFrameIterator(nsPresContext* aPresContext, nsIFrame *aStart,
                   nsIteratorType aType, bool aLockScroll, bool aFollowOOFs,
-                  bool aSkipPopupChecks, bool aSkipShadow);
+                  bool aSkipPopupChecks);
 
 protected:
   virtual ~nsFrameIterator() {}
 
   void      setCurrent(nsIFrame *aFrame){mCurrent = aFrame;}
   nsIFrame *getCurrent(){return mCurrent;}
   nsIFrame *getStart(){return mStart;}
   nsIFrame *getLast(){return mLast;}
@@ -89,17 +89,16 @@ protected:
    */
   nsIFrame* GetPlaceholderFrame(nsIFrame* aFrame);
   bool      IsPopupFrame(nsIFrame* aFrame);
 
   nsPresContext* const mPresContext;
   const bool mLockScroll;
   const bool mFollowOOFs;
   const bool mSkipPopupChecks;
-  const bool mSkipShadow;
   const nsIteratorType mType;
 
 private:
   nsIFrame* const mStart;
   nsIFrame* mCurrent;
   nsIFrame* mLast; //the last one that was in current;
   int8_t    mOffEdge; //0= no -1 to far prev, 1 to far next;
 };
@@ -107,29 +106,51 @@ private:
 
 
 // Bidi visual iterator
 class nsVisualIterator: public nsFrameIterator
 {
 public:
   nsVisualIterator(nsPresContext* aPresContext, nsIFrame *aStart,
                    nsIteratorType aType, bool aLockScroll,
-                   bool aFollowOOFs, bool aSkipPopupChecks,
-                   bool aSkipShadow) :
+                   bool aFollowOOFs, bool aSkipPopupChecks) :
   nsFrameIterator(aPresContext, aStart, aType, aLockScroll,
-                  aFollowOOFs, aSkipPopupChecks, aSkipShadow) {}
+                  aFollowOOFs, aSkipPopupChecks) {}
 
 protected:
   nsIFrame* GetFirstChildInner(nsIFrame* aFrame) override;
   nsIFrame* GetLastChildInner(nsIFrame* aFrame) override;
 
   nsIFrame* GetNextSiblingInner(nsIFrame* aFrame) override;
   nsIFrame* GetPrevSiblingInner(nsIFrame* aFrame) override;
 };
 
+// Frame iterator that walks only frames of light DOM contents without
+// ancestor assigned to a slot. Primarily for focus navigation.
+class nsLightFrameIterator final : public nsFrameIterator
+{
+public:
+  nsLightFrameIterator(nsPresContext* aPresContext, nsIFrame *aStart,
+                       nsIteratorType aType, bool aLockScroll,
+                       bool aFollowOOFs, bool aSkipPopupChecks) :
+  nsFrameIterator(aPresContext, aStart, aType, aLockScroll,
+                  aFollowOOFs, aSkipPopupChecks) {}
+
+protected:
+  nsIFrame* GetFirstChildInner(nsIFrame* aFrame) override;
+  nsIFrame* GetLastChildInner(nsIFrame* aFrame) override;
+
+  nsIFrame* GetNextSiblingInner(nsIFrame* aFrame) override;
+  nsIFrame* GetPrevSiblingInner(nsIFrame* aFrame) override;
+
+  // Returns true if aFrame's content is in light DOM and has no
+  // ancestor assigned to a slot
+  bool IsLightFrame(nsIFrame* aFrame);
+};
+
 /************IMPLEMENTATIONS**************/
 
 nsresult
 NS_CreateFrameTraversal(nsIFrameTraversal** aResult)
 {
   NS_ENSURE_ARG_POINTER(aResult);
 
   nsCOMPtr<nsIFrameTraversal> t = new nsFrameTraversal();
@@ -155,21 +176,25 @@ NS_NewFrameTraversal(nsIFrameEnumerator 
   if (aFollowOOFs) {
     aStart = nsPlaceholderFrame::GetRealFrameFor(aStart);
   }
 
   nsCOMPtr<nsIFrameEnumerator> trav;
   if (aVisual) {
     trav = new nsVisualIterator(aPresContext, aStart, aType,
                                 aLockInScrollView, aFollowOOFs,
-                                aSkipPopupChecks, aSkipShadow);
+                                aSkipPopupChecks);
+  } else if (aSkipShadow) {
+    trav = new nsLightFrameIterator(aPresContext, aStart, aType,
+                                    aLockInScrollView, aFollowOOFs,
+                                    aSkipPopupChecks);
   } else {
     trav = new nsFrameIterator(aPresContext, aStart, aType,
                                aLockInScrollView, aFollowOOFs,
-                               aSkipPopupChecks, aSkipShadow);
+                               aSkipPopupChecks);
   }
   trav.forget(aEnumerator);
   return NS_OK;
 }
 
 
 nsFrameTraversal::nsFrameTraversal()
 {
@@ -198,23 +223,21 @@ NS_IMETHODIMP
 }
 
 // nsFrameIterator implementation
 
 NS_IMPL_ISUPPORTS(nsFrameIterator, nsIFrameEnumerator)
 
 nsFrameIterator::nsFrameIterator(nsPresContext* aPresContext, nsIFrame *aStart,
                                  nsIteratorType aType, bool aLockInScrollView,
-                                 bool aFollowOOFs, bool aSkipPopupChecks,
-                                 bool aSkipShadow)
+                                 bool aFollowOOFs, bool aSkipPopupChecks)
 : mPresContext(aPresContext),
   mLockScroll(aLockInScrollView),
   mFollowOOFs(aFollowOOFs),
   mSkipPopupChecks(aSkipPopupChecks),
-  mSkipShadow(aSkipShadow),
   mType(aType),
   mStart(aStart),
   mCurrent(aStart),
   mLast(aStart),
   mOffEdge(0)
 {
   MOZ_ASSERT(!aFollowOOFs || !aStart->IsPlaceholderFrame(),
              "Caller should have resolved placeholder frame");
@@ -406,49 +429,31 @@ nsFrameIterator::GetParentFrameNotPopup(
   }
 
   return nullptr;
 }
 
 nsIFrame*
 nsFrameIterator::GetFirstChild(nsIFrame* aFrame)
 {
-  if (mSkipShadow) {
-    // Skip frames rendered from contents in shadow tree,
-    // primarily for focus navigation
-    nsIContent* content = aFrame->GetContent();
-    if (content && content->GetShadowRoot()) {
-      return nullptr;
-    }
-  }
-
   nsIFrame* result = GetFirstChildInner(aFrame);
   if (mLockScroll && result && result->IsScrollFrame())
     return nullptr;
   if (result && mFollowOOFs) {
     result = nsPlaceholderFrame::GetRealFrameFor(result);
 
     if (IsPopupFrame(result))
       result = GetNextSibling(result);
   }
   return result;
 }
 
 nsIFrame*
 nsFrameIterator::GetLastChild(nsIFrame* aFrame)
 {
-  if (mSkipShadow) {
-    // Skip frames rendered from contents in shadow tree,
-    // primarily for focus navigation
-    nsIContent* content = aFrame->GetContent();
-    if (content && content->GetShadowRoot()) {
-      return nullptr;
-    }
-  }
-
   nsIFrame* result = GetLastChildInner(aFrame);
   if (mLockScroll && result && result->IsScrollFrame())
     return nullptr;
   if (result && mFollowOOFs) {
     result = nsPlaceholderFrame::GetRealFrameFor(result);
 
     if (IsPopupFrame(result))
       result = GetPrevSibling(result);
@@ -488,32 +493,36 @@ nsFrameIterator::GetPrevSibling(nsIFrame
 
   if (mFollowOOFs && IsPopupFrame(result))
     result = GetPrevSibling(result);
 
   return result;
 }
 
 nsIFrame*
-nsFrameIterator::GetFirstChildInner(nsIFrame* aFrame) {
+nsFrameIterator::GetFirstChildInner(nsIFrame* aFrame)
+{
   return aFrame->PrincipalChildList().FirstChild();
 }
 
 nsIFrame*
-nsFrameIterator::GetLastChildInner(nsIFrame* aFrame) {
+nsFrameIterator::GetLastChildInner(nsIFrame* aFrame)
+{
   return aFrame->PrincipalChildList().LastChild();
 }
 
 nsIFrame*
-nsFrameIterator::GetNextSiblingInner(nsIFrame* aFrame) {
+nsFrameIterator::GetNextSiblingInner(nsIFrame* aFrame)
+{
   return aFrame->GetNextSibling();
 }
 
 nsIFrame*
-nsFrameIterator::GetPrevSiblingInner(nsIFrame* aFrame) {
+nsFrameIterator::GetPrevSiblingInner(nsIFrame* aFrame)
+{
   return aFrame->GetPrevSibling();
 }
 
 
 nsIFrame*
 nsFrameIterator::GetPlaceholderFrame(nsIFrame* aFrame)
 {
   if (MOZ_LIKELY(!aFrame || !aFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW))) {
@@ -533,32 +542,99 @@ nsFrameIterator::IsPopupFrame(nsIFrame* 
 
   return (aFrame &&
           aFrame->StyleDisplay()->mDisplay == StyleDisplay::MozPopup);
 }
 
 // nsVisualIterator implementation
 
 nsIFrame*
-nsVisualIterator::GetFirstChildInner(nsIFrame* aFrame) {
+nsVisualIterator::GetFirstChildInner(nsIFrame* aFrame)
+{
   return aFrame->PrincipalChildList().GetNextVisualFor(nullptr);
 }
 
 nsIFrame*
-nsVisualIterator::GetLastChildInner(nsIFrame* aFrame) {
+nsVisualIterator::GetLastChildInner(nsIFrame* aFrame)
+{
   return aFrame->PrincipalChildList().GetPrevVisualFor(nullptr);
 }
 
 nsIFrame*
-nsVisualIterator::GetNextSiblingInner(nsIFrame* aFrame) {
+nsVisualIterator::GetNextSiblingInner(nsIFrame* aFrame)
+{
   nsIFrame* parent = GetParentFrame(aFrame);
   if (!parent)
     return nullptr;
   return parent->PrincipalChildList().GetNextVisualFor(aFrame);
 }
 
 nsIFrame*
-nsVisualIterator::GetPrevSiblingInner(nsIFrame* aFrame) {
+nsVisualIterator::GetPrevSiblingInner(nsIFrame* aFrame)
+{
   nsIFrame* parent = GetParentFrame(aFrame);
   if (!parent)
     return nullptr;
   return parent->PrincipalChildList().GetPrevVisualFor(aFrame);
 }
+
+// nsLightFrameIterator implementation
+
+nsIFrame*
+nsLightFrameIterator::GetFirstChildInner(nsIFrame* aFrame)
+{
+  nsIFrame* child = nsFrameIterator::GetFirstChildInner(aFrame);
+  return IsLightFrame(child) ? child : GetNextSiblingInner(child);
+}
+
+nsIFrame*
+nsLightFrameIterator::GetLastChildInner(nsIFrame* aFrame)
+{
+  nsIFrame* child = nsFrameIterator::GetLastChildInner(aFrame);
+  return IsLightFrame(child) ? child : GetPrevSiblingInner(child);
+}
+
+nsIFrame*
+nsLightFrameIterator::GetNextSiblingInner(nsIFrame* aFrame)
+{
+  nsIFrame* sibling;
+  for (sibling = nsFrameIterator::GetNextSiblingInner(aFrame);
+       !IsLightFrame(sibling);
+       sibling = nsFrameIterator::GetNextSiblingInner(sibling));
+  return sibling;
+}
+
+nsIFrame*
+nsLightFrameIterator::GetPrevSiblingInner(nsIFrame* aFrame)
+{
+  nsIFrame* sibling;
+  for (sibling = nsFrameIterator::GetPrevSiblingInner(aFrame);
+       !IsLightFrame(sibling);
+       sibling = nsFrameIterator::GetPrevSiblingInner(sibling));
+  return sibling;
+}
+
+bool
+nsLightFrameIterator::IsLightFrame(nsIFrame* aFrame)
+{
+  if (!aFrame) {
+    return true;
+  }
+
+  nsIContent* content = aFrame->GetContent();
+  if (!content) {
+    return true;
+  }
+
+  // Return false if content is in shadow DOM
+  if (content->IsInShadowTree()) {
+    return false;
+  }
+
+  // Return false if some ancestor is assigned to a slot
+  for (; content; content = content->GetParent()) {
+    if (content->GetAssignedSlot()) {
+      return false;
+    }
+  }
+
+  return true;
+}
\ No newline at end of file