Bug 1349462 - Part 1. Rename IsSVGText as IsInSVGTextSubtree. draft
authorcku <cku@mozilla.com>
Thu, 23 Mar 2017 15:29:11 +0800
changeset 503547 52a79ccf04a4ae40cfddfb90653f9c03449ecfab
parent 503306 7513b3f42058e9bcf9950d4acf4647d4ad2240f0
child 503548 1be77e92d69021f2a73a3dc0756880d572f7a7e3
push id50613
push userbmo:cku@mozilla.com
push dateThu, 23 Mar 2017 09:14:03 +0000
bugs1349462
milestone55.0a1
Bug 1349462 - Part 1. Rename IsSVGText as IsInSVGTextSubtree. MozReview-Commit-ID: LTo6c8tTtaf
layout/base/RestyleManager.cpp
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsLayoutUtils.cpp
layout/generic/ReflowInput.cpp
layout/generic/nsBlockFrame.cpp
layout/generic/nsFrame.cpp
layout/generic/nsIFrame.h
layout/generic/nsInlineFrame.cpp
layout/generic/nsLineLayout.cpp
layout/generic/nsTextFrame.cpp
layout/style/nsFontFaceUtils.cpp
layout/style/nsStyleStructInlines.h
layout/svg/nsSVGEffects.cpp
layout/svg/nsSVGUtils.cpp
layout/svg/nsSVGUtils.h
--- a/layout/base/RestyleManager.cpp
+++ b/layout/base/RestyleManager.cpp
@@ -965,17 +965,17 @@ FrameHasPositionedPlaceholderDescendants
 
   for (nsIFrame::ChildListIterator lists(aFrame); !lists.IsDone(); lists.Next()) {
     for (nsIFrame* f : lists.CurrentList()) {
       if (f->GetType() == nsGkAtoms::placeholderFrame) {
         nsIFrame* outOfFlow =
           nsPlaceholderFrame::GetRealFrameForPlaceholder(f);
         // If SVG text frames could appear here, they could confuse us since
         // they ignore their position style ... but they can't.
-        NS_ASSERTION(!outOfFlow->IsSVGText(),
+        NS_ASSERTION(!nsSVGUtils::IsInSVGTextSubtree(outOfFlow),
                      "SVG text frames can't be out of flow");
         if (aPositionMask & (1 << outOfFlow->StyleDisplay()->mPosition)) {
           return true;
         }
       }
       uint32_t positionMask = aPositionMask;
       // NOTE:  It's tempting to check f->IsAbsPosContainingBlock() or
       // f->IsFixedPosContainingBlock() here.  However, that would only
@@ -1088,17 +1088,17 @@ DoApplyRenderingChangeToTree(nsIFrame* a
       if ((aChange & nsChangeHint_UpdateEffects) &&
           aFrame->IsFrameOfType(nsIFrame::eSVG) &&
           !(aFrame->GetStateBits() & NS_STATE_IS_OUTER_SVG)) {
         // Need to update our overflow rects:
         nsSVGUtils::ScheduleReflowSVG(aFrame);
       }
     }
     if (aChange & nsChangeHint_UpdateTextPath) {
-      if (aFrame->IsSVGText()) {
+      if (nsSVGUtils::IsInSVGTextSubtree(aFrame)) {
         // Invalidate and reflow the entire SVGTextFrame:
         NS_ASSERTION(aFrame->GetContent()->IsSVGElement(nsGkAtoms::textPath),
                      "expected frame for a <textPath> element");
         nsIFrame* text =
           nsLayoutUtils::GetClosestFrameOfType(aFrame, nsGkAtoms::svgTextFrame);
         NS_ASSERTION(text, "expected to find an ancestor SVGTextFrame");
         static_cast<SVGTextFrame*>(text)->NotifyGlyphMetricsChange();
       } else {
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -421,17 +421,17 @@ IsInlineFrame(const nsIFrame* aFrame)
 /**
  * True if aFrame is an instance of an SVG frame class or is an inline/block
  * frame being used for SVG text.
  */
 static bool
 IsFrameForSVG(const nsIFrame* aFrame)
 {
   return aFrame->IsFrameOfType(nsIFrame::eSVG) ||
-         aFrame->IsSVGText();
+         nsSVGUtils::IsInSVGTextSubtree(aFrame);
 }
 
 /**
  * Returns true iff aFrame explicitly prevents its descendants from floating
  * (at least, down to the level of descendants which themselves are
  * float-containing blocks -- those will manage the floating status of any
  * lower-level descendents inside them, of course).
  */
@@ -1135,17 +1135,18 @@ nsFrameConstructorState::GetGeometricPar
   // elements. (1) has the usual problems when multiple frames share the same
   // content (notice all the special cases in this file dealing with inner
   // tables and table wrappers which share the same content). (2) requires some
   // work and possible factoring.
   //
   // XXXbz couldn't we just force position to "static" on roots and
   // float to "none"?  That's OK per CSS 2.1, as far as I can tell.
 
-  if (aContentParentFrame && aContentParentFrame->IsSVGText()) {
+  if (aContentParentFrame &&
+      nsSVGUtils::IsInSVGTextSubtree(aContentParentFrame)) {
     return aContentParentFrame;
   }
 
   if (aStyleDisplay->IsFloatingStyle() && mFloatedItems.containingBlock) {
     NS_ASSERTION(!aStyleDisplay->IsAbsolutelyPositionedStyle(),
                  "Absolutely positioned _and_ floating?");
     return mFloatedItems.containingBlock;
   }
@@ -3442,17 +3443,17 @@ nsCSSFrameConstructor::FindTextData(nsIF
 {
   if (aParentFrame && IsFrameForSVG(aParentFrame)) {
     nsIFrame *ancestorFrame =
       nsSVGUtils::GetFirstNonAAncestorFrame(aParentFrame);
     if (ancestorFrame) {
       static const FrameConstructionData sSVGTextData =
         FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT | FCDATA_IS_SVG_TEXT,
                     NS_NewTextFrame);
-      if (ancestorFrame->IsSVGText()) {
+      if (nsSVGUtils::IsInSVGTextSubtree(ancestorFrame)) {
         return &sSVGTextData;
       }
     }
     return nullptr;
   }
 
   static const FrameConstructionData sTextData =
     FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT, NS_NewTextFrame);
@@ -4043,17 +4044,17 @@ nsCSSFrameConstructor::ConstructFrameFro
         // This check is identical to nsStyleDisplay::IsAbsPosContainingBlock
         // except without the assertion that the style display and frame match.
         // When constructing scroll frames we intentionally use the style
         // display for the outer, but make the inner the containing block.
         if ((maybeAbsoluteContainingBlockDisplay->IsAbsolutelyPositionedStyle() ||
              maybeAbsoluteContainingBlockDisplay->IsRelativelyPositionedStyle() ||
              maybeAbsoluteContainingBlockDisplay->IsFixedPosContainingBlock(
                  maybeAbsoluteContainingBlockStyleFrame)) &&
-            !maybeAbsoluteContainingBlockStyleFrame->IsSVGText()) {
+            !nsSVGUtils::IsInSVGTextSubtree(maybeAbsoluteContainingBlockStyleFrame)) {
           nsContainerFrame* cf = static_cast<nsContainerFrame*>(
               maybeAbsoluteContainingBlock);
           aState.PushAbsoluteContainingBlock(cf, cf, absoluteSaveState);
         }
       }
 
       if (!aItem.mAnonChildren.IsEmpty()) {
         NS_ASSERTION(!(bits & FCDATA_USE_CHILD_ITEMS),
@@ -4966,17 +4967,17 @@ nsCSSFrameConstructor::ConstructNonScrol
   // we can check it later in nsFrame::ApplyPaginatedOverflowClipping.
   bool clipPaginatedOverflow =
     (aItem.mFCData->mBits & FCDATA_FORCED_NON_SCROLLABLE_BLOCK) != 0;
   nsFrameState flags = nsFrameState(0);
   if ((aDisplay->IsAbsolutelyPositionedStyle() ||
        aDisplay->IsFloatingStyle() ||
        StyleDisplay::InlineBlock == aDisplay->mDisplay ||
        clipPaginatedOverflow) &&
-      !aParentFrame->IsSVGText()) {
+      !nsSVGUtils::IsInSVGTextSubtree(aParentFrame)) {
     flags = NS_BLOCK_FORMATTING_CONTEXT_STATE_BITS;
     if (clipPaginatedOverflow) {
       flags |= NS_BLOCK_CLIP_PAGINATED_OVERFLOW;
     }
   }
 
   nsContainerFrame* newFrame = aConstructor(mPresShell, styleContext);
   newFrame->AddStateBits(flags);
@@ -5674,17 +5675,17 @@ nsCSSFrameConstructor::DoAddFrameConstru
                                                    nsStyleContext* aStyleContext,
                                                    bool aSuppressWhiteSpaceOptimizations,
                                                    nsContainerFrame* aParentFrame,
                                                    nsTArray<nsIAnonymousContentCreator::ContentInfo>* aAnonChildren,
                                                    FrameConstructionItemList& aItems)
 {
   uint32_t flags = ITEM_ALLOW_XBL_BASE | ITEM_ALLOW_PAGE_BREAK;
   if (aParentFrame) {
-    if (aParentFrame->IsSVGText()) {
+    if (nsSVGUtils::IsInSVGTextSubtree(aParentFrame)) {
       flags |= ITEM_IS_WITHIN_SVG_TEXT;
     }
     if (aParentFrame->GetType() == nsGkAtoms::blockFrame &&
         aParentFrame->GetParent() &&
         aParentFrame->GetParent()->GetType() == nsGkAtoms::svgTextFrame) {
       flags |= ITEM_ALLOWS_TEXT_PATH_CHILD;
     }
   }
@@ -11566,17 +11567,18 @@ nsCSSFrameConstructor::CreateLetterFrame
     nsFrameConstructorState state(mPresShell,
                                   matchContext,
                                   GetAbsoluteContainingBlock(aParentFrame, FIXED_POS),
                                   GetAbsoluteContainingBlock(aParentFrame, ABS_POS),
                                   aBlockContinuation);
 
     // Create the right type of first-letter frame
     const nsStyleDisplay* display = sc->StyleDisplay();
-    if (display->IsFloatingStyle() && !aParentFrame->IsSVGText()) {
+    if (display->IsFloatingStyle() &&
+        !nsSVGUtils::IsInSVGTextSubtree(aParentFrame)) {
       // Make a floating first-letter frame
       CreateFloatingLetterFrame(state, aTextContent, textFrame,
                                 aParentFrame, sc, aResult);
     }
     else {
       // Make an inflow first-letter frame
       nsFirstLetterFrame* letterFrame = NS_NewFirstLetterFrame(mPresShell, sc);
 
@@ -12140,17 +12142,17 @@ nsCSSFrameConstructor::ConstructInline(n
   //   Text("f")
 
   nsIContent* const content = aItem.mContent;
   nsStyleContext* const styleContext = aItem.mStyleContext;
 
   bool positioned =
     StyleDisplay::Inline == aDisplay->mDisplay &&
     aDisplay->IsRelativelyPositionedStyle() &&
-    !aParentFrame->IsSVGText();
+    !nsSVGUtils::IsInSVGTextSubtree(aParentFrame);
 
   nsInlineFrame* newFrame = NS_NewInlineFrame(mPresShell, styleContext);
 
   // Initialize the frame
   InitAndRestoreFrame(aState, content, aParentFrame, newFrame);
 
   // Inline frames can always have generated content
   newFrame->AddStateBits(NS_FRAME_MAY_HAVE_GENERATED_CONTENT);
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -2410,17 +2410,17 @@ nsLayoutUtils::GetEventCoordinatesRelati
   nsIPresShell* shell = aFrame->PresContext()->PresShell();
 
   // XXX Bug 1224748 - Update nsLayoutUtils functions to correctly handle nsPresShell resolution
   widgetToView = widgetToView.RemoveResolution(GetCurrentAPZResolutionScale(shell));
 
   /* If we encountered a transform, we can't do simple arithmetic to figure
    * out how to convert back to aFrame's coordinates and must use the CTM.
    */
-  if (transformFound || aFrame->IsSVGText()) {
+  if (transformFound || nsSVGUtils::IsInSVGTextSubtree(aFrame)) {
     return TransformRootPointToFrame(aFrame, widgetToView);
   }
 
   /* Otherwise, all coordinate systems are translations of one another,
    * so we can just subtract out the difference.
    */
   return widgetToView - aFrame->GetOffsetToCrossDoc(rootFrame);
 }
@@ -3049,17 +3049,17 @@ TransformGfxRectToAncestor(nsIFrame *aFr
                         std::numeric_limits<float>::max(),
                         std::numeric_limits<float>::max());
   return ctm.TransformAndClipBounds(aRect, maxBounds);
 }
 
 static SVGTextFrame*
 GetContainingSVGTextFrame(nsIFrame* aFrame)
 {
-  if (!aFrame->IsSVGText()) {
+  if (!nsSVGUtils::IsInSVGTextSubtree(aFrame)) {
     return nullptr;
   }
 
   return static_cast<SVGTextFrame*>
     (nsLayoutUtils::GetClosestFrameOfType(aFrame->GetParent(),
                                           nsGkAtoms::svgTextFrame));
 }
 
@@ -8102,17 +8102,17 @@ nsLayoutUtils::InflationMinFontSizeFor(c
   MOZ_ASSERT(false, "root should always be container");
 
   return 0;
 }
 
 float
 nsLayoutUtils::FontSizeInflationFor(const nsIFrame *aFrame)
 {
-  if (aFrame->IsSVGText()) {
+  if (nsSVGUtils::IsInSVGTextSubtree(aFrame)) {
     const nsIFrame* container = aFrame;
     while (container->GetType() != nsGkAtoms::svgTextFrame) {
       container = container->GetParent();
     }
     NS_ASSERTION(container, "expected to find an ancestor SVGTextFrame");
     return
       static_cast<const SVGTextFrame*>(container)->GetFontSizeScaleFactor();
   }
--- a/layout/generic/ReflowInput.cpp
+++ b/layout/generic/ReflowInput.cpp
@@ -2530,17 +2530,17 @@ SizeComputationInput::InitOffsets(Writin
                                                 mFrame, disp->mAppearance,
                                                 &widget)) {
     ComputedPhysicalPadding().top = presContext->DevPixelsToAppUnits(widget.top);
     ComputedPhysicalPadding().right = presContext->DevPixelsToAppUnits(widget.right);
     ComputedPhysicalPadding().bottom = presContext->DevPixelsToAppUnits(widget.bottom);
     ComputedPhysicalPadding().left = presContext->DevPixelsToAppUnits(widget.left);
     needPaddingProp = false;
   }
-  else if (mFrame->IsSVGText()) {
+  else if (nsSVGUtils::IsInSVGTextSubtree(mFrame)) {
     ComputedPhysicalPadding().SizeTo(0, 0, 0, 0);
     needPaddingProp = false;
   }
   else if (aPadding) { // padding is an input arg
     ComputedPhysicalPadding() = *aPadding;
     needPaddingProp = mFrame->StylePadding()->IsWidthDependent() ||
 	  (mFrame->GetStateBits() & NS_FRAME_REFLOW_ROOT);
   }
@@ -2584,17 +2584,17 @@ SizeComputationInput::InitOffsets(Writin
       presContext->DevPixelsToAppUnits(widget.top);
     ComputedPhysicalBorderPadding().right =
       presContext->DevPixelsToAppUnits(widget.right);
     ComputedPhysicalBorderPadding().bottom =
       presContext->DevPixelsToAppUnits(widget.bottom);
     ComputedPhysicalBorderPadding().left =
       presContext->DevPixelsToAppUnits(widget.left);
   }
-  else if (mFrame->IsSVGText()) {
+  else if (nsSVGUtils::IsInSVGTextSubtree(mFrame)) {
     ComputedPhysicalBorderPadding().SizeTo(0, 0, 0, 0);
   }
   else if (aBorder) {  // border is an input arg
     ComputedPhysicalBorderPadding() = *aBorder;
   }
   else {
     ComputedPhysicalBorderPadding() = mFrame->StyleBorder()->GetComputedBorder();
   }
@@ -2863,17 +2863,17 @@ ReflowInput::CalcLineHeight(nsIContent* 
   return lineHeight;
 }
 
 bool
 SizeComputationInput::ComputeMargin(WritingMode aWM,
                                 const LogicalSize& aPercentBasis)
 {
   // SVG text frames have no margin.
-  if (mFrame->IsSVGText()) {
+  if (nsSVGUtils::IsInSVGTextSubtree(mFrame)) {
     return false;
   }
 
   // If style style can provide us the margin directly, then use it.
   const nsStyleMargin *styleMargin = mFrame->StyleMargin();
 
   bool isCBDependent = !styleMargin->GetMargin(ComputedPhysicalMargin());
   if (isCBDependent) {
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -463,29 +463,29 @@ nsIAtom*
 nsBlockFrame::GetType() const
 {
   return nsGkAtoms::blockFrame;
 }
 
 void
 nsBlockFrame::InvalidateFrame(uint32_t aDisplayItemKey)
 {
-  if (IsSVGText()) {
+  if (nsSVGUtils::IsInSVGTextSubtree(this)) {
     NS_ASSERTION(GetParent()->GetType() == nsGkAtoms::svgTextFrame,
                  "unexpected block frame in SVG text");
     GetParent()->InvalidateFrame();
     return;
   }
   nsContainerFrame::InvalidateFrame(aDisplayItemKey);
 }
 
 void
 nsBlockFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey)
 {
-  if (IsSVGText()) {
+  if (nsSVGUtils::IsInSVGTextSubtree(this)) {
     NS_ASSERTION(GetParent()->GetType() == nsGkAtoms::svgTextFrame,
                  "unexpected block frame in SVG text");
     GetParent()->InvalidateFrame();
     return;
   }
   nsContainerFrame::InvalidateFrameWithRect(aRect, aDisplayItemKey);
 }
 
@@ -1912,17 +1912,17 @@ nsBlockFrame::MarkLineDirty(LineIterator
  * resizing optimizations
  */
 static inline bool
 IsAlignedLeft(uint8_t aAlignment,
               uint8_t aDirection,
               uint8_t aUnicodeBidi,
               nsIFrame* aFrame)
 {
-  return aFrame->IsSVGText() ||
+  return nsSVGUtils::IsInSVGTextSubtree(aFrame) ||
          NS_STYLE_TEXT_ALIGN_LEFT == aAlignment ||
          (((NS_STYLE_TEXT_ALIGN_START == aAlignment &&
            NS_STYLE_DIRECTION_LTR == aDirection) ||
           (NS_STYLE_TEXT_ALIGN_END == aAlignment &&
            NS_STYLE_DIRECTION_RTL == aDirection)) &&
          !(NS_STYLE_UNICODE_BIDI_PLAINTEXT & aUnicodeBidi));
 }
 
@@ -4594,17 +4594,17 @@ nsBlockFrame::PlaceLine(BlockReflowInput
   /**
    * text-align-last defaults to the same value as text-align when
    * text-align-last is set to auto (except when text-align is set to justify),
    * so in that case we don't need to set isLastLine.
    *
    * In other words, isLastLine really means isLastLineAndWeCare.
    */
   bool isLastLine =
-    !IsSVGText() &&
+    !nsSVGUtils::IsInSVGTextSubtree(this) &&
     ((NS_STYLE_TEXT_ALIGN_AUTO != styleText->mTextAlignLast ||
       NS_STYLE_TEXT_ALIGN_JUSTIFY == styleText->mTextAlign) &&
      (aLineLayout.GetLineEndsInBR() ||
       IsLastLine(aState, aLine)));
 
   aLineLayout.TextAlignLine(aLine, isLastLine);
 
   // From here on, pfd->mBounds rectangles are incorrect because bidi
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -868,17 +868,17 @@ AddAndRemoveImageAssociations(nsFrame* a
     }
   }
 }
 
 // Subclass hook for style post processing
 /* virtual */ void
 nsFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
 {
-  if (IsSVGText()) {
+  if (nsSVGUtils::IsInSVGTextSubtree(this)) {
     SVGTextFrame* svgTextFrame = static_cast<SVGTextFrame*>(
         nsLayoutUtils::GetClosestFrameOfType(this, nsGkAtoms::svgTextFrame));
     nsIFrame* anonBlock = svgTextFrame->PrincipalChildList().FirstChild();
     // Just as in SVGTextFrame::DidSetStyleContext, we need to ensure that
     // any non-display SVGTextFrames get reflowed when a child text frame
     // gets new style.
     //
     // Note that we must check NS_FRAME_FIRST_REFLOW on our SVGTextFrame's
@@ -1117,17 +1117,17 @@ const nsIFrame::ChildListID nsIFrame::kN
 #endif
 
 /* virtual */ nsMargin
 nsIFrame::GetUsedMargin() const
 {
   nsMargin margin(0, 0, 0, 0);
   if (((mState & NS_FRAME_FIRST_REFLOW) &&
        !(mState & NS_FRAME_IN_REFLOW)) ||
-      IsSVGText())
+      nsSVGUtils::IsInSVGTextSubtree(this))
     return margin;
 
   nsMargin *m = Properties().Get(UsedMarginProperty());
   if (m) {
     margin = *m;
   } else {
     if (!StyleMargin()->GetMargin(margin)) {
       // If we get here, our caller probably shouldn't be calling us...
@@ -1139,17 +1139,17 @@ nsIFrame::GetUsedMargin() const
 }
 
 /* virtual */ nsMargin
 nsIFrame::GetUsedBorder() const
 {
   nsMargin border(0, 0, 0, 0);
   if (((mState & NS_FRAME_FIRST_REFLOW) &&
        !(mState & NS_FRAME_IN_REFLOW)) ||
-      IsSVGText())
+      nsSVGUtils::IsInSVGTextSubtree(this))
     return border;
 
   // Theme methods don't use const-ness.
   nsIFrame *mutable_this = const_cast<nsIFrame*>(this);
 
   const nsStyleDisplay *disp = StyleDisplay();
   if (mutable_this->IsThemed(disp)) {
     nsIntMargin result;
@@ -1174,17 +1174,17 @@ nsIFrame::GetUsedBorder() const
 }
 
 /* virtual */ nsMargin
 nsIFrame::GetUsedPadding() const
 {
   nsMargin padding(0, 0, 0, 0);
   if (((mState & NS_FRAME_FIRST_REFLOW) &&
        !(mState & NS_FRAME_IN_REFLOW)) ||
-      IsSVGText())
+      nsSVGUtils::IsInSVGTextSubtree(this))
     return padding;
 
   // Theme methods don't use const-ness.
   nsIFrame *mutable_this = const_cast<nsIFrame*>(this);
 
   const nsStyleDisplay *disp = StyleDisplay();
   if (mutable_this->IsThemed(disp)) {
     nsPresContext *presContext = PresContext();
@@ -4382,17 +4382,17 @@ static FrameTarget GetSelectionClosestFr
     nsIFrame::FrameWithDistance closest = { nullptr, nscoord_MAX, nscoord_MAX };
     for (; kid; kid = kid->GetNextSibling()) {
       if (!SelfIsSelectable(kid, aFlags) || kid->IsEmpty())
         continue;
 
       kid->FindCloserFrameForSelection(aPoint, &closest);
     }
     if (closest.mFrame) {
-      if (closest.mFrame->IsSVGText())
+      if (nsSVGUtils::IsInSVGTextSubtree(closest.mFrame))
         return FrameTarget(closest.mFrame, false, false);
       return GetSelectionClosestFrameForChild(closest.mFrame, aPoint, aFlags);
     }
   }
   return FrameTarget(aFrame, false, false);
 }
 
 nsIFrame::ContentOffsets OffsetsForSingleFrame(nsIFrame* aFrame, nsPoint aPoint)
@@ -4513,17 +4513,17 @@ nsIFrame::ContentOffsets nsIFrame::GetCo
     offsets.secondaryOffset = offsets.offset;
     offsets.associate = offsets.offset == range.start ?
         CARET_ASSOCIATE_AFTER : CARET_ASSOCIATE_BEFORE;
     return offsets;
   }
 
   nsPoint pt;
   if (closest.frame != this) {
-    if (closest.frame->IsSVGText()) {
+    if (nsSVGUtils::IsInSVGTextSubtree(closest.frame)) {
       pt = nsLayoutUtils::TransformAncestorPointToFrame(closest.frame,
                                                         aPoint, this);
     } else {
       pt = aPoint - closest.frame->GetOffsetTo(this);
     }
   } else {
     pt = aPoint;
   }
@@ -9533,17 +9533,17 @@ ConvertSVGDominantBaselineToVerticalAlig
     NS_NOTREACHED("unexpected aDominantBaseline value");
     return NS_STYLE_VERTICAL_ALIGN_BASELINE;
   }
 }
 
 uint8_t
 nsIFrame::VerticalAlignEnum() const
 {
-  if (IsSVGText()) {
+  if (nsSVGUtils::IsInSVGTextSubtree(this)) {
     uint8_t dominantBaseline;
     for (const nsIFrame* frame = this; frame; frame = frame->GetParent()) {
       dominantBaseline = frame->StyleSVGReset()->mDominantBaseline;
       if (dominantBaseline != NS_STYLE_DOMINANT_BASELINE_AUTO ||
           frame->GetType() == nsGkAtoms::svgTextFrame) {
         break;
       }
     }
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -3525,18 +3525,16 @@ public:
    * of the enumerated values.  If this is an SVG text frame, it returns a value
    * that corresponds to the value of dominant-baseline.  If the
    * vertical-align property has length or percentage value, this returns
    * eInvalidVerticalAlign.
    */
   uint8_t VerticalAlignEnum() const;
   enum { eInvalidVerticalAlign = 0xFF };
 
-  bool IsSVGText() const { return mState & NS_FRAME_IS_SVG_TEXT; }
-
   void CreateOwnLayerIfNeeded(nsDisplayListBuilder* aBuilder, nsDisplayList* aList);
 
   /**
    * Adds the NS_FRAME_IN_POPUP state bit to aFrame, and
    * all descendant frames (including cross-doc ones).
    */
   static void AddInPopupStateBitToDescendants(nsIFrame* aFrame);
   /**
--- a/layout/generic/nsInlineFrame.cpp
+++ b/layout/generic/nsInlineFrame.cpp
@@ -60,30 +60,30 @@ nsIAtom*
 nsInlineFrame::GetType() const
 {
   return nsGkAtoms::inlineFrame;
 }
 
 void
 nsInlineFrame::InvalidateFrame(uint32_t aDisplayItemKey)
 {
-  if (IsSVGText()) {
+  if (nsSVGUtils::IsInSVGTextSubtree(this)) {
     nsIFrame* svgTextFrame =
       nsLayoutUtils::GetClosestFrameOfType(GetParent(),
                                            nsGkAtoms::svgTextFrame);
     svgTextFrame->InvalidateFrame();
     return;
   }
   nsContainerFrame::InvalidateFrame(aDisplayItemKey);
 }
 
 void
 nsInlineFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey)
 {
-  if (IsSVGText()) {
+  if (nsSVGUtils::IsInSVGTextSubtree(this)) {
     nsIFrame* svgTextFrame =
       nsLayoutUtils::GetClosestFrameOfType(GetParent(),
                                            nsGkAtoms::svgTextFrame);
     svgTextFrame->InvalidateFrame();
     return;
   }
   nsContainerFrame::InvalidateFrameWithRect(aRect, aDisplayItemKey);
 }
@@ -482,17 +482,17 @@ nsInlineFrame::AttributeChanged(int32_t 
 {
   nsresult rv =
     nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
 
   if (NS_FAILED(rv)) {
     return rv;
   }
 
-  if (IsSVGText()) {
+  if (nsSVGUtils::IsInSVGTextSubtree(this)) {
     SVGTextFrame* f = static_cast<SVGTextFrame*>(
       nsLayoutUtils::GetClosestFrameOfType(this, nsGkAtoms::svgTextFrame));
     f->HandleAttributeChangeInDescendant(mContent->AsElement(),
                                          aNameSpaceID, aAttribute);
   }
 
   return NS_OK;
 }
--- a/layout/generic/nsLineLayout.cpp
+++ b/layout/generic/nsLineLayout.cpp
@@ -74,17 +74,17 @@ nsLineLayout::nsLineLayout(nsPresContext
     mNeedBackup(false),
     mInFirstLine(false),
     mGotLineBox(false),
     mInFirstLetter(false),
     mHasBullet(false),
     mDirtyNextLine(false),
     mLineAtStart(false),
     mHasRuby(false),
-    mSuppressLineWrap(aOuterReflowInput->mFrame->IsSVGText())
+    mSuppressLineWrap(nsSVGUtils::IsInSVGTextSubtree(aOuterReflowInput->mFrame))
 {
   MOZ_ASSERT(aOuterReflowInput, "aOuterReflowInput must not be null");
   NS_ASSERTION(aFloatManager || aOuterReflowInput->mFrame->GetType() ==
                                   nsGkAtoms::letterFrame,
                "float manager should be present");
   MOZ_ASSERT((!!mBaseLineLayout) ==
              (aOuterReflowInput->mFrame->GetType() ==
               nsGkAtoms::rubyTextContainerFrame),
@@ -1735,17 +1735,17 @@ nsLineLayout::AdjustLeadings(nsIFrame* s
     }
   }
 }
 
 static float
 GetInflationForBlockDirAlignment(nsIFrame* aFrame,
                                  nscoord aInflationMinFontSize)
 {
-  if (aFrame->IsSVGText()) {
+  if (nsSVGUtils::IsInSVGTextSubtree(aFrame)) {
     const nsIFrame* container =
       nsLayoutUtils::GetClosestFrameOfType(aFrame, nsGkAtoms::svgTextFrame);
     NS_ASSERTION(container, "expected to find an ancestor SVGTextFrame");
     return
       static_cast<const SVGTextFrame*>(container)->GetFontSizeScaleFactor();
   }
   return nsLayoutUtils::FontSizeInflationInner(aFrame, aInflationMinFontSize);
 }
@@ -3135,17 +3135,17 @@ nsLineLayout::TextAlignLine(nsLineBox* a
       if (textAlign == NS_STYLE_TEXT_ALIGN_JUSTIFY) {
         textAlign = NS_STYLE_TEXT_ALIGN_START;
       }
     } else {
       textAlign = mStyleText->mTextAlignLast;
     }
   }
 
-  bool isSVG = mBlockReflowInput->mFrame->IsSVGText();
+  bool isSVG = nsSVGUtils::IsInSVGTextSubtree(mBlockReflowInput->mFrame);
   bool doTextAlign = remainingISize > 0 || textAlignTrue;
 
   int32_t additionalGaps = 0;
   if (!isSVG && (mHasRuby || (doTextAlign &&
                               textAlign == NS_STYLE_TEXT_ALIGN_JUSTIFY))) {
     JustificationComputationState computeState;
     ComputeFrameJustification(psd, computeState);
     if (mHasRuby && computeState.mFirstParticipant) {
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -330,24 +330,24 @@ public:
     mResolveColors = aResolveColors;
   }
 
   nscolor GetTextColor();
 
   // SVG text has its own painting process, so we should never get its stroke
   // property from here.
   nscolor GetWebkitTextStrokeColor() {
-    if (mFrame->IsSVGText()) {
+    if (nsSVGUtils::IsInSVGTextSubtree(mFrame)) {
       return 0;
     }
     return mFrame->StyleColor()->
       CalcComplexColor(mFrame->StyleText()->mWebkitTextStrokeColor);
   }
   float GetWebkitTextStrokeWidth() {
-    if (mFrame->IsSVGText()) {
+    if (nsSVGUtils::IsInSVGTextSubtree(mFrame)) {
       return 0.0f;
     }
     nscoord coord = mFrame->StyleText()->mWebkitTextStrokeWidth;
     return mFrame->PresContext()->AppUnitsToFloatDevPixels(coord);
   }
 
   /**
    * Compute the colors for normally-selected text. Returns false if
@@ -678,17 +678,18 @@ InvalidateFrameDueToGlyphsChanged(nsIFra
   for (nsIFrame* f = aFrame; f;
        f = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(f)) {
     f->InvalidateFrame();
 
     // If this is a non-display text frame within SVG <text>, we need
     // to reflow the SVGTextFrame. (This is similar to reflowing the
     // SVGTextFrame in response to style changes, in
     // SVGTextFrame::DidSetStyleContext.)
-    if (f->IsSVGText() && f->GetStateBits() & NS_FRAME_IS_NONDISPLAY) {
+    if (nsSVGUtils::IsInSVGTextSubtree(f) &&
+        f->GetStateBits() & NS_FRAME_IS_NONDISPLAY) {
       auto svgTextFrame = static_cast<SVGTextFrame*>(
                             nsLayoutUtils::GetClosestFrameOfType(f,
                             nsGkAtoms::svgTextFrame));
       svgTextFrame->ScheduleReflowSVGNonDisplayText(nsIPresShell::eResize);
     } else {
       // Theoretically we could just update overflow areas, perhaps using
       // OverflowChangedTracker, but that would do a bunch of work eagerly that
       // we should probably do lazily here since there could be a lot
@@ -1720,17 +1721,17 @@ GetSpaceWidthAppUnits(const gfxTextRun* 
              aTextRun->GetAppUnitsPerDevUnit());
 
   return spaceWidthAppUnits;
 }
 
 static nscoord
 LetterSpacing(nsIFrame* aFrame, const nsStyleText* aStyleText = nullptr)
 {
-  if (aFrame->IsSVGText()) {
+  if (nsSVGUtils::IsInSVGTextSubtree(aFrame)) {
     return 0;
   }
   if (!aStyleText) {
     aStyleText = aFrame->StyleText();
   }
 
   const nsStyleCoord& coord = aStyleText->mLetterSpacing;
   if (eStyleUnit_Coord == coord.GetUnit()) {
@@ -1739,17 +1740,17 @@ LetterSpacing(nsIFrame* aFrame, const ns
   return 0;
 }
 
 // This function converts non-coord values (e.g. percentages) to nscoord.
 static nscoord
 WordSpacing(nsIFrame* aFrame, const gfxTextRun* aTextRun,
             const nsStyleText* aStyleText = nullptr)
 {
-  if (aFrame->IsSVGText()) {
+  if (nsSVGUtils::IsInSVGTextSubtree(aFrame)) {
     return 0;
   }
   if (!aStyleText) {
     aStyleText = aFrame->StyleText();
   }
 
   const nsStyleCoord& coord = aStyleText->mWordSpacing;
   if (coord.IsCoordPercentCalcUnit()) {
@@ -1759,17 +1760,17 @@ WordSpacing(nsIFrame* aFrame, const gfxT
   return 0;
 }
 
 // Returns gfxTextRunFactory::TEXT_ENABLE_SPACING if non-standard
 // letter-spacing or word-spacing is present.
 static uint32_t
 GetSpacingFlags(nsIFrame* aFrame, const nsStyleText* aStyleText = nullptr)
 {
-  if (aFrame->IsSVGText()) {
+  if (nsSVGUtils::IsInSVGTextSubtree(aFrame)) {
     return 0;
   }
 
   const nsStyleText* styleText = aFrame->StyleText();
   const nsStyleCoord& ls = styleText->mLetterSpacing;
   const nsStyleCoord& ws = styleText->mWordSpacing;
 
   // It's possible to have a calc() value that computes to zero but for which
@@ -2055,17 +2056,17 @@ BuildTextRunsScanner::BuildTextRunForFra
     userMappedFlows = reinterpret_cast<TextRunMappedFlow*>(userData + 1);
     userDataToDestroy = userData;
   }
 
   uint32_t currentTransformedTextOffset = 0;
 
   uint32_t nextBreakIndex = 0;
   nsTextFrame* nextBreakBeforeFrame = GetNextBreakBeforeFrame(&nextBreakIndex);
-  bool isSVG = mLineContainer->IsSVGText();
+  bool isSVG = nsSVGUtils::IsInSVGTextSubtree(mLineContainer);
   bool enabledJustification =
     (mLineContainer->StyleText()->mTextAlign == NS_STYLE_TEXT_ALIGN_JUSTIFY ||
      mLineContainer->StyleText()->mTextAlignLast == NS_STYLE_TEXT_ALIGN_JUSTIFY);
 
   const nsStyleText* textStyle = nullptr;
   const nsStyleFont* fontStyle = nullptr;
   nsStyleContext* lastStyleContext = nullptr;
   for (uint32_t i = 0; i < mMappedFlows.Length(); ++i) {
@@ -3782,17 +3783,17 @@ nsTextPaintStyle::EnsureSufficientContra
     return true;
   }
   return false;
 }
 
 nscolor
 nsTextPaintStyle::GetTextColor()
 {
-  if (mFrame->IsSVGText()) {
+  if (nsSVGUtils::IsInSVGTextSubtree(mFrame)) {
     if (!mResolveColors)
       return NS_SAME_AS_FOREGROUND_COLOR;
 
     const nsStyleSVG* style = mFrame->StyleSVG();
     switch (style->mFill.Type()) {
       case eStyleSVGPaintType_None:
         return NS_RGBA(0, 0, 0, 0);
       case eStyleSVGPaintType_Color:
@@ -4028,22 +4029,22 @@ nsTextPaintStyle::InitSelectionColorsAnd
   }
 
   mSelectionTextColor =
     LookAndFeel::GetColor(LookAndFeel::eColorID_TextSelectForeground);
 
   if (mResolveColors) {
     // On MacOS X, we don't exchange text color and BG color.
     if (mSelectionTextColor == NS_DONT_CHANGE_COLOR) {
-      nscolor frameColor = mFrame->IsSVGText()
+      nscolor frameColor = nsSVGUtils::IsInSVGTextSubtree(mFrame)
         ? mFrame->GetVisitedDependentColor(&nsStyleSVG::mFill)
         : mFrame->GetVisitedDependentColor(&nsStyleText::mWebkitTextFillColor);
       mSelectionTextColor = EnsureDifferentColors(frameColor, mSelectionBGColor);
     } else if (mSelectionTextColor == NS_CHANGE_COLOR_IF_SAME_AS_BG) {
-      nscolor frameColor = mFrame->IsSVGText()
+      nscolor frameColor = nsSVGUtils::IsInSVGTextSubtree(mFrame)
         ? mFrame->GetVisitedDependentColor(&nsStyleSVG::mFill)
         : mFrame->GetVisitedDependentColor(&nsStyleText::mWebkitTextFillColor);
       if (frameColor == mSelectionBGColor) {
         mSelectionTextColor =
           LookAndFeel::GetColor(LookAndFeel::eColorID_TextSelectForegroundCustom);
       }
     } else {
       EnsureSufficientContrast(&mSelectionTextColor, &mSelectionBGColor);
@@ -4599,30 +4600,30 @@ nsTextFrame::LastContinuation() const
   }
   MOZ_ASSERT(lastContinuation, "post-condition failed");
   return lastContinuation;
 }
 
 void
 nsTextFrame::InvalidateFrame(uint32_t aDisplayItemKey)
 {
-  if (IsSVGText()) {
+  if (nsSVGUtils::IsInSVGTextSubtree(this)) {
     nsIFrame* svgTextFrame =
       nsLayoutUtils::GetClosestFrameOfType(GetParent(),
                                            nsGkAtoms::svgTextFrame);
     svgTextFrame->InvalidateFrame();
     return;
   }
   nsFrame::InvalidateFrame(aDisplayItemKey);
 }
 
 void
 nsTextFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey)
 {
-  if (IsSVGText()) {
+  if (nsSVGUtils::IsInSVGTextSubtree(this)) {
     nsIFrame* svgTextFrame =
       nsLayoutUtils::GetClosestFrameOfType(GetParent(),
                                            nsGkAtoms::svgTextFrame);
     svgTextFrame->InvalidateFrame();
     return;
   }
   nsFrame::InvalidateFrameWithRect(aRect, aDisplayItemKey);
 }
@@ -5161,17 +5162,17 @@ nsTextFrame::BuildDisplayList(nsDisplayL
   const nsStyleColor* sc = StyleColor();
   const nsStyleText* st = StyleText();
   bool isTextTransparent =
     NS_GET_A(sc->CalcComplexColor(st->mWebkitTextFillColor)) == 0 &&
     NS_GET_A(sc->CalcComplexColor(st->mWebkitTextStrokeColor)) == 0;
   Maybe<bool> isSelected;
   if (((GetStateBits() & TEXT_NO_RENDERED_GLYPHS) ||
        (isTextTransparent && !StyleText()->HasTextShadow())) &&
-      aBuilder->IsForPainting() && !IsSVGText()) {
+      aBuilder->IsForPainting() && !nsSVGUtils::IsInSVGTextSubtree(this)) {
     isSelected.emplace(IsSelected());
     if (!isSelected.value()) {
       TextDecorations textDecs;
       GetTextDecorations(PresContext(), eResolvedColors, textDecs);
       if (!textDecs.HasDecorationLines()) {
         return;
       }
     }
@@ -5380,17 +5381,17 @@ nsTextFrame::GetTextDecorations(
     physicalBlockStartOffset +=
       vertical ? f->GetNormalPosition().x : f->GetNormalPosition().y;
 
     const uint8_t style = styleText->mTextDecorationStyle;
     if (textDecorations) {
       nscolor color;
       if (useOverride) {
         color = overrideColor;
-      } else if (IsSVGText()) {
+      } else if (nsSVGUtils::IsInSVGTextSubtree(this)) {
         // XXX We might want to do something with text-decoration-color when
         //     painting SVG text, but it's not clear what we should do.  We
         //     at least need SVG text decorations to paint with 'fill' if
         //     text-decoration-color has its initial value currentColor.
         //     We could choose to interpret currentColor as "currentFill"
         //     for SVG text, and have e.g. text-decoration-color:red to
         //     override the fill paint of the decoration.
         color = aColorResolution == eResolvedColors ?
@@ -5453,17 +5454,17 @@ nsTextFrame::GetTextDecorations(
       break;
     }
   }
 }
 
 static float
 GetInflationForTextDecorations(nsIFrame* aFrame, nscoord aInflationMinFontSize)
 {
-  if (aFrame->IsSVGText()) {
+  if (nsSVGUtils::IsInSVGTextSubtree(aFrame)) {
     const nsIFrame* container = aFrame;
     while (container->GetType() != nsGkAtoms::svgTextFrame) {
       container = container->GetParent();
     }
     NS_ASSERTION(container, "expected to find an ancestor SVGTextFrame");
     return
       static_cast<const SVGTextFrame*>(container)->GetFontSizeScaleFactor();
   }
@@ -6638,17 +6639,17 @@ nsTextFrame::GetCaretColorAt(int32_t aOf
                   aOffset <= contentOffset + contentLength,
                   "aOffset must be in the frame's range");
   int32_t offsetInFrame = aOffset - contentOffset;
   if (offsetInFrame < 0 || offsetInFrame >= contentLength) {
     return result;
   }
 
   bool isSolidTextColor = true;
-  if (IsSVGText()) {
+  if (nsSVGUtils::IsInSVGTextSubtree(this)) {
     const nsStyleSVG* style = StyleSVG();
     if (style->mFill.Type() != eStyleSVGPaintType_None &&
         style->mFill.Type() != eStyleSVGPaintType_Color) {
       isSolidTextColor = false;
     }
   }
 
   nsTextPaintStyle textPaintStyle(this);
@@ -9605,17 +9606,17 @@ nsTextFrame::ReflowText(nsLineLayout& aL
     mContent->DeleteProperty(nsGkAtoms::newline);
   }
 
   // Compute space and letter counts for justification, if required
   if (!textStyle->WhiteSpaceIsSignificant() &&
       (lineContainer->StyleText()->mTextAlign == NS_STYLE_TEXT_ALIGN_JUSTIFY ||
        lineContainer->StyleText()->mTextAlignLast == NS_STYLE_TEXT_ALIGN_JUSTIFY ||
        shouldSuppressLineBreak) &&
-      !lineContainer->IsSVGText()) {
+      !nsSVGUtils::IsInSVGTextSubtree(lineContainer)) {
     AddStateBits(TEXT_JUSTIFICATION_ENABLED);
     Range range(uint32_t(offset), uint32_t(offset + charsFit));
     aLineLayout.SetJustificationInfo(provider.ComputeJustification(range));
   }
 
   SetLength(contentLength, &aLineLayout, ALLOW_FRAME_CREATION_AND_DESTRUCTION);
 
   InvalidateFrame();
--- a/layout/style/nsFontFaceUtils.cpp
+++ b/layout/style/nsFontFaceUtils.cpp
@@ -66,34 +66,35 @@ FrameUsesFont(nsIFrame* aFrame, const gf
 
   return false;
 }
 
 static void
 ScheduleReflow(nsIPresShell* aShell, nsIFrame* aFrame)
 {
   nsIFrame* f = aFrame;
-  if (f->IsFrameOfType(nsIFrame::eSVG) || f->IsSVGText()) {
+  if (f->IsFrameOfType(nsIFrame::eSVG) || nsSVGUtils::IsInSVGTextSubtree(f)) {
     // SVG frames (and the non-SVG descendants of an SVGTextFrame) need special
     // reflow handling.  We need to search upwards for the first displayed
     // nsSVGOuterSVGFrame or non-SVG frame, which is the frame we can call
     // FrameNeedsReflow on.  (This logic is based on
     // nsSVGUtils::ScheduleReflowSVG and
     // SVGTextFrame::ScheduleReflowSVGNonDisplayText.)
     if (f->GetStateBits() & NS_FRAME_IS_NONDISPLAY) {
       while (f) {
         if (!(f->GetStateBits() & NS_FRAME_IS_NONDISPLAY)) {
           if (NS_SUBTREE_DIRTY(f)) {
             // This is a displayed frame, so if it is already dirty, we
             // will be reflowed soon anyway.  No need to call
             // FrameNeedsReflow again, then.
             return;
           }
           if (f->GetStateBits() & NS_STATE_IS_OUTER_SVG ||
-              !(f->IsFrameOfType(nsIFrame::eSVG) || f->IsSVGText())) {
+              !(f->IsFrameOfType(nsIFrame::eSVG) ||
+                nsSVGUtils::IsInSVGTextSubtree(f))) {
             break;
           }
           f->AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
         }
         f = f->GetParent();
       }
       MOZ_ASSERT(f, "should have found an ancestor frame to reflow");
     }
--- a/layout/style/nsStyleStructInlines.h
+++ b/layout/style/nsStyleStructInlines.h
@@ -10,17 +10,17 @@
 
 #ifndef nsStyleStructInlines_h_
 #define nsStyleStructInlines_h_
 
 #include "nsIFrame.h"
 #include "nsStyleStruct.h"
 #include "nsIContent.h" // for GetParent()
 #include "nsTextFrame.h" // for nsTextFrame::ShouldSuppressLineBreak
-
+#include "nsSVGUtils.h" // for nsSVGUtils::IsInSVGTextSubtree
 #include "mozilla/ServoStyleSet.h"
 
 inline void
 nsStyleImage::EnsureCachedBIData() const
 {
   if (!mCachedBIData) {
     const_cast<nsStyleImage*>(this)->mCachedBIData =
       mozilla::MakeUnique<CachedBorderImageData>();
@@ -60,83 +60,85 @@ nsStyleText::NewlineIsSignificant(const 
          !aContextFrame->ShouldSuppressLineBreak() &&
          !aContextFrame->StyleContext()->IsTextCombined();
 }
 
 bool
 nsStyleText::WhiteSpaceCanWrap(const nsIFrame* aContextFrame) const
 {
   NS_ASSERTION(aContextFrame->StyleText() == this, "unexpected aContextFrame");
-  return WhiteSpaceCanWrapStyle() && !aContextFrame->IsSVGText() &&
+  return WhiteSpaceCanWrapStyle() &&
+         !nsSVGUtils::IsInSVGTextSubtree(aContextFrame) &&
          !aContextFrame->StyleContext()->IsTextCombined();
 }
 
 bool
 nsStyleText::WordCanWrap(const nsIFrame* aContextFrame) const
 {
   NS_ASSERTION(aContextFrame->StyleText() == this, "unexpected aContextFrame");
-  return WordCanWrapStyle() && !aContextFrame->IsSVGText();
+  return WordCanWrapStyle() && !nsSVGUtils::IsInSVGTextSubtree(aContextFrame);
 }
 
 bool
 nsStyleDisplay::IsBlockInside(const nsIFrame* aContextFrame) const
 {
   NS_ASSERTION(aContextFrame->StyleDisplay() == this, "unexpected aContextFrame");
-  if (aContextFrame->IsSVGText()) {
+  if (nsSVGUtils::IsInSVGTextSubtree(aContextFrame)) {
     return aContextFrame->GetType() == nsGkAtoms::blockFrame;
   }
   return IsBlockInsideStyle();
 }
 
 bool
 nsStyleDisplay::IsBlockOutside(const nsIFrame* aContextFrame) const
 {
   NS_ASSERTION(aContextFrame->StyleDisplay() == this, "unexpected aContextFrame");
-  if (aContextFrame->IsSVGText()) {
+  if (nsSVGUtils::IsInSVGTextSubtree(aContextFrame)) {
     return aContextFrame->GetType() == nsGkAtoms::blockFrame;
   }
   return IsBlockOutsideStyle();
 }
 
 bool
 nsStyleDisplay::IsInlineOutside(const nsIFrame* aContextFrame) const
 {
   NS_ASSERTION(aContextFrame->StyleDisplay() == this, "unexpected aContextFrame");
-  if (aContextFrame->IsSVGText()) {
+  if (nsSVGUtils::IsInSVGTextSubtree(aContextFrame)) {
     return aContextFrame->GetType() != nsGkAtoms::blockFrame;
   }
   return IsInlineOutsideStyle();
 }
 
 bool
 nsStyleDisplay::IsOriginalDisplayInlineOutside(const nsIFrame* aContextFrame) const
 {
   NS_ASSERTION(aContextFrame->StyleDisplay() == this, "unexpected aContextFrame");
-  if (aContextFrame->IsSVGText()) {
+  if (nsSVGUtils::IsInSVGTextSubtree(aContextFrame)) {
     return aContextFrame->GetType() != nsGkAtoms::blockFrame;
   }
   return IsOriginalDisplayInlineOutsideStyle();
 }
 
 mozilla::StyleDisplay
 nsStyleDisplay::GetDisplay(const nsIFrame* aContextFrame) const
 {
   NS_ASSERTION(aContextFrame->StyleDisplay() == this, "unexpected aContextFrame");
-  if (aContextFrame->IsSVGText() && mDisplay != mozilla::StyleDisplay::None) {
+  if (nsSVGUtils::IsInSVGTextSubtree(aContextFrame) &&
+      mDisplay != mozilla::StyleDisplay::None) {
     return aContextFrame->GetType() == nsGkAtoms::blockFrame ?
              mozilla::StyleDisplay::Block : mozilla::StyleDisplay::Inline;
   }
   return mDisplay;
 }
 
 bool
 nsStyleDisplay::IsFloating(const nsIFrame* aContextFrame) const
 {
   NS_ASSERTION(aContextFrame->StyleDisplay() == this, "unexpected aContextFrame");
-  return IsFloatingStyle() && !aContextFrame->IsSVGText();
+  return IsFloatingStyle() && !nsSVGUtils::IsInSVGTextSubtree(aContextFrame);
 }
 
 // If you change this function, also change the corresponding block in
 // nsCSSFrameConstructor::ConstructFrameFromItemInternal that references
 // this function in comments.
 bool
 nsStyleDisplay::HasTransform(const nsIFrame* aContextFrame) const
 {
@@ -180,17 +182,17 @@ bool
 nsStyleDisplay::IsFixedPosContainingBlock(const nsIFrame* aContextFrame) const
 {
   // NOTE: Any CSS properties that influence the output of this function
   // should have the CSS_PROPERTY_FIXPOS_CB set on them.
   if (!HasFixedPosContainingBlockStyleInternal(aContextFrame->StyleContext()) &&
       !HasTransform(aContextFrame)) {
     return false;
   }
-  return !aContextFrame->IsSVGText();
+  return !nsSVGUtils::IsInSVGTextSubtree(aContextFrame);
 }
 
 template<class StyleContextLike>
 bool
 nsStyleDisplay::HasAbsPosContainingBlockStyleInternal(
                   StyleContextLike* aStyleContext) const
 {
   // NOTE: Any CSS properties that influence the output of this function
@@ -218,31 +220,33 @@ nsStyleDisplay::IsAbsPosContainingBlock(
   // NOTE: Any CSS properties that influence the output of this function
   // should have the CSS_PROPERTY_ABSPOS_CB set on them.
   nsStyleContext* sc = aContextFrame->StyleContext();
   if (!HasAbsPosContainingBlockStyleInternal(sc) &&
       !HasFixedPosContainingBlockStyleInternal(sc) &&
       !HasTransform(aContextFrame)) {
     return false;
   }
-  return !aContextFrame->IsSVGText();
+  return !nsSVGUtils::IsInSVGTextSubtree(aContextFrame);
 }
 
 bool
 nsStyleDisplay::IsRelativelyPositioned(const nsIFrame* aContextFrame) const
 {
   NS_ASSERTION(aContextFrame->StyleDisplay() == this, "unexpected aContextFrame");
-  return IsRelativelyPositionedStyle() && !aContextFrame->IsSVGText();
+  return IsRelativelyPositionedStyle() &&
+         !nsSVGUtils::IsInSVGTextSubtree(aContextFrame);
 }
 
 bool
 nsStyleDisplay::IsAbsolutelyPositioned(const nsIFrame* aContextFrame) const
 {
   NS_ASSERTION(aContextFrame->StyleDisplay() == this, "unexpected aContextFrame");
-  return IsAbsolutelyPositionedStyle() && !aContextFrame->IsSVGText();
+  return IsAbsolutelyPositionedStyle() &&
+         !nsSVGUtils::IsInSVGTextSubtree(aContextFrame);
 }
 
 uint8_t
 nsStyleUserInterface::GetEffectivePointerEvents(nsIFrame* aFrame) const
 {
   if (aFrame->GetContent() && !aFrame->GetContent()->GetParent()) {
     // The root element has a cluster of frames associated with it
     // (root scroll frame, canvas frame, the actual primary frame). Make
--- a/layout/svg/nsSVGEffects.cpp
+++ b/layout/svg/nsSVGEffects.cpp
@@ -413,17 +413,18 @@ void
 nsSVGTextPathProperty::DoUpdate()
 {
   nsSVGRenderingObserverProperty::DoUpdate();
 
   nsIFrame* frame = mFrameReference.Get();
   if (!frame)
     return;
 
-  NS_ASSERTION(frame->IsFrameOfType(nsIFrame::eSVG) || frame->IsSVGText(),
+  NS_ASSERTION(frame->IsFrameOfType(nsIFrame::eSVG) ||
+               nsSVGUtils::IsInSVGTextSubtree(frame),
                "SVG frame expected");
 
   // Avoid getting into an infinite loop of reflows if the <textPath> is
   // pointing to one of its ancestors.  TargetIsValid returns true iff
   // the target element is a <path> element, and we would not have this
   // nsSVGTextPathProperty if this <textPath> were a descendant of the
   // target <path>.
   //
--- a/layout/svg/nsSVGUtils.cpp
+++ b/layout/svg/nsSVGUtils.cpp
@@ -428,25 +428,26 @@ nsSVGUtils::GetUserToCanvasTM(nsIFrame *
     nsSVGElement *content = static_cast<nsSVGElement*>(aFrame->GetContent());
     tm = content->PrependLocalTransformsTo(
                     GetCanvasTM(aFrame->GetParent()),
                     eUserSpaceToParent);
   }
   return tm;
 }
 
-void 
+void
 nsSVGUtils::NotifyChildrenOfSVGChange(nsIFrame *aFrame, uint32_t aFlags)
 {
   for (nsIFrame* kid : aFrame->PrincipalChildList()) {
     nsSVGDisplayableFrame* SVGFrame = do_QueryFrame(kid);
     if (SVGFrame) {
-      SVGFrame->NotifySVGChanged(aFlags); 
+      SVGFrame->NotifySVGChanged(aFlags);
     } else {
-      NS_ASSERTION(kid->IsFrameOfType(nsIFrame::eSVG) || kid->IsSVGText(),
+      NS_ASSERTION(kid->IsFrameOfType(nsIFrame::eSVG) ||
+                   nsSVGUtils::IsInSVGTextSubtree(kid),
                    "SVG frame expected");
       // recurse into the children of container frames e.g. <clipPath>, <mask>
       // in case they have child frames with transformation matrices
       if (kid->IsFrameOfType(nsIFrame::eSVG)) {
         NotifyChildrenOfSVGChange(kid, aFlags);
       }
     }
   }
@@ -627,17 +628,17 @@ private:
 
     if (!(mFrame->GetStateBits() & NS_FRAME_IS_NONDISPLAY)) {
       // aFrame has a valid visual overflow rect, so clip to it before calling
       // PushGroup() to minimize the size of the surfaces we'll composite:
       gfxContextMatrixAutoSaveRestore matrixAutoSaveRestore(mSourceCtx);
       mSourceCtx->Multiply(aTransform);
       nsRect overflowRect = mFrame->GetVisualOverflowRectRelativeToSelf();
       if (mFrame->IsFrameOfType(nsIFrame::eSVGGeometry) ||
-          mFrame->IsSVGText()) {
+          nsSVGUtils::IsInSVGTextSubtree(mFrame)) {
         // Unlike containers, leaf frames do not include GetPosition() in
         // GetCanvasTM().
         overflowRect = overflowRect + mFrame->GetPosition();
       }
       mSourceCtx->Clip(NSRectToSnappedRect(overflowRect,
                                            mFrame->PresContext()->AppUnitsPerDevPixel(),
                                            *mSourceCtx->GetDrawTarget()));
     }
@@ -690,17 +691,17 @@ nsSVGUtils::PaintFrameWithEffects(nsIFra
   if (aDirtyRect &&
       !(aFrame->GetStateBits() & NS_FRAME_IS_NONDISPLAY)) {
     // Here we convert aFrame's paint bounds to outer-<svg> device space,
     // compare it to aDirtyRect, and return early if they don't intersect.
     // We don't do this optimization for nondisplay SVG since nondisplay
     // SVG doesn't maintain bounds/overflow rects.
     nsRect overflowRect = aFrame->GetVisualOverflowRectRelativeToSelf();
     if (aFrame->IsFrameOfType(nsIFrame::eSVGGeometry) ||
-        aFrame->IsSVGText()) {
+        nsSVGUtils::IsInSVGTextSubtree(aFrame)) {
       // Unlike containers, leaf frames do not include GetPosition() in
       // GetCanvasTM().
       overflowRect = overflowRect + aFrame->GetPosition();
     }
     int32_t appUnitsPerDevPx = aFrame->PresContext()->AppUnitsPerDevPixel();
     gfxMatrix tm = aTransform;
     if (aFrame->IsFrameOfType(nsIFrame::eSVG | nsIFrame::eSVGContainer)) {
       gfx::Matrix childrenOnlyTM;
@@ -1100,23 +1101,23 @@ nsSVGUtils::SetClipRect(gfxContext *aCon
 
 gfxRect
 nsSVGUtils::GetBBox(nsIFrame *aFrame, uint32_t aFlags)
 {
   if (aFrame->GetContent()->IsNodeOfType(nsINode::eTEXT)) {
     aFrame = aFrame->GetParent();
   }
 
-  if (aFrame->IsSVGText()) {
+  if (nsSVGUtils::IsInSVGTextSubtree(aFrame)) {
     // It is possible to apply a gradient, pattern, clipping path, mask or
     // filter to text. When one of these facilities is applied to text
     // the bounding box is the entire text element in all
     // cases.
     nsIFrame* ancestor = GetFirstNonAAncestorFrame(aFrame);
-    if (ancestor && ancestor->IsSVGText()) {
+    if (ancestor && nsSVGUtils::IsInSVGTextSubtree(ancestor)) {
       while (ancestor->GetType() != nsGkAtoms::svgTextFrame) {
         ancestor = ancestor->GetParent();
       }
     }
     aFrame = ancestor;
   }
 
   nsSVGDisplayableFrame* svg = do_QueryFrame(aFrame);
@@ -1233,17 +1234,17 @@ nsSVGUtils::FrameSpaceInCSSPxToUserSpace
   if (!(aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT)) {
     // The user space for non-SVG frames is defined as the bounding box of the
     // frame's border-box rects over all continuations.
     return gfxPoint();
   }
 
   // Leaf frames apply their own offset inside their user space.
   if (aFrame->IsFrameOfType(nsIFrame::eSVGGeometry) ||
-      aFrame->IsSVGText()) {
+      nsSVGUtils::IsInSVGTextSubtree(aFrame)) {
     return nsLayoutUtils::RectToGfxRect(aFrame->GetRect(),
                                          nsPresContext::AppUnitsPerCSSPixel()).TopLeft();
   }
 
   // For foreignObject frames, nsSVGUtils::GetBBox applies their local
   // transform, so we need to do the same here.
   if (aFrame->GetType() == nsGkAtoms::svgForeignObjectFrame) {
     gfxMatrix transform = static_cast<nsSVGElement*>(aFrame->GetContent())->
@@ -1397,17 +1398,18 @@ PathExtentsToMaxStrokeExtents(const gfxR
   return strokeExtents;
 }
 
 /*static*/ gfxRect
 nsSVGUtils::PathExtentsToMaxStrokeExtents(const gfxRect& aPathExtents,
                                           nsTextFrame* aFrame,
                                           const gfxMatrix& aMatrix)
 {
-  NS_ASSERTION(aFrame->IsSVGText(), "expected an nsTextFrame for SVG text");
+  NS_ASSERTION(nsSVGUtils::IsInSVGTextSubtree(aFrame),
+               "expected an nsTextFrame for SVG text");
   return ::PathExtentsToMaxStrokeExtents(aPathExtents, aFrame, 0.5, aMatrix);
 }
 
 /*static*/ gfxRect
 nsSVGUtils::PathExtentsToMaxStrokeExtents(const gfxRect& aPathExtents,
                                           SVGGeometryFrame* aFrame,
                                           const gfxMatrix& aMatrix)
 {
--- a/layout/svg/nsSVGUtils.h
+++ b/layout/svg/nsSVGUtils.h
@@ -604,11 +604,16 @@ public:
   /**
    * SVG frames expect to paint in SVG user units, which are equal to CSS px
    * units. This method provides a transform matrix to multiply onto a
    * gfxContext's current transform to convert the context's current units from
    * its usual dev pixels to SVG user units/CSS px to keep the SVG code happy.
    */
   static gfxMatrix
   GetCSSPxToDevPxMatrix(nsIFrame* aNonSVGFrame);
+
+  static bool IsInSVGTextSubtree(const nsIFrame* aFrame) {
+    // Returns true if the frame is an SVGTextFrame or one of its descendants.
+    return aFrame->GetStateBits() & NS_FRAME_IS_SVG_TEXT;
+  }
 };
 
 #endif