layout/generic/nsPlaceholderFrame.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/layout/generic/nsPlaceholderFrame.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,257 @@
     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 +/*
    1.10 + * rendering object for the point that anchors out-of-flow rendering
    1.11 + * objects such as floats and absolutely positioned elements
    1.12 + */
    1.13 +
    1.14 +#include "nsPlaceholderFrame.h"
    1.15 +
    1.16 +#include "nsDisplayList.h"
    1.17 +#include "nsFrameManager.h"
    1.18 +#include "nsLayoutUtils.h"
    1.19 +#include "nsPresContext.h"
    1.20 +#include "nsRenderingContext.h"
    1.21 +#include "nsIFrameInlines.h"
    1.22 +
    1.23 +nsIFrame*
    1.24 +NS_NewPlaceholderFrame(nsIPresShell* aPresShell, nsStyleContext* aContext,
    1.25 +                       nsFrameState aTypeBit)
    1.26 +{
    1.27 +  return new (aPresShell) nsPlaceholderFrame(aContext, aTypeBit);
    1.28 +}
    1.29 +
    1.30 +NS_IMPL_FRAMEARENA_HELPERS(nsPlaceholderFrame)
    1.31 +
    1.32 +#ifdef DEBUG
    1.33 +NS_QUERYFRAME_HEAD(nsPlaceholderFrame)
    1.34 +  NS_QUERYFRAME_ENTRY(nsPlaceholderFrame)
    1.35 +NS_QUERYFRAME_TAIL_INHERITING(nsFrame)
    1.36 +#endif
    1.37 +
    1.38 +/* virtual */ nsSize
    1.39 +nsPlaceholderFrame::GetMinSize(nsBoxLayoutState& aBoxLayoutState)
    1.40 +{
    1.41 +  nsSize size(0, 0);
    1.42 +  DISPLAY_MIN_SIZE(this, size);
    1.43 +  return size;
    1.44 +}
    1.45 +
    1.46 +/* virtual */ nsSize
    1.47 +nsPlaceholderFrame::GetPrefSize(nsBoxLayoutState& aBoxLayoutState)
    1.48 +{
    1.49 +  nsSize size(0, 0);
    1.50 +  DISPLAY_PREF_SIZE(this, size);
    1.51 +  return size;
    1.52 +}
    1.53 +
    1.54 +/* virtual */ nsSize
    1.55 +nsPlaceholderFrame::GetMaxSize(nsBoxLayoutState& aBoxLayoutState)
    1.56 +{
    1.57 +  nsSize size(NS_INTRINSICSIZE, NS_INTRINSICSIZE);
    1.58 +  DISPLAY_MAX_SIZE(this, size);
    1.59 +  return size;
    1.60 +}
    1.61 +
    1.62 +/* virtual */ void
    1.63 +nsPlaceholderFrame::AddInlineMinWidth(nsRenderingContext* aRenderingContext,
    1.64 +                                      nsIFrame::InlineMinWidthData* aData)
    1.65 +{
    1.66 +  // Override AddInlineMinWith so that *nothing* happens.  In
    1.67 +  // particular, we don't want to zero out |aData->trailingWhitespace|,
    1.68 +  // since nsLineLayout skips placeholders when trimming trailing
    1.69 +  // whitespace, and we don't want to set aData->skipWhitespace to
    1.70 +  // false.
    1.71 +
    1.72 +  // ...but push floats onto the list
    1.73 +  if (mOutOfFlowFrame->IsFloating()) {
    1.74 +    nscoord floatWidth =
    1.75 +      nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
    1.76 +                                           mOutOfFlowFrame,
    1.77 +                                           nsLayoutUtils::MIN_WIDTH);
    1.78 +    aData->floats.AppendElement(
    1.79 +      InlineIntrinsicWidthData::FloatInfo(mOutOfFlowFrame, floatWidth));
    1.80 +  }
    1.81 +}
    1.82 +
    1.83 +/* virtual */ void
    1.84 +nsPlaceholderFrame::AddInlinePrefWidth(nsRenderingContext* aRenderingContext,
    1.85 +                                       nsIFrame::InlinePrefWidthData* aData)
    1.86 +{
    1.87 +  // Override AddInlinePrefWith so that *nothing* happens.  In
    1.88 +  // particular, we don't want to zero out |aData->trailingWhitespace|,
    1.89 +  // since nsLineLayout skips placeholders when trimming trailing
    1.90 +  // whitespace, and we don't want to set aData->skipWhitespace to
    1.91 +  // false.
    1.92 +
    1.93 +  // ...but push floats onto the list
    1.94 +  if (mOutOfFlowFrame->IsFloating()) {
    1.95 +    nscoord floatWidth =
    1.96 +      nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
    1.97 +                                           mOutOfFlowFrame,
    1.98 +                                           nsLayoutUtils::PREF_WIDTH);
    1.99 +    aData->floats.AppendElement(
   1.100 +      InlineIntrinsicWidthData::FloatInfo(mOutOfFlowFrame, floatWidth));
   1.101 +  }
   1.102 +}
   1.103 +
   1.104 +nsresult
   1.105 +nsPlaceholderFrame::Reflow(nsPresContext*           aPresContext,
   1.106 +                           nsHTMLReflowMetrics&     aDesiredSize,
   1.107 +                           const nsHTMLReflowState& aReflowState,
   1.108 +                           nsReflowStatus&          aStatus)
   1.109 +{
   1.110 +#ifdef DEBUG
   1.111 +  // We should be getting reflowed before our out-of-flow.
   1.112 +  // If this is our first reflow, and our out-of-flow has already received its
   1.113 +  // first reflow (before us), complain.
   1.114 +  // XXXdholbert This "look for a previous continuation or IB-split sibling"
   1.115 +  // code could use nsLayoutUtils::GetPrevContinuationOrIBSplitSibling(), if
   1.116 +  // we ever add a function like that. (We currently have a "Next" version.)
   1.117 +  if ((GetStateBits() & NS_FRAME_FIRST_REFLOW) &&
   1.118 +      !(mOutOfFlowFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
   1.119 +
   1.120 +    // Unfortunately, this can currently happen when the placeholder is in a
   1.121 +    // later continuation or later IB-split sibling than its out-of-flow (as
   1.122 +    // is the case in some of our existing unit tests). So for now, in that
   1.123 +    // case, we'll warn instead of asserting.
   1.124 +    bool isInContinuationOrIBSplit = false;
   1.125 +    nsIFrame* ancestor = this;
   1.126 +    while ((ancestor = ancestor->GetParent())) {
   1.127 +      if (ancestor->GetPrevContinuation() ||
   1.128 +          ancestor->Properties().Get(IBSplitPrevSibling())) {
   1.129 +        isInContinuationOrIBSplit = true;
   1.130 +        break;
   1.131 +      }
   1.132 +    }
   1.133 +
   1.134 +    if (isInContinuationOrIBSplit) {
   1.135 +      NS_WARNING("Out-of-flow frame got reflowed before its placeholder");
   1.136 +    } else {
   1.137 +      NS_ERROR("Out-of-flow frame got reflowed before its placeholder");
   1.138 +    }
   1.139 +  }
   1.140 +#endif
   1.141 +
   1.142 +  DO_GLOBAL_REFLOW_COUNT("nsPlaceholderFrame");
   1.143 +  DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
   1.144 +  aDesiredSize.Width() = 0;
   1.145 +  aDesiredSize.Height() = 0;
   1.146 +
   1.147 +  aStatus = NS_FRAME_COMPLETE;
   1.148 +  NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
   1.149 +  return NS_OK;
   1.150 +}
   1.151 +
   1.152 +void
   1.153 +nsPlaceholderFrame::DestroyFrom(nsIFrame* aDestructRoot)
   1.154 +{
   1.155 +  nsIFrame* oof = mOutOfFlowFrame;
   1.156 +  if (oof) {
   1.157 +    // Unregister out-of-flow frame
   1.158 +    nsFrameManager* fm = PresContext()->GetPresShell()->FrameManager();
   1.159 +    fm->UnregisterPlaceholderFrame(this);
   1.160 +    mOutOfFlowFrame = nullptr;
   1.161 +    // If aDestructRoot is not an ancestor of the out-of-flow frame,
   1.162 +    // then call RemoveFrame on it here.
   1.163 +    // Also destroy it here if it's a popup frame. (Bug 96291)
   1.164 +    if ((GetStateBits() & PLACEHOLDER_FOR_POPUP) ||
   1.165 +        !nsLayoutUtils::IsProperAncestorFrame(aDestructRoot, oof)) {
   1.166 +      ChildListID listId = nsLayoutUtils::GetChildListNameFor(oof);
   1.167 +      fm->RemoveFrame(listId, oof);
   1.168 +    }
   1.169 +    // else oof will be destroyed by its parent
   1.170 +  }
   1.171 +
   1.172 +  nsFrame::DestroyFrom(aDestructRoot);
   1.173 +}
   1.174 +
   1.175 +nsIAtom*
   1.176 +nsPlaceholderFrame::GetType() const
   1.177 +{
   1.178 +  return nsGkAtoms::placeholderFrame;
   1.179 +}
   1.180 +
   1.181 +/* virtual */ bool
   1.182 +nsPlaceholderFrame::CanContinueTextRun() const
   1.183 +{
   1.184 +  if (!mOutOfFlowFrame) {
   1.185 +    return false;
   1.186 +  }
   1.187 +  // first-letter frames can continue text runs, and placeholders for floated
   1.188 +  // first-letter frames can too
   1.189 +  return mOutOfFlowFrame->CanContinueTextRun();
   1.190 +}
   1.191 +
   1.192 +nsIFrame*
   1.193 +nsPlaceholderFrame::GetParentStyleContextFrame() const
   1.194 +{
   1.195 +  NS_PRECONDITION(GetParent(), "How can we not have a parent here?");
   1.196 +
   1.197 +  // Lie about our pseudo so we can step out of all anon boxes and
   1.198 +  // pseudo-elements.  The other option would be to reimplement the
   1.199 +  // {ib} split gunk here.
   1.200 +  return CorrectStyleParentFrame(GetParent(), nsGkAtoms::placeholderFrame);
   1.201 +}
   1.202 +
   1.203 +
   1.204 +#ifdef DEBUG
   1.205 +static void
   1.206 +PaintDebugPlaceholder(nsIFrame* aFrame, nsRenderingContext* aCtx,
   1.207 +                      const nsRect& aDirtyRect, nsPoint aPt)
   1.208 +{
   1.209 +  aCtx->SetColor(NS_RGB(0, 255, 255));
   1.210 +  nscoord x = nsPresContext::CSSPixelsToAppUnits(-5);
   1.211 +  aCtx->FillRect(aPt.x + x, aPt.y,
   1.212 +                 nsPresContext::CSSPixelsToAppUnits(13),
   1.213 +                 nsPresContext::CSSPixelsToAppUnits(3));
   1.214 +  nscoord y = nsPresContext::CSSPixelsToAppUnits(-10);
   1.215 +  aCtx->FillRect(aPt.x, aPt.y + y,
   1.216 +                 nsPresContext::CSSPixelsToAppUnits(3),
   1.217 +                 nsPresContext::CSSPixelsToAppUnits(10));
   1.218 +}
   1.219 +#endif // DEBUG
   1.220 +
   1.221 +#if defined(DEBUG) || (defined(MOZ_REFLOW_PERF_DSP) && defined(MOZ_REFLOW_PERF))
   1.222 +
   1.223 +void
   1.224 +nsPlaceholderFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
   1.225 +                                     const nsRect&           aDirtyRect,
   1.226 +                                     const nsDisplayListSet& aLists)
   1.227 +{
   1.228 +  DO_GLOBAL_REFLOW_COUNT_DSP("nsPlaceholderFrame");
   1.229 +  
   1.230 +#ifdef DEBUG
   1.231 +  if (GetShowFrameBorders()) {
   1.232 +    aLists.Outlines()->AppendNewToTop(
   1.233 +      new (aBuilder) nsDisplayGeneric(aBuilder, this, PaintDebugPlaceholder,
   1.234 +                                      "DebugPlaceholder",
   1.235 +                                      nsDisplayItem::TYPE_DEBUG_PLACEHOLDER));
   1.236 +  }
   1.237 +#endif
   1.238 +}
   1.239 +#endif // DEBUG || (MOZ_REFLOW_PERF_DSP && MOZ_REFLOW_PERF)
   1.240 +
   1.241 +#ifdef DEBUG_FRAME_DUMP
   1.242 +nsresult
   1.243 +nsPlaceholderFrame::GetFrameName(nsAString& aResult) const
   1.244 +{
   1.245 +  return MakeFrameName(NS_LITERAL_STRING("Placeholder"), aResult);
   1.246 +}
   1.247 +
   1.248 +void
   1.249 +nsPlaceholderFrame::List(FILE* out, const char* aPrefix, uint32_t aFlags) const
   1.250 +{
   1.251 +  nsCString str;
   1.252 +  ListGeneric(str, aPrefix, aFlags);
   1.253 +
   1.254 +  if (mOutOfFlowFrame) {
   1.255 +    str += " outOfFlowFrame=";
   1.256 +    nsFrame::ListTag(str, mOutOfFlowFrame);
   1.257 +  }
   1.258 +  fprintf_stderr(out, "%s\n", str.get());
   1.259 +}
   1.260 +#endif

mercurial