layout/generic/nsInlineFrame.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/layout/generic/nsInlineFrame.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1130 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +/* rendering object for CSS display:inline objects */
    1.10 +
    1.11 +#include "nsInlineFrame.h"
    1.12 +#include "nsLineLayout.h"
    1.13 +#include "nsBlockFrame.h"
    1.14 +#include "nsPlaceholderFrame.h"
    1.15 +#include "nsGkAtoms.h"
    1.16 +#include "nsStyleContext.h"
    1.17 +#include "nsPresContext.h"
    1.18 +#include "nsRenderingContext.h"
    1.19 +#include "nsCSSAnonBoxes.h"
    1.20 +#include "nsAutoPtr.h"
    1.21 +#include "RestyleManager.h"
    1.22 +#include "nsDisplayList.h"
    1.23 +#include "mozilla/Likely.h"
    1.24 +
    1.25 +#ifdef DEBUG
    1.26 +#undef NOISY_PUSHING
    1.27 +#endif
    1.28 +
    1.29 +using namespace mozilla;
    1.30 +using namespace mozilla::layout;
    1.31 +
    1.32 +
    1.33 +//////////////////////////////////////////////////////////////////////
    1.34 +
    1.35 +// Basic nsInlineFrame methods
    1.36 +
    1.37 +nsIFrame*
    1.38 +NS_NewInlineFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
    1.39 +{
    1.40 +  return new (aPresShell) nsInlineFrame(aContext);
    1.41 +}
    1.42 +
    1.43 +NS_IMPL_FRAMEARENA_HELPERS(nsInlineFrame)
    1.44 +
    1.45 +NS_QUERYFRAME_HEAD(nsInlineFrame)
    1.46 +  NS_QUERYFRAME_ENTRY(nsInlineFrame)
    1.47 +NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
    1.48 +
    1.49 +#ifdef DEBUG_FRAME_DUMP
    1.50 +nsresult
    1.51 +nsInlineFrame::GetFrameName(nsAString& aResult) const
    1.52 +{
    1.53 +  return MakeFrameName(NS_LITERAL_STRING("Inline"), aResult);
    1.54 +}
    1.55 +#endif
    1.56 +
    1.57 +nsIAtom*
    1.58 +nsInlineFrame::GetType() const
    1.59 +{
    1.60 +  return nsGkAtoms::inlineFrame;
    1.61 +}
    1.62 +
    1.63 +void
    1.64 +nsInlineFrame::InvalidateFrame(uint32_t aDisplayItemKey)
    1.65 +{
    1.66 +  if (IsSVGText()) {
    1.67 +    nsIFrame* svgTextFrame =
    1.68 +      nsLayoutUtils::GetClosestFrameOfType(GetParent(),
    1.69 +                                           nsGkAtoms::svgTextFrame);
    1.70 +    svgTextFrame->InvalidateFrame();
    1.71 +    return;
    1.72 +  }
    1.73 +  nsInlineFrameBase::InvalidateFrame(aDisplayItemKey);
    1.74 +}
    1.75 +
    1.76 +void
    1.77 +nsInlineFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey)
    1.78 +{
    1.79 +  if (IsSVGText()) {
    1.80 +    nsIFrame* svgTextFrame =
    1.81 +      nsLayoutUtils::GetClosestFrameOfType(GetParent(),
    1.82 +                                           nsGkAtoms::svgTextFrame);
    1.83 +    svgTextFrame->InvalidateFrame();
    1.84 +    return;
    1.85 +  }
    1.86 +  nsInlineFrameBase::InvalidateFrameWithRect(aRect, aDisplayItemKey);
    1.87 +}
    1.88 +
    1.89 +static inline bool
    1.90 +IsMarginZero(const nsStyleCoord &aCoord)
    1.91 +{
    1.92 +  return aCoord.GetUnit() == eStyleUnit_Auto ||
    1.93 +         nsLayoutUtils::IsMarginZero(aCoord);
    1.94 +}
    1.95 +
    1.96 +/* virtual */ bool
    1.97 +nsInlineFrame::IsSelfEmpty()
    1.98 +{
    1.99 +#if 0
   1.100 +  // I used to think inline frames worked this way, but it seems they
   1.101 +  // don't.  At least not in our codebase.
   1.102 +  if (GetPresContext()->CompatibilityMode() == eCompatibility_FullStandards) {
   1.103 +    return false;
   1.104 +  }
   1.105 +#endif
   1.106 +  const nsStyleMargin* margin = StyleMargin();
   1.107 +  const nsStyleBorder* border = StyleBorder();
   1.108 +  const nsStylePadding* padding = StylePadding();
   1.109 +  // XXX Top and bottom removed, since they shouldn't affect things, but this
   1.110 +  // doesn't really match with nsLineLayout.cpp's setting of
   1.111 +  // ZeroEffectiveSpanBox, anymore, so what should this really be?
   1.112 +  bool haveRight =
   1.113 +    border->GetComputedBorderWidth(NS_SIDE_RIGHT) != 0 ||
   1.114 +    !nsLayoutUtils::IsPaddingZero(padding->mPadding.GetRight()) ||
   1.115 +    !IsMarginZero(margin->mMargin.GetRight());
   1.116 +  bool haveLeft =
   1.117 +    border->GetComputedBorderWidth(NS_SIDE_LEFT) != 0 ||
   1.118 +    !nsLayoutUtils::IsPaddingZero(padding->mPadding.GetLeft()) ||
   1.119 +    !IsMarginZero(margin->mMargin.GetLeft());
   1.120 +  if (haveLeft || haveRight) {
   1.121 +    if (GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) {
   1.122 +      bool haveStart, haveEnd;
   1.123 +      if (NS_STYLE_DIRECTION_LTR == StyleVisibility()->mDirection) {
   1.124 +        haveStart = haveLeft;
   1.125 +        haveEnd = haveRight;
   1.126 +      } else {
   1.127 +        haveStart = haveRight;
   1.128 +        haveEnd = haveLeft;
   1.129 +      }
   1.130 +      // For ib-split frames, ignore things we know we'll skip in GetSkipSides.
   1.131 +      // XXXbz should we be doing this for non-ib-split frames too, in a more
   1.132 +      // general way?
   1.133 +
   1.134 +      // Get the first continuation eagerly, as a performance optimization, to
   1.135 +      // avoid having to get it twice..
   1.136 +      nsIFrame* firstCont = FirstContinuation();
   1.137 +      return
   1.138 +        (!haveStart || firstCont->FrameIsNonFirstInIBSplit()) &&
   1.139 +        (!haveEnd || firstCont->FrameIsNonLastInIBSplit());
   1.140 +    }
   1.141 +    return false;
   1.142 +  }
   1.143 +  return true;
   1.144 +}
   1.145 +
   1.146 +bool
   1.147 +nsInlineFrame::IsEmpty()
   1.148 +{
   1.149 +  if (!IsSelfEmpty()) {
   1.150 +    return false;
   1.151 +  }
   1.152 +
   1.153 +  for (nsIFrame *kid = mFrames.FirstChild(); kid; kid = kid->GetNextSibling()) {
   1.154 +    if (!kid->IsEmpty())
   1.155 +      return false;
   1.156 +  }
   1.157 +
   1.158 +  return true;
   1.159 +}
   1.160 +
   1.161 +nsIFrame::FrameSearchResult
   1.162 +nsInlineFrame::PeekOffsetCharacter(bool aForward, int32_t* aOffset,
   1.163 +                                   bool aRespectClusters)
   1.164 +{
   1.165 +  // Override the implementation in nsFrame, to skip empty inline frames
   1.166 +  NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
   1.167 +  int32_t startOffset = *aOffset;
   1.168 +  if (startOffset < 0)
   1.169 +    startOffset = 1;
   1.170 +  if (aForward == (startOffset == 0)) {
   1.171 +    // We're before the frame and moving forward, or after it and moving backwards:
   1.172 +    // skip to the other side, but keep going.
   1.173 +    *aOffset = 1 - startOffset;
   1.174 +  }
   1.175 +  return CONTINUE;
   1.176 +}
   1.177 +
   1.178 +void
   1.179 +nsInlineFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
   1.180 +                                const nsRect&           aDirtyRect,
   1.181 +                                const nsDisplayListSet& aLists)
   1.182 +{
   1.183 +  BuildDisplayListForInline(aBuilder, aDirtyRect, aLists);
   1.184 +
   1.185 +  // The sole purpose of this is to trigger display of the selection
   1.186 +  // window for Named Anchors, which don't have any children and
   1.187 +  // normally don't have any size, but in Editor we use CSS to display
   1.188 +  // an image to represent this "hidden" element.
   1.189 +  if (!mFrames.FirstChild()) {
   1.190 +    DisplaySelectionOverlay(aBuilder, aLists.Content());
   1.191 +  }
   1.192 +}
   1.193 +
   1.194 +//////////////////////////////////////////////////////////////////////
   1.195 +// Reflow methods
   1.196 +
   1.197 +/* virtual */ void
   1.198 +nsInlineFrame::AddInlineMinWidth(nsRenderingContext *aRenderingContext,
   1.199 +                                 nsIFrame::InlineMinWidthData *aData)
   1.200 +{
   1.201 +  DoInlineIntrinsicWidth(aRenderingContext, aData, nsLayoutUtils::MIN_WIDTH);
   1.202 +}
   1.203 +
   1.204 +/* virtual */ void
   1.205 +nsInlineFrame::AddInlinePrefWidth(nsRenderingContext *aRenderingContext,
   1.206 +                                  nsIFrame::InlinePrefWidthData *aData)
   1.207 +{
   1.208 +  DoInlineIntrinsicWidth(aRenderingContext, aData, nsLayoutUtils::PREF_WIDTH);
   1.209 +}
   1.210 +
   1.211 +/* virtual */ nsSize
   1.212 +nsInlineFrame::ComputeSize(nsRenderingContext *aRenderingContext,
   1.213 +                           nsSize aCBSize, nscoord aAvailableWidth,
   1.214 +                           nsSize aMargin, nsSize aBorder, nsSize aPadding,
   1.215 +                           uint32_t aFlags)
   1.216 +{
   1.217 +  // Inlines and text don't compute size before reflow.
   1.218 +  return nsSize(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
   1.219 +}
   1.220 +
   1.221 +nsRect
   1.222 +nsInlineFrame::ComputeTightBounds(gfxContext* aContext) const
   1.223 +{
   1.224 +  // be conservative
   1.225 +  if (StyleContext()->HasTextDecorationLines()) {
   1.226 +    return GetVisualOverflowRect();
   1.227 +  }
   1.228 +  return ComputeSimpleTightBounds(aContext);
   1.229 +}
   1.230 +
   1.231 +void
   1.232 +nsInlineFrame::ReparentFloatsForInlineChild(nsIFrame* aOurLineContainer,
   1.233 +                                            nsIFrame* aFrame,
   1.234 +                                            bool aReparentSiblings)
   1.235 +{
   1.236 +  // XXXbz this would be better if it took a nsFrameList or a frame
   1.237 +  // list slice....
   1.238 +  NS_ASSERTION(aOurLineContainer->GetNextContinuation() ||
   1.239 +               aOurLineContainer->GetPrevContinuation(),
   1.240 +               "Don't call this when we have no continuation, it's a waste");
   1.241 +  if (!aFrame) {
   1.242 +    NS_ASSERTION(aReparentSiblings, "Why did we get called?");
   1.243 +    return;
   1.244 +  }
   1.245 +
   1.246 +  nsIFrame* ancestor = aFrame;
   1.247 +  do {
   1.248 +    ancestor = ancestor->GetParent();
   1.249 +    if (!ancestor)
   1.250 +      return;
   1.251 +  } while (!ancestor->IsFloatContainingBlock());
   1.252 +
   1.253 +  if (ancestor == aOurLineContainer)
   1.254 +    return;
   1.255 +
   1.256 +  nsBlockFrame* ourBlock = nsLayoutUtils::GetAsBlock(aOurLineContainer);
   1.257 +  NS_ASSERTION(ourBlock, "Not a block, but broke vertically?");
   1.258 +  nsBlockFrame* frameBlock = nsLayoutUtils::GetAsBlock(ancestor);
   1.259 +  NS_ASSERTION(frameBlock, "ancestor not a block");
   1.260 +
   1.261 +  while (true) {
   1.262 +    ourBlock->ReparentFloats(aFrame, frameBlock, false);
   1.263 +
   1.264 +    if (!aReparentSiblings)
   1.265 +      return;
   1.266 +    nsIFrame* next = aFrame->GetNextSibling();
   1.267 +    if (!next)
   1.268 +      return;
   1.269 +    if (next->GetParent() == aFrame->GetParent()) {
   1.270 +      aFrame = next;
   1.271 +      continue;
   1.272 +    }
   1.273 +    // This is paranoid and will hardly ever get hit ... but we can't actually
   1.274 +    // trust that the frames in the sibling chain all have the same parent,
   1.275 +    // because lazy reparenting may be going on. If we find a different
   1.276 +    // parent we need to redo our analysis.
   1.277 +    ReparentFloatsForInlineChild(aOurLineContainer, next, aReparentSiblings);
   1.278 +    return;
   1.279 +  }
   1.280 +}
   1.281 +
   1.282 +static void
   1.283 +ReparentChildListStyle(nsPresContext* aPresContext,
   1.284 +                       const nsFrameList::Slice& aFrames,
   1.285 +                       nsIFrame* aParentFrame)
   1.286 +{
   1.287 +  RestyleManager* restyleManager = aPresContext->RestyleManager();
   1.288 +
   1.289 +  for (nsFrameList::Enumerator e(aFrames); !e.AtEnd(); e.Next()) {
   1.290 +    NS_ASSERTION(e.get()->GetParent() == aParentFrame, "Bogus parentage");
   1.291 +    restyleManager->ReparentStyleContext(e.get());
   1.292 +    nsLayoutUtils::MarkDescendantsDirty(e.get());
   1.293 +  }
   1.294 +}
   1.295 +
   1.296 +nsresult
   1.297 +nsInlineFrame::Reflow(nsPresContext*          aPresContext,
   1.298 +                      nsHTMLReflowMetrics&     aMetrics,
   1.299 +                      const nsHTMLReflowState& aReflowState,
   1.300 +                      nsReflowStatus&          aStatus)
   1.301 +{
   1.302 +  DO_GLOBAL_REFLOW_COUNT("nsInlineFrame");
   1.303 +  DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus);
   1.304 +  if (nullptr == aReflowState.mLineLayout) {
   1.305 +    return NS_ERROR_INVALID_ARG;
   1.306 +  }
   1.307 +  if (IsFrameTreeTooDeep(aReflowState, aMetrics, aStatus)) {
   1.308 +    return NS_OK;
   1.309 +  }
   1.310 +
   1.311 +  bool    lazilySetParentPointer = false;
   1.312 +
   1.313 +  nsIFrame* lineContainer = aReflowState.mLineLayout->LineContainerFrame();
   1.314 +
   1.315 +   // Check for an overflow list with our prev-in-flow
   1.316 +  nsInlineFrame* prevInFlow = (nsInlineFrame*)GetPrevInFlow();
   1.317 +  if (prevInFlow) {
   1.318 +    AutoFrameListPtr prevOverflowFrames(aPresContext,
   1.319 +                                        prevInFlow->StealOverflowFrames());
   1.320 +    if (prevOverflowFrames) {
   1.321 +      // When pushing and pulling frames we need to check for whether any
   1.322 +      // views need to be reparented.
   1.323 +      nsContainerFrame::ReparentFrameViewList(*prevOverflowFrames, prevInFlow,
   1.324 +                                              this);
   1.325 +
   1.326 +      // Check if we should do the lazilySetParentPointer optimization.
   1.327 +      // Only do it in simple cases where we're being reflowed for the
   1.328 +      // first time, nothing (e.g. bidi resolution) has already given
   1.329 +      // us children, and there's no next-in-flow, so all our frames
   1.330 +      // will be taken from prevOverflowFrames.
   1.331 +      if ((GetStateBits() & NS_FRAME_FIRST_REFLOW) && mFrames.IsEmpty() &&
   1.332 +          !GetNextInFlow()) {
   1.333 +        // If our child list is empty, just put the new frames into it.
   1.334 +        // Note that we don't set the parent pointer for the new frames. Instead wait
   1.335 +        // to do this until we actually reflow the frame. If the overflow list contains
   1.336 +        // thousands of frames this is a big performance issue (see bug #5588)
   1.337 +        mFrames.SetFrames(*prevOverflowFrames);
   1.338 +        lazilySetParentPointer = true;
   1.339 +      } else {
   1.340 +        // Assign all floats to our block if necessary
   1.341 +        if (lineContainer && lineContainer->GetPrevContinuation()) {
   1.342 +          ReparentFloatsForInlineChild(lineContainer,
   1.343 +                                       prevOverflowFrames->FirstChild(),
   1.344 +                                       true);
   1.345 +        }
   1.346 +        // Insert the new frames at the beginning of the child list
   1.347 +        // and set their parent pointer
   1.348 +        const nsFrameList::Slice& newFrames =
   1.349 +          mFrames.InsertFrames(this, nullptr, *prevOverflowFrames);
   1.350 +        // If our prev in flow was under the first continuation of a first-line
   1.351 +        // frame then we need to reparent the style contexts to remove the
   1.352 +        // the special first-line styling. In the lazilySetParentPointer case
   1.353 +        // we reparent the style contexts when we set their parents in
   1.354 +        // nsInlineFrame::ReflowFrames and nsInlineFrame::ReflowInlineFrame.
   1.355 +        if (aReflowState.mLineLayout->GetInFirstLine()) {
   1.356 +          ReparentChildListStyle(aPresContext, newFrames, this);
   1.357 +        }
   1.358 +      }
   1.359 +    }
   1.360 +  }
   1.361 +
   1.362 +  // It's also possible that we have an overflow list for ourselves
   1.363 +#ifdef DEBUG
   1.364 +  if (GetStateBits() & NS_FRAME_FIRST_REFLOW) {
   1.365 +    // If it's our initial reflow, then we should not have an overflow list.
   1.366 +    // However, add an assertion in case we get reflowed more than once with
   1.367 +    // the initial reflow reason
   1.368 +    nsFrameList* overflowFrames = GetOverflowFrames();
   1.369 +    NS_ASSERTION(!overflowFrames || overflowFrames->IsEmpty(),
   1.370 +                 "overflow list is not empty for initial reflow");
   1.371 +  }
   1.372 +#endif
   1.373 +  if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
   1.374 +    DrainFlags flags =
   1.375 +      lazilySetParentPointer ? eDontReparentFrames : DrainFlags(0);
   1.376 +    if (aReflowState.mLineLayout->GetInFirstLine()) {
   1.377 +      flags = DrainFlags(flags | eInFirstLine);
   1.378 +    }
   1.379 +    DrainSelfOverflowListInternal(flags, lineContainer);
   1.380 +  }
   1.381 +
   1.382 +  // Set our own reflow state (additional state above and beyond
   1.383 +  // aReflowState)
   1.384 +  InlineReflowState irs;
   1.385 +  irs.mPrevFrame = nullptr;
   1.386 +  irs.mLineContainer = lineContainer;
   1.387 +  irs.mLineLayout = aReflowState.mLineLayout;
   1.388 +  irs.mNextInFlow = (nsInlineFrame*) GetNextInFlow();
   1.389 +  irs.mSetParentPointer = lazilySetParentPointer;
   1.390 +
   1.391 +  nsresult rv;
   1.392 +  if (mFrames.IsEmpty()) {
   1.393 +    // Try to pull over one frame before starting so that we know
   1.394 +    // whether we have an anonymous block or not.
   1.395 +    bool complete;
   1.396 +    (void) PullOneFrame(aPresContext, irs, &complete);
   1.397 +  }
   1.398 +
   1.399 +  rv = ReflowFrames(aPresContext, aReflowState, irs, aMetrics, aStatus);
   1.400 +
   1.401 +  ReflowAbsoluteFrames(aPresContext, aMetrics, aReflowState, aStatus);
   1.402 +
   1.403 +  // Note: the line layout code will properly compute our
   1.404 +  // overflow-rect state for us.
   1.405 +
   1.406 +  NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics);
   1.407 +  return rv;
   1.408 +}
   1.409 +
   1.410 +bool
   1.411 +nsInlineFrame::DrainSelfOverflowListInternal(DrainFlags aFlags,
   1.412 +                                             nsIFrame* aLineContainer)
   1.413 +{
   1.414 +  AutoFrameListPtr overflowFrames(PresContext(), StealOverflowFrames());
   1.415 +  if (overflowFrames) {
   1.416 +    NS_ASSERTION(mFrames.NotEmpty(), "overflow list w/o frames");
   1.417 +    // The frames on our own overflowlist may have been pushed by a
   1.418 +    // previous lazilySetParentPointer Reflow so we need to ensure the
   1.419 +    // correct parent pointer.  This is sometimes skipped by Reflow.
   1.420 +    if (!(aFlags & eDontReparentFrames)) {
   1.421 +      nsIFrame* firstChild = overflowFrames->FirstChild();
   1.422 +      if (aLineContainer && aLineContainer->GetPrevContinuation()) {
   1.423 +        ReparentFloatsForInlineChild(aLineContainer, firstChild, true);
   1.424 +      }
   1.425 +      const bool inFirstLine = (aFlags & eInFirstLine);
   1.426 +      RestyleManager* restyleManager = PresContext()->RestyleManager();
   1.427 +      for (nsIFrame* f = firstChild; f; f = f->GetNextSibling()) {
   1.428 +        f->SetParent(this);
   1.429 +        if (inFirstLine) {
   1.430 +          restyleManager->ReparentStyleContext(f);
   1.431 +          nsLayoutUtils::MarkDescendantsDirty(f);
   1.432 +        }
   1.433 +      }
   1.434 +    }
   1.435 +    bool result = !overflowFrames->IsEmpty();
   1.436 +    mFrames.AppendFrames(nullptr, *overflowFrames);
   1.437 +    return result;
   1.438 +  }
   1.439 +  return false;
   1.440 +}
   1.441 +
   1.442 +/* virtual */ bool
   1.443 +nsInlineFrame::DrainSelfOverflowList()
   1.444 +{
   1.445 +  nsIFrame* lineContainer = nsLayoutUtils::FindNearestBlockAncestor(this);
   1.446 +  // Add the eInFirstLine flag if we have a ::first-line ancestor frame.
   1.447 +  // No need to look further than the nearest line container though.
   1.448 +  DrainFlags flags = DrainFlags(0);
   1.449 +  for (nsIFrame* p = GetParent(); p != lineContainer; p = p->GetParent()) {
   1.450 +    if (p->GetType() == nsGkAtoms::lineFrame) {
   1.451 +      flags = DrainFlags(flags | eInFirstLine);
   1.452 +      break;
   1.453 +    }
   1.454 +  }
   1.455 +  return DrainSelfOverflowListInternal(flags, lineContainer);
   1.456 +}
   1.457 +
   1.458 +/* virtual */ bool
   1.459 +nsInlineFrame::CanContinueTextRun() const
   1.460 +{
   1.461 +  // We can continue a text run through an inline frame
   1.462 +  return true;
   1.463 +}
   1.464 +
   1.465 +/* virtual */ void
   1.466 +nsInlineFrame::PullOverflowsFromPrevInFlow()
   1.467 +{
   1.468 +  nsInlineFrame* prevInFlow = static_cast<nsInlineFrame*>(GetPrevInFlow());
   1.469 +  if (prevInFlow) {
   1.470 +    nsPresContext* presContext = PresContext();
   1.471 +    AutoFrameListPtr prevOverflowFrames(presContext,
   1.472 +                                        prevInFlow->StealOverflowFrames());
   1.473 +    if (prevOverflowFrames) {
   1.474 +      // Assume that our prev-in-flow has the same line container that we do.
   1.475 +      nsContainerFrame::ReparentFrameViewList(*prevOverflowFrames, prevInFlow,
   1.476 +                                              this);
   1.477 +      mFrames.InsertFrames(this, nullptr, *prevOverflowFrames);
   1.478 +    }
   1.479 +  }
   1.480 +}
   1.481 +
   1.482 +nsresult
   1.483 +nsInlineFrame::ReflowFrames(nsPresContext* aPresContext,
   1.484 +                            const nsHTMLReflowState& aReflowState,
   1.485 +                            InlineReflowState& irs,
   1.486 +                            nsHTMLReflowMetrics& aMetrics,
   1.487 +                            nsReflowStatus& aStatus)
   1.488 +{
   1.489 +  nsresult rv = NS_OK;
   1.490 +  aStatus = NS_FRAME_COMPLETE;
   1.491 +
   1.492 +  nsLineLayout* lineLayout = aReflowState.mLineLayout;
   1.493 +  bool inFirstLine = aReflowState.mLineLayout->GetInFirstLine();
   1.494 +  RestyleManager* restyleManager = aPresContext->RestyleManager();
   1.495 +  WritingMode wm = aReflowState.GetWritingMode();
   1.496 +  nscoord startEdge = 0;
   1.497 +  // Don't offset by our start borderpadding if we have a prev continuation or
   1.498 +  // if we're in a part of an {ib} split other than the first one.
   1.499 +  if (!GetPrevContinuation() && !FrameIsNonFirstInIBSplit()) {
   1.500 +    startEdge = aReflowState.ComputedLogicalBorderPadding().IStart(wm);
   1.501 +  }
   1.502 +  nscoord availableISize = aReflowState.AvailableISize();
   1.503 +  NS_ASSERTION(availableISize != NS_UNCONSTRAINEDSIZE,
   1.504 +               "should no longer use available widths");
   1.505 +  // Subtract off inline axis border+padding from availableISize
   1.506 +  availableISize -= startEdge;
   1.507 +  availableISize -= aReflowState.ComputedLogicalBorderPadding().IEnd(wm);
   1.508 +  lineLayout->BeginSpan(this, &aReflowState, startEdge,
   1.509 +                        startEdge + availableISize, &mBaseline);
   1.510 +
   1.511 +  // First reflow our principal children.
   1.512 +  nsIFrame* frame = mFrames.FirstChild();
   1.513 +  bool done = false;
   1.514 +  while (frame) {
   1.515 +    // Check if we should lazily set the child frame's parent pointer.
   1.516 +    if (irs.mSetParentPointer) {
   1.517 +      bool havePrevBlock =
   1.518 +        irs.mLineContainer && irs.mLineContainer->GetPrevContinuation();
   1.519 +      nsIFrame* child = frame;
   1.520 +      do {
   1.521 +        // If our block is the first in flow, then any floats under the pulled
   1.522 +        // frame must already belong to our block.
   1.523 +        if (havePrevBlock) {
   1.524 +          // This has to happen before we update frame's parent; we need to
   1.525 +          // know frame's ancestry under its old block.
   1.526 +          // The blockChildren.ContainsFrame check performed by
   1.527 +          // ReparentFloatsForInlineChild here may be slow, but we can't
   1.528 +          // easily avoid it because we don't know where 'frame' originally
   1.529 +          // came from. If we really really have to optimize this we could
   1.530 +          // cache whether frame->GetParent() is under its containing blocks
   1.531 +          // overflowList or not.
   1.532 +          ReparentFloatsForInlineChild(irs.mLineContainer, child, false);
   1.533 +        }
   1.534 +        child->SetParent(this);
   1.535 +        if (inFirstLine) {
   1.536 +          restyleManager->ReparentStyleContext(child);
   1.537 +          nsLayoutUtils::MarkDescendantsDirty(child);
   1.538 +        }
   1.539 +        // We also need to do the same for |frame|'s next-in-flows that are in
   1.540 +        // the sibling list. Otherwise, if we reflow |frame| and it's complete
   1.541 +        // we'll crash when trying to delete its next-in-flow.
   1.542 +        // This scenario doesn't happen often, but it can happen.
   1.543 +        nsIFrame* nextSibling = child->GetNextSibling();
   1.544 +        child = child->GetNextInFlow();
   1.545 +        if (MOZ_UNLIKELY(child)) {
   1.546 +          while (child != nextSibling && nextSibling) {
   1.547 +            nextSibling = nextSibling->GetNextSibling();
   1.548 +          }
   1.549 +          if (!nextSibling) {
   1.550 +            child = nullptr;
   1.551 +          }
   1.552 +        }
   1.553 +        MOZ_ASSERT(!child || mFrames.ContainsFrame(child));
   1.554 +      } while (child);
   1.555 +
   1.556 +      // Fix the parent pointer for ::first-letter child frame next-in-flows,
   1.557 +      // so nsFirstLetterFrame::Reflow can destroy them safely (bug 401042).
   1.558 +      nsIFrame* realFrame = nsPlaceholderFrame::GetRealFrameFor(frame);
   1.559 +      if (realFrame->GetType() == nsGkAtoms::letterFrame) {
   1.560 +        nsIFrame* child = realFrame->GetFirstPrincipalChild();
   1.561 +        if (child) {
   1.562 +          NS_ASSERTION(child->GetType() == nsGkAtoms::textFrame,
   1.563 +                       "unexpected frame type");
   1.564 +          nsIFrame* nextInFlow = child->GetNextInFlow();
   1.565 +          for ( ; nextInFlow; nextInFlow = nextInFlow->GetNextInFlow()) {
   1.566 +            NS_ASSERTION(nextInFlow->GetType() == nsGkAtoms::textFrame,
   1.567 +                         "unexpected frame type");
   1.568 +            if (mFrames.ContainsFrame(nextInFlow)) {
   1.569 +              nextInFlow->SetParent(this);
   1.570 +              if (inFirstLine) {
   1.571 +                restyleManager->ReparentStyleContext(nextInFlow);
   1.572 +                nsLayoutUtils::MarkDescendantsDirty(nextInFlow);
   1.573 +              }
   1.574 +            }
   1.575 +            else {
   1.576 +#ifdef DEBUG              
   1.577 +              // Once we find a next-in-flow that isn't ours none of the
   1.578 +              // remaining next-in-flows should be either.
   1.579 +              for ( ; nextInFlow; nextInFlow = nextInFlow->GetNextInFlow()) {
   1.580 +                NS_ASSERTION(!mFrames.ContainsFrame(nextInFlow),
   1.581 +                             "unexpected letter frame flow");
   1.582 +              }
   1.583 +#endif
   1.584 +              break;
   1.585 +            }
   1.586 +          }
   1.587 +        }
   1.588 +      }
   1.589 +    }
   1.590 +    MOZ_ASSERT(frame->GetParent() == this);
   1.591 +
   1.592 +    if (!done) {
   1.593 +      bool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK();
   1.594 +      rv = ReflowInlineFrame(aPresContext, aReflowState, irs, frame, aStatus);
   1.595 +      done = NS_FAILED(rv) ||
   1.596 +             NS_INLINE_IS_BREAK(aStatus) || 
   1.597 +             (!reflowingFirstLetter && NS_FRAME_IS_NOT_COMPLETE(aStatus));
   1.598 +      if (done) {
   1.599 +        if (!irs.mSetParentPointer) {
   1.600 +          break;
   1.601 +        }
   1.602 +        // Keep reparenting the remaining siblings, but don't reflow them.
   1.603 +        nsFrameList* pushedFrames = GetOverflowFrames();
   1.604 +        if (pushedFrames && pushedFrames->FirstChild() == frame) {
   1.605 +          // Don't bother if |frame| was pushed to our overflow list.
   1.606 +          break;
   1.607 +        }
   1.608 +      } else {
   1.609 +        irs.mPrevFrame = frame;
   1.610 +      }
   1.611 +    }
   1.612 +    frame = frame->GetNextSibling();
   1.613 +  }
   1.614 +
   1.615 +  // Attempt to pull frames from our next-in-flow until we can't
   1.616 +  if (!done && GetNextInFlow()) {
   1.617 +    while (true) {
   1.618 +      bool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK();
   1.619 +      bool isComplete;
   1.620 +      if (!frame) { // Could be non-null if we pulled a first-letter frame and
   1.621 +                    // it created a continuation, since we don't push those.
   1.622 +        frame = PullOneFrame(aPresContext, irs, &isComplete);
   1.623 +      }
   1.624 +#ifdef NOISY_PUSHING
   1.625 +      printf("%p pulled up %p\n", this, frame);
   1.626 +#endif
   1.627 +      if (nullptr == frame) {
   1.628 +        if (!isComplete) {
   1.629 +          aStatus = NS_FRAME_NOT_COMPLETE;
   1.630 +        }
   1.631 +        break;
   1.632 +      }
   1.633 +      rv = ReflowInlineFrame(aPresContext, aReflowState, irs, frame, aStatus);
   1.634 +      if (NS_FAILED(rv) ||
   1.635 +          NS_INLINE_IS_BREAK(aStatus) || 
   1.636 +          (!reflowingFirstLetter && NS_FRAME_IS_NOT_COMPLETE(aStatus))) {
   1.637 +        break;
   1.638 +      }
   1.639 +      irs.mPrevFrame = frame;
   1.640 +      frame = frame->GetNextSibling();
   1.641 +    }
   1.642 +  }
   1.643 +
   1.644 +  NS_ASSERTION(!NS_FRAME_IS_COMPLETE(aStatus) || !GetOverflowFrames(),
   1.645 +               "We can't be complete AND have overflow frames!");
   1.646 +
   1.647 +  // If after reflowing our children they take up no area then make
   1.648 +  // sure that we don't either.
   1.649 +  //
   1.650 +  // Note: CSS demands that empty inline elements still affect the
   1.651 +  // line-height calculations. However, continuations of an inline
   1.652 +  // that are empty we force to empty so that things like collapsed
   1.653 +  // whitespace in an inline element don't affect the line-height.
   1.654 +  aMetrics.ISize() = lineLayout->EndSpan(this);
   1.655 +
   1.656 +  // Compute final width.
   1.657 +
   1.658 +  // Make sure to not include our start border and padding if we have a prev
   1.659 +  // continuation or if we're in a part of an {ib} split other than the first
   1.660 +  // one.
   1.661 +  if (!GetPrevContinuation() && !FrameIsNonFirstInIBSplit()) {
   1.662 +    aMetrics.ISize() += aReflowState.ComputedLogicalBorderPadding().IStart(wm);
   1.663 +  }
   1.664 +
   1.665 +  /*
   1.666 +   * We want to only apply the end border and padding if we're the last
   1.667 +   * continuation and either not in an {ib} split or the last part of it.  To
   1.668 +   * be the last continuation we have to be complete (so that we won't get a
   1.669 +   * next-in-flow) and have no non-fluid continuations on our continuation
   1.670 +   * chain.
   1.671 +   */
   1.672 +  if (NS_FRAME_IS_COMPLETE(aStatus) &&
   1.673 +      !LastInFlow()->GetNextContinuation() &&
   1.674 +      !FrameIsNonLastInIBSplit()) {
   1.675 +    aMetrics.Width() += aReflowState.ComputedLogicalBorderPadding().IEnd(wm);
   1.676 +  }
   1.677 +
   1.678 +  nsRefPtr<nsFontMetrics> fm;
   1.679 +  float inflation = nsLayoutUtils::FontSizeInflationFor(this);
   1.680 +  nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm), inflation);
   1.681 +  aReflowState.rendContext->SetFont(fm);
   1.682 +
   1.683 +  if (fm) {
   1.684 +    // Compute final height of the frame.
   1.685 +    //
   1.686 +    // Do things the standard css2 way -- though it's hard to find it
   1.687 +    // in the css2 spec! It's actually found in the css1 spec section
   1.688 +    // 4.4 (you will have to read between the lines to really see
   1.689 +    // it).
   1.690 +    //
   1.691 +    // The height of our box is the sum of our font size plus the top
   1.692 +    // and bottom border and padding. The height of children do not
   1.693 +    // affect our height.
   1.694 +    aMetrics.SetTopAscent(fm->MaxAscent());
   1.695 +    aMetrics.Height() = fm->MaxHeight();
   1.696 +  } else {
   1.697 +    NS_WARNING("Cannot get font metrics - defaulting sizes to 0");
   1.698 +    aMetrics.SetTopAscent(aMetrics.Height() = 0);
   1.699 +  }
   1.700 +  aMetrics.SetTopAscent(aMetrics.TopAscent() + aReflowState.ComputedPhysicalBorderPadding().top);
   1.701 +  aMetrics.Height() += aReflowState.ComputedPhysicalBorderPadding().top +
   1.702 +    aReflowState.ComputedPhysicalBorderPadding().bottom;
   1.703 +
   1.704 +  // For now our overflow area is zero. The real value will be
   1.705 +  // computed in |nsLineLayout::RelativePositionFrames|.
   1.706 +  aMetrics.mOverflowAreas.Clear();
   1.707 +
   1.708 +#ifdef NOISY_FINAL_SIZE
   1.709 +  ListTag(stdout);
   1.710 +  printf(": metrics=%d,%d ascent=%d\n",
   1.711 +         aMetrics.Width(), aMetrics.Height(), aMetrics.TopAscent());
   1.712 +#endif
   1.713 +
   1.714 +  return rv;
   1.715 +}
   1.716 +
   1.717 +nsresult
   1.718 +nsInlineFrame::ReflowInlineFrame(nsPresContext* aPresContext,
   1.719 +                                 const nsHTMLReflowState& aReflowState,
   1.720 +                                 InlineReflowState& irs,
   1.721 +                                 nsIFrame* aFrame,
   1.722 +                                 nsReflowStatus& aStatus)
   1.723 +{
   1.724 +  nsLineLayout* lineLayout = aReflowState.mLineLayout;
   1.725 +  bool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK();
   1.726 +  bool pushedFrame;
   1.727 +  nsresult rv =
   1.728 +    lineLayout->ReflowFrame(aFrame, aStatus, nullptr, pushedFrame);
   1.729 +  
   1.730 +  if (NS_FAILED(rv)) {
   1.731 +    return rv;
   1.732 +  }
   1.733 +
   1.734 +  if (NS_INLINE_IS_BREAK_BEFORE(aStatus)) {
   1.735 +    if (aFrame != mFrames.FirstChild()) {
   1.736 +      // Change break-before status into break-after since we have
   1.737 +      // already placed at least one child frame. This preserves the
   1.738 +      // break-type so that it can be propagated upward.
   1.739 +      aStatus = NS_FRAME_NOT_COMPLETE |
   1.740 +        NS_INLINE_BREAK | NS_INLINE_BREAK_AFTER |
   1.741 +        (aStatus & NS_INLINE_BREAK_TYPE_MASK);
   1.742 +      PushFrames(aPresContext, aFrame, irs.mPrevFrame, irs);
   1.743 +    }
   1.744 +    else {
   1.745 +      // Preserve reflow status when breaking-before our first child
   1.746 +      // and propagate it upward without modification.
   1.747 +    }
   1.748 +    return NS_OK;
   1.749 +  }
   1.750 +
   1.751 +  // Create a next-in-flow if needed.
   1.752 +  if (!NS_FRAME_IS_FULLY_COMPLETE(aStatus)) {
   1.753 +    nsIFrame* newFrame;
   1.754 +    rv = CreateNextInFlow(aFrame, newFrame);
   1.755 +    if (NS_FAILED(rv)) {
   1.756 +      return rv;
   1.757 +    }
   1.758 +  }
   1.759 +
   1.760 +  if (NS_INLINE_IS_BREAK_AFTER(aStatus)) {
   1.761 +    nsIFrame* nextFrame = aFrame->GetNextSibling();
   1.762 +    if (nextFrame) {
   1.763 +      NS_FRAME_SET_INCOMPLETE(aStatus);
   1.764 +      PushFrames(aPresContext, nextFrame, aFrame, irs);
   1.765 +    }
   1.766 +    else {
   1.767 +      // We must return an incomplete status if there are more child
   1.768 +      // frames remaining in a next-in-flow that follows this frame.
   1.769 +      nsInlineFrame* nextInFlow = static_cast<nsInlineFrame*>(GetNextInFlow());
   1.770 +      while (nextInFlow) {
   1.771 +        if (nextInFlow->mFrames.NotEmpty()) {
   1.772 +          NS_FRAME_SET_INCOMPLETE(aStatus);
   1.773 +          break;
   1.774 +        }
   1.775 +        nextInFlow = static_cast<nsInlineFrame*>(nextInFlow->GetNextInFlow());
   1.776 +      }
   1.777 +    }
   1.778 +    return NS_OK;
   1.779 +  }
   1.780 +
   1.781 +  if (!NS_FRAME_IS_FULLY_COMPLETE(aStatus) && !reflowingFirstLetter) {
   1.782 +    nsIFrame* nextFrame = aFrame->GetNextSibling();
   1.783 +    if (nextFrame) {
   1.784 +      PushFrames(aPresContext, nextFrame, aFrame, irs);
   1.785 +    }
   1.786 +  }
   1.787 +  return NS_OK;
   1.788 +}
   1.789 +
   1.790 +nsIFrame*
   1.791 +nsInlineFrame::PullOneFrame(nsPresContext* aPresContext,
   1.792 +                            InlineReflowState& irs,
   1.793 +                            bool* aIsComplete)
   1.794 +{
   1.795 +  bool isComplete = true;
   1.796 +
   1.797 +  nsIFrame* frame = nullptr;
   1.798 +  nsInlineFrame* nextInFlow = irs.mNextInFlow;
   1.799 +  while (nextInFlow) {
   1.800 +    frame = nextInFlow->mFrames.FirstChild();
   1.801 +    if (!frame) {
   1.802 +      // The nextInFlow's principal list has no frames, try its overflow list.
   1.803 +      nsFrameList* overflowFrames = nextInFlow->GetOverflowFrames();
   1.804 +      if (overflowFrames) {
   1.805 +        frame = overflowFrames->RemoveFirstChild();
   1.806 +        if (overflowFrames->IsEmpty()) {
   1.807 +          // We're stealing the only frame - delete the overflow list.
   1.808 +          nextInFlow->DestroyOverflowList();
   1.809 +        } else {
   1.810 +          // We leave the remaining frames on the overflow list (rather than
   1.811 +          // putting them on nextInFlow's principal list) so we don't have to
   1.812 +          // set up the parent for them.
   1.813 +        }
   1.814 +        // ReparentFloatsForInlineChild needs it to be on a child list -
   1.815 +        // we remove it again below.
   1.816 +        nextInFlow->mFrames.SetFrames(frame);
   1.817 +      }
   1.818 +    }
   1.819 +
   1.820 +    if (frame) {
   1.821 +      // If our block has no next continuation, then any floats belonging to
   1.822 +      // the pulled frame must belong to our block already. This check ensures
   1.823 +      // we do no extra work in the common non-vertical-breaking case.
   1.824 +      if (irs.mLineContainer && irs.mLineContainer->GetNextContinuation()) {
   1.825 +        // The blockChildren.ContainsFrame check performed by
   1.826 +        // ReparentFloatsForInlineChild will be fast because frame's ancestor
   1.827 +        // will be the first child of its containing block.
   1.828 +        ReparentFloatsForInlineChild(irs.mLineContainer, frame, false);
   1.829 +      }
   1.830 +      nextInFlow->mFrames.RemoveFirstChild();
   1.831 +      // nsFirstLineFrame::PullOneFrame calls ReparentStyleContext.
   1.832 +
   1.833 +      mFrames.InsertFrame(this, irs.mPrevFrame, frame);
   1.834 +      isComplete = false;
   1.835 +      if (irs.mLineLayout) {
   1.836 +        irs.mLineLayout->SetDirtyNextLine();
   1.837 +      }
   1.838 +      nsContainerFrame::ReparentFrameView(frame, nextInFlow, this);
   1.839 +      break;
   1.840 +    }
   1.841 +    nextInFlow = static_cast<nsInlineFrame*>(nextInFlow->GetNextInFlow());
   1.842 +    irs.mNextInFlow = nextInFlow;
   1.843 +  }
   1.844 +
   1.845 +  *aIsComplete = isComplete;
   1.846 +  return frame;
   1.847 +}
   1.848 +
   1.849 +void
   1.850 +nsInlineFrame::PushFrames(nsPresContext* aPresContext,
   1.851 +                          nsIFrame* aFromChild,
   1.852 +                          nsIFrame* aPrevSibling,
   1.853 +                          InlineReflowState& aState)
   1.854 +{
   1.855 +  NS_PRECONDITION(aFromChild, "null pointer");
   1.856 +  NS_PRECONDITION(aPrevSibling, "pushing first child");
   1.857 +  NS_PRECONDITION(aPrevSibling->GetNextSibling() == aFromChild, "bad prev sibling");
   1.858 +
   1.859 +#ifdef NOISY_PUSHING
   1.860 +  printf("%p pushing aFromChild %p, disconnecting from prev sib %p\n", 
   1.861 +         this, aFromChild, aPrevSibling);
   1.862 +#endif
   1.863 +
   1.864 +  // Add the frames to our overflow list (let our next in flow drain
   1.865 +  // our overflow list when it is ready)
   1.866 +  SetOverflowFrames(mFrames.RemoveFramesAfter(aPrevSibling));
   1.867 +  if (aState.mLineLayout) {
   1.868 +    aState.mLineLayout->SetDirtyNextLine();
   1.869 +  }
   1.870 +}
   1.871 +
   1.872 +
   1.873 +//////////////////////////////////////////////////////////////////////
   1.874 +
   1.875 +int
   1.876 +nsInlineFrame::GetLogicalSkipSides(const nsHTMLReflowState* aReflowState) const
   1.877 +{
   1.878 +  int skip = 0;
   1.879 +  if (!IsFirst()) {
   1.880 +    nsInlineFrame* prev = (nsInlineFrame*) GetPrevContinuation();
   1.881 +    if ((GetStateBits() & NS_INLINE_FRAME_BIDI_VISUAL_STATE_IS_SET) ||
   1.882 +        (prev && (prev->mRect.height || prev->mRect.width))) {
   1.883 +      // Prev continuation is not empty therefore we don't render our start
   1.884 +      // border edge.
   1.885 +      skip |= LOGICAL_SIDE_I_START;
   1.886 +    }
   1.887 +    else {
   1.888 +      // If the prev continuation is empty, then go ahead and let our start
   1.889 +      // edge border render.
   1.890 +    }
   1.891 +  }
   1.892 +  if (!IsLast()) {
   1.893 +    nsInlineFrame* next = (nsInlineFrame*) GetNextContinuation();
   1.894 +    if ((GetStateBits() & NS_INLINE_FRAME_BIDI_VISUAL_STATE_IS_SET) ||
   1.895 +        (next && (next->mRect.height || next->mRect.width))) {
   1.896 +      // Next continuation is not empty therefore we don't render our end
   1.897 +      // border edge.
   1.898 +      skip |= LOGICAL_SIDE_I_END;
   1.899 +    }
   1.900 +    else {
   1.901 +      // If the next continuation is empty, then go ahead and let our end
   1.902 +      // edge border render.
   1.903 +    }
   1.904 +  }
   1.905 +
   1.906 +  if (GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) {
   1.907 +    // All but the last part of an {ib} split should skip the "end" side (as
   1.908 +    // determined by this frame's direction) and all but the first part of such
   1.909 +    // a split should skip the "start" side.  But figuring out which part of
   1.910 +    // the split we are involves getting our first continuation, which might be
   1.911 +    // expensive.  So don't bother if we already have the relevant bits set.
   1.912 +    if (skip != LOGICAL_SIDES_I_BOTH) {
   1.913 +      // We're missing one of the skip bits, so check whether we need to set it.
   1.914 +      // Only get the first continuation once, as an optimization.
   1.915 +      nsIFrame* firstContinuation = FirstContinuation();
   1.916 +      if (firstContinuation->FrameIsNonLastInIBSplit()) {
   1.917 +        skip |= LOGICAL_SIDE_I_END;
   1.918 +      }
   1.919 +      if (firstContinuation->FrameIsNonFirstInIBSplit()) {
   1.920 +        skip |= LOGICAL_SIDE_I_START;
   1.921 +      }
   1.922 +    }
   1.923 +  }
   1.924 +
   1.925 +  return skip;
   1.926 +}
   1.927 +
   1.928 +nscoord
   1.929 +nsInlineFrame::GetBaseline() const
   1.930 +{
   1.931 +  return mBaseline;
   1.932 +}
   1.933 +
   1.934 +#ifdef ACCESSIBILITY
   1.935 +a11y::AccType
   1.936 +nsInlineFrame::AccessibleType()
   1.937 +{
   1.938 +  // Broken image accessibles are created here, because layout
   1.939 +  // replaces the image or image control frame with an inline frame
   1.940 +  nsIAtom *tagAtom = mContent->Tag();
   1.941 +  if (tagAtom == nsGkAtoms::input)  // Broken <input type=image ... />
   1.942 +    return a11y::eHTMLButtonType;
   1.943 +  if (tagAtom == nsGkAtoms::img)  // Create accessible for broken <img>
   1.944 +    return a11y::eHyperTextType;
   1.945 +
   1.946 +  return a11y::eNoType;
   1.947 +}
   1.948 +#endif
   1.949 +
   1.950 +//////////////////////////////////////////////////////////////////////
   1.951 +
   1.952 +// nsLineFrame implementation
   1.953 +
   1.954 +nsIFrame*
   1.955 +NS_NewFirstLineFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
   1.956 +{
   1.957 +  return new (aPresShell) nsFirstLineFrame(aContext);
   1.958 +}
   1.959 +
   1.960 +NS_IMPL_FRAMEARENA_HELPERS(nsFirstLineFrame)
   1.961 +
   1.962 +void
   1.963 +nsFirstLineFrame::Init(nsIContent* aContent, nsIFrame* aParent,
   1.964 +                       nsIFrame* aPrevInFlow)
   1.965 +{
   1.966 +  nsInlineFrame::Init(aContent, aParent, aPrevInFlow);
   1.967 +  if (!aPrevInFlow) {
   1.968 +    MOZ_ASSERT(StyleContext()->GetPseudo() == nsCSSPseudoElements::firstLine);
   1.969 +    return;
   1.970 +  }
   1.971 +
   1.972 +  // This frame is a continuation - fixup the style context if aPrevInFlow
   1.973 +  // is the first-in-flow (the only one with a ::first-line pseudo).
   1.974 +  if (aPrevInFlow->StyleContext()->GetPseudo() == nsCSSPseudoElements::firstLine) {
   1.975 +    MOZ_ASSERT(FirstInFlow() == aPrevInFlow);
   1.976 +    // Create a new style context that is a child of the parent
   1.977 +    // style context thus removing the ::first-line style. This way
   1.978 +    // we behave as if an anonymous (unstyled) span was the child
   1.979 +    // of the parent frame.
   1.980 +    nsStyleContext* parentContext = aParent->StyleContext();
   1.981 +    nsRefPtr<nsStyleContext> newSC = PresContext()->StyleSet()->
   1.982 +      ResolveAnonymousBoxStyle(nsCSSAnonBoxes::mozLineFrame, parentContext);
   1.983 +    SetStyleContext(newSC);
   1.984 +  } else {
   1.985 +    MOZ_ASSERT(FirstInFlow() != aPrevInFlow);
   1.986 +    MOZ_ASSERT(aPrevInFlow->StyleContext()->GetPseudo() ==
   1.987 +                 nsCSSAnonBoxes::mozLineFrame);
   1.988 +  }
   1.989 +}
   1.990 +
   1.991 +#ifdef DEBUG_FRAME_DUMP
   1.992 +nsresult
   1.993 +nsFirstLineFrame::GetFrameName(nsAString& aResult) const
   1.994 +{
   1.995 +  return MakeFrameName(NS_LITERAL_STRING("Line"), aResult);
   1.996 +}
   1.997 +#endif
   1.998 +
   1.999 +nsIAtom*
  1.1000 +nsFirstLineFrame::GetType() const
  1.1001 +{
  1.1002 +  return nsGkAtoms::lineFrame;
  1.1003 +}
  1.1004 +
  1.1005 +nsIFrame*
  1.1006 +nsFirstLineFrame::PullOneFrame(nsPresContext* aPresContext, InlineReflowState& irs,
  1.1007 +                               bool* aIsComplete)
  1.1008 +{
  1.1009 +  nsIFrame* frame = nsInlineFrame::PullOneFrame(aPresContext, irs, aIsComplete);
  1.1010 +  if (frame && !GetPrevInFlow()) {
  1.1011 +    // We are a first-line frame. Fixup the child frames
  1.1012 +    // style-context that we just pulled.
  1.1013 +    NS_ASSERTION(frame->GetParent() == this, "Incorrect parent?");
  1.1014 +    aPresContext->RestyleManager()->ReparentStyleContext(frame);
  1.1015 +    nsLayoutUtils::MarkDescendantsDirty(frame);
  1.1016 +  }
  1.1017 +  return frame;
  1.1018 +}
  1.1019 +
  1.1020 +nsresult
  1.1021 +nsFirstLineFrame::Reflow(nsPresContext* aPresContext,
  1.1022 +                         nsHTMLReflowMetrics& aMetrics,
  1.1023 +                         const nsHTMLReflowState& aReflowState,
  1.1024 +                         nsReflowStatus& aStatus)
  1.1025 +{
  1.1026 +  if (nullptr == aReflowState.mLineLayout) {
  1.1027 +    return NS_ERROR_INVALID_ARG;
  1.1028 +  }
  1.1029 +
  1.1030 +  nsIFrame* lineContainer = aReflowState.mLineLayout->LineContainerFrame();
  1.1031 +
  1.1032 +  // Check for an overflow list with our prev-in-flow
  1.1033 +  nsFirstLineFrame* prevInFlow = (nsFirstLineFrame*)GetPrevInFlow();
  1.1034 +  if (prevInFlow) {
  1.1035 +    AutoFrameListPtr prevOverflowFrames(aPresContext,
  1.1036 +                                        prevInFlow->StealOverflowFrames());
  1.1037 +    if (prevOverflowFrames) {
  1.1038 +      // Assign all floats to our block if necessary
  1.1039 +      if (lineContainer && lineContainer->GetPrevContinuation()) {
  1.1040 +        ReparentFloatsForInlineChild(lineContainer,
  1.1041 +                                     prevOverflowFrames->FirstChild(),
  1.1042 +                                     true);
  1.1043 +      }
  1.1044 +      const nsFrameList::Slice& newFrames =
  1.1045 +        mFrames.InsertFrames(this, nullptr, *prevOverflowFrames);
  1.1046 +      ReparentChildListStyle(aPresContext, newFrames, this);
  1.1047 +    }
  1.1048 +  }
  1.1049 +
  1.1050 +  // It's also possible that we have an overflow list for ourselves.
  1.1051 +  DrainSelfOverflowList();
  1.1052 +
  1.1053 +  // Set our own reflow state (additional state above and beyond
  1.1054 +  // aReflowState)
  1.1055 +  InlineReflowState irs;
  1.1056 +  irs.mPrevFrame = nullptr;
  1.1057 +  irs.mLineContainer = lineContainer;
  1.1058 +  irs.mLineLayout = aReflowState.mLineLayout;
  1.1059 +  irs.mNextInFlow = (nsInlineFrame*) GetNextInFlow();
  1.1060 +
  1.1061 +  nsresult rv;
  1.1062 +  bool wasEmpty = mFrames.IsEmpty();
  1.1063 +  if (wasEmpty) {
  1.1064 +    // Try to pull over one frame before starting so that we know
  1.1065 +    // whether we have an anonymous block or not.
  1.1066 +    bool complete;
  1.1067 +    PullOneFrame(aPresContext, irs, &complete);
  1.1068 +  }
  1.1069 +
  1.1070 +  if (nullptr == GetPrevInFlow()) {
  1.1071 +    // XXX This is pretty sick, but what we do here is to pull-up, in
  1.1072 +    // advance, all of the next-in-flows children. We re-resolve their
  1.1073 +    // style while we are at at it so that when we reflow they have
  1.1074 +    // the right style.
  1.1075 +    //
  1.1076 +    // All of this is so that text-runs reflow properly.
  1.1077 +    irs.mPrevFrame = mFrames.LastChild();
  1.1078 +    for (;;) {
  1.1079 +      bool complete;
  1.1080 +      nsIFrame* frame = PullOneFrame(aPresContext, irs, &complete);
  1.1081 +      if (!frame) {
  1.1082 +        break;
  1.1083 +      }
  1.1084 +      irs.mPrevFrame = frame;
  1.1085 +    }
  1.1086 +    irs.mPrevFrame = nullptr;
  1.1087 +  }
  1.1088 +
  1.1089 +  NS_ASSERTION(!aReflowState.mLineLayout->GetInFirstLine(),
  1.1090 +               "Nested first-line frames? BOGUS");
  1.1091 +  aReflowState.mLineLayout->SetInFirstLine(true);
  1.1092 +  rv = ReflowFrames(aPresContext, aReflowState, irs, aMetrics, aStatus);
  1.1093 +  aReflowState.mLineLayout->SetInFirstLine(false);
  1.1094 +
  1.1095 +  ReflowAbsoluteFrames(aPresContext, aMetrics, aReflowState, aStatus);
  1.1096 +
  1.1097 +  // Note: the line layout code will properly compute our overflow state for us
  1.1098 +
  1.1099 +  return rv;
  1.1100 +}
  1.1101 +
  1.1102 +/* virtual */ void
  1.1103 +nsFirstLineFrame::PullOverflowsFromPrevInFlow()
  1.1104 +{
  1.1105 +  nsFirstLineFrame* prevInFlow = static_cast<nsFirstLineFrame*>(GetPrevInFlow());
  1.1106 +  if (prevInFlow) {
  1.1107 +    nsPresContext* presContext = PresContext();
  1.1108 +    AutoFrameListPtr prevOverflowFrames(presContext,
  1.1109 +                                        prevInFlow->StealOverflowFrames());
  1.1110 +    if (prevOverflowFrames) {
  1.1111 +      // Assume that our prev-in-flow has the same line container that we do.
  1.1112 +      const nsFrameList::Slice& newFrames =
  1.1113 +        mFrames.InsertFrames(this, nullptr, *prevOverflowFrames);
  1.1114 +      ReparentChildListStyle(presContext, newFrames, this);
  1.1115 +    }
  1.1116 +  }
  1.1117 +}
  1.1118 +
  1.1119 +/* virtual */ bool
  1.1120 +nsFirstLineFrame::DrainSelfOverflowList()
  1.1121 +{
  1.1122 +  AutoFrameListPtr overflowFrames(PresContext(), StealOverflowFrames());
  1.1123 +  if (overflowFrames) {
  1.1124 +    NS_ASSERTION(mFrames.NotEmpty(), "overflow list w/o frames");
  1.1125 +
  1.1126 +    bool result = !overflowFrames->IsEmpty();
  1.1127 +    const nsFrameList::Slice& newFrames =
  1.1128 +      mFrames.AppendFrames(nullptr, *overflowFrames);
  1.1129 +    ReparentChildListStyle(PresContext(), newFrames, this);
  1.1130 +    return result;
  1.1131 +  }
  1.1132 +  return false;
  1.1133 +}

mercurial