LCOV - code coverage report
Current view: top level - layout/generic - nsInlineFrame.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 530 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 41 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : /* rendering object for CSS display:inline objects */
       7             : 
       8             : #include "gfxContext.h"
       9             : #include "nsInlineFrame.h"
      10             : #include "nsLineLayout.h"
      11             : #include "nsBlockFrame.h"
      12             : #include "nsPlaceholderFrame.h"
      13             : #include "nsGkAtoms.h"
      14             : #include "nsStyleContext.h"
      15             : #include "nsPresContext.h"
      16             : #include "nsCSSAnonBoxes.h"
      17             : #include "mozilla/RestyleManager.h"
      18             : #include "mozilla/RestyleManagerInlines.h"
      19             : #include "nsDisplayList.h"
      20             : #include "mozilla/Likely.h"
      21             : #include "SVGTextFrame.h"
      22             : #include "nsStyleChangeList.h"
      23             : #include "mozilla/StyleSetHandle.h"
      24             : #include "mozilla/StyleSetHandleInlines.h"
      25             : #include "mozilla/ServoStyleSet.h"
      26             : 
      27             : #ifdef DEBUG
      28             : #undef NOISY_PUSHING
      29             : #endif
      30             : 
      31             : using namespace mozilla;
      32             : using namespace mozilla::layout;
      33             : 
      34             : 
      35             : //////////////////////////////////////////////////////////////////////
      36             : 
      37             : // Basic nsInlineFrame methods
      38             : 
      39             : nsInlineFrame*
      40           0 : NS_NewInlineFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
      41             : {
      42           0 :   return new (aPresShell) nsInlineFrame(aContext);
      43             : }
      44             : 
      45           0 : NS_IMPL_FRAMEARENA_HELPERS(nsInlineFrame)
      46             : 
      47           0 : NS_QUERYFRAME_HEAD(nsInlineFrame)
      48           0 :   NS_QUERYFRAME_ENTRY(nsInlineFrame)
      49           0 : NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
      50             : 
      51             : #ifdef DEBUG_FRAME_DUMP
      52             : nsresult
      53           0 : nsInlineFrame::GetFrameName(nsAString& aResult) const
      54             : {
      55           0 :   return MakeFrameName(NS_LITERAL_STRING("Inline"), aResult);
      56             : }
      57             : #endif
      58             : 
      59             : void
      60           0 : nsInlineFrame::InvalidateFrame(uint32_t aDisplayItemKey)
      61             : {
      62           0 :   if (nsSVGUtils::IsInSVGTextSubtree(this)) {
      63             :     nsIFrame* svgTextFrame = nsLayoutUtils::GetClosestFrameOfType(
      64           0 :       GetParent(), LayoutFrameType::SVGText);
      65           0 :     svgTextFrame->InvalidateFrame();
      66           0 :     return;
      67             :   }
      68           0 :   nsContainerFrame::InvalidateFrame(aDisplayItemKey);
      69             : }
      70             : 
      71             : void
      72           0 : nsInlineFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey)
      73             : {
      74           0 :   if (nsSVGUtils::IsInSVGTextSubtree(this)) {
      75             :     nsIFrame* svgTextFrame = nsLayoutUtils::GetClosestFrameOfType(
      76           0 :       GetParent(), LayoutFrameType::SVGText);
      77           0 :     svgTextFrame->InvalidateFrame();
      78           0 :     return;
      79             :   }
      80           0 :   nsContainerFrame::InvalidateFrameWithRect(aRect, aDisplayItemKey);
      81             : }
      82             : 
      83             : static inline bool
      84           0 : IsMarginZero(const nsStyleCoord &aCoord)
      85             : {
      86           0 :   return aCoord.GetUnit() == eStyleUnit_Auto ||
      87           0 :          nsLayoutUtils::IsMarginZero(aCoord);
      88             : }
      89             : 
      90             : /* virtual */ bool
      91           0 : nsInlineFrame::IsSelfEmpty()
      92             : {
      93             : #if 0
      94             :   // I used to think inline frames worked this way, but it seems they
      95             :   // don't.  At least not in our codebase.
      96             :   if (GetPresContext()->CompatibilityMode() == eCompatibility_FullStandards) {
      97             :     return false;
      98             :   }
      99             : #endif
     100           0 :   const nsStyleMargin* margin = StyleMargin();
     101           0 :   const nsStyleBorder* border = StyleBorder();
     102           0 :   const nsStylePadding* padding = StylePadding();
     103             :   // Block-start and -end ignored, since they shouldn't affect things, but this
     104             :   // doesn't really match with nsLineLayout.cpp's setting of
     105             :   // ZeroEffectiveSpanBox, anymore, so what should this really be?
     106           0 :   WritingMode wm = GetWritingMode();
     107             :   bool haveStart, haveEnd;
     108             :   // Initially set up haveStart and haveEnd in terms of visual (LTR/TTB)
     109             :   // coordinates; we'll exchange them later if bidi-RTL is in effect to
     110             :   // get logical start and end flags.
     111           0 :   if (wm.IsVertical()) {
     112           0 :     haveStart =
     113           0 :       border->GetComputedBorderWidth(eSideTop) != 0 ||
     114           0 :       !nsLayoutUtils::IsPaddingZero(padding->mPadding.GetTop()) ||
     115           0 :       !IsMarginZero(margin->mMargin.GetTop());
     116           0 :     haveEnd =
     117           0 :       border->GetComputedBorderWidth(eSideBottom) != 0 ||
     118           0 :       !nsLayoutUtils::IsPaddingZero(padding->mPadding.GetBottom()) ||
     119           0 :       !IsMarginZero(margin->mMargin.GetBottom());
     120             :   } else {
     121           0 :     haveStart =
     122           0 :       border->GetComputedBorderWidth(eSideLeft) != 0 ||
     123           0 :       !nsLayoutUtils::IsPaddingZero(padding->mPadding.GetLeft()) ||
     124           0 :       !IsMarginZero(margin->mMargin.GetLeft());
     125           0 :     haveEnd =
     126           0 :       border->GetComputedBorderWidth(eSideRight) != 0 ||
     127           0 :       !nsLayoutUtils::IsPaddingZero(padding->mPadding.GetRight()) ||
     128           0 :       !IsMarginZero(margin->mMargin.GetRight());
     129             :   }
     130           0 :   if (haveStart || haveEnd) {
     131             :     // We skip this block and return false for box-decoration-break:clone since
     132             :     // in that case all the continuations will have the border/padding/margin.
     133           0 :     if ((GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) &&
     134           0 :         StyleBorder()->mBoxDecorationBreak == StyleBoxDecorationBreak::Slice) {
     135             :       // When direction=rtl, we need to consider logical rather than visual
     136             :       // start and end, so swap the flags.
     137           0 :       if (!wm.IsBidiLTR()) {
     138           0 :         Swap(haveStart, haveEnd);
     139             :       }
     140             :       // For ib-split frames, ignore things we know we'll skip in GetSkipSides.
     141             :       // XXXbz should we be doing this for non-ib-split frames too, in a more
     142             :       // general way?
     143             : 
     144             :       // Get the first continuation eagerly, as a performance optimization, to
     145             :       // avoid having to get it twice..
     146           0 :       nsIFrame* firstCont = FirstContinuation();
     147             :       return
     148           0 :         (!haveStart || firstCont->FrameIsNonFirstInIBSplit()) &&
     149           0 :         (!haveEnd || firstCont->FrameIsNonLastInIBSplit());
     150             :     }
     151           0 :     return false;
     152             :   }
     153           0 :   return true;
     154             : }
     155             : 
     156             : bool
     157           0 : nsInlineFrame::IsEmpty()
     158             : {
     159           0 :   if (!IsSelfEmpty()) {
     160           0 :     return false;
     161             :   }
     162             : 
     163           0 :   for (nsIFrame* kid : mFrames) {
     164           0 :     if (!kid->IsEmpty())
     165           0 :       return false;
     166             :   }
     167             : 
     168           0 :   return true;
     169             : }
     170             : 
     171             : nsIFrame::FrameSearchResult
     172           0 : nsInlineFrame::PeekOffsetCharacter(bool aForward, int32_t* aOffset,
     173             :                                    PeekOffsetCharacterOptions aOptions)
     174             : {
     175             :   // Override the implementation in nsFrame, to skip empty inline frames
     176           0 :   NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
     177           0 :   int32_t startOffset = *aOffset;
     178           0 :   if (startOffset < 0)
     179           0 :     startOffset = 1;
     180           0 :   if (aForward == (startOffset == 0)) {
     181             :     // We're before the frame and moving forward, or after it and moving backwards:
     182             :     // skip to the other side, but keep going.
     183           0 :     *aOffset = 1 - startOffset;
     184             :   }
     185           0 :   return CONTINUE;
     186             : }
     187             : 
     188             : void
     189           0 : nsInlineFrame::DestroyFrom(nsIFrame* aDestructRoot)
     190             : {
     191           0 :   nsFrameList* overflowFrames = GetOverflowFrames();
     192           0 :   if (overflowFrames) {
     193             :     // Fixup the parent pointers for any child frames on the OverflowList.
     194             :     // nsIFrame::DestroyFrom depends on that to find the sticky scroll
     195             :     // container (an ancestor).
     196           0 :     nsIFrame* lineContainer = nsLayoutUtils::FindNearestBlockAncestor(this);
     197           0 :     DrainSelfOverflowListInternal(eForDestroy, lineContainer);
     198             :   }
     199           0 :   nsContainerFrame::DestroyFrom(aDestructRoot);
     200           0 : }
     201             : 
     202             : nsresult
     203           0 : nsInlineFrame::StealFrame(nsIFrame* aChild)
     204             : {
     205           0 :   if (MaybeStealOverflowContainerFrame(aChild)) {
     206           0 :     return NS_OK;
     207             :   }
     208             : 
     209           0 :   nsInlineFrame* parent = this;
     210           0 :   bool removed = false;
     211           0 :   do {
     212           0 :     removed = parent->mFrames.StartRemoveFrame(aChild);
     213           0 :     if (removed) {
     214           0 :       break;
     215             :     }
     216             : 
     217             :     // We didn't find the child in our principal child list.
     218             :     // Maybe it's on the overflow list?
     219           0 :     nsFrameList* frameList = parent->GetOverflowFrames();
     220           0 :     if (frameList) {
     221           0 :       removed = frameList->ContinueRemoveFrame(aChild);
     222           0 :       if (frameList->IsEmpty()) {
     223           0 :         parent->DestroyOverflowList();
     224             :       }
     225           0 :       if (removed) {
     226           0 :         break;
     227             :       }
     228             :     }
     229             : 
     230             :     // Due to our "lazy reparenting" optimization 'aChild' might not actually
     231             :     // be on any of our child lists, but instead in one of our next-in-flows.
     232           0 :     parent = static_cast<nsInlineFrame*>(parent->GetNextInFlow());
     233           0 :   } while (parent);
     234             : 
     235           0 :   MOZ_ASSERT(removed, "nsInlineFrame::StealFrame: can't find aChild");
     236           0 :   return removed ? NS_OK : NS_ERROR_UNEXPECTED;
     237             : }
     238             : 
     239             : void
     240           0 : nsInlineFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
     241             :                                 const nsRect&           aDirtyRect,
     242             :                                 const nsDisplayListSet& aLists)
     243             : {
     244           0 :   BuildDisplayListForInline(aBuilder, aDirtyRect, aLists);
     245             : 
     246             :   // The sole purpose of this is to trigger display of the selection
     247             :   // window for Named Anchors, which don't have any children and
     248             :   // normally don't have any size, but in Editor we use CSS to display
     249             :   // an image to represent this "hidden" element.
     250           0 :   if (!mFrames.FirstChild()) {
     251           0 :     DisplaySelectionOverlay(aBuilder, aLists.Content());
     252             :   }
     253           0 : }
     254             : 
     255             : //////////////////////////////////////////////////////////////////////
     256             : // Reflow methods
     257             : 
     258             : /* virtual */ void
     259           0 : nsInlineFrame::AddInlineMinISize(gfxContext *aRenderingContext,
     260             :                                  nsIFrame::InlineMinISizeData *aData)
     261             : {
     262           0 :   DoInlineIntrinsicISize(aRenderingContext, aData, nsLayoutUtils::MIN_ISIZE);
     263           0 : }
     264             : 
     265             : /* virtual */ void
     266           0 : nsInlineFrame::AddInlinePrefISize(gfxContext *aRenderingContext,
     267             :                                   nsIFrame::InlinePrefISizeData *aData)
     268             : {
     269           0 :   DoInlineIntrinsicISize(aRenderingContext, aData, nsLayoutUtils::PREF_ISIZE);
     270           0 :   aData->mLineIsEmpty = false;
     271           0 : }
     272             : 
     273             : /* virtual */
     274             : LogicalSize
     275           0 : nsInlineFrame::ComputeSize(gfxContext *aRenderingContext,
     276             :                            WritingMode aWM,
     277             :                            const LogicalSize& aCBSize,
     278             :                            nscoord aAvailableISize,
     279             :                            const LogicalSize& aMargin,
     280             :                            const LogicalSize& aBorder,
     281             :                            const LogicalSize& aPadding,
     282             :                            ComputeSizeFlags aFlags)
     283             : {
     284             :   // Inlines and text don't compute size before reflow.
     285           0 :   return LogicalSize(aWM, NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
     286             : }
     287             : 
     288             : nsRect
     289           0 : nsInlineFrame::ComputeTightBounds(DrawTarget* aDrawTarget) const
     290             : {
     291             :   // be conservative
     292           0 :   if (StyleContext()->HasTextDecorationLines()) {
     293           0 :     return GetVisualOverflowRect();
     294             :   }
     295           0 :   return ComputeSimpleTightBounds(aDrawTarget);
     296             : }
     297             : 
     298             : void
     299           0 : nsInlineFrame::ReparentFloatsForInlineChild(nsIFrame* aOurLineContainer,
     300             :                                             nsIFrame* aFrame,
     301             :                                             bool aReparentSiblings)
     302             : {
     303             :   // XXXbz this would be better if it took a nsFrameList or a frame
     304             :   // list slice....
     305           0 :   NS_ASSERTION(aOurLineContainer->GetNextContinuation() ||
     306             :                aOurLineContainer->GetPrevContinuation(),
     307             :                "Don't call this when we have no continuation, it's a waste");
     308           0 :   if (!aFrame) {
     309           0 :     NS_ASSERTION(aReparentSiblings, "Why did we get called?");
     310           0 :     return;
     311             :   }
     312             : 
     313           0 :   nsBlockFrame* frameBlock = nsLayoutUtils::GetFloatContainingBlock(aFrame);
     314           0 :   if (!frameBlock || frameBlock == aOurLineContainer) {
     315           0 :     return;
     316             :   }
     317             : 
     318           0 :   nsBlockFrame* ourBlock = nsLayoutUtils::GetAsBlock(aOurLineContainer);
     319           0 :   NS_ASSERTION(ourBlock, "Not a block, but broke vertically?");
     320             : 
     321             :   while (true) {
     322           0 :     ourBlock->ReparentFloats(aFrame, frameBlock, false);
     323             : 
     324           0 :     if (!aReparentSiblings)
     325           0 :       return;
     326           0 :     nsIFrame* next = aFrame->GetNextSibling();
     327           0 :     if (!next)
     328           0 :       return;
     329           0 :     if (next->GetParent() == aFrame->GetParent()) {
     330           0 :       aFrame = next;
     331           0 :       continue;
     332             :     }
     333             :     // This is paranoid and will hardly ever get hit ... but we can't actually
     334             :     // trust that the frames in the sibling chain all have the same parent,
     335             :     // because lazy reparenting may be going on. If we find a different
     336             :     // parent we need to redo our analysis.
     337           0 :     ReparentFloatsForInlineChild(aOurLineContainer, next, aReparentSiblings);
     338           0 :     return;
     339           0 :   }
     340             : }
     341             : 
     342             : static void
     343           0 : ReparentChildListStyle(nsPresContext* aPresContext,
     344             :                        const nsFrameList::Slice& aFrames,
     345             :                        nsIFrame* aParentFrame)
     346             : {
     347           0 :   RestyleManager* restyleManager = aPresContext->RestyleManager();
     348             : 
     349           0 :   for (nsFrameList::Enumerator e(aFrames); !e.AtEnd(); e.Next()) {
     350           0 :     NS_ASSERTION(e.get()->GetParent() == aParentFrame, "Bogus parentage");
     351           0 :     restyleManager->ReparentStyleContext(e.get());
     352           0 :     nsLayoutUtils::MarkDescendantsDirty(e.get());
     353             :   }
     354           0 : }
     355             : 
     356             : void
     357           0 : nsInlineFrame::Reflow(nsPresContext*          aPresContext,
     358             :                       ReflowOutput&     aMetrics,
     359             :                       const ReflowInput& aReflowInput,
     360             :                       nsReflowStatus&          aStatus)
     361             : {
     362           0 :   MarkInReflow();
     363           0 :   DO_GLOBAL_REFLOW_COUNT("nsInlineFrame");
     364           0 :   DISPLAY_REFLOW(aPresContext, this, aReflowInput, aMetrics, aStatus);
     365           0 :   if (nullptr == aReflowInput.mLineLayout) {
     366           0 :     NS_ERROR("must have non-null aReflowInput.mLineLayout");
     367           0 :     return;
     368             :   }
     369           0 :   if (IsFrameTreeTooDeep(aReflowInput, aMetrics, aStatus)) {
     370           0 :     return;
     371             :   }
     372             : 
     373           0 :   bool    lazilySetParentPointer = false;
     374             : 
     375           0 :   nsIFrame* lineContainer = aReflowInput.mLineLayout->LineContainerFrame();
     376             : 
     377             :    // Check for an overflow list with our prev-in-flow
     378           0 :   nsInlineFrame* prevInFlow = (nsInlineFrame*)GetPrevInFlow();
     379           0 :   if (prevInFlow) {
     380             :     AutoFrameListPtr prevOverflowFrames(aPresContext,
     381           0 :                                         prevInFlow->StealOverflowFrames());
     382           0 :     if (prevOverflowFrames) {
     383             :       // When pushing and pulling frames we need to check for whether any
     384             :       // views need to be reparented.
     385           0 :       nsContainerFrame::ReparentFrameViewList(*prevOverflowFrames, prevInFlow,
     386           0 :                                               this);
     387             : 
     388             :       // Check if we should do the lazilySetParentPointer optimization.
     389             :       // Only do it in simple cases where we're being reflowed for the
     390             :       // first time, nothing (e.g. bidi resolution) has already given
     391             :       // us children, and there's no next-in-flow, so all our frames
     392             :       // will be taken from prevOverflowFrames.
     393           0 :       if ((GetStateBits() & NS_FRAME_FIRST_REFLOW) && mFrames.IsEmpty() &&
     394           0 :           !GetNextInFlow()) {
     395             :         // If our child list is empty, just put the new frames into it.
     396             :         // Note that we don't set the parent pointer for the new frames. Instead wait
     397             :         // to do this until we actually reflow the frame. If the overflow list contains
     398             :         // thousands of frames this is a big performance issue (see bug #5588)
     399           0 :         mFrames.SetFrames(*prevOverflowFrames);
     400           0 :         lazilySetParentPointer = true;
     401             :       } else {
     402             :         // Assign all floats to our block if necessary
     403           0 :         if (lineContainer && lineContainer->GetPrevContinuation()) {
     404           0 :           ReparentFloatsForInlineChild(lineContainer,
     405             :                                        prevOverflowFrames->FirstChild(),
     406           0 :                                        true);
     407             :         }
     408             :         // Insert the new frames at the beginning of the child list
     409             :         // and set their parent pointer
     410             :         const nsFrameList::Slice& newFrames =
     411           0 :           mFrames.InsertFrames(this, nullptr, *prevOverflowFrames);
     412             :         // If our prev in flow was under the first continuation of a first-line
     413             :         // frame then we need to reparent the style contexts to remove the
     414             :         // the special first-line styling. In the lazilySetParentPointer case
     415             :         // we reparent the style contexts when we set their parents in
     416             :         // nsInlineFrame::ReflowFrames and nsInlineFrame::ReflowInlineFrame.
     417           0 :         if (aReflowInput.mLineLayout->GetInFirstLine()) {
     418           0 :           ReparentChildListStyle(aPresContext, newFrames, this);
     419             :         }
     420             :       }
     421             :     }
     422             :   }
     423             : 
     424             :   // It's also possible that we have an overflow list for ourselves
     425             : #ifdef DEBUG
     426           0 :   if (GetStateBits() & NS_FRAME_FIRST_REFLOW) {
     427             :     // If it's our initial reflow, then we should not have an overflow list.
     428             :     // However, add an assertion in case we get reflowed more than once with
     429             :     // the initial reflow reason
     430           0 :     nsFrameList* overflowFrames = GetOverflowFrames();
     431           0 :     NS_ASSERTION(!overflowFrames || overflowFrames->IsEmpty(),
     432             :                  "overflow list is not empty for initial reflow");
     433             :   }
     434             : #endif
     435           0 :   if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
     436             :     DrainFlags flags =
     437           0 :       lazilySetParentPointer ? eDontReparentFrames : DrainFlags(0);
     438           0 :     if (aReflowInput.mLineLayout->GetInFirstLine()) {
     439           0 :       flags = DrainFlags(flags | eInFirstLine);
     440             :     }
     441           0 :     DrainSelfOverflowListInternal(flags, lineContainer);
     442             :   }
     443             : 
     444             :   // Set our own reflow state (additional state above and beyond
     445             :   // aReflowInput)
     446           0 :   InlineReflowInput irs;
     447           0 :   irs.mPrevFrame = nullptr;
     448           0 :   irs.mLineContainer = lineContainer;
     449           0 :   irs.mLineLayout = aReflowInput.mLineLayout;
     450           0 :   irs.mNextInFlow = (nsInlineFrame*) GetNextInFlow();
     451           0 :   irs.mSetParentPointer = lazilySetParentPointer;
     452             : 
     453           0 :   if (mFrames.IsEmpty()) {
     454             :     // Try to pull over one frame before starting so that we know
     455             :     // whether we have an anonymous block or not.
     456             :     bool complete;
     457           0 :     (void) PullOneFrame(aPresContext, irs, &complete);
     458             :   }
     459             : 
     460           0 :   ReflowFrames(aPresContext, aReflowInput, irs, aMetrics, aStatus);
     461             : 
     462           0 :   ReflowAbsoluteFrames(aPresContext, aMetrics, aReflowInput, aStatus);
     463             : 
     464             :   // Note: the line layout code will properly compute our
     465             :   // overflow-rect state for us.
     466             : 
     467           0 :   NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aMetrics);
     468             : }
     469             : 
     470             : nsresult
     471           0 : nsInlineFrame::AttributeChanged(int32_t aNameSpaceID,
     472             :                                 nsIAtom* aAttribute,
     473             :                                 int32_t aModType)
     474             : {
     475             :   nsresult rv =
     476           0 :     nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
     477             : 
     478           0 :   if (NS_FAILED(rv)) {
     479           0 :     return rv;
     480             :   }
     481             : 
     482           0 :   if (nsSVGUtils::IsInSVGTextSubtree(this)) {
     483             :     SVGTextFrame* f = static_cast<SVGTextFrame*>(
     484           0 :       nsLayoutUtils::GetClosestFrameOfType(this, LayoutFrameType::SVGText));
     485           0 :     f->HandleAttributeChangeInDescendant(mContent->AsElement(),
     486           0 :                                          aNameSpaceID, aAttribute);
     487             :   }
     488             : 
     489           0 :   return NS_OK;
     490             : }
     491             : 
     492             : bool
     493           0 : nsInlineFrame::DrainSelfOverflowListInternal(DrainFlags aFlags,
     494             :                                              nsIFrame* aLineContainer)
     495             : {
     496           0 :   AutoFrameListPtr overflowFrames(PresContext(), StealOverflowFrames());
     497           0 :   if (overflowFrames) {
     498             :     // The frames on our own overflowlist may have been pushed by a
     499             :     // previous lazilySetParentPointer Reflow so we need to ensure the
     500             :     // correct parent pointer.  This is sometimes skipped by Reflow.
     501           0 :     if (!(aFlags & eDontReparentFrames)) {
     502           0 :       nsIFrame* firstChild = overflowFrames->FirstChild();
     503           0 :       if (aLineContainer && aLineContainer->GetPrevContinuation()) {
     504           0 :         ReparentFloatsForInlineChild(aLineContainer, firstChild, true);
     505             :       }
     506             :       const bool doReparentSC =
     507           0 :         (aFlags & eInFirstLine) && !(aFlags & eForDestroy);
     508           0 :       RestyleManager* restyleManager = PresContext()->RestyleManager();
     509           0 :       for (nsIFrame* f = firstChild; f; f = f->GetNextSibling()) {
     510           0 :         f->SetParent(this);
     511           0 :         if (doReparentSC) {
     512           0 :           restyleManager->ReparentStyleContext(f);
     513           0 :           nsLayoutUtils::MarkDescendantsDirty(f);
     514             :         }
     515             :       }
     516             :     }
     517           0 :     bool result = !overflowFrames->IsEmpty();
     518           0 :     mFrames.AppendFrames(nullptr, *overflowFrames);
     519           0 :     return result;
     520             :   }
     521           0 :   return false;
     522             : }
     523             : 
     524             : /* virtual */ bool
     525           0 : nsInlineFrame::DrainSelfOverflowList()
     526             : {
     527           0 :   nsIFrame* lineContainer = nsLayoutUtils::FindNearestBlockAncestor(this);
     528             :   // Add the eInFirstLine flag if we have a ::first-line ancestor frame.
     529             :   // No need to look further than the nearest line container though.
     530           0 :   DrainFlags flags = DrainFlags(0);
     531           0 :   for (nsIFrame* p = GetParent(); p != lineContainer; p = p->GetParent()) {
     532           0 :     if (p->IsLineFrame()) {
     533           0 :       flags = DrainFlags(flags | eInFirstLine);
     534           0 :       break;
     535             :     }
     536             :   }
     537           0 :   return DrainSelfOverflowListInternal(flags, lineContainer);
     538             : }
     539             : 
     540             : /* virtual */ bool
     541           0 : nsInlineFrame::CanContinueTextRun() const
     542             : {
     543             :   // We can continue a text run through an inline frame
     544           0 :   return true;
     545             : }
     546             : 
     547             : /* virtual */ void
     548           0 : nsInlineFrame::PullOverflowsFromPrevInFlow()
     549             : {
     550           0 :   nsInlineFrame* prevInFlow = static_cast<nsInlineFrame*>(GetPrevInFlow());
     551           0 :   if (prevInFlow) {
     552           0 :     nsPresContext* presContext = PresContext();
     553             :     AutoFrameListPtr prevOverflowFrames(presContext,
     554           0 :                                         prevInFlow->StealOverflowFrames());
     555           0 :     if (prevOverflowFrames) {
     556             :       // Assume that our prev-in-flow has the same line container that we do.
     557           0 :       nsContainerFrame::ReparentFrameViewList(*prevOverflowFrames, prevInFlow,
     558           0 :                                               this);
     559           0 :       mFrames.InsertFrames(this, nullptr, *prevOverflowFrames);
     560             :     }
     561             :   }
     562           0 : }
     563             : 
     564             : void
     565           0 : nsInlineFrame::ReflowFrames(nsPresContext* aPresContext,
     566             :                             const ReflowInput& aReflowInput,
     567             :                             InlineReflowInput& irs,
     568             :                             ReflowOutput& aMetrics,
     569             :                             nsReflowStatus& aStatus)
     570             : {
     571           0 :   aStatus.Reset();
     572             : 
     573           0 :   nsLineLayout* lineLayout = aReflowInput.mLineLayout;
     574           0 :   bool inFirstLine = aReflowInput.mLineLayout->GetInFirstLine();
     575           0 :   RestyleManager* restyleManager = aPresContext->RestyleManager();
     576           0 :   WritingMode frameWM = aReflowInput.GetWritingMode();
     577           0 :   WritingMode lineWM = aReflowInput.mLineLayout->mRootSpan->mWritingMode;
     578           0 :   LogicalMargin framePadding = aReflowInput.ComputedLogicalBorderPadding();
     579           0 :   nscoord startEdge = 0;
     580             :   const bool boxDecorationBreakClone =
     581           0 :     MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak ==
     582             :                    StyleBoxDecorationBreak::Clone);
     583             :   // Don't offset by our start borderpadding if we have a prev continuation or
     584             :   // if we're in a part of an {ib} split other than the first one. For
     585             :   // box-decoration-break:clone we always offset our start since all
     586             :   // continuations have border/padding.
     587           0 :   if ((!GetPrevContinuation() && !FrameIsNonFirstInIBSplit()) ||
     588             :       boxDecorationBreakClone) {
     589           0 :     startEdge = framePadding.IStart(frameWM);
     590             :   }
     591           0 :   nscoord availableISize = aReflowInput.AvailableISize();
     592           0 :   NS_ASSERTION(availableISize != NS_UNCONSTRAINEDSIZE,
     593             :                "should no longer use available widths");
     594             :   // Subtract off inline axis border+padding from availableISize
     595           0 :   availableISize -= startEdge;
     596           0 :   availableISize -= framePadding.IEnd(frameWM);
     597           0 :   lineLayout->BeginSpan(this, &aReflowInput, startEdge,
     598           0 :                         startEdge + availableISize, &mBaseline);
     599             : 
     600             :   // First reflow our principal children.
     601           0 :   nsIFrame* frame = mFrames.FirstChild();
     602           0 :   bool done = false;
     603           0 :   while (frame) {
     604             :     // Check if we should lazily set the child frame's parent pointer.
     605           0 :     if (irs.mSetParentPointer) {
     606             :       bool havePrevBlock =
     607           0 :         irs.mLineContainer && irs.mLineContainer->GetPrevContinuation();
     608           0 :       nsIFrame* child = frame;
     609           0 :       do {
     610             :         // If our block is the first in flow, then any floats under the pulled
     611             :         // frame must already belong to our block.
     612           0 :         if (havePrevBlock) {
     613             :           // This has to happen before we update frame's parent; we need to
     614             :           // know frame's ancestry under its old block.
     615             :           // The blockChildren.ContainsFrame check performed by
     616             :           // ReparentFloatsForInlineChild here may be slow, but we can't
     617             :           // easily avoid it because we don't know where 'frame' originally
     618             :           // came from. If we really really have to optimize this we could
     619             :           // cache whether frame->GetParent() is under its containing blocks
     620             :           // overflowList or not.
     621           0 :           ReparentFloatsForInlineChild(irs.mLineContainer, child, false);
     622             :         }
     623           0 :         child->SetParent(this);
     624           0 :         if (inFirstLine) {
     625           0 :           restyleManager->ReparentStyleContext(child);
     626           0 :           nsLayoutUtils::MarkDescendantsDirty(child);
     627             :         }
     628             :         // We also need to do the same for |frame|'s next-in-flows that are in
     629             :         // the sibling list. Otherwise, if we reflow |frame| and it's complete
     630             :         // we'll crash when trying to delete its next-in-flow.
     631             :         // This scenario doesn't happen often, but it can happen.
     632           0 :         nsIFrame* nextSibling = child->GetNextSibling();
     633           0 :         child = child->GetNextInFlow();
     634           0 :         if (MOZ_UNLIKELY(child)) {
     635           0 :           while (child != nextSibling && nextSibling) {
     636           0 :             nextSibling = nextSibling->GetNextSibling();
     637             :           }
     638           0 :           if (!nextSibling) {
     639           0 :             child = nullptr;
     640             :           }
     641             :         }
     642           0 :         MOZ_ASSERT(!child || mFrames.ContainsFrame(child));
     643           0 :       } while (child);
     644             : 
     645             :       // Fix the parent pointer for ::first-letter child frame next-in-flows,
     646             :       // so nsFirstLetterFrame::Reflow can destroy them safely (bug 401042).
     647           0 :       nsIFrame* realFrame = nsPlaceholderFrame::GetRealFrameFor(frame);
     648           0 :       if (realFrame->IsLetterFrame()) {
     649           0 :         nsIFrame* child = realFrame->PrincipalChildList().FirstChild();
     650           0 :         if (child) {
     651           0 :           NS_ASSERTION(child->IsTextFrame(), "unexpected frame type");
     652           0 :           nsIFrame* nextInFlow = child->GetNextInFlow();
     653           0 :           for ( ; nextInFlow; nextInFlow = nextInFlow->GetNextInFlow()) {
     654           0 :             NS_ASSERTION(nextInFlow->IsTextFrame(), "unexpected frame type");
     655           0 :             if (mFrames.ContainsFrame(nextInFlow)) {
     656           0 :               nextInFlow->SetParent(this);
     657           0 :               if (inFirstLine) {
     658           0 :                 restyleManager->ReparentStyleContext(nextInFlow);
     659           0 :                 nsLayoutUtils::MarkDescendantsDirty(nextInFlow);
     660             :               }
     661             :             }
     662             :             else {
     663             : #ifdef DEBUG
     664             :               // Once we find a next-in-flow that isn't ours none of the
     665             :               // remaining next-in-flows should be either.
     666           0 :               for ( ; nextInFlow; nextInFlow = nextInFlow->GetNextInFlow()) {
     667           0 :                 NS_ASSERTION(!mFrames.ContainsFrame(nextInFlow),
     668             :                              "unexpected letter frame flow");
     669             :               }
     670             : #endif
     671           0 :               break;
     672             :             }
     673             :           }
     674             :         }
     675             :       }
     676             :     }
     677           0 :     MOZ_ASSERT(frame->GetParent() == this);
     678             : 
     679           0 :     if (!done) {
     680           0 :       bool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK();
     681           0 :       ReflowInlineFrame(aPresContext, aReflowInput, irs, frame, aStatus);
     682           0 :       done = aStatus.IsInlineBreak() ||
     683           0 :              (!reflowingFirstLetter && aStatus.IsIncomplete());
     684           0 :       if (done) {
     685           0 :         if (!irs.mSetParentPointer) {
     686           0 :           break;
     687             :         }
     688             :         // Keep reparenting the remaining siblings, but don't reflow them.
     689           0 :         nsFrameList* pushedFrames = GetOverflowFrames();
     690           0 :         if (pushedFrames && pushedFrames->FirstChild() == frame) {
     691             :           // Don't bother if |frame| was pushed to our overflow list.
     692           0 :           break;
     693             :         }
     694             :       } else {
     695           0 :         irs.mPrevFrame = frame;
     696             :       }
     697             :     }
     698           0 :     frame = frame->GetNextSibling();
     699             :   }
     700             : 
     701             :   // Attempt to pull frames from our next-in-flow until we can't
     702           0 :   if (!done && GetNextInFlow()) {
     703             :     while (true) {
     704           0 :       bool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK();
     705             :       bool isComplete;
     706           0 :       if (!frame) { // Could be non-null if we pulled a first-letter frame and
     707             :                     // it created a continuation, since we don't push those.
     708           0 :         frame = PullOneFrame(aPresContext, irs, &isComplete);
     709             :       }
     710             : #ifdef NOISY_PUSHING
     711             :       printf("%p pulled up %p\n", this, frame);
     712             : #endif
     713           0 :       if (nullptr == frame) {
     714           0 :         if (!isComplete) {
     715           0 :           aStatus.Reset();
     716           0 :           aStatus.SetIncomplete();
     717             :         }
     718           0 :         break;
     719             :       }
     720           0 :       ReflowInlineFrame(aPresContext, aReflowInput, irs, frame, aStatus);
     721           0 :       if (aStatus.IsInlineBreak() ||
     722           0 :           (!reflowingFirstLetter && aStatus.IsIncomplete())) {
     723           0 :         break;
     724             :       }
     725           0 :       irs.mPrevFrame = frame;
     726           0 :       frame = frame->GetNextSibling();
     727           0 :     }
     728             :   }
     729             : 
     730           0 :   NS_ASSERTION(!aStatus.IsComplete() || !GetOverflowFrames(),
     731             :                "We can't be complete AND have overflow frames!");
     732             : 
     733             :   // If after reflowing our children they take up no area then make
     734             :   // sure that we don't either.
     735             :   //
     736             :   // Note: CSS demands that empty inline elements still affect the
     737             :   // line-height calculations. However, continuations of an inline
     738             :   // that are empty we force to empty so that things like collapsed
     739             :   // whitespace in an inline element don't affect the line-height.
     740           0 :   aMetrics.ISize(lineWM) = lineLayout->EndSpan(this);
     741             : 
     742             :   // Compute final width.
     743             : 
     744             :   // XXX Note that that the padding start and end are in the frame's
     745             :   //     writing mode, but the metrics' inline-size is in the line's
     746             :   //     writing mode. This makes sense if the line and frame are both
     747             :   //     vertical or both horizontal, but what should happen with
     748             :   //     orthogonal inlines?
     749             : 
     750             :   // Make sure to not include our start border and padding if we have a prev
     751             :   // continuation or if we're in a part of an {ib} split other than the first
     752             :   // one.  For box-decoration-break:clone we always include our start border
     753             :   // and padding since all continuations have them.
     754           0 :   if ((!GetPrevContinuation() && !FrameIsNonFirstInIBSplit()) ||
     755             :       boxDecorationBreakClone) {
     756           0 :     aMetrics.ISize(lineWM) += framePadding.IStart(frameWM);
     757             :   }
     758             : 
     759             :   /*
     760             :    * We want to only apply the end border and padding if we're the last
     761             :    * continuation and either not in an {ib} split or the last part of it.  To
     762             :    * be the last continuation we have to be complete (so that we won't get a
     763             :    * next-in-flow) and have no non-fluid continuations on our continuation
     764             :    * chain.  For box-decoration-break:clone we always apply the end border and
     765             :    * padding since all continuations have them.
     766             :    */
     767           0 :   if ((aStatus.IsComplete() &&
     768           0 :        !LastInFlow()->GetNextContinuation() &&
     769           0 :        !FrameIsNonLastInIBSplit()) ||
     770             :       boxDecorationBreakClone) {
     771           0 :     aMetrics.ISize(lineWM) += framePadding.IEnd(frameWM);
     772             :   }
     773             : 
     774           0 :   nsLayoutUtils::SetBSizeFromFontMetrics(this, aMetrics,
     775           0 :                                          framePadding, lineWM, frameWM);
     776             : 
     777             :   // For now our overflow area is zero. The real value will be
     778             :   // computed in |nsLineLayout::RelativePositionFrames|.
     779           0 :   aMetrics.mOverflowAreas.Clear();
     780             : 
     781             : #ifdef NOISY_FINAL_SIZE
     782             :   ListTag(stdout);
     783             :   printf(": metrics=%d,%d ascent=%d\n",
     784             :          aMetrics.Width(), aMetrics.Height(), aMetrics.TopAscent());
     785             : #endif
     786           0 : }
     787             : 
     788             : void
     789           0 : nsInlineFrame::ReflowInlineFrame(nsPresContext* aPresContext,
     790             :                                  const ReflowInput& aReflowInput,
     791             :                                  InlineReflowInput& irs,
     792             :                                  nsIFrame* aFrame,
     793             :                                  nsReflowStatus& aStatus)
     794             : {
     795           0 :   nsLineLayout* lineLayout = aReflowInput.mLineLayout;
     796           0 :   bool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK();
     797             :   bool pushedFrame;
     798           0 :   lineLayout->ReflowFrame(aFrame, aStatus, nullptr, pushedFrame);
     799             : 
     800           0 :   if (aStatus.IsInlineBreakBefore()) {
     801           0 :     if (aFrame != mFrames.FirstChild()) {
     802             :       // Change break-before status into break-after since we have
     803             :       // already placed at least one child frame. This preserves the
     804             :       // break-type so that it can be propagated upward.
     805           0 :       StyleClear oldBreakType = aStatus.BreakType();
     806           0 :       aStatus.Reset();
     807           0 :       aStatus.SetIncomplete();
     808           0 :       aStatus.SetInlineLineBreakAfter(oldBreakType);
     809           0 :       PushFrames(aPresContext, aFrame, irs.mPrevFrame, irs);
     810             :     }
     811             :     else {
     812             :       // Preserve reflow status when breaking-before our first child
     813             :       // and propagate it upward without modification.
     814             :     }
     815           0 :     return;
     816             :   }
     817             : 
     818             :   // Create a next-in-flow if needed.
     819           0 :   if (!aStatus.IsFullyComplete()) {
     820           0 :     CreateNextInFlow(aFrame);
     821             :   }
     822             : 
     823           0 :   if (aStatus.IsInlineBreakAfter()) {
     824           0 :     nsIFrame* nextFrame = aFrame->GetNextSibling();
     825           0 :     if (nextFrame) {
     826           0 :       aStatus.SetIncomplete();
     827           0 :       PushFrames(aPresContext, nextFrame, aFrame, irs);
     828             :     }
     829             :     else {
     830             :       // We must return an incomplete status if there are more child
     831             :       // frames remaining in a next-in-flow that follows this frame.
     832           0 :       nsInlineFrame* nextInFlow = static_cast<nsInlineFrame*>(GetNextInFlow());
     833           0 :       while (nextInFlow) {
     834           0 :         if (nextInFlow->mFrames.NotEmpty()) {
     835           0 :           aStatus.SetIncomplete();
     836           0 :           break;
     837             :         }
     838           0 :         nextInFlow = static_cast<nsInlineFrame*>(nextInFlow->GetNextInFlow());
     839             :       }
     840             :     }
     841           0 :     return;
     842             :   }
     843             : 
     844           0 :   if (!aStatus.IsFullyComplete() && !reflowingFirstLetter) {
     845           0 :     nsIFrame* nextFrame = aFrame->GetNextSibling();
     846           0 :     if (nextFrame) {
     847           0 :       PushFrames(aPresContext, nextFrame, aFrame, irs);
     848             :     }
     849             :   }
     850             : }
     851             : 
     852             : nsIFrame*
     853           0 : nsInlineFrame::PullOneFrame(nsPresContext* aPresContext,
     854             :                             InlineReflowInput& irs,
     855             :                             bool* aIsComplete)
     856             : {
     857           0 :   bool isComplete = true;
     858             : 
     859           0 :   nsIFrame* frame = nullptr;
     860           0 :   nsInlineFrame* nextInFlow = irs.mNextInFlow;
     861           0 :   while (nextInFlow) {
     862           0 :     frame = nextInFlow->mFrames.FirstChild();
     863           0 :     if (!frame) {
     864             :       // The nextInFlow's principal list has no frames, try its overflow list.
     865           0 :       nsFrameList* overflowFrames = nextInFlow->GetOverflowFrames();
     866           0 :       if (overflowFrames) {
     867           0 :         frame = overflowFrames->RemoveFirstChild();
     868           0 :         if (overflowFrames->IsEmpty()) {
     869             :           // We're stealing the only frame - delete the overflow list.
     870           0 :           nextInFlow->DestroyOverflowList();
     871             :         } else {
     872             :           // We leave the remaining frames on the overflow list (rather than
     873             :           // putting them on nextInFlow's principal list) so we don't have to
     874             :           // set up the parent for them.
     875             :         }
     876             :         // ReparentFloatsForInlineChild needs it to be on a child list -
     877             :         // we remove it again below.
     878           0 :         nextInFlow->mFrames.SetFrames(frame);
     879             :       }
     880             :     }
     881             : 
     882           0 :     if (frame) {
     883             :       // If our block has no next continuation, then any floats belonging to
     884             :       // the pulled frame must belong to our block already. This check ensures
     885             :       // we do no extra work in the common non-vertical-breaking case.
     886           0 :       if (irs.mLineContainer && irs.mLineContainer->GetNextContinuation()) {
     887             :         // The blockChildren.ContainsFrame check performed by
     888             :         // ReparentFloatsForInlineChild will be fast because frame's ancestor
     889             :         // will be the first child of its containing block.
     890           0 :         ReparentFloatsForInlineChild(irs.mLineContainer, frame, false);
     891             :       }
     892           0 :       nextInFlow->mFrames.RemoveFirstChild();
     893             :       // nsFirstLineFrame::PullOneFrame calls ReparentStyleContext.
     894             : 
     895           0 :       mFrames.InsertFrame(this, irs.mPrevFrame, frame);
     896           0 :       isComplete = false;
     897           0 :       if (irs.mLineLayout) {
     898           0 :         irs.mLineLayout->SetDirtyNextLine();
     899             :       }
     900           0 :       nsContainerFrame::ReparentFrameView(frame, nextInFlow, this);
     901           0 :       break;
     902             :     }
     903           0 :     nextInFlow = static_cast<nsInlineFrame*>(nextInFlow->GetNextInFlow());
     904           0 :     irs.mNextInFlow = nextInFlow;
     905             :   }
     906             : 
     907           0 :   *aIsComplete = isComplete;
     908           0 :   return frame;
     909             : }
     910             : 
     911             : void
     912           0 : nsInlineFrame::PushFrames(nsPresContext* aPresContext,
     913             :                           nsIFrame* aFromChild,
     914             :                           nsIFrame* aPrevSibling,
     915             :                           InlineReflowInput& aState)
     916             : {
     917           0 :   NS_PRECONDITION(aFromChild, "null pointer");
     918           0 :   NS_PRECONDITION(aPrevSibling, "pushing first child");
     919           0 :   NS_PRECONDITION(aPrevSibling->GetNextSibling() == aFromChild, "bad prev sibling");
     920             : 
     921             : #ifdef NOISY_PUSHING
     922             :   printf("%p pushing aFromChild %p, disconnecting from prev sib %p\n",
     923             :          this, aFromChild, aPrevSibling);
     924             : #endif
     925             : 
     926             :   // Add the frames to our overflow list (let our next in flow drain
     927             :   // our overflow list when it is ready)
     928           0 :   SetOverflowFrames(mFrames.RemoveFramesAfter(aPrevSibling));
     929           0 :   if (aState.mLineLayout) {
     930           0 :     aState.mLineLayout->SetDirtyNextLine();
     931             :   }
     932           0 : }
     933             : 
     934             : 
     935             : //////////////////////////////////////////////////////////////////////
     936             : 
     937             : nsIFrame::LogicalSides
     938           0 : nsInlineFrame::GetLogicalSkipSides(const ReflowInput* aReflowInput) const
     939             : {
     940           0 :   if (MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak ==
     941             :                      StyleBoxDecorationBreak::Clone)) {
     942           0 :     return LogicalSides();
     943             :   }
     944             : 
     945           0 :   LogicalSides skip;
     946           0 :   if (!IsFirst()) {
     947           0 :     nsInlineFrame* prev = (nsInlineFrame*) GetPrevContinuation();
     948           0 :     if ((GetStateBits() & NS_INLINE_FRAME_BIDI_VISUAL_STATE_IS_SET) ||
     949           0 :         (prev && (prev->mRect.height || prev->mRect.width))) {
     950             :       // Prev continuation is not empty therefore we don't render our start
     951             :       // border edge.
     952           0 :       skip |= eLogicalSideBitsIStart;
     953             :     }
     954             :     else {
     955             :       // If the prev continuation is empty, then go ahead and let our start
     956             :       // edge border render.
     957             :     }
     958             :   }
     959           0 :   if (!IsLast()) {
     960           0 :     nsInlineFrame* next = (nsInlineFrame*) GetNextContinuation();
     961           0 :     if ((GetStateBits() & NS_INLINE_FRAME_BIDI_VISUAL_STATE_IS_SET) ||
     962           0 :         (next && (next->mRect.height || next->mRect.width))) {
     963             :       // Next continuation is not empty therefore we don't render our end
     964             :       // border edge.
     965           0 :       skip |= eLogicalSideBitsIEnd;
     966             :     }
     967             :     else {
     968             :       // If the next continuation is empty, then go ahead and let our end
     969             :       // edge border render.
     970             :     }
     971             :   }
     972             : 
     973           0 :   if (GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) {
     974             :     // All but the last part of an {ib} split should skip the "end" side (as
     975             :     // determined by this frame's direction) and all but the first part of such
     976             :     // a split should skip the "start" side.  But figuring out which part of
     977             :     // the split we are involves getting our first continuation, which might be
     978             :     // expensive.  So don't bother if we already have the relevant bits set.
     979           0 :     if (skip != LogicalSides(eLogicalSideBitsIBoth)) {
     980             :       // We're missing one of the skip bits, so check whether we need to set it.
     981             :       // Only get the first continuation once, as an optimization.
     982           0 :       nsIFrame* firstContinuation = FirstContinuation();
     983           0 :       if (firstContinuation->FrameIsNonLastInIBSplit()) {
     984           0 :         skip |= eLogicalSideBitsIEnd;
     985             :       }
     986           0 :       if (firstContinuation->FrameIsNonFirstInIBSplit()) {
     987           0 :         skip |= eLogicalSideBitsIStart;
     988             :       }
     989             :     }
     990             :   }
     991             : 
     992           0 :   return skip;
     993             : }
     994             : 
     995             : nscoord
     996           0 : nsInlineFrame::GetLogicalBaseline(mozilla::WritingMode aWritingMode) const
     997             : {
     998           0 :   return mBaseline;
     999             : }
    1000             : 
    1001             : #ifdef ACCESSIBILITY
    1002             : a11y::AccType
    1003           0 : nsInlineFrame::AccessibleType()
    1004             : {
    1005             :   // Broken image accessibles are created here, because layout
    1006             :   // replaces the image or image control frame with an inline frame
    1007           0 :   if (mContent->IsHTMLElement(nsGkAtoms::input))  // Broken <input type=image ... />
    1008           0 :     return a11y::eHTMLButtonType;
    1009           0 :   if (mContent->IsHTMLElement(nsGkAtoms::img))  // Create accessible for broken <img>
    1010           0 :     return a11y::eHyperTextType;
    1011             : 
    1012           0 :   return a11y::eNoType;
    1013             : }
    1014             : #endif
    1015             : 
    1016             : void
    1017           0 : nsInlineFrame::UpdateStyleOfOwnedAnonBoxesForIBSplit(
    1018             :   ServoRestyleState& aRestyleState)
    1019             : {
    1020           0 :   MOZ_ASSERT(GetStateBits() & NS_FRAME_OWNS_ANON_BOXES,
    1021             :              "Why did we get called?");
    1022           0 :   MOZ_ASSERT(GetStateBits() & NS_FRAME_PART_OF_IBSPLIT,
    1023             :              "Why did we have the NS_FRAME_OWNS_ANON_BOXES bit set?");
    1024             :   // Note: this assert _looks_ expensive, but it's cheap in all the cases when
    1025             :   // it passes!
    1026           0 :   MOZ_ASSERT(nsLayoutUtils::FirstContinuationOrIBSplitSibling(this) == this,
    1027             :              "Only the primary frame of the inline in a block-inside-inline "
    1028             :              "split should have NS_FRAME_OWNS_ANON_BOXES");
    1029           0 :   MOZ_ASSERT(mContent->GetPrimaryFrame() == this,
    1030             :              "We should be the primary frame for our element");
    1031             : 
    1032           0 :   nsIFrame* blockFrame = GetProperty(nsIFrame::IBSplitSibling());
    1033           0 :   MOZ_ASSERT(blockFrame, "Why did we have an IB split?");
    1034             : 
    1035             :   // The later inlines need to get our style.
    1036           0 :   nsStyleContext* ourStyle = StyleContext();
    1037             : 
    1038             :   // The anonymous block's style inherits from ours, and we already have our new
    1039             :   // style context.
    1040             :   RefPtr<nsStyleContext> newContext =
    1041           0 :     aRestyleState.StyleSet().ResolveInheritingAnonymousBoxStyle(
    1042           0 :       nsCSSAnonBoxes::mozBlockInsideInlineWrapper, ourStyle);
    1043             : 
    1044             :   // We're guaranteed that newContext only differs from the old style context on
    1045             :   // the block in things they might inherit from us.  And changehint processing
    1046             :   // guarantees walking the continuation and ib-sibling chains, so our existing
    1047             :   // changehint being in aChangeList is good enough.  So we don't need to touch
    1048             :   // aChangeList at all here.
    1049             : 
    1050           0 :   while (blockFrame) {
    1051           0 :     MOZ_ASSERT(!blockFrame->GetPrevContinuation(),
    1052             :                "Must be first continuation");
    1053             : 
    1054           0 :     MOZ_ASSERT(blockFrame->StyleContext()->GetPseudo() ==
    1055             :                nsCSSAnonBoxes::mozBlockInsideInlineWrapper,
    1056             :                "Unexpected kind of style context");
    1057             : 
    1058             :     // We don't want to just walk through using GetNextContinuationWithSameStyle
    1059             :     // here, because we want to set updated style contexts on both our
    1060             :     // ib-sibling blocks and inlines.
    1061           0 :     for (nsIFrame* cont = blockFrame; cont; cont = cont->GetNextContinuation()) {
    1062           0 :       cont->SetStyleContext(newContext);
    1063             :     }
    1064             : 
    1065           0 :     nsIFrame* nextInline = blockFrame->GetProperty(nsIFrame::IBSplitSibling());
    1066           0 :     MOZ_ASSERT(nextInline, "There is always a trailing inline in an IB split");
    1067             : 
    1068           0 :     for (nsIFrame* cont = nextInline; cont; cont = cont->GetNextContinuation()) {
    1069           0 :       cont->SetStyleContext(ourStyle);
    1070             :     }
    1071           0 :     blockFrame = nextInline->GetProperty(nsIFrame::IBSplitSibling());
    1072             :   }
    1073           0 : }
    1074             : 
    1075             : //////////////////////////////////////////////////////////////////////
    1076             : 
    1077             : // nsLineFrame implementation
    1078             : 
    1079             : nsFirstLineFrame*
    1080           0 : NS_NewFirstLineFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
    1081             : {
    1082           0 :   return new (aPresShell) nsFirstLineFrame(aContext);
    1083             : }
    1084             : 
    1085           0 : NS_IMPL_FRAMEARENA_HELPERS(nsFirstLineFrame)
    1086             : 
    1087             : void
    1088           0 : nsFirstLineFrame::Init(nsIContent*       aContent,
    1089             :                        nsContainerFrame* aParent,
    1090             :                        nsIFrame*         aPrevInFlow)
    1091             : {
    1092           0 :   nsInlineFrame::Init(aContent, aParent, aPrevInFlow);
    1093           0 :   if (!aPrevInFlow) {
    1094           0 :     MOZ_ASSERT(StyleContext()->GetPseudo() == nsCSSPseudoElements::firstLine);
    1095           0 :     return;
    1096             :   }
    1097             : 
    1098             :   // This frame is a continuation - fixup the style context if aPrevInFlow
    1099             :   // is the first-in-flow (the only one with a ::first-line pseudo).
    1100           0 :   if (aPrevInFlow->StyleContext()->GetPseudo() == nsCSSPseudoElements::firstLine) {
    1101           0 :     MOZ_ASSERT(FirstInFlow() == aPrevInFlow);
    1102             :     // Create a new style context that is a child of the parent
    1103             :     // style context thus removing the ::first-line style. This way
    1104             :     // we behave as if an anonymous (unstyled) span was the child
    1105             :     // of the parent frame.
    1106           0 :     nsStyleContext* parentContext = aParent->StyleContext();
    1107           0 :     RefPtr<nsStyleContext> newSC = PresContext()->StyleSet()->
    1108           0 :       ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::mozLineFrame,
    1109           0 :                                          parentContext);
    1110           0 :     SetStyleContext(newSC);
    1111             :   } else {
    1112           0 :     MOZ_ASSERT(FirstInFlow() != aPrevInFlow);
    1113           0 :     MOZ_ASSERT(aPrevInFlow->StyleContext()->GetPseudo() ==
    1114             :                  nsCSSAnonBoxes::mozLineFrame);
    1115             :   }
    1116             : }
    1117             : 
    1118             : #ifdef DEBUG_FRAME_DUMP
    1119             : nsresult
    1120           0 : nsFirstLineFrame::GetFrameName(nsAString& aResult) const
    1121             : {
    1122           0 :   return MakeFrameName(NS_LITERAL_STRING("Line"), aResult);
    1123             : }
    1124             : #endif
    1125             : 
    1126             : nsIFrame*
    1127           0 : nsFirstLineFrame::PullOneFrame(nsPresContext* aPresContext, InlineReflowInput& irs,
    1128             :                                bool* aIsComplete)
    1129             : {
    1130           0 :   nsIFrame* frame = nsInlineFrame::PullOneFrame(aPresContext, irs, aIsComplete);
    1131           0 :   if (frame && !GetPrevInFlow()) {
    1132             :     // We are a first-line frame. Fixup the child frames
    1133             :     // style-context that we just pulled.
    1134           0 :     NS_ASSERTION(frame->GetParent() == this, "Incorrect parent?");
    1135           0 :     aPresContext->RestyleManager()->ReparentStyleContext(frame);
    1136           0 :     nsLayoutUtils::MarkDescendantsDirty(frame);
    1137             :   }
    1138           0 :   return frame;
    1139             : }
    1140             : 
    1141             : void
    1142           0 : nsFirstLineFrame::Reflow(nsPresContext* aPresContext,
    1143             :                          ReflowOutput& aMetrics,
    1144             :                          const ReflowInput& aReflowInput,
    1145             :                          nsReflowStatus& aStatus)
    1146             : {
    1147           0 :   MarkInReflow();
    1148           0 :   if (nullptr == aReflowInput.mLineLayout) {
    1149           0 :     return;  // XXX does this happen? why?
    1150             :   }
    1151             : 
    1152           0 :   nsIFrame* lineContainer = aReflowInput.mLineLayout->LineContainerFrame();
    1153             : 
    1154             :   // Check for an overflow list with our prev-in-flow
    1155           0 :   nsFirstLineFrame* prevInFlow = (nsFirstLineFrame*)GetPrevInFlow();
    1156           0 :   if (prevInFlow) {
    1157             :     AutoFrameListPtr prevOverflowFrames(aPresContext,
    1158           0 :                                         prevInFlow->StealOverflowFrames());
    1159           0 :     if (prevOverflowFrames) {
    1160             :       // Assign all floats to our block if necessary
    1161           0 :       if (lineContainer && lineContainer->GetPrevContinuation()) {
    1162           0 :         ReparentFloatsForInlineChild(lineContainer,
    1163             :                                      prevOverflowFrames->FirstChild(),
    1164           0 :                                      true);
    1165             :       }
    1166             :       const nsFrameList::Slice& newFrames =
    1167           0 :         mFrames.InsertFrames(this, nullptr, *prevOverflowFrames);
    1168           0 :       ReparentChildListStyle(aPresContext, newFrames, this);
    1169             :     }
    1170             :   }
    1171             : 
    1172             :   // It's also possible that we have an overflow list for ourselves.
    1173           0 :   DrainSelfOverflowList();
    1174             : 
    1175             :   // Set our own reflow state (additional state above and beyond
    1176             :   // aReflowInput)
    1177           0 :   InlineReflowInput irs;
    1178           0 :   irs.mPrevFrame = nullptr;
    1179           0 :   irs.mLineContainer = lineContainer;
    1180           0 :   irs.mLineLayout = aReflowInput.mLineLayout;
    1181           0 :   irs.mNextInFlow = (nsInlineFrame*) GetNextInFlow();
    1182             : 
    1183           0 :   bool wasEmpty = mFrames.IsEmpty();
    1184           0 :   if (wasEmpty) {
    1185             :     // Try to pull over one frame before starting so that we know
    1186             :     // whether we have an anonymous block or not.
    1187             :     bool complete;
    1188           0 :     PullOneFrame(aPresContext, irs, &complete);
    1189             :   }
    1190             : 
    1191           0 :   if (nullptr == GetPrevInFlow()) {
    1192             :     // XXX This is pretty sick, but what we do here is to pull-up, in
    1193             :     // advance, all of the next-in-flows children. We re-resolve their
    1194             :     // style while we are at at it so that when we reflow they have
    1195             :     // the right style.
    1196             :     //
    1197             :     // All of this is so that text-runs reflow properly.
    1198           0 :     irs.mPrevFrame = mFrames.LastChild();
    1199             :     for (;;) {
    1200             :       bool complete;
    1201           0 :       nsIFrame* frame = PullOneFrame(aPresContext, irs, &complete);
    1202           0 :       if (!frame) {
    1203           0 :         break;
    1204             :       }
    1205           0 :       irs.mPrevFrame = frame;
    1206           0 :     }
    1207           0 :     irs.mPrevFrame = nullptr;
    1208             :   }
    1209             : 
    1210           0 :   NS_ASSERTION(!aReflowInput.mLineLayout->GetInFirstLine(),
    1211             :                "Nested first-line frames? BOGUS");
    1212           0 :   aReflowInput.mLineLayout->SetInFirstLine(true);
    1213           0 :   ReflowFrames(aPresContext, aReflowInput, irs, aMetrics, aStatus);
    1214           0 :   aReflowInput.mLineLayout->SetInFirstLine(false);
    1215             : 
    1216           0 :   ReflowAbsoluteFrames(aPresContext, aMetrics, aReflowInput, aStatus);
    1217             : 
    1218             :   // Note: the line layout code will properly compute our overflow state for us
    1219             : }
    1220             : 
    1221             : /* virtual */ void
    1222           0 : nsFirstLineFrame::PullOverflowsFromPrevInFlow()
    1223             : {
    1224           0 :   nsFirstLineFrame* prevInFlow = static_cast<nsFirstLineFrame*>(GetPrevInFlow());
    1225           0 :   if (prevInFlow) {
    1226           0 :     nsPresContext* presContext = PresContext();
    1227             :     AutoFrameListPtr prevOverflowFrames(presContext,
    1228           0 :                                         prevInFlow->StealOverflowFrames());
    1229           0 :     if (prevOverflowFrames) {
    1230             :       // Assume that our prev-in-flow has the same line container that we do.
    1231             :       const nsFrameList::Slice& newFrames =
    1232           0 :         mFrames.InsertFrames(this, nullptr, *prevOverflowFrames);
    1233           0 :       ReparentChildListStyle(presContext, newFrames, this);
    1234             :     }
    1235             :   }
    1236           0 : }
    1237             : 
    1238             : /* virtual */ bool
    1239           0 : nsFirstLineFrame::DrainSelfOverflowList()
    1240             : {
    1241           0 :   AutoFrameListPtr overflowFrames(PresContext(), StealOverflowFrames());
    1242           0 :   if (overflowFrames) {
    1243           0 :     bool result = !overflowFrames->IsEmpty();
    1244             :     const nsFrameList::Slice& newFrames =
    1245           0 :       mFrames.AppendFrames(nullptr, *overflowFrames);
    1246           0 :     ReparentChildListStyle(PresContext(), newFrames, this);
    1247           0 :     return result;
    1248             :   }
    1249           0 :   return false;
    1250             : }

Generated by: LCOV version 1.13