Bug 1454340: Get rid of SetAsUndisplayedContent. r?mats draft
authorEmilio Cobos Álvarez <emilio@crisal.io>
Mon, 16 Apr 2018 00:08:29 +0200
changeset 782935 53a698b63ff3755c55e718bed402178ad0b15d32
parent 782933 b83286d5dc6fd286cb7bc9a002d78aecca65fd28
push id106571
push userbmo:emilio@crisal.io
push dateMon, 16 Apr 2018 12:00:51 +0000
reviewersmats
bugs1454340
milestone61.0a1
Bug 1454340: Get rid of SetAsUndisplayedContent. r?mats Move the assertion to the earliest point where it can happen instead, and do it automatically on exit if it's generated content instead of relying on manual calls. MozReview-Commit-ID: 5oPwXg2o22V
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsCSSFrameConstructor.h
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -5559,32 +5559,16 @@ nsCSSFrameConstructor::AddFrameConstruct
     return;
   }
   RefPtr<ComputedStyle> computedStyle = ResolveComputedStyle(aContent);
   DoAddFrameConstructionItems(aState, aContent, computedStyle,
                               aSuppressWhiteSpaceOptimizations, parentFrame,
                               nullptr, aItems);
 }
 
-void
-nsCSSFrameConstructor::SetAsUndisplayedContent(nsFrameConstructorState& aState,
-                                               FrameConstructionItemList& aList,
-                                               nsIContent* aContent,
-                                               ComputedStyle* aComputedStyle,
-                                               bool aIsGeneratedContent)
-{
-  if (aComputedStyle->GetPseudo()) {
-    if (aIsGeneratedContent) {
-      aContent->UnbindFromTree();
-    }
-    return;
-  }
-  MOZ_ASSERT(!aIsGeneratedContent, "Should have had pseudo type");
-}
-
 // Whether we should suppress frames for a child under a <select> frame.
 //
 // Never create frames for non-option/optgroup kids of <select> and non-option
 // kids of <optgroup> inside a <select>.
 // XXXbz it's not clear how this should best work with XBL.
 static bool
 ShouldSuppressFrameInSelect(const nsIContent* aParent,
                             const nsIContent* aChild)
@@ -5712,22 +5696,32 @@ nsCSSFrameConstructor::AddFrameConstruct
         if (overridenNamespace == kNameSpaceID_XUL) {
           tag = overridenTag;
         }
       }
     }
   }
 
   const bool isGeneratedContent = !!(aFlags & ITEM_IS_GENERATED_CONTENT);
