Bug 1097499 part 3 - Add a separate anonbox for text nodes. r=heycam draft
authorXidorn Quan <quanxunzhen@gmail.com>
Tue, 19 Apr 2016 16:38:26 +1000
changeset 354598 4737b1bd505cf0c7963ab98de887f3a4a9b46f26
parent 354597 5df302beee6d59745314ee15f8b3f7af191e13d2
child 354599 00ea0c37c5fa40e55c7eeeb700b7d53cb9d65737
push id16138
push userxquan@mozilla.com
push dateThu, 21 Apr 2016 11:18:53 +0000
reviewersheycam
bugs1097499
milestone48.0a1
Bug 1097499 part 3 - Add a separate anonbox for text nodes. r=heycam MozReview-Commit-ID: 1GfoFEGhyka
layout/base/RestyleManager.cpp
layout/base/nsCSSFrameConstructor.cpp
layout/forms/nsComboboxControlFrame.cpp
layout/forms/nsGfxButtonControlFrame.cpp
layout/generic/nsFirstLetterFrame.cpp
layout/generic/nsFlexContainerFrame.cpp
layout/generic/nsFrame.cpp
layout/style/ServoStyleSet.cpp
layout/style/ServoStyleSet.h
layout/style/StyleSetHandle.h
layout/style/StyleSetHandleInlines.h
layout/style/nsCSSAnonBoxList.h
layout/style/nsCSSAnonBoxes.h
layout/style/nsCSSParser.cpp
layout/style/nsStyleContext.cpp
layout/style/nsStyleSet.cpp
layout/style/nsStyleSet.h
--- a/layout/base/RestyleManager.cpp
+++ b/layout/base/RestyleManager.cpp
@@ -3113,17 +3113,17 @@ ElementRestyler::MoveStyleContextsForCon
           type == nsGkAtoms::lineFrame) {
         return false;
       }
       if (sc->HasChildThatUsesGrandancestorStyle()) {
         // XXX Not sure if we need this?
         return false;
       }
       nsIAtom* pseudoTag = sc->GetPseudo();
-      if (pseudoTag && pseudoTag != nsCSSAnonBoxes::mozNonElement) {
+      if (pseudoTag && !nsCSSAnonBoxes::IsNonElement(pseudoTag)) {
         return false;
       }
       aContextsToMove.AppendElement(sc);
     }
   }
   return true;
 }
 
@@ -3546,31 +3546,34 @@ ElementRestyler::ComputeRestyleResultFro
   }
 
   // We also ignore frames for pseudos, as their style contexts have
   // inheritance structures that do not match the frame inheritance
   // structure.  To avoid enumerating and checking all of the cases
   // where we have this kind of inheritance, we keep restyling past
   // pseudos.
   nsIAtom* pseudoTag = oldContext->GetPseudo();
