Bug 1409083 Part 3: Add a GetFirstNonAnonBoxDescendant function to unpack anonymous flex items. draft
authorBrad Werth <bwerth@mozilla.com>
Wed, 22 Nov 2017 16:44:19 -0800
changeset 710142 49a7d68e3522d466e475c0c73a30abaa4c894d01
parent 710141 4a5d0b1920bc1fd06fd8bc7f8e431ceb921383e6
child 710143 8b60a2affbebd423a356dca7782ec0685e2ed540
push id92753
push userbwerth@mozilla.com
push dateFri, 08 Dec 2017 18:49:19 +0000
bugs1409083
milestone59.0a1
Bug 1409083 Part 3: Add a GetFirstNonAnonBoxDescendant function to unpack anonymous flex items. This patch is effectively just resurrecting a function that was previously removed in https://hg.mozilla.org/mozilla-central/rev/173a4f49dfe3#l1.96 . MozReview-Commit-ID: 4PXSOu4tzzU
layout/generic/nsFlexContainerFrame.cpp
--- a/layout/generic/nsFlexContainerFrame.cpp
+++ b/layout/generic/nsFlexContainerFrame.cpp
@@ -152,16 +152,59 @@ ConvertLegacyStyleToJustifyContent(const
       return NS_STYLE_ALIGN_SPACE_BETWEEN;
   }
 
   MOZ_ASSERT_UNREACHABLE("Unrecognized mBoxPack enum value");
   // Fall back to default value of "justify-content" property:
   return NS_STYLE_ALIGN_FLEX_START;
 }
 
+// Helper-function to find the first non-anonymous-box descendent of aFrame.
+static nsIFrame*
+GetFirstNonAnonBoxDescendant(nsIFrame* aFrame)
+{
+  while (aFrame) {
+    nsAtom* pseudoTag = aFrame->StyleContext()->GetPseudo();
+
+    // If aFrame isn't an anonymous container, then it'll do.
+    if (!pseudoTag ||                                 // No pseudotag.
+        !nsCSSAnonBoxes::IsAnonBox(pseudoTag) ||      // Pseudotag isn't anon.
+        nsCSSAnonBoxes::IsNonElement(pseudoTag)) {    // Text, not a container.
+      break;
+    }
+
+    // Otherwise, descend to its first child and repeat.
+
+    // SPECIAL CASE: if we're dealing with an anonymous table, then it might
+    // be wrapping something non-anonymous in its caption or col-group lists
+    // (instead of its principal child list), so we have to look there.
+    // (Note: For anonymous tables that have a non-anon cell *and* a non-anon
+    // column, we'll always return the column. This is fine; we're really just
+    // looking for a handle to *anything* with a meaningful content node inside
+    // the table, for use in DOM comparisons to things outside of the table.)
+    if (MOZ_UNLIKELY(aFrame->IsTableWrapperFrame())) {
+      nsIFrame* captionDescendant =
+        GetFirstNonAnonBoxDescendant(aFrame->GetChildList(kCaptionList).FirstChild());
+      if (captionDescendant) {
+        return captionDescendant;
+      }
+    } else if (MOZ_UNLIKELY(aFrame->IsTableFrame())) {
+      nsIFrame* colgroupDescendant =
+        GetFirstNonAnonBoxDescendant(aFrame->GetChildList(kColGroupList).FirstChild());
+      if (colgroupDescendant) {
+        return colgroupDescendant;
+      }
+    }
+
+    // USUAL CASE: Descend to the first child in principal list.
+    aFrame = aFrame->PrincipalChildList().FirstChild();
+  }
+  return aFrame;
+}
+
 // Indicates whether advancing along the given axis is equivalent to
 // increasing our X or Y position (as opposed to decreasing it).
 static inline bool
 AxisGrowsInPositiveDirection(AxisOrientationType aAxis)
 {
   return eAxis_LR == aAxis || eAxis_TB == aAxis;
 }
 
@@ -4306,20 +4349,42 @@ nsFlexContainerFrame::DoFlexLayout(nsPre
         ComputedFlexLineInfo::GrowthState::UNCHANGED;
 
       // The remaining lineInfo properties will be filled out at the
       // end of this function, when we have real values. But we still
       // add all the items here, so we can capture computed data for
       // each item.
       for (const FlexItem* item = line->GetFirstItem(); item;
            item = item->getNext()) {
+        nsIFrame* frame = item->Frame();
+
+        // The frame may be for an element, or it may be for an
+        // anonymous flex item, e.g. wrapping one or more text nodes.
+        // DevTools wants the content node for the actual child in
+        // the DOM tree, so we descend through anonymous boxes.
+        nsIFrame* targetFrame = GetFirstNonAnonBoxDescendant(frame);
+        nsIContent* content = targetFrame->GetContent();
+
+        // Skip over content that is only whitespace, which might
+        // have been broken off from a text node which is our real
+        // target.
+        while (content && content->TextIsOnlyWhitespace()) {
+          // If content is only whitespace, try the frame sibling.
+          targetFrame = targetFrame->GetNextSibling();
+          if (targetFrame) {
+            content = targetFrame->GetContent();
+          } else {
+            content = nullptr;
+          }
+        }
+
         ComputedFlexItemInfo* itemInfo =
           lineInfo->mItems.AppendElement();
 
-        itemInfo->mNode = item->Frame()->GetContent();
+        itemInfo->mNode = content;
 
         // mMainBaseSize and itemInfo->mMainDeltaSize will
         // be filled out in ResolveFlexibleLengths().
 
         // Other FlexItem properties can be captured now.
         itemInfo->mMainMinSize = item->GetMainMinSize();
         itemInfo->mMainMaxSize = item->GetMainMaxSize();
         itemInfo->mCrossMinSize = item->GetCrossMinSize();