+  MOZ_ASSERT(!isGeneratedContent || computedStyle->GetPseudo(),
+             "Generated content should be a pseudo-element");
+
+  FrameConstructionItem* item = nullptr;
+  auto cleanupGeneratedContent = mozilla::MakeScopeExit([&]() {
+    if (isGeneratedContent && !item) {
+      MOZ_ASSERT(!IsDisplayContents(aContent),
+                 "This would need to change if we support display: contents "
+                 "in generated content");
+      aContent->UnbindFromTree();
+    }
+  });
 
   // Pre-check for display "none" - if we find that, don't create
   // any frame at all
   if (display->mDisplay == StyleDisplay::None) {
-    SetAsUndisplayedContent(aState, aItems, aContent, computedStyle,
-                            isGeneratedContent);
     return;
   }
 
   if (display->mDisplay == StyleDisplay::Contents) {
     if (aParentFrame) {
       // FIXME(emilio): Pretty sure aParentFrame can't be null here.
       aParentFrame->AddStateBits(NS_FRAME_MAY_HAVE_GENERATED_CONTENT);
     }
@@ -5753,32 +5747,26 @@ nsCSSFrameConstructor::AddFrameConstruct
                                aItems);
     return;
   }
 
   bool isText = !aContent->IsElement();
 
   nsIContent* parent = aParentFrame ? aParentFrame->GetContent() : nullptr;
   if (ShouldSuppressFrameInSelect(parent, aContent)) {
-    if (!isText) {
-      SetAsUndisplayedContent(aState, aItems, aContent, computedStyle,
-                              isGeneratedContent);
-    }
     return;
   }
 
   // When constructing a child of a non-open <details>, create only the frame
   // for the main <summary> element, and skip other elements.  This only applies
   // to things that are not roots of native anonymous subtrees (except for
   // ::before and ::after); we always want to create "internal" anonymous
   // content.
   auto* details = HTMLDetailsElement::FromNodeOrNull(parent);
   if (ShouldSuppressFrameInNonOpenDetails(details, aContent)) {
-    SetAsUndisplayedContent(aState, aItems, aContent, computedStyle,
-                            isGeneratedContent);
     return;
   }
 
   bool isPopup = false;
   // Try to find frame construction data for this content
   const FrameConstructionData* data;
   if (isText) {
     data = FindTextData(aParentFrame);
@@ -5790,18 +5778,16 @@ nsCSSFrameConstructor::AddFrameConstruct
     Element* element = aContent->AsElement();
 
     // Don't create frames for non-SVG element children of SVG elements.
     if (namespaceId != kNameSpaceID_SVG &&
         ((aParentFrame &&
           IsFrameForSVG(aParentFrame) &&
           !aParentFrame->IsFrameOfType(nsIFrame::eSVGForeignObject)) ||
          (aFlags & ITEM_IS_WITHIN_SVG_TEXT))) {
-      SetAsUndisplayedContent(aState, aItems, element, computedStyle,
-                              isGeneratedContent);
       return;
     }
 
     data = FindHTMLData(element, tag, namespaceId, aParentFrame,
                         computedStyle);
     if (!data) {
       data = FindXULTagData(element, tag, namespaceId, computedStyle);
     }
@@ -5823,57 +5809,52 @@ nsCSSFrameConstructor::AddFrameConstruct
     // And general display types
     if (!data) {
       data = FindDisplayData(display, element, computedStyle);
     }
 
     MOZ_ASSERT(data, "Should have frame construction data now");
 
     if (data->mBits & FCDATA_SUPPRESS_FRAME) {
-      SetAsUndisplayedContent(aState, aItems, element, computedStyle, isGeneratedContent);
       return;
     }
 
 #ifdef MOZ_XUL
     if ((data->mBits & FCDATA_IS_POPUP) &&
         (!aParentFrame || // Parent is inline
          !aParentFrame->IsMenuFrame())) {
       if (!aState.mPopupItems.containingBlock &&
           !aState.mHavePendingPopupgroup) {
-        SetAsUndisplayedContent(aState, aItems, element, computedStyle,
-                                isGeneratedContent);
         return;
       }
 
       isPopup = true;
     }
 #endif /* MOZ_XUL */
   }
 
   uint32_t bits = data->mBits;
 
   // Inside colgroups, suppress everything except columns.
   if (aParentFrame && aParentFrame->IsTableColGroupFrame() &&
       (!(bits & FCDATA_IS_TABLE_PART) ||
        display->mDisplay != StyleDisplay::TableColumn)) {
-    SetAsUndisplayedContent(aState, aItems, aContent, computedStyle, isGeneratedContent);
     return;
   }
 
   bool canHavePageBreak =
     (aFlags & ITEM_ALLOW_PAGE_BREAK) && aState.mPresContext->IsPaginated() &&
     !display->IsAbsolutelyPositionedStyle() &&
     !(aParentFrame && aParentFrame->IsGridContainerFrame()) &&
     !(bits & FCDATA_IS_TABLE_PART) && !(bits & FCDATA_IS_SVG_TEXT);
 
   if (canHavePageBreak && display->mBreakBefore) {
     AddPageBreakItem(aContent, aItems);
   }
 
-  FrameConstructionItem* item = nullptr;
   if (details && details->Open()) {
     auto* summary = HTMLSummaryElement::FromNode(aContent);
     if (summary && summary->IsMainSummary()) {
       // If details is open, the main summary needs to be rendered as if it is
       // the first child, so add the item to the front of the item list.
       item = aItems.PrependItem(this, data, aContent, pendingBinding,
                                 computedStyle.forget(),
                                 aSuppressWhiteSpaceOptimizations,
--- a/layout/base/nsCSSFrameConstructor.h
+++ b/layout/base/nsCSSFrameConstructor.h
@@ -2113,27 +2113,16 @@ private:
   // may be constructed based on tag, not based on aDisplay!
   bool IsValidSibling(nsIFrame*              aSibling,
                       nsIContent*            aContent,
                       mozilla::StyleDisplay& aDisplay);
 
   void QuotesDirty();
   void CountersDirty();
 
-  /**
-   * Add the pair (aContent, aComputedStyle) to the undisplayed items
-   * in aList as needed.  This method enforces the invariant that all
-   * styles in the undisplayed content map must be non-pseudo contexts and also
-   * handles unbinding undisplayed generated content as needed.
-   */
-  void SetAsUndisplayedContent(nsFrameConstructorState& aState,
-                               FrameConstructionItemList& aList,
-                               nsIContent* aContent,
-                               ComputedStyle* aComputedStyle,
-                               bool aIsGeneratedContent);
   // Create touch caret frame.
   void ConstructAnonymousContentForCanvas(nsFrameConstructorState& aState,
                                           nsIFrame* aFrame,
                                           nsIContent* aDocElement);
 
 public:
 
   friend class nsFrameConstructorState;