-  if (pseudoTag && pseudoTag != nsCSSAnonBoxes::mozNonElement) {
+  if (pseudoTag && !nsCSSAnonBoxes::IsNonElement(pseudoTag)) {
     LOG_RESTYLE_CONTINUE("the old style context is for a pseudo");
     aRestyleResult = eRestyleResult_Continue;
     aCanStopWithStyleChange = false;
     return;
   }
 
   nsIFrame* parent = mFrame->GetParent();
 
   if (parent) {
     // Also if the parent has a pseudo, as this frame's style context will
     // be inheriting from a grandparent frame's style context (or a further
     // ancestor).
     nsIAtom* parentPseudoTag = parent->StyleContext()->GetPseudo();
-    if (parentPseudoTag && parentPseudoTag != nsCSSAnonBoxes::mozNonElement) {
+    if (parentPseudoTag &&
+        parentPseudoTag != nsCSSAnonBoxes::mozOtherNonElement) {
+      MOZ_ASSERT(parentPseudoTag != nsCSSAnonBoxes::mozText,
+                 "Style of text node should not be parent of anything");
       LOG_RESTYLE_CONTINUE("the old style context's parent is for a pseudo");
       aRestyleResult = eRestyleResult_Continue;
       // Parent style context pseudo-ness doesn't affect whether we can
       // return eRestyleResult_StopWithStyleChange.
       //
       // If we had later conditions to check in this function, we would
       // continue to check them, in case we set aCanStopWithStyleChange to
       // false.
@@ -3917,21 +3920,20 @@ ElementRestyler::RestyleSelf(nsIFrame* a
     (prevContinuationContext = prevContinuation->StyleContext())
       ->GetPseudo() == oldContext->GetPseudo() &&
      prevContinuationContext->GetParent() == parentContext;
   if (copyFromContinuation) {
     // Just use the style context from the frame's previous
     // continuation.
     LOG_RESTYLE("using previous continuation's context");
     newContext = prevContinuationContext;
-  }
-  else if (pseudoTag == nsCSSAnonBoxes::mozNonElement) {
+  } else if (nsCSSAnonBoxes::IsNonElement(pseudoTag)) {
     NS_ASSERTION(aSelf->GetContent(),
                  "non pseudo-element frame without content node");
-    newContext = styleSet->ResolveStyleForNonElement(parentContext);
+    newContext = styleSet->ResolveStyleForNonElement(parentContext, pseudoTag);
   }
   else {
     Element* element = ElementForStyleContext(mParentContent, aSelf, pseudoType);
     if (!MustRestyleSelf(aRestyleHint, element)) {
       if (CanReparentStyleContext(aRestyleHint)) {
         LOG_RESTYLE("reparenting style context");
         newContext =
           styleSet->ReparentStyleContext(oldContext, parentContext, element);
@@ -4266,17 +4268,17 @@ ElementRestyler::RestyleSelf(nsIFrame* a
        ++contextIndex) {
     LOG_RESTYLE("extra context %d", contextIndex);
     LOG_RESTYLE_INDENT();
     RefPtr<nsStyleContext> newExtraContext;
     nsIAtom* const extraPseudoTag = oldExtraContext->GetPseudo();
     const CSSPseudoElementType extraPseudoType =
       oldExtraContext->GetPseudoType();
     NS_ASSERTION(extraPseudoTag &&
-                 extraPseudoTag != nsCSSAnonBoxes::mozNonElement,
+                 !nsCSSAnonBoxes::IsNonElement(extraPseudoTag),
                  "extra style context is not pseudo element");
     Element* element = extraPseudoType != CSSPseudoElementType::AnonBox
                          ? mContent->AsElement() : nullptr;
     if (!MustRestyleSelf(aRestyleHint, element)) {
       if (CanReparentStyleContext(aRestyleHint)) {
         newExtraContext =
           styleSet->ReparentStyleContext(oldExtraContext, newContext, element);
       } else {
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -2996,17 +2996,17 @@ nsCSSFrameConstructor::CreatePlaceholder
                                                  nsIContent*       aContent,
                                                  nsIFrame*         aFrame,
                                                  nsStyleContext*   aParentStyle,
                                                  nsContainerFrame* aParentFrame,
                                                  nsIFrame*         aPrevInFlow,
                                                  nsFrameState      aTypeBit)
 {
   RefPtr<nsStyleContext> placeholderStyle = aPresShell->StyleSet()->
-    ResolveStyleForNonElement(aParentStyle);
+    ResolveStyleForNonElement(aParentStyle, nsCSSAnonBoxes::mozOtherNonElement);
 
   // The placeholder frame gets a pseudo style context
   nsPlaceholderFrame* placeholderFrame =
     (nsPlaceholderFrame*)NS_NewPlaceholderFrame(aPresShell, placeholderStyle,
                                                 aTypeBit);
 
   placeholderFrame->Init(aContent, aParentFrame, aPrevInFlow);
 
@@ -4955,17 +4955,18 @@ nsCSSFrameConstructor::ResolveStyleConte
     } else {
       result = styleSet->ResolveStyleFor(aContent->AsElement(),
                                          aParentStyleContext);
     }
   } else {
     NS_ASSERTION(aContent->IsNodeOfType(nsINode::eTEXT),
                  "shouldn't waste time creating style contexts for "
                  "comments and processing instructions");
-    result = styleSet->ResolveStyleForNonElement(aParentStyleContext);
+    result = styleSet->ResolveStyleForNonElement(aParentStyleContext,
+                                                 nsCSSAnonBoxes::mozText);
   }
 
   // ServoRestyleManager does not handle transitions yet, and when it does
   // it probably won't need to track reframed style contexts to start
   // transitions correctly.
   if (mozilla::RestyleManager* geckoRM = RestyleManager()->GetAsGecko()) {
     RestyleManager::ReframingStyleContexts* rsc =
       geckoRM->GetReframingStyleContexts();
@@ -11098,19 +11099,19 @@ nsCSSFrameConstructor::CreateFloatingLet
   nsContainerFrame* containingBlock = aState.GetGeometricParent(
     aStyleContext->StyleDisplay(), aParentFrame);
   InitAndRestoreFrame(aState, letterContent, containingBlock, letterFrame);
 
   // Init the text frame to refer to the letter frame. Make sure we
   // get a proper style context for it (the one passed in is for the
   // letter frame and will have the float property set on it; the text
   // frame shouldn't have that set).
-  RefPtr<nsStyleContext> textSC;
   StyleSetHandle styleSet = mPresShell->StyleSet();
-  textSC = styleSet->ResolveStyleForNonElement(aStyleContext);
+  RefPtr<nsStyleContext> textSC = styleSet->
+    ResolveStyleForNonElement(aStyleContext, nsCSSAnonBoxes::mozText);
   aTextFrame->SetStyleContextWithoutNotification(textSC);
   InitAndRestoreFrame(aState, aTextContent, letterFrame, aTextFrame);
 
   // And then give the text frame to the letter frame
   SetInitialSingleChild(letterFrame, aTextFrame);
 
   // See if we will need to continue the text frame (does it contain
   // more than just the first-letter text or not?) If it does, then we
@@ -11118,18 +11119,18 @@ nsCSSFrameConstructor::CreateFloatingLet
   nsIFrame* nextTextFrame = nullptr;
   if (NeedFirstLetterContinuation(aTextContent)) {
     // Create continuation
     nextTextFrame =
       CreateContinuingFrame(aState.mPresContext, aTextFrame, aParentFrame);
     // Repair the continuations style context
     nsStyleContext* parentStyleContext = aStyleContext->GetParent();
     if (parentStyleContext) {
-      RefPtr<nsStyleContext> newSC;
-      newSC = styleSet->ResolveStyleForNonElement(parentStyleContext);
+      RefPtr<nsStyleContext> newSC = styleSet->
+        ResolveStyleForNonElement(parentStyleContext, nsCSSAnonBoxes::mozText);
       nextTextFrame->SetStyleContext(newSC);
     }
   }
 
   NS_ASSERTION(aResult.IsEmpty(), "aResult should be an empty nsFrameItems!");
   // Put the new float before any of the floats in the block we're doing
   // first-letter for, that is, before any floats whose parent is
   // containingBlock.
@@ -11172,18 +11173,18 @@ nsCSSFrameConstructor::CreateLetterFrame
   // Use content from containing block so that we can actually
   // find a matching style rule.
   nsIContent* blockContent = aBlockFrame->GetContent();
 
   // Create first-letter style rule
   RefPtr<nsStyleContext> sc = GetFirstLetterStyle(blockContent,
                                                     parentStyleContext);
   if (sc) {
-    RefPtr<nsStyleContext> textSC;
-    textSC = mPresShell->StyleSet()->ResolveStyleForNonElement(sc);
+    RefPtr<nsStyleContext> textSC = mPresShell->StyleSet()->
+      ResolveStyleForNonElement(sc, nsCSSAnonBoxes::mozText);
 
     // Create a new text frame (the original one will be discarded)
     // pass a temporary stylecontext, the correct one will be set
     // later.  Start off by unsetting the primary frame for
     // aTextContent, so it's no longer pointing to the to-be-destroyed
     // frame.
     // XXXbz it would be really nice to destroy the old frame _first_,
     // then create the new one, so we could avoid this hack.
@@ -11371,18 +11372,18 @@ nsCSSFrameConstructor::RemoveFloatingFir
   // Create a new text frame with the right style context that maps
   // all of the content that was previously part of the letter frame
   // (and probably continued elsewhere).
   nsStyleContext* parentSC = parentFrame->StyleContext();
   nsIContent* textContent = textFrame->GetContent();
   if (!textContent) {
     return NS_OK;
   }
-  RefPtr<nsStyleContext> newSC;
-  newSC = aPresShell->StyleSet()->ResolveStyleForNonElement(parentSC);
+  RefPtr<nsStyleContext> newSC = aPresShell->StyleSet()->
+    ResolveStyleForNonElement(parentSC, nsCSSAnonBoxes::mozText);
   nsIFrame* newTextFrame = NS_NewTextFrame(aPresShell, newSC);
   newTextFrame->Init(textContent, parentFrame, nullptr);
 
   // Destroy the old text frame's continuations (the old text frame
   // will be destroyed when its letter frame is destroyed).
   nsIFrame* frameToDelete = textFrame->LastContinuation();
   while (frameToDelete != textFrame) {
     nsIFrame* nextFrameToDelete = frameToDelete->GetPrevContinuation();
@@ -11444,18 +11445,18 @@ nsCSSFrameConstructor::RemoveFirstLetter
       nsStyleContext* parentSC = aFrame->StyleContext();
       if (!parentSC) {
         break;
       }
       nsIContent* textContent = textFrame->GetContent();
       if (!textContent) {
         break;
       }
-      RefPtr<nsStyleContext> newSC;
-      newSC = aPresShell->StyleSet()->ResolveStyleForNonElement(parentSC);
+      RefPtr<nsStyleContext> newSC = aPresShell->StyleSet()->
+        ResolveStyleForNonElement(parentSC, nsCSSAnonBoxes::mozText);
       textFrame = NS_NewTextFrame(aPresShell, newSC);
       textFrame->Init(textContent, aFrame, nullptr);
 
       // Next rip out the kid and replace it with the text frame
       RemoveFrame(kPrincipalList, kid);
 
       // Now that the old frames are gone, we can start pointing to our
       // new primary frame.
--- a/layout/forms/nsComboboxControlFrame.cpp
+++ b/layout/forms/nsComboboxControlFrame.cpp
@@ -1367,17 +1367,18 @@ nsComboboxControlFrame::CreateFrameFor(n
   // create the style contexts for the anonymous block frame and text frame
   RefPtr<nsStyleContext> styleContext;
   styleContext = styleSet->
     ResolveAnonymousBoxStyle(nsCSSAnonBoxes::mozDisplayComboboxControlFrame,
                              mStyleContext,
                              nsStyleSet::eSkipParentDisplayBasedStyleFixup);
 
   RefPtr<nsStyleContext> textStyleContext;
-  textStyleContext = styleSet->ResolveStyleForNonElement(mStyleContext);
+  textStyleContext = styleSet->
+    ResolveStyleForNonElement(mStyleContext, nsCSSAnonBoxes::mozText);
 
   // Start by creating our anonymous block frame
   mDisplayFrame = new (shell) nsComboboxDisplayFrame(styleContext, this);
   mDisplayFrame->Init(mContent, this, nullptr);
 
   // Create a text frame and put it inside the block frame
   nsIFrame* textFrame = NS_NewTextFrame(shell, textStyleContext);
 
--- a/layout/forms/nsGfxButtonControlFrame.cpp
+++ b/layout/forms/nsGfxButtonControlFrame.cpp
@@ -86,17 +86,17 @@ nsGfxButtonControlFrame::CreateFrameFor(
   nsIFrame * newFrame = nullptr;
 
   if (aContent == mTextContent) {
     nsContainerFrame* parentFrame = do_QueryFrame(mFrames.FirstChild());
 
     nsPresContext* presContext = PresContext();
     RefPtr<nsStyleContext> textStyleContext;
     textStyleContext = presContext->StyleSet()->
-      ResolveStyleForNonElement(mStyleContext);
+      ResolveStyleForNonElement(mStyleContext, nsCSSAnonBoxes::mozText);
 
     newFrame = NS_NewTextFrame(presContext->PresShell(), textStyleContext);
     // initialize the text frame
     newFrame->Init(mTextContent, parentFrame, nullptr);
     mTextContent->SetPrimaryFrame(newFrame);
   }
 
   return newFrame;
--- a/layout/generic/nsFirstLetterFrame.cpp
+++ b/layout/generic/nsFirstLetterFrame.cpp
@@ -65,17 +65,18 @@ nsFirstLetterFrame::Init(nsIContent*    
   RefPtr<nsStyleContext> newSC;
   if (aPrevInFlow) {
     // Get proper style context for ourselves.  We're creating the frame
     // that represents everything *except* the first letter, so just create
     // a style context like we would for a text node.
     nsStyleContext* parentStyleContext = mStyleContext->GetParent();
     if (parentStyleContext) {
       newSC = PresContext()->StyleSet()->
-        ResolveStyleForNonElement(parentStyleContext);
+        ResolveStyleForNonElement(parentStyleContext,
+                                  nsCSSAnonBoxes::mozOtherNonElement);
       SetStyleContextWithoutNotification(newSC);
     }
   }
 
   nsContainerFrame::Init(aContent, aParent, aPrevInFlow);
 }
 
 void
@@ -326,17 +327,18 @@ nsFirstLetterFrame::CreateContinuationFo
     CreateContinuingFrame(aPresContext, aChild, parent, aIsFluid);
 
   // The continuation will have gotten the first letter style from its
   // prev continuation, so we need to repair the style context so it
   // doesn't have the first letter styling.
   nsStyleContext* parentSC = this->StyleContext()->GetParent();
   if (parentSC) {
     RefPtr<nsStyleContext> newSC;
-    newSC = presShell->StyleSet()->ResolveStyleForNonElement(parentSC);
+    newSC = presShell->StyleSet()->
+      ResolveStyleForNonElement(parentSC, nsCSSAnonBoxes::mozOtherNonElement);
     continuation->SetStyleContext(newSC);
     nsLayoutUtils::MarkDescendantsDirty(continuation);
   }
 
   //XXX Bidi may not be involved but we have to use the list name
   // kNoReflowPrincipalList because this is just like creating a continuation
   // except we have to insert it in a different place and we don't want a
   // reflow command to try to be issued.
@@ -380,17 +382,18 @@ nsFirstLetterFrame::DrainOverflowFrames(
   if (kid) {
     RefPtr<nsStyleContext> sc;
     nsIContent* kidContent = kid->GetContent();
     if (kidContent) {
       NS_ASSERTION(kidContent->IsNodeOfType(nsINode::eTEXT),
                    "should contain only text nodes");
       nsStyleContext* parentSC = prevInFlow ? mStyleContext->GetParent() :
                                               mStyleContext;
-      sc = aPresContext->StyleSet()->ResolveStyleForNonElement(parentSC);
+      sc = aPresContext->StyleSet()->
+        ResolveStyleForNonElement(parentSC, nsCSSAnonBoxes::mozText);
       kid->SetStyleContext(sc);
       nsLayoutUtils::MarkDescendantsDirty(kid);
     }
   }
 }
 
 nscoord
 nsFirstLetterFrame::GetLogicalBaseline(WritingMode aWritingMode) const
--- a/layout/generic/nsFlexContainerFrame.cpp
+++ b/layout/generic/nsFlexContainerFrame.cpp
@@ -990,17 +990,17 @@ static nsIFrame*
 GetFirstNonAnonBoxDescendant(nsIFrame* aFrame)
 {
   while (aFrame) {
     nsIAtom* 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.
-        pseudoTag == nsCSSAnonBoxes::mozNonElement) { // Text, not a container.
+        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.
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -8286,17 +8286,17 @@ GetCorrectedParent(const nsIFrame* aFram
 nsIFrame*
 nsFrame::CorrectStyleParentFrame(nsIFrame* aProspectiveParent,
                                  nsIAtom* aChildPseudo)
 {
   NS_PRECONDITION(aProspectiveParent, "Must have a prospective parent");
 
   // Anon boxes are parented to their actual parent already, except
   // for non-elements.  Those should not be treated as an anon box.
-  if (aChildPseudo && aChildPseudo != nsCSSAnonBoxes::mozNonElement &&
+  if (aChildPseudo && !nsCSSAnonBoxes::IsNonElement(aChildPseudo) &&
       nsCSSAnonBoxes::IsAnonBox(aChildPseudo)) {
     NS_ASSERTION(aChildPseudo != nsCSSAnonBoxes::mozAnonymousBlock &&
                  aChildPseudo != nsCSSAnonBoxes::mozAnonymousPositionedBlock,
                  "Should have dealt with kids that have "
                  "NS_FRAME_PART_OF_IBSPLIT elsewhere");
     return aProspectiveParent;
   }
 
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -91,17 +91,18 @@ already_AddRefed<nsStyleContext>
 ServoStyleSet::ResolveStyleFor(Element* aElement,
                                nsStyleContext* aParentContext,
                                TreeMatchContext& aTreeMatchContext)
 {
   MOZ_CRASH("stylo: not implemented");
 }
 
 already_AddRefed<nsStyleContext>
-ServoStyleSet::ResolveStyleForNonElement(nsStyleContext* aParentContext)
+ServoStyleSet::ResolveStyleForNonElement(nsStyleContext* aParentContext,
+                                         nsIAtom* aPseudoTag)
 {
   MOZ_CRASH("stylo: not implemented");
 }
 
 already_AddRefed<nsStyleContext>
 ServoStyleSet::ResolvePseudoElementStyle(Element* aParentElement,
                                          CSSPseudoElementType aType,
                                          nsStyleContext* aParentContext,
--- a/layout/style/ServoStyleSet.h
+++ b/layout/style/ServoStyleSet.h
@@ -58,17 +58,18 @@ public:
                   nsStyleContext* aParentContext);
 
   already_AddRefed<nsStyleContext>
   ResolveStyleFor(dom::Element* aElement,
                   nsStyleContext* aParentContext,
                   TreeMatchContext& aTreeMatchContext);
 
   already_AddRefed<nsStyleContext>
-  ResolveStyleForNonElement(nsStyleContext* aParentContext);
+  ResolveStyleForNonElement(nsStyleContext* aParentContext,
+                            nsIAtom* aPseudoTag);
 
   already_AddRefed<nsStyleContext>
   ResolvePseudoElementStyle(dom::Element* aParentElement,
                             mozilla::CSSPseudoElementType aType,
                             nsStyleContext* aParentContext,
                             dom::Element* aPseudoElement);
 
   // aFlags is an nsStyleSet flags bitfield
--- a/layout/style/StyleSetHandle.h
+++ b/layout/style/StyleSetHandle.h
@@ -114,17 +114,18 @@ public:
     inline already_AddRefed<nsStyleContext>
     ResolveStyleFor(dom::Element* aElement,
                     nsStyleContext* aParentContext);
     inline already_AddRefed<nsStyleContext>
     ResolveStyleFor(dom::Element* aElement,
                     nsStyleContext* aParentContext,
                     TreeMatchContext& aTreeMatchContext);
     inline already_AddRefed<nsStyleContext>
-    ResolveStyleForNonElement(nsStyleContext* aParentContext);
+    ResolveStyleForNonElement(nsStyleContext* aParentContext,
+                              nsIAtom* aPseudoTag);
     inline already_AddRefed<nsStyleContext>
     ResolvePseudoElementStyle(dom::Element* aParentElement,
                               mozilla::CSSPseudoElementType aType,
                               nsStyleContext* aParentContext,
                               dom::Element* aPseudoElement);
     inline already_AddRefed<nsStyleContext>
     ResolveAnonymousBoxStyle(nsIAtom* aPseudoTag, nsStyleContext* aParentContext,
                              uint32_t aFlags = 0);
--- a/layout/style/StyleSetHandleInlines.h
+++ b/layout/style/StyleSetHandleInlines.h
@@ -89,19 +89,20 @@ already_AddRefed<nsStyleContext>
 StyleSetHandle::Ptr::ResolveStyleFor(dom::Element* aElement,
                                      nsStyleContext* aParentContext,
                                      TreeMatchContext& aTreeMatchContext)
 {
   FORWARD(ResolveStyleFor, (aElement, aParentContext, aTreeMatchContext));
 }
 
 already_AddRefed<nsStyleContext>
-StyleSetHandle::Ptr::ResolveStyleForNonElement(nsStyleContext* aParentContext)
+StyleSetHandle::Ptr::ResolveStyleForNonElement(nsStyleContext* aParentContext,
+                                               nsIAtom* aPseudoTag)
 {
-  FORWARD(ResolveStyleForNonElement, (aParentContext));
+  FORWARD(ResolveStyleForNonElement, (aParentContext, aPseudoTag));
 }
 
 already_AddRefed<nsStyleContext>
 StyleSetHandle::Ptr::ResolvePseudoElementStyle(dom::Element* aParentElement,
                                                CSSPseudoElementType aType,
                                                nsStyleContext* aParentContext,
                                                dom::Element* aPseudoElement)
 {
--- a/layout/style/nsCSSAnonBoxList.h
+++ b/layout/style/nsCSSAnonBoxList.h
@@ -14,17 +14,23 @@
  * done to it.  The entries should be kept in some sort of logical
  * order.  The first argument to CSS_ANON_BOX is the C++ identifier of
  * the atom.  The second argument is the string value of the atom.
  */
 
 // OUTPUT_CLASS=nsCSSAnonBoxes
 // MACRO_NAME=CSS_ANON_BOX
 
-CSS_ANON_BOX(mozNonElement, ":-moz-non-element")
+// ::-moz-text and ::-moz-other-non-element are non-elements which no
+// rule will match.
+CSS_ANON_BOX(mozText, ":-moz-text")
+// This anonymous box has two uses:
+// 1. placeholder frames,
+// 2. nsFirstLetterFrames for content outside the ::first-letter.
+CSS_ANON_BOX(mozOtherNonElement, ":-moz-other-non-element")
 
 CSS_ANON_BOX(mozAnonymousBlock, ":-moz-anonymous-block")
 CSS_ANON_BOX(mozAnonymousPositionedBlock, ":-moz-anonymous-positioned-block")
 CSS_ANON_BOX(mozMathMLAnonymousBlock, ":-moz-mathml-anonymous-block")
 CSS_ANON_BOX(mozXULAnonymousBlock, ":-moz-xul-anonymous-block")
 
 // Framesets
 CSS_ANON_BOX(horizontalFramesetBorder, ":-moz-hframeset-border")
--- a/layout/style/nsCSSAnonBoxes.h
+++ b/layout/style/nsCSSAnonBoxes.h
@@ -18,15 +18,17 @@ class nsCSSAnonBoxes {
 public:
 
   static void AddRefAtoms();
 
   static bool IsAnonBox(nsIAtom *aAtom);
 #ifdef MOZ_XUL
   static bool IsTreePseudoElement(nsIAtom* aPseudo);
 #endif
+  static bool IsNonElement(nsIAtom* aPseudo)
+    { return aPseudo == mozText || aPseudo == mozOtherNonElement; }
 
 #define CSS_ANON_BOX(_name, _value) static nsICSSAnonBoxPseudo* _name;
 #include "nsCSSAnonBoxList.h"
 #undef CSS_ANON_BOX
 };
 
 #endif /* nsCSSAnonBoxes_h___ */
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -30,16 +30,17 @@
 #include "nsStyleConsts.h"
 #include "nsNetUtil.h"
 #include "nsCOMPtr.h"
 #include "nsString.h"
 #include "nsIAtom.h"
 #include "nsColor.h"
 #include "nsCSSPseudoClasses.h"
 #include "nsCSSPseudoElements.h"
+#include "nsCSSAnonBoxes.h"
 #include "nsNameSpaceManager.h"
 #include "nsXMLNameSpaceMap.h"
 #include "nsError.h"
 #include "nsIMediaList.h"
 #include "nsStyleUtil.h"
 #include "nsIPrincipal.h"
 #include "nsICSSUnprefixingService.h"
 #include "mozilla/Snprintf.h"
@@ -5922,16 +5923,23 @@ CSSParserImpl::ParsePseudoSelector(int32
         (pseudoClassType != nsCSSPseudoClasses::ePseudoClass_NotPseudoClass &&
          nsCSSPseudoClasses::PseudoClassIsUASheetAndChromeOnly(pseudoClassType))))) {
     // This pseudo-element or pseudo-class is not exposed to content.
     REPORT_UNEXPECTED_TOKEN(PEPseudoSelUnknown);
     UngetToken();
     return eSelectorParsingStatus_Error;
   }
 
+  if (nsCSSAnonBoxes::IsNonElement(pseudo)) {
+    // Non-element anonymous boxes should not match any rule.
+    REPORT_UNEXPECTED_TOKEN(PEPseudoSelUnknown);
+    UngetToken();
+    return eSelectorParsingStatus_Error;
+  }
+
   // We currently allow :-moz-placeholder and ::-moz-placeholder. We have to
   // be a bit stricter regarding the pseudo-element parsing rules.
   if (pseudoElementType == CSSPseudoElementType::mozPlaceholder &&
       pseudoClassType == nsCSSPseudoClasses::ePseudoClass_mozPlaceholder) {
     if (parsingPseudoElement) {
       pseudoClassType = nsCSSPseudoClasses::ePseudoClass_NotPseudoClass;
     } else {
       pseudoElementType = CSSPseudoElementType::NotPseudo;
--- a/layout/style/nsStyleContext.cpp
+++ b/layout/style/nsStyleContext.cpp
@@ -570,17 +570,17 @@ ShouldSuppressLineBreak(const nsStyleCon
     return false;
   }
   // Display value of any anonymous box should not be touched. In most
   // cases, anonymous boxes are actually not in ruby frame, but instead,
   // some other frame with a ruby display value. Non-element pseudos
   // which represents text frames, as well as ruby pseudos are excluded
   // because we still want to set the flag for them.
   if (aContext->GetPseudoType() == CSSPseudoElementType::AnonBox &&
-      aContext->GetPseudo() != nsCSSAnonBoxes::mozNonElement &&
+      !nsCSSAnonBoxes::IsNonElement(aContext->GetPseudo()) &&
       !RubyUtils::IsRubyPseudo(aContext->GetPseudo())) {
     return false;
   }
   if (aParentContext->ShouldSuppressLineBreak()) {
     // Line break suppressing bit is propagated to any children of
     // line participants, which include inline, contents, and inline
     // ruby boxes.
     if (aParentDisplay->mDisplay == NS_STYLE_DISPLAY_INLINE ||
@@ -739,17 +739,17 @@ nsStyleContext::ApplyStyleFixups(bool aS
     while (containerDisp->mDisplay == NS_STYLE_DISPLAY_CONTENTS) {
       if (!containerContext->GetParent()) {
         break;
       }
       containerContext = containerContext->GetParent();
       containerDisp = containerContext->StyleDisplay();
     }
     if (ShouldBlockifyChildren(containerDisp) &&
-        GetPseudo() != nsCSSAnonBoxes::mozNonElement) {
+        !nsCSSAnonBoxes::IsNonElement(GetPseudo())) {
       // NOTE: Technically, we shouldn't modify the 'display' value of
       // positioned elements, since they aren't flex/grid items. However,
       // we don't need to worry about checking for that, because if we're
       // positioned, we'll have already been through a call to
       // EnsureBlockDisplay() in nsRuleNode, so this call here won't change
       // anything. So we're OK.
       uint8_t displayVal = disp->mDisplay;
       nsRuleNode::EnsureBlockDisplay(displayVal);
@@ -810,17 +810,17 @@ nsStyleContext::ApplyStyleFixups(bool aS
    * According to https://drafts.csswg.org/css-writing-modes-3/#block-flow:
    *
    * If a box has a different block flow direction than its containing block:
    *   * If the box has a specified display of inline, its display computes
    *     to inline-block. [CSS21]
    *   ...etc.
    */
   if (disp->mDisplay == NS_STYLE_DISPLAY_INLINE &&
-      mPseudoTag != nsCSSAnonBoxes::mozNonElement &&
+      !nsCSSAnonBoxes::IsNonElement(mPseudoTag) &&
       mParent) {
     auto cbContext = mParent;
     while (cbContext->StyleDisplay()->mDisplay == NS_STYLE_DISPLAY_CONTENTS) {
       cbContext = cbContext->mParent;
     }
     MOZ_ASSERT(cbContext, "the root context can't have display:contents");
     // We don't need the full mozilla::WritingMode value (incorporating dir
     // and text-orientation) here; just the writing-mode property is enough.
--- a/layout/style/nsStyleSet.cpp
+++ b/layout/style/nsStyleSet.cpp
@@ -1776,22 +1776,22 @@ nsStyleSet::ResolveStyleWithoutAnimation
                                 eSkipStartingAnimations);
 
   restyleManager->SetSkipAnimationRules(oldSkipAnimationRules);
 
   return result.forget();
 }
 
 already_AddRefed<nsStyleContext>
-nsStyleSet::ResolveStyleForNonElement(nsStyleContext* aParentContext)
+nsStyleSet::ResolveStyleForNonElement(nsStyleContext* aParentContext,
+                                      nsIAtom* aPseudoTag)
 {
-  return GetContext(aParentContext, mRuleTree, nullptr,
-                    nsCSSAnonBoxes::mozNonElement,
-                    CSSPseudoElementType::AnonBox, nullptr,
-                    eNoFlags);
+  MOZ_ASSERT(nsCSSAnonBoxes::IsNonElement(aPseudoTag));
+  return GetContext(aParentContext, mRuleTree, nullptr, aPseudoTag,
+                    CSSPseudoElementType::AnonBox, nullptr, eNoFlags);
 }
 
 void
 nsStyleSet::WalkRestrictionRule(CSSPseudoElementType aPseudoType,
                                 nsRuleWalker* aRuleWalker)
 {
   // This needs to match GetPseudoRestriction in nsRuleNode.cpp.
   aRuleWalker->SetLevel(SheetType::Agent, false, false);
--- a/layout/style/nsStyleSet.h
+++ b/layout/style/nsStyleSet.h
@@ -161,21 +161,26 @@ class nsStyleSet final
     ResolveStyleWithoutAnimation(mozilla::dom::Element* aElement,
                                  nsStyleContext* aStyleContext,
                                  nsRestyleHint aWhichToRemove);
 
   // Get a style context for a non-element (which no rules will match),
   // such as text nodes, placeholder frames, and the nsFirstLetterFrame
   // for everything after the first letter.
   //
-  // Perhaps this should go away and we shouldn't even create style
-  // contexts for such content nodes.  However, not doing any rule
-  // matching for them is a first step.
+  // aPseudoTag can be either mozText or mozOtherNonElement.
+  //
+  // Perhaps mozOtherNonElement should go away and we shouldn't even
+  // create style contexts for such content nodes.  However, not doing
+  // any rule matching for them is a first step.
+  // When text-combine-upright is not present, we may also want to avoid
+  // resolving style contexts for text frames as well.
   already_AddRefed<nsStyleContext>
-  ResolveStyleForNonElement(nsStyleContext* aParentContext);
+  ResolveStyleForNonElement(nsStyleContext* aParentContext,
+                            nsIAtom* aPseudoTag);
 
   // Get a style context for a pseudo-element.  aParentElement must be
   // non-null.  aPseudoID is the CSSPseudoElementType for the
   // pseudo-element.  aPseudoElement must be non-null if the pseudo-element
   // type is one that allows user action pseudo-classes after it or allows
   // style attributes; otherwise, it is ignored.
   already_AddRefed<nsStyleContext>
   ResolvePseudoElementStyle(mozilla::dom::Element* aParentElement,