layout/generic/nsFrame.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/layout/generic/nsFrame.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,9892 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +// vim:cindent:ts=2:et:sw=2:
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +/* base class of all rendering objects */
    1.11 +
    1.12 +#include "nsFrame.h"
    1.13 +
    1.14 +#include "mozilla/Attributes.h"
    1.15 +#include "mozilla/DebugOnly.h"
    1.16 +
    1.17 +#include "nsCOMPtr.h"
    1.18 +#include "nsFrameList.h"
    1.19 +#include "nsPlaceholderFrame.h"
    1.20 +#include "nsIContent.h"
    1.21 +#include "nsContentUtils.h"
    1.22 +#include "nsIAtom.h"
    1.23 +#include "nsString.h"
    1.24 +#include "nsReadableUtils.h"
    1.25 +#include "nsStyleContext.h"
    1.26 +#include "nsTableOuterFrame.h"
    1.27 +#include "nsView.h"
    1.28 +#include "nsViewManager.h"
    1.29 +#include "nsIScrollableFrame.h"
    1.30 +#include "nsPresContext.h"
    1.31 +#include "nsStyleConsts.h"
    1.32 +#include "nsIPresShell.h"
    1.33 +#include "prlog.h"
    1.34 +#include "prprf.h"
    1.35 +#include <stdarg.h>
    1.36 +#include "nsFrameManager.h"
    1.37 +#include "nsLayoutUtils.h"
    1.38 +
    1.39 +#include "nsIDOMNode.h"
    1.40 +#include "nsISelection.h"
    1.41 +#include "nsISelectionPrivate.h"
    1.42 +#include "nsFrameSelection.h"
    1.43 +#include "nsGkAtoms.h"
    1.44 +#include "nsCSSAnonBoxes.h"
    1.45 +
    1.46 +#include "nsFrameTraversal.h"
    1.47 +#include "nsRange.h"
    1.48 +#include "nsITextControlFrame.h"
    1.49 +#include "nsNameSpaceManager.h"
    1.50 +#include "nsIPercentHeightObserver.h"
    1.51 +#include "nsStyleStructInlines.h"
    1.52 +#include <algorithm>
    1.53 +
    1.54 +#include "nsBidiPresUtils.h"
    1.55 +
    1.56 +// For triple-click pref
    1.57 +#include "imgIContainer.h"
    1.58 +#include "imgIRequest.h"
    1.59 +#include "nsError.h"
    1.60 +#include "nsContainerFrame.h"
    1.61 +#include "nsBoxLayoutState.h"
    1.62 +#include "nsBlockFrame.h"
    1.63 +#include "nsDisplayList.h"
    1.64 +#include "nsSVGIntegrationUtils.h"
    1.65 +#include "nsSVGEffects.h"
    1.66 +#include "nsChangeHint.h"
    1.67 +#include "nsDeckFrame.h"
    1.68 +#include "nsSubDocumentFrame.h"
    1.69 +#include "SVGTextFrame.h"
    1.70 +
    1.71 +#include "gfxContext.h"
    1.72 +#include "nsRenderingContext.h"
    1.73 +#include "nsAbsoluteContainingBlock.h"
    1.74 +#include "StickyScrollContainer.h"
    1.75 +#include "nsFontInflationData.h"
    1.76 +#include "gfxASurface.h"
    1.77 +#include "nsRegion.h"
    1.78 +#include "nsIFrameInlines.h"
    1.79 +
    1.80 +#include "mozilla/AsyncEventDispatcher.h"
    1.81 +#include "mozilla/EventListenerManager.h"
    1.82 +#include "mozilla/EventStateManager.h"
    1.83 +#include "mozilla/EventStates.h"
    1.84 +#include "mozilla/Preferences.h"
    1.85 +#include "mozilla/LookAndFeel.h"
    1.86 +#include "mozilla/MouseEvents.h"
    1.87 +#include "mozilla/css/ImageLoader.h"
    1.88 +#include "mozilla/gfx/Tools.h"
    1.89 +#include "nsPrintfCString.h"
    1.90 +
    1.91 +using namespace mozilla;
    1.92 +using namespace mozilla::css;
    1.93 +using namespace mozilla::dom;
    1.94 +using namespace mozilla::layers;
    1.95 +using namespace mozilla::layout;
    1.96 +
    1.97 +// Struct containing cached metrics for box-wrapped frames.
    1.98 +struct nsBoxLayoutMetrics
    1.99 +{
   1.100 +  nsSize mPrefSize;
   1.101 +  nsSize mMinSize;
   1.102 +  nsSize mMaxSize;
   1.103 +
   1.104 +  nsSize mBlockMinSize;
   1.105 +  nsSize mBlockPrefSize;
   1.106 +  nscoord mBlockAscent;
   1.107 +
   1.108 +  nscoord mFlex;
   1.109 +  nscoord mAscent;
   1.110 +
   1.111 +  nsSize mLastSize;
   1.112 +};
   1.113 +
   1.114 +struct nsContentAndOffset
   1.115 +{
   1.116 +  nsIContent* mContent;
   1.117 +  int32_t mOffset;
   1.118 +};
   1.119 +
   1.120 +// Some Misc #defines
   1.121 +#define SELECTION_DEBUG        0
   1.122 +#define FORCE_SELECTION_UPDATE 1
   1.123 +#define CALC_DEBUG             0
   1.124 +
   1.125 +
   1.126 +#include "nsILineIterator.h"
   1.127 +
   1.128 +//non Hack prototypes
   1.129 +#if 0
   1.130 +static void RefreshContentFrames(nsPresContext* aPresContext, nsIContent * aStartContent, nsIContent * aEndContent);
   1.131 +#endif
   1.132 +
   1.133 +#include "prenv.h"
   1.134 +
   1.135 +// Formerly the nsIFrameDebug interface
   1.136 +
   1.137 +#ifdef DEBUG
   1.138 +static bool gShowFrameBorders = false;
   1.139 +
   1.140 +void nsFrame::ShowFrameBorders(bool aEnable)
   1.141 +{
   1.142 +  gShowFrameBorders = aEnable;
   1.143 +}
   1.144 +
   1.145 +bool nsFrame::GetShowFrameBorders()
   1.146 +{
   1.147 +  return gShowFrameBorders;
   1.148 +}
   1.149 +
   1.150 +static bool gShowEventTargetFrameBorder = false;
   1.151 +
   1.152 +void nsFrame::ShowEventTargetFrameBorder(bool aEnable)
   1.153 +{
   1.154 +  gShowEventTargetFrameBorder = aEnable;
   1.155 +}
   1.156 +
   1.157 +bool nsFrame::GetShowEventTargetFrameBorder()
   1.158 +{
   1.159 +  return gShowEventTargetFrameBorder;
   1.160 +}
   1.161 +
   1.162 +/**
   1.163 + * Note: the log module is created during library initialization which
   1.164 + * means that you cannot perform logging before then.
   1.165 + */
   1.166 +static PRLogModuleInfo* gLogModule;
   1.167 +
   1.168 +static PRLogModuleInfo* gStyleVerifyTreeLogModuleInfo;
   1.169 +
   1.170 +static uint32_t gStyleVerifyTreeEnable = 0x55;
   1.171 +
   1.172 +bool
   1.173 +nsFrame::GetVerifyStyleTreeEnable()
   1.174 +{
   1.175 +  if (gStyleVerifyTreeEnable == 0x55) {
   1.176 +    if (nullptr == gStyleVerifyTreeLogModuleInfo) {
   1.177 +      gStyleVerifyTreeLogModuleInfo = PR_NewLogModule("styleverifytree");
   1.178 +      gStyleVerifyTreeEnable = 0 != gStyleVerifyTreeLogModuleInfo->level;
   1.179 +    }
   1.180 +  }
   1.181 +  return gStyleVerifyTreeEnable;
   1.182 +}
   1.183 +
   1.184 +void
   1.185 +nsFrame::SetVerifyStyleTreeEnable(bool aEnabled)
   1.186 +{
   1.187 +  gStyleVerifyTreeEnable = aEnabled;
   1.188 +}
   1.189 +
   1.190 +PRLogModuleInfo*
   1.191 +nsFrame::GetLogModuleInfo()
   1.192 +{
   1.193 +  if (nullptr == gLogModule) {
   1.194 +    gLogModule = PR_NewLogModule("frame");
   1.195 +  }
   1.196 +  return gLogModule;
   1.197 +}
   1.198 +
   1.199 +#endif
   1.200 +
   1.201 +static void
   1.202 +DestroyAbsoluteContainingBlock(void* aPropertyValue)
   1.203 +{
   1.204 +  delete static_cast<nsAbsoluteContainingBlock*>(aPropertyValue);
   1.205 +}
   1.206 +
   1.207 +NS_DECLARE_FRAME_PROPERTY(AbsoluteContainingBlockProperty, DestroyAbsoluteContainingBlock)
   1.208 +
   1.209 +bool
   1.210 +nsIFrame::HasAbsolutelyPositionedChildren() const {
   1.211 +  return IsAbsoluteContainer() && GetAbsoluteContainingBlock()->HasAbsoluteFrames();
   1.212 +}
   1.213 +
   1.214 +nsAbsoluteContainingBlock*
   1.215 +nsIFrame::GetAbsoluteContainingBlock() const {
   1.216 +  NS_ASSERTION(IsAbsoluteContainer(), "The frame is not marked as an abspos container correctly");
   1.217 +  nsAbsoluteContainingBlock* absCB = static_cast<nsAbsoluteContainingBlock*>
   1.218 +    (Properties().Get(AbsoluteContainingBlockProperty()));
   1.219 +  NS_ASSERTION(absCB, "The frame is marked as an abspos container but doesn't have the property");
   1.220 +  return absCB;
   1.221 +}
   1.222 +
   1.223 +void
   1.224 +nsIFrame::MarkAsAbsoluteContainingBlock()
   1.225 +{
   1.226 +  MOZ_ASSERT(GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
   1.227 +  NS_ASSERTION(!Properties().Get(AbsoluteContainingBlockProperty()),
   1.228 +               "Already has an abs-pos containing block property?");
   1.229 +  NS_ASSERTION(!HasAnyStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN),
   1.230 +               "Already has NS_FRAME_HAS_ABSPOS_CHILDREN state bit?");
   1.231 +  AddStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN);
   1.232 +  Properties().Set(AbsoluteContainingBlockProperty(), new nsAbsoluteContainingBlock(GetAbsoluteListID()));
   1.233 +}
   1.234 +
   1.235 +void
   1.236 +nsIFrame::MarkAsNotAbsoluteContainingBlock()
   1.237 +{
   1.238 +  NS_ASSERTION(!HasAbsolutelyPositionedChildren(), "Think of the children!");
   1.239 +  NS_ASSERTION(Properties().Get(AbsoluteContainingBlockProperty()),
   1.240 +               "Should have an abs-pos containing block property");
   1.241 +  NS_ASSERTION(HasAnyStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN),
   1.242 +               "Should have NS_FRAME_HAS_ABSPOS_CHILDREN state bit");
   1.243 +  MOZ_ASSERT(HasAnyStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN));
   1.244 +  RemoveStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN);
   1.245 +  Properties().Delete(AbsoluteContainingBlockProperty());
   1.246 +}
   1.247 +
   1.248 +bool
   1.249 +nsIFrame::CheckAndClearPaintedState()
   1.250 +{
   1.251 +  bool result = (GetStateBits() & NS_FRAME_PAINTED_THEBES);
   1.252 +  RemoveStateBits(NS_FRAME_PAINTED_THEBES);
   1.253 +  
   1.254 +  nsIFrame::ChildListIterator lists(this);
   1.255 +  for (; !lists.IsDone(); lists.Next()) {
   1.256 +    nsFrameList::Enumerator childFrames(lists.CurrentList());
   1.257 +    for (; !childFrames.AtEnd(); childFrames.Next()) {
   1.258 +      nsIFrame* child = childFrames.get();
   1.259 +      if (child->CheckAndClearPaintedState()) {
   1.260 +        result = true;
   1.261 +      }
   1.262 +    }
   1.263 +  }
   1.264 +  return result;
   1.265 +}
   1.266 +
   1.267 +bool
   1.268 +nsIFrame::IsVisibleConsideringAncestors(uint32_t aFlags) const
   1.269 +{
   1.270 +  if (!StyleVisibility()->IsVisible()) {
   1.271 +    return false;
   1.272 +  }
   1.273 +
   1.274 +  const nsIFrame* frame = this;
   1.275 +  while (frame) {
   1.276 +    nsView* view = frame->GetView();
   1.277 +    if (view && view->GetVisibility() == nsViewVisibility_kHide)
   1.278 +      return false;
   1.279 +    
   1.280 +    nsIFrame* parent = frame->GetParent();
   1.281 +    nsDeckFrame* deck = do_QueryFrame(parent);
   1.282 +    if (deck) {
   1.283 +      if (deck->GetSelectedBox() != frame)
   1.284 +        return false;
   1.285 +    }
   1.286 +
   1.287 +    if (parent) {
   1.288 +      frame = parent;
   1.289 +    } else {
   1.290 +      parent = nsLayoutUtils::GetCrossDocParentFrame(frame);
   1.291 +      if (!parent)
   1.292 +        break;
   1.293 +
   1.294 +      if ((aFlags & nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) == 0 &&
   1.295 +          parent->PresContext()->IsChrome() && !frame->PresContext()->IsChrome()) {
   1.296 +        break;
   1.297 +      }
   1.298 +
   1.299 +      if (!parent->StyleVisibility()->IsVisible())
   1.300 +        return false;
   1.301 +
   1.302 +      frame = parent;
   1.303 +    }
   1.304 +  }
   1.305 +
   1.306 +  return true;
   1.307 +}
   1.308 +
   1.309 +void
   1.310 +nsIFrame::FindCloserFrameForSelection(
   1.311 +                                 nsPoint aPoint,
   1.312 +                                 nsIFrame::FrameWithDistance* aCurrentBestFrame)
   1.313 +{
   1.314 +  if (nsLayoutUtils::PointIsCloserToRect(aPoint, mRect,
   1.315 +                                         aCurrentBestFrame->mXDistance,
   1.316 +                                         aCurrentBestFrame->mYDistance)) {
   1.317 +    aCurrentBestFrame->mFrame = this;
   1.318 +  }
   1.319 +}
   1.320 +
   1.321 +void
   1.322 +nsIFrame::ContentStatesChanged(mozilla::EventStates aStates)
   1.323 +{
   1.324 +}
   1.325 +
   1.326 +void
   1.327 +NS_MergeReflowStatusInto(nsReflowStatus* aPrimary, nsReflowStatus aSecondary)
   1.328 +{
   1.329 +  *aPrimary |= aSecondary &
   1.330 +    (NS_FRAME_NOT_COMPLETE | NS_FRAME_OVERFLOW_INCOMPLETE |
   1.331 +     NS_FRAME_TRUNCATED | NS_FRAME_REFLOW_NEXTINFLOW);
   1.332 +  if (*aPrimary & NS_FRAME_NOT_COMPLETE) {
   1.333 +    *aPrimary &= ~NS_FRAME_OVERFLOW_INCOMPLETE;
   1.334 +  }
   1.335 +}
   1.336 +
   1.337 +void
   1.338 +nsWeakFrame::Init(nsIFrame* aFrame)
   1.339 +{
   1.340 +  Clear(mFrame ? mFrame->PresContext()->GetPresShell() : nullptr);
   1.341 +  mFrame = aFrame;
   1.342 +  if (mFrame) {
   1.343 +    nsIPresShell* shell = mFrame->PresContext()->GetPresShell();
   1.344 +    NS_WARN_IF_FALSE(shell, "Null PresShell in nsWeakFrame!");
   1.345 +    if (shell) {
   1.346 +      shell->AddWeakFrame(this);
   1.347 +    } else {
   1.348 +      mFrame = nullptr;
   1.349 +    }
   1.350 +  }
   1.351 +}
   1.352 +
   1.353 +nsIFrame*
   1.354 +NS_NewEmptyFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
   1.355 +{
   1.356 +  return new (aPresShell) nsFrame(aContext);
   1.357 +}
   1.358 +
   1.359 +nsFrame::nsFrame(nsStyleContext* aContext)
   1.360 +{
   1.361 +  MOZ_COUNT_CTOR(nsFrame);
   1.362 +
   1.363 +  mState = NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY;
   1.364 +  mStyleContext = aContext;
   1.365 +  mStyleContext->AddRef();
   1.366 +}
   1.367 +
   1.368 +nsFrame::~nsFrame()
   1.369 +{
   1.370 +  MOZ_COUNT_DTOR(nsFrame);
   1.371 +
   1.372 +  NS_IF_RELEASE(mContent);
   1.373 +  mStyleContext->Release();
   1.374 +}
   1.375 +
   1.376 +NS_IMPL_FRAMEARENA_HELPERS(nsFrame)
   1.377 +
   1.378 +// Dummy operator delete.  Will never be called, but must be defined
   1.379 +// to satisfy some C++ ABIs.
   1.380 +void
   1.381 +nsFrame::operator delete(void *, size_t)
   1.382 +{
   1.383 +  NS_RUNTIMEABORT("nsFrame::operator delete should never be called");
   1.384 +}
   1.385 +
   1.386 +NS_QUERYFRAME_HEAD(nsFrame)
   1.387 +  NS_QUERYFRAME_ENTRY(nsIFrame)
   1.388 +NS_QUERYFRAME_TAIL_INHERITANCE_ROOT
   1.389 +
   1.390 +/////////////////////////////////////////////////////////////////////////////
   1.391 +// nsIFrame
   1.392 +
   1.393 +static bool
   1.394 +IsFontSizeInflationContainer(nsIFrame* aFrame,
   1.395 +                             const nsStyleDisplay* aStyleDisplay)
   1.396 +{
   1.397 +  /*
   1.398 +   * Font size inflation is built around the idea that we're inflating
   1.399 +   * the fonts for a pan-and-zoom UI so that when the user scales up a
   1.400 +   * block or other container to fill the width of the device, the fonts
   1.401 +   * will be readable.  To do this, we need to pick what counts as a
   1.402 +   * container.
   1.403 +   *
   1.404 +   * From a code perspective, the only hard requirement is that frames
   1.405 +   * that are line participants
   1.406 +   * (nsIFrame::IsFrameOfType(nsIFrame::eLineParticipant)) are never
   1.407 +   * containers, since line layout assumes that the inflation is
   1.408 +   * consistent within a line.
   1.409 +   *
   1.410 +   * This is not an imposition, since we obviously want a bunch of text
   1.411 +   * (possibly with inline elements) flowing within a block to count the
   1.412 +   * block (or higher) as its container.
   1.413 +   *
   1.414 +   * We also want form controls, including the text in the anonymous
   1.415 +   * content inside of them, to match each other and the text next to
   1.416 +   * them, so they and their anonymous content should also not be a
   1.417 +   * container.
   1.418 +   *
   1.419 +   * However, because we can't reliably compute sizes across XUL during
   1.420 +   * reflow, any XUL frame with a XUL parent is always a container.
   1.421 +   *
   1.422 +   * There are contexts where it would be nice if some blocks didn't
   1.423 +   * count as a container, so that, for example, an indented quotation
   1.424 +   * didn't end up with a smaller font size.  However, it's hard to
   1.425 +   * distinguish these situations where we really do want the indented
   1.426 +   * thing to count as a container, so we don't try, and blocks are
   1.427 +   * always containers.
   1.428 +   */
   1.429 +
   1.430 +  // The root frame should always be an inflation container.
   1.431 +  if (!aFrame->GetParent()) {
   1.432 +    return true;
   1.433 +  }
   1.434 +
   1.435 +  nsIContent *content = aFrame->GetContent();
   1.436 +  bool isInline = (aFrame->GetDisplay() == NS_STYLE_DISPLAY_INLINE ||
   1.437 +                   (aFrame->IsFloating() &&
   1.438 +                    aFrame->GetType() == nsGkAtoms::letterFrame) ||
   1.439 +                   // Given multiple frames for the same node, only the
   1.440 +                   // outer one should be considered a container.
   1.441 +                   // (Important, e.g., for nsSelectsAreaFrame.)
   1.442 +                   (aFrame->GetParent()->GetContent() == content) ||
   1.443 +                   (content && (content->IsHTML(nsGkAtoms::option) ||
   1.444 +                                content->IsHTML(nsGkAtoms::optgroup) ||
   1.445 +                                content->IsHTML(nsGkAtoms::select) ||
   1.446 +                                content->IsInNativeAnonymousSubtree()))) &&
   1.447 +                  !(aFrame->IsBoxFrame() && aFrame->GetParent()->IsBoxFrame());
   1.448 +  NS_ASSERTION(!aFrame->IsFrameOfType(nsIFrame::eLineParticipant) ||
   1.449 +               isInline ||
   1.450 +               // br frames and mathml frames report being line
   1.451 +               // participants even when their position or display is
   1.452 +               // set
   1.453 +               aFrame->GetType() == nsGkAtoms::brFrame ||
   1.454 +               aFrame->IsFrameOfType(nsIFrame::eMathML),
   1.455 +               "line participants must not be containers");
   1.456 +  NS_ASSERTION(aFrame->GetType() != nsGkAtoms::bulletFrame || isInline,
   1.457 +               "bullets should not be containers");
   1.458 +  return !isInline;
   1.459 +}
   1.460 +
   1.461 +void
   1.462 +nsFrame::Init(nsIContent*      aContent,
   1.463 +              nsIFrame*        aParent,
   1.464 +              nsIFrame*        aPrevInFlow)
   1.465 +{
   1.466 +  NS_PRECONDITION(!mContent, "Double-initing a frame?");
   1.467 +  NS_ASSERTION(IsFrameOfType(eDEBUGAllFrames) &&
   1.468 +               !IsFrameOfType(eDEBUGNoFrames),
   1.469 +               "IsFrameOfType implementation that doesn't call base class");
   1.470 +
   1.471 +  mContent = aContent;
   1.472 +  mParent = aParent;
   1.473 +
   1.474 +  if (aContent) {
   1.475 +    NS_ADDREF(aContent);
   1.476 +  }
   1.477 +
   1.478 +  if (aPrevInFlow) {
   1.479 +    // Make sure the general flags bits are the same
   1.480 +    nsFrameState state = aPrevInFlow->GetStateBits();
   1.481 +
   1.482 +    // Make bits that are currently off (see constructor) the same:
   1.483 +    mState |= state & (NS_FRAME_INDEPENDENT_SELECTION |
   1.484 +                       NS_FRAME_PART_OF_IBSPLIT |
   1.485 +                       NS_FRAME_MAY_BE_TRANSFORMED |
   1.486 +                       NS_FRAME_MAY_HAVE_GENERATED_CONTENT |
   1.487 +                       NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
   1.488 +  }
   1.489 +  if (mParent) {
   1.490 +    nsFrameState state = mParent->GetStateBits();
   1.491 +
   1.492 +    // Make bits that are currently off (see constructor) the same:
   1.493 +    mState |= state & (NS_FRAME_INDEPENDENT_SELECTION |
   1.494 +                       NS_FRAME_GENERATED_CONTENT |
   1.495 +                       NS_FRAME_IS_SVG_TEXT |
   1.496 +                       NS_FRAME_IN_POPUP |
   1.497 +                       NS_FRAME_IS_NONDISPLAY);
   1.498 +  }
   1.499 +  const nsStyleDisplay *disp = StyleDisplay();
   1.500 +  if (disp->HasTransform(this)) {
   1.501 +    // The frame gets reconstructed if we toggle the -moz-transform
   1.502 +    // property, so we can set this bit here and then ignore it.
   1.503 +    mState |= NS_FRAME_MAY_BE_TRANSFORMED;
   1.504 +  }
   1.505 +  if (disp->mPosition == NS_STYLE_POSITION_STICKY &&
   1.506 +      !aPrevInFlow &&
   1.507 +      !(mState & NS_FRAME_IS_NONDISPLAY) &&
   1.508 +      !disp->IsInnerTableStyle()) {
   1.509 +    // Note that we only add first continuations, but we really only
   1.510 +    // want to add first continuation-or-ib-split-siblings.  But since we
   1.511 +    // don't yet know if we're a later part of a block-in-inline split,
   1.512 +    // we'll just add later members of a block-in-inline split here, and
   1.513 +    // then StickyScrollContainer will remove them later.
   1.514 +    // We don't currently support relative positioning of inner table
   1.515 +    // elements (bug 35168), so exclude them from sticky positioning too.
   1.516 +    StickyScrollContainer* ssc =
   1.517 +      StickyScrollContainer::GetStickyScrollContainerForFrame(this);
   1.518 +    if (ssc) {
   1.519 +      ssc->AddFrame(this);
   1.520 +    }
   1.521 +  }
   1.522 +
   1.523 +  if (nsLayoutUtils::FontSizeInflationEnabled(PresContext()) || !GetParent()
   1.524 +#ifdef DEBUG
   1.525 +      // We have assertions that check inflation invariants even when
   1.526 +      // font size inflation is not enabled.
   1.527 +      || true
   1.528 +#endif
   1.529 +      ) {
   1.530 +    if (IsFontSizeInflationContainer(this, disp)) {
   1.531 +      AddStateBits(NS_FRAME_FONT_INFLATION_CONTAINER);
   1.532 +      if (!GetParent() ||
   1.533 +          // I'd use NS_FRAME_OUT_OF_FLOW, but it's not set yet.
   1.534 +          disp->IsFloating(this) || disp->IsAbsolutelyPositioned(this)) {
   1.535 +        AddStateBits(NS_FRAME_FONT_INFLATION_FLOW_ROOT);
   1.536 +      }
   1.537 +    }
   1.538 +    NS_ASSERTION(GetParent() ||
   1.539 +                 (GetStateBits() & NS_FRAME_FONT_INFLATION_CONTAINER),
   1.540 +                 "root frame should always be a container");
   1.541 +  }
   1.542 +
   1.543 +  DidSetStyleContext(nullptr);
   1.544 +
   1.545 +  if (IsBoxWrapped())
   1.546 +    InitBoxMetrics(false);
   1.547 +}
   1.548 +
   1.549 +nsresult nsFrame::SetInitialChildList(ChildListID     aListID,
   1.550 +                                           nsFrameList&    aChildList)
   1.551 +{
   1.552 +  // XXX This shouldn't be getting called at all, but currently is for backwards
   1.553 +  // compatility reasons...
   1.554 +#if 0
   1.555 +  NS_ERROR("not a container");
   1.556 +  return NS_ERROR_UNEXPECTED;
   1.557 +#else
   1.558 +  NS_ASSERTION(aChildList.IsEmpty(), "not a container");
   1.559 +  return NS_OK;
   1.560 +#endif
   1.561 +}
   1.562 +
   1.563 +nsresult
   1.564 +nsFrame::AppendFrames(ChildListID     aListID,
   1.565 +                      nsFrameList&    aFrameList)
   1.566 +{
   1.567 +  NS_PRECONDITION(false, "not a container");
   1.568 +  return NS_ERROR_UNEXPECTED;
   1.569 +}
   1.570 +
   1.571 +nsresult
   1.572 +nsFrame::InsertFrames(ChildListID     aListID,
   1.573 +                      nsIFrame*       aPrevFrame,
   1.574 +                      nsFrameList&    aFrameList)
   1.575 +{
   1.576 +  NS_PRECONDITION(false, "not a container");
   1.577 +  return NS_ERROR_UNEXPECTED;
   1.578 +}
   1.579 +
   1.580 +nsresult
   1.581 +nsFrame::RemoveFrame(ChildListID     aListID,
   1.582 +                     nsIFrame*       aOldFrame)
   1.583 +{
   1.584 +  NS_PRECONDITION(false, "not a container");
   1.585 +  return NS_ERROR_UNEXPECTED;
   1.586 +}
   1.587 +
   1.588 +void
   1.589 +nsFrame::DestroyFrom(nsIFrame* aDestructRoot)
   1.590 +{
   1.591 +  NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
   1.592 +    "destroy called on frame while scripts not blocked");
   1.593 +  NS_ASSERTION(!GetNextSibling() && !GetPrevSibling(),
   1.594 +               "Frames should be removed before destruction.");
   1.595 +  NS_ASSERTION(aDestructRoot, "Must specify destruct root");
   1.596 +  MOZ_ASSERT(!HasAbsolutelyPositionedChildren());
   1.597 +
   1.598 +  nsSVGEffects::InvalidateDirectRenderingObservers(this);
   1.599 +
   1.600 +  if (StyleDisplay()->mPosition == NS_STYLE_POSITION_STICKY) {
   1.601 +    StickyScrollContainer* ssc =
   1.602 +      StickyScrollContainer::GetStickyScrollContainerForFrame(this);
   1.603 +    if (ssc) {
   1.604 +      ssc->RemoveFrame(this);
   1.605 +    }
   1.606 +  }
   1.607 +
   1.608 +  // Get the view pointer now before the frame properties disappear
   1.609 +  // when we call NotifyDestroyingFrame()
   1.610 +  nsView* view = GetView();
   1.611 +  nsPresContext* presContext = PresContext();
   1.612 +
   1.613 +  nsIPresShell *shell = presContext->GetPresShell();
   1.614 +  if (mState & NS_FRAME_OUT_OF_FLOW) {
   1.615 +    nsPlaceholderFrame* placeholder =
   1.616 +      shell->FrameManager()->GetPlaceholderFrameFor(this);
   1.617 +    NS_ASSERTION(!placeholder || (aDestructRoot != this),
   1.618 +                 "Don't call Destroy() on OOFs, call Destroy() on the placeholder.");
   1.619 +    NS_ASSERTION(!placeholder ||
   1.620 +                 nsLayoutUtils::IsProperAncestorFrame(aDestructRoot, placeholder),
   1.621 +                 "Placeholder relationship should have been torn down already; "
   1.622 +                 "this might mean we have a stray placeholder in the tree.");
   1.623 +    if (placeholder) {
   1.624 +      shell->FrameManager()->UnregisterPlaceholderFrame(placeholder);
   1.625 +      placeholder->SetOutOfFlowFrame(nullptr);
   1.626 +    }
   1.627 +  }
   1.628 +
   1.629 +  // If we have any IB split siblings, clear their references to us.
   1.630 +  // (Note: This has to happen before we call shell->NotifyDestroyingFrame,
   1.631 +  // because that clears our Properties() table.)
   1.632 +  if (mState & NS_FRAME_PART_OF_IBSPLIT) {
   1.633 +    // Delete previous sibling's reference to me.
   1.634 +    nsIFrame* prevSib = static_cast<nsIFrame*>
   1.635 +      (Properties().Get(nsIFrame::IBSplitPrevSibling()));
   1.636 +    if (prevSib) {
   1.637 +      NS_WARN_IF_FALSE(this ==
   1.638 +         prevSib->Properties().Get(nsIFrame::IBSplitSibling()),
   1.639 +         "IB sibling chain is inconsistent");
   1.640 +      prevSib->Properties().Delete(nsIFrame::IBSplitSibling());
   1.641 +    }
   1.642 +
   1.643 +    // Delete next sibling's reference to me.
   1.644 +    nsIFrame* nextSib = static_cast<nsIFrame*>
   1.645 +      (Properties().Get(nsIFrame::IBSplitSibling()));
   1.646 +    if (nextSib) {
   1.647 +      NS_WARN_IF_FALSE(this ==
   1.648 +         nextSib->Properties().Get(nsIFrame::IBSplitPrevSibling()),
   1.649 +         "IB sibling chain is inconsistent");
   1.650 +      nextSib->Properties().Delete(nsIFrame::IBSplitPrevSibling());
   1.651 +    }
   1.652 +  }
   1.653 +
   1.654 +  shell->NotifyDestroyingFrame(this);
   1.655 +
   1.656 +  if (mState & NS_FRAME_EXTERNAL_REFERENCE) {
   1.657 +    shell->ClearFrameRefs(this);
   1.658 +  }
   1.659 +
   1.660 +  if (view) {
   1.661 +    // Break association between view and frame
   1.662 +    view->SetFrame(nullptr);
   1.663 +
   1.664 +    // Destroy the view
   1.665 +    view->Destroy();
   1.666 +  }
   1.667 +
   1.668 +  // Make sure that our deleted frame can't be returned from GetPrimaryFrame()
   1.669 +  if (mContent && mContent->GetPrimaryFrame() == this) {
   1.670 +    mContent->SetPrimaryFrame(nullptr);
   1.671 +  }
   1.672 +
   1.673 +  // Must retrieve the object ID before calling destructors, so the
   1.674 +  // vtable is still valid.
   1.675 +  //
   1.676 +  // Note to future tweakers: having the method that returns the
   1.677 +  // object size call the destructor will not avoid an indirect call;
   1.678 +  // the compiler cannot devirtualize the call to the destructor even
   1.679 +  // if it's from a method defined in the same class.
   1.680 +
   1.681 +  nsQueryFrame::FrameIID id = GetFrameId();
   1.682 +  this->~nsFrame();
   1.683 +
   1.684 +  // Now that we're totally cleaned out, we need to add ourselves to
   1.685 +  // the presshell's recycler.
   1.686 +  shell->FreeFrame(id, this);
   1.687 +}
   1.688 +
   1.689 +nsresult
   1.690 +nsFrame::GetOffsets(int32_t &aStart, int32_t &aEnd) const
   1.691 +{
   1.692 +  aStart = 0;
   1.693 +  aEnd = 0;
   1.694 +  return NS_OK;
   1.695 +}
   1.696 +
   1.697 +// Subclass hook for style post processing
   1.698 +/* virtual */ void
   1.699 +nsFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
   1.700 +{
   1.701 +  if (IsSVGText()) {
   1.702 +    SVGTextFrame* svgTextFrame = static_cast<SVGTextFrame*>(
   1.703 +        nsLayoutUtils::GetClosestFrameOfType(this, nsGkAtoms::svgTextFrame));
   1.704 +    nsIFrame* anonBlock = svgTextFrame->GetFirstPrincipalChild();
   1.705 +    // Just as in SVGTextFrame::DidSetStyleContext, we need to ensure that
   1.706 +    // any non-display SVGTextFrames get reflowed when a child text frame
   1.707 +    // gets new style.
   1.708 +    //
   1.709 +    // Note that we must check NS_FRAME_FIRST_REFLOW on our SVGTextFrame's
   1.710 +    // anonymous block frame rather than our self, since NS_FRAME_FIRST_REFLOW
   1.711 +    // may be set on us if we're a new frame that has been inserted after the
   1.712 +    // document's first reflow. (In which case this DidSetStyleContext call may
   1.713 +    // be happening under frame construction under a Reflow() call.)
   1.714 +    if (anonBlock && !(anonBlock->GetStateBits() & NS_FRAME_FIRST_REFLOW) &&
   1.715 +        (svgTextFrame->GetStateBits() & NS_FRAME_IS_NONDISPLAY) &&
   1.716 +        !(svgTextFrame->GetStateBits() & NS_STATE_SVG_TEXT_IN_REFLOW)) {
   1.717 +      svgTextFrame->ScheduleReflowSVGNonDisplayText();
   1.718 +    }
   1.719 +  }
   1.720 +
   1.721 +  ImageLoader* imageLoader = PresContext()->Document()->StyleImageLoader();
   1.722 +
   1.723 +  // If the old context had a background image image and new context
   1.724 +  // does not have the same image, clear the image load notifier
   1.725 +  // (which keeps the image loading, if it still is) for the frame.
   1.726 +  // We want to do this conservatively because some frames paint their
   1.727 +  // backgrounds from some other frame's style data, and we don't want
   1.728 +  // to clear those notifiers unless we have to.  (They'll be reset
   1.729 +  // when we paint, although we could miss a notification in that
   1.730 +  // interval.)
   1.731 +  const nsStyleBackground *oldBG = aOldStyleContext ?
   1.732 +                                   aOldStyleContext->StyleBackground() :
   1.733 +                                   nullptr;
   1.734 +  const nsStyleBackground *newBG = StyleBackground();
   1.735 +  if (oldBG) {
   1.736 +    NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, oldBG) {
   1.737 +      // If there is an image in oldBG that's not in newBG, drop it.
   1.738 +      if (i >= newBG->mImageCount ||
   1.739 +          !oldBG->mLayers[i].mImage.ImageDataEquals(newBG->mLayers[i].mImage)) {
   1.740 +        const nsStyleImage& oldImage = oldBG->mLayers[i].mImage;
   1.741 +        if (oldImage.GetType() != eStyleImageType_Image) {
   1.742 +          continue;
   1.743 +        }
   1.744 +
   1.745 +        imageLoader->DisassociateRequestFromFrame(oldImage.GetImageData(),
   1.746 +                                                  this);
   1.747 +      }          
   1.748 +    }
   1.749 +  }
   1.750 +
   1.751 +  NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, newBG) {
   1.752 +    // If there is an image in newBG that's not in oldBG, add it.
   1.753 +    if (!oldBG || i >= oldBG->mImageCount ||
   1.754 +        !newBG->mLayers[i].mImage.ImageDataEquals(oldBG->mLayers[i].mImage)) {
   1.755 +      const nsStyleImage& newImage = newBG->mLayers[i].mImage;
   1.756 +      if (newImage.GetType() != eStyleImageType_Image) {
   1.757 +        continue;
   1.758 +      }
   1.759 +
   1.760 +      imageLoader->AssociateRequestToFrame(newImage.GetImageData(), this);
   1.761 +    }          
   1.762 +  }
   1.763 +
   1.764 +  if (aOldStyleContext) {
   1.765 +    // If we detect a change on margin, padding or border, we store the old
   1.766 +    // values on the frame itself between now and reflow, so if someone
   1.767 +    // calls GetUsed(Margin|Border|Padding)() before the next reflow, we
   1.768 +    // can give an accurate answer.
   1.769 +    // We don't want to set the property if one already exists.
   1.770 +    FrameProperties props = Properties();
   1.771 +    nsMargin oldValue(0, 0, 0, 0);
   1.772 +    nsMargin newValue(0, 0, 0, 0);
   1.773 +    const nsStyleMargin* oldMargin = aOldStyleContext->PeekStyleMargin();
   1.774 +    if (oldMargin && oldMargin->GetMargin(oldValue)) {
   1.775 +      if ((!StyleMargin()->GetMargin(newValue) || oldValue != newValue) &&
   1.776 +          !props.Get(UsedMarginProperty())) {
   1.777 +        props.Set(UsedMarginProperty(), new nsMargin(oldValue));
   1.778 +      }
   1.779 +    }
   1.780 +
   1.781 +    const nsStylePadding* oldPadding = aOldStyleContext->PeekStylePadding();
   1.782 +    if (oldPadding && oldPadding->GetPadding(oldValue)) {
   1.783 +      if ((!StylePadding()->GetPadding(newValue) || oldValue != newValue) &&
   1.784 +          !props.Get(UsedPaddingProperty())) {
   1.785 +        props.Set(UsedPaddingProperty(), new nsMargin(oldValue));
   1.786 +      }
   1.787 +    }
   1.788 +
   1.789 +    const nsStyleBorder* oldBorder = aOldStyleContext->PeekStyleBorder();
   1.790 +    if (oldBorder) {
   1.791 +      oldValue = oldBorder->GetComputedBorder();
   1.792 +      newValue = StyleBorder()->GetComputedBorder();
   1.793 +      if (oldValue != newValue &&
   1.794 +          !props.Get(UsedBorderProperty())) {
   1.795 +        props.Set(UsedBorderProperty(), new nsMargin(oldValue));
   1.796 +      }
   1.797 +    }
   1.798 +  }
   1.799 +
   1.800 +  imgIRequest *oldBorderImage = aOldStyleContext
   1.801 +    ? aOldStyleContext->StyleBorder()->GetBorderImageRequest()
   1.802 +    : nullptr;
   1.803 +  imgIRequest *newBorderImage = StyleBorder()->GetBorderImageRequest();
   1.804 +  // FIXME (Bug 759996): The following is no longer true.
   1.805 +  // For border-images, we can't be as conservative (we need to set the
   1.806 +  // new loaders if there has been any change) since the CalcDifference
   1.807 +  // call depended on the result of GetComputedBorder() and that result
   1.808 +  // depends on whether the image has loaded, start the image load now
   1.809 +  // so that we'll get notified when it completes loading and can do a
   1.810 +  // restyle.  Otherwise, the image might finish loading from the
   1.811 +  // network before we start listening to its notifications, and then
   1.812 +  // we'll never know that it's finished loading.  Likewise, we want to
   1.813 +  // do this for freshly-created frames to prevent a similar race if the
   1.814 +  // image loads between reflow (which can depend on whether the image
   1.815 +  // is loaded) and paint.  We also don't really care about any callers
   1.816 +  // who try to paint borders with a different style context, because
   1.817 +  // they won't have the correct size for the border either.
   1.818 +  if (oldBorderImage != newBorderImage) {
   1.819 +    // stop and restart the image loading/notification
   1.820 +    if (oldBorderImage) {
   1.821 +      imageLoader->DisassociateRequestFromFrame(oldBorderImage, this);
   1.822 +    }
   1.823 +    if (newBorderImage) {
   1.824 +      imageLoader->AssociateRequestToFrame(newBorderImage, this);
   1.825 +    }
   1.826 +  }
   1.827 +
   1.828 +  // If the page contains markup that overrides text direction, and
   1.829 +  // does not contain any characters that would activate the Unicode
   1.830 +  // bidi algorithm, we need to call |SetBidiEnabled| on the pres
   1.831 +  // context before reflow starts.  See bug 115921.
   1.832 +  if (StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL) {
   1.833 +    PresContext()->SetBidiEnabled();
   1.834 +  }
   1.835 +}
   1.836 +
   1.837 +// MSVC fails with link error "one or more multiply defined symbols found",
   1.838 +// gcc fails with "hidden symbol `nsIFrame::kPrincipalList' isn't defined"
   1.839 +// etc if they are not defined.
   1.840 +#ifndef _MSC_VER
   1.841 +// static nsIFrame constants; initialized in the header file.
   1.842 +const nsIFrame::ChildListID nsIFrame::kPrincipalList;
   1.843 +const nsIFrame::ChildListID nsIFrame::kAbsoluteList;
   1.844 +const nsIFrame::ChildListID nsIFrame::kBulletList;
   1.845 +const nsIFrame::ChildListID nsIFrame::kCaptionList;
   1.846 +const nsIFrame::ChildListID nsIFrame::kColGroupList;
   1.847 +const nsIFrame::ChildListID nsIFrame::kExcessOverflowContainersList;
   1.848 +const nsIFrame::ChildListID nsIFrame::kFixedList;
   1.849 +const nsIFrame::ChildListID nsIFrame::kFloatList;
   1.850 +const nsIFrame::ChildListID nsIFrame::kOverflowContainersList;
   1.851 +const nsIFrame::ChildListID nsIFrame::kOverflowList;
   1.852 +const nsIFrame::ChildListID nsIFrame::kOverflowOutOfFlowList;
   1.853 +const nsIFrame::ChildListID nsIFrame::kPopupList;
   1.854 +const nsIFrame::ChildListID nsIFrame::kPushedFloatsList;
   1.855 +const nsIFrame::ChildListID nsIFrame::kSelectPopupList;
   1.856 +const nsIFrame::ChildListID nsIFrame::kNoReflowPrincipalList;
   1.857 +#endif
   1.858 +
   1.859 +/* virtual */ nsMargin
   1.860 +nsIFrame::GetUsedMargin() const
   1.861 +{
   1.862 +  nsMargin margin(0, 0, 0, 0);
   1.863 +  if (((mState & NS_FRAME_FIRST_REFLOW) &&
   1.864 +       !(mState & NS_FRAME_IN_REFLOW)) ||
   1.865 +      IsSVGText())
   1.866 +    return margin;
   1.867 +
   1.868 +  nsMargin *m = static_cast<nsMargin*>
   1.869 +                           (Properties().Get(UsedMarginProperty()));
   1.870 +  if (m) {
   1.871 +    margin = *m;
   1.872 +  } else {
   1.873 +    DebugOnly<bool> hasMargin = StyleMargin()->GetMargin(margin);
   1.874 +    NS_ASSERTION(hasMargin, "We should have a margin here! (out of memory?)");
   1.875 +  }
   1.876 +  return margin;
   1.877 +}
   1.878 +
   1.879 +/* virtual */ nsMargin
   1.880 +nsIFrame::GetUsedBorder() const
   1.881 +{
   1.882 +  nsMargin border(0, 0, 0, 0);
   1.883 +  if (((mState & NS_FRAME_FIRST_REFLOW) &&
   1.884 +       !(mState & NS_FRAME_IN_REFLOW)) ||
   1.885 +      IsSVGText())
   1.886 +    return border;
   1.887 +
   1.888 +  // Theme methods don't use const-ness.
   1.889 +  nsIFrame *mutable_this = const_cast<nsIFrame*>(this);
   1.890 +
   1.891 +  const nsStyleDisplay *disp = StyleDisplay();
   1.892 +  if (mutable_this->IsThemed(disp)) {
   1.893 +    nsIntMargin result;
   1.894 +    nsPresContext *presContext = PresContext();
   1.895 +    presContext->GetTheme()->GetWidgetBorder(presContext->DeviceContext(),
   1.896 +                                             mutable_this, disp->mAppearance,
   1.897 +                                             &result);
   1.898 +    border.left = presContext->DevPixelsToAppUnits(result.left);
   1.899 +    border.top = presContext->DevPixelsToAppUnits(result.top);
   1.900 +    border.right = presContext->DevPixelsToAppUnits(result.right);
   1.901 +    border.bottom = presContext->DevPixelsToAppUnits(result.bottom);
   1.902 +    return border;
   1.903 +  }
   1.904 +
   1.905 +  nsMargin *b = static_cast<nsMargin*>
   1.906 +                           (Properties().Get(UsedBorderProperty()));
   1.907 +  if (b) {
   1.908 +    border = *b;
   1.909 +  } else {
   1.910 +    border = StyleBorder()->GetComputedBorder();
   1.911 +  }
   1.912 +  return border;
   1.913 +}
   1.914 +
   1.915 +/* virtual */ nsMargin
   1.916 +nsIFrame::GetUsedPadding() const
   1.917 +{
   1.918 +  nsMargin padding(0, 0, 0, 0);
   1.919 +  if (((mState & NS_FRAME_FIRST_REFLOW) &&
   1.920 +       !(mState & NS_FRAME_IN_REFLOW)) ||
   1.921 +      IsSVGText())
   1.922 +    return padding;
   1.923 +
   1.924 +  // Theme methods don't use const-ness.
   1.925 +  nsIFrame *mutable_this = const_cast<nsIFrame*>(this);
   1.926 +
   1.927 +  const nsStyleDisplay *disp = StyleDisplay();
   1.928 +  if (mutable_this->IsThemed(disp)) {
   1.929 +    nsPresContext *presContext = PresContext();
   1.930 +    nsIntMargin widget;
   1.931 +    if (presContext->GetTheme()->GetWidgetPadding(presContext->DeviceContext(),
   1.932 +                                                  mutable_this,
   1.933 +                                                  disp->mAppearance,
   1.934 +                                                  &widget)) {
   1.935 +      padding.top = presContext->DevPixelsToAppUnits(widget.top);
   1.936 +      padding.right = presContext->DevPixelsToAppUnits(widget.right);
   1.937 +      padding.bottom = presContext->DevPixelsToAppUnits(widget.bottom);
   1.938 +      padding.left = presContext->DevPixelsToAppUnits(widget.left);
   1.939 +      return padding;
   1.940 +    }
   1.941 +  }
   1.942 +
   1.943 +  nsMargin *p = static_cast<nsMargin*>
   1.944 +                           (Properties().Get(UsedPaddingProperty()));
   1.945 +  if (p) {
   1.946 +    padding = *p;
   1.947 +  } else {
   1.948 +    DebugOnly<bool> hasPadding = StylePadding()->GetPadding(padding);
   1.949 +    NS_ASSERTION(hasPadding, "We should have padding here! (out of memory?)");
   1.950 +  }
   1.951 +  return padding;
   1.952 +}
   1.953 +
   1.954 +int
   1.955 +nsIFrame::GetSkipSides(const nsHTMLReflowState* aReflowState) const
   1.956 +{
   1.957 +  // Convert the logical skip sides to physical sides using the frame's
   1.958 +  // writing mode
   1.959 +  WritingMode writingMode = GetWritingMode();
   1.960 +  int logicalSkip = GetLogicalSkipSides(aReflowState);
   1.961 +  int skip = 0;
   1.962 +
   1.963 +  if (logicalSkip & LOGICAL_SIDE_B_START) {
   1.964 +    if (writingMode.IsVertical()) {
   1.965 +      skip |= 1 << (writingMode.IsVerticalLR() ? NS_SIDE_LEFT : NS_SIDE_RIGHT);
   1.966 +    } else {
   1.967 +      skip |= 1 << NS_SIDE_TOP;
   1.968 +    }
   1.969 +  }
   1.970 +
   1.971 +  if (logicalSkip & LOGICAL_SIDE_B_END) {
   1.972 +    if (writingMode.IsVertical()) {
   1.973 +      skip |= 1 << (writingMode.IsVerticalLR() ? NS_SIDE_RIGHT : NS_SIDE_LEFT);
   1.974 +    } else {
   1.975 +      skip |= 1 << NS_SIDE_BOTTOM;
   1.976 +    }
   1.977 +  }
   1.978 +
   1.979 +  if (logicalSkip & LOGICAL_SIDE_I_START) {
   1.980 +    if (writingMode.IsVertical()) {
   1.981 +      skip |= 1 << NS_SIDE_TOP;
   1.982 +    } else {
   1.983 +      skip |= 1 << (writingMode.IsBidiLTR() ? NS_SIDE_LEFT : NS_SIDE_RIGHT);
   1.984 +    }
   1.985 +  }
   1.986 +
   1.987 +  if (logicalSkip & LOGICAL_SIDE_I_END) {
   1.988 +    if (writingMode.IsVertical()) {
   1.989 +      skip |= 1 << NS_SIDE_BOTTOM;
   1.990 +    } else {
   1.991 +      skip |= 1 << (writingMode.IsBidiLTR() ? NS_SIDE_RIGHT : NS_SIDE_LEFT);
   1.992 +    }
   1.993 +  }
   1.994 +
   1.995 +  return skip;
   1.996 +}
   1.997 +
   1.998 +
   1.999 +void
  1.1000 +nsIFrame::ApplySkipSides(nsMargin& aMargin,
  1.1001 +                         const nsHTMLReflowState* aReflowState) const
  1.1002 +{
  1.1003 +  int skipSides = GetSkipSides(aReflowState);
  1.1004 +  if (skipSides & (1 << NS_SIDE_TOP)) {
  1.1005 +    aMargin.top = 0;
  1.1006 +  }
  1.1007 +  if (skipSides & (1 << NS_SIDE_RIGHT)) {
  1.1008 +    aMargin.right = 0;
  1.1009 +  }
  1.1010 +  if (skipSides & (1 << NS_SIDE_BOTTOM)) {
  1.1011 +    aMargin.bottom = 0;
  1.1012 +  }
  1.1013 +  if (skipSides & (1 << NS_SIDE_LEFT)) {
  1.1014 +    aMargin.left = 0;
  1.1015 +  }
  1.1016 +}
  1.1017 +
  1.1018 +void
  1.1019 +nsIFrame::ApplyLogicalSkipSides(LogicalMargin& aMargin,
  1.1020 +                                const nsHTMLReflowState* aReflowState) const
  1.1021 +{
  1.1022 +  int skipSides = GetLogicalSkipSides(aReflowState);
  1.1023 +  if (skipSides & (LOGICAL_SIDE_B_START)) {
  1.1024 +    aMargin.BStart(GetWritingMode()) = 0;
  1.1025 +  }
  1.1026 +  if (skipSides & (LOGICAL_SIDE_I_END)) {
  1.1027 +    aMargin.IEnd(GetWritingMode()) = 0;
  1.1028 +  }
  1.1029 +  if (skipSides & (LOGICAL_SIDE_B_END)) {
  1.1030 +    aMargin.BEnd(GetWritingMode()) = 0;
  1.1031 +  }
  1.1032 +  if (skipSides & (LOGICAL_SIDE_I_START)) {
  1.1033 +    aMargin.IStart(GetWritingMode()) = 0;
  1.1034 +  }
  1.1035 +}
  1.1036 +
  1.1037 +nsRect
  1.1038 +nsIFrame::GetPaddingRectRelativeToSelf() const
  1.1039 +{
  1.1040 +  nsMargin border(GetUsedBorder());
  1.1041 +  ApplySkipSides(border);
  1.1042 +  nsRect r(0, 0, mRect.width, mRect.height);
  1.1043 +  r.Deflate(border);
  1.1044 +  return r;
  1.1045 +}
  1.1046 +
  1.1047 +nsRect
  1.1048 +nsIFrame::GetPaddingRect() const
  1.1049 +{
  1.1050 +  return GetPaddingRectRelativeToSelf() + GetPosition();
  1.1051 +}
  1.1052 +
  1.1053 +WritingMode
  1.1054 +nsIFrame::GetWritingMode(nsIFrame* aSubFrame) const
  1.1055 +{
  1.1056 +  WritingMode writingMode = GetWritingMode();
  1.1057 +
  1.1058 +  if (!writingMode.IsVertical() &&
  1.1059 +      (StyleTextReset()->mUnicodeBidi & NS_STYLE_UNICODE_BIDI_PLAINTEXT)) {
  1.1060 +    nsBidiLevel frameLevel = nsBidiPresUtils::GetFrameBaseLevel(aSubFrame);
  1.1061 +    writingMode.SetDirectionFromBidiLevel(frameLevel);
  1.1062 +  }
  1.1063 +
  1.1064 +  return writingMode;
  1.1065 +}
  1.1066 +
  1.1067 +nsRect
  1.1068 +nsIFrame::GetMarginRectRelativeToSelf() const
  1.1069 +{
  1.1070 +  nsMargin m = GetUsedMargin();
  1.1071 +  ApplySkipSides(m);
  1.1072 +  nsRect r(0, 0, mRect.width, mRect.height);
  1.1073 +  r.Inflate(m);
  1.1074 +  return r;
  1.1075 +}
  1.1076 +
  1.1077 +bool
  1.1078 +nsIFrame::IsTransformed() const
  1.1079 +{
  1.1080 +  return ((mState & NS_FRAME_MAY_BE_TRANSFORMED) &&
  1.1081 +          (StyleDisplay()->HasTransform(this) ||
  1.1082 +           IsSVGTransformed() ||
  1.1083 +           (mContent &&
  1.1084 +            nsLayoutUtils::HasAnimationsForCompositor(mContent,
  1.1085 +                                                      eCSSProperty_transform) &&
  1.1086 +            IsFrameOfType(eSupportsCSSTransforms) &&
  1.1087 +            mContent->GetPrimaryFrame() == this)));
  1.1088 +}
  1.1089 +
  1.1090 +bool
  1.1091 +nsIFrame::HasOpacityInternal(float aThreshold) const
  1.1092 +{
  1.1093 +  MOZ_ASSERT(0.0 <= aThreshold && aThreshold <= 1.0, "Invalid argument");
  1.1094 +  const nsStyleDisplay* displayStyle = StyleDisplay();
  1.1095 +  return StyleDisplay()->mOpacity < aThreshold ||
  1.1096 +         (displayStyle->mWillChangeBitField & NS_STYLE_WILL_CHANGE_OPACITY) ||
  1.1097 +         (mContent &&
  1.1098 +           nsLayoutUtils::HasAnimationsForCompositor(mContent,
  1.1099 +                                                     eCSSProperty_opacity) &&
  1.1100 +           mContent->GetPrimaryFrame() == this);
  1.1101 +}
  1.1102 +
  1.1103 +bool
  1.1104 +nsIFrame::IsSVGTransformed(gfx::Matrix *aOwnTransforms,
  1.1105 +                           gfx::Matrix *aFromParentTransforms) const
  1.1106 +{
  1.1107 +  return false;
  1.1108 +}
  1.1109 +
  1.1110 +bool
  1.1111 +nsIFrame::Preserves3DChildren() const
  1.1112 +{
  1.1113 +  const nsStyleDisplay* disp = StyleDisplay();
  1.1114 +  if (disp->mTransformStyle != NS_STYLE_TRANSFORM_STYLE_PRESERVE_3D ||
  1.1115 +      !IsFrameOfType(nsIFrame::eSupportsCSSTransforms)) {
  1.1116 +    return false;
  1.1117 +  }
  1.1118 +
  1.1119 +  // If we're all scroll frame, then all descendants will be clipped, so we can't preserve 3d.
  1.1120 +  if (GetType() == nsGkAtoms::scrollFrame) {
  1.1121 +    return false;
  1.1122 +  }
  1.1123 +
  1.1124 +  nsRect temp;
  1.1125 +  return !nsFrame::ShouldApplyOverflowClipping(this, disp) &&
  1.1126 +         !GetClipPropClipRect(disp, &temp, GetSize()) &&
  1.1127 +         !nsSVGIntegrationUtils::UsingEffectsForFrame(this);
  1.1128 +}
  1.1129 +
  1.1130 +bool
  1.1131 +nsIFrame::Preserves3D() const
  1.1132 +{
  1.1133 +  if (!GetParent() || !GetParent()->Preserves3DChildren()) {
  1.1134 +    return false;
  1.1135 +  }
  1.1136 +  return StyleDisplay()->HasTransform(this) || StyleDisplay()->BackfaceIsHidden();
  1.1137 +}
  1.1138 +
  1.1139 +bool
  1.1140 +nsIFrame::HasPerspective() const
  1.1141 +{
  1.1142 +  if (!IsTransformed()) {
  1.1143 +    return false;
  1.1144 +  }
  1.1145 +  nsStyleContext* parentStyleContext = StyleContext()->GetParent();
  1.1146 +  if (!parentStyleContext) {
  1.1147 +    return false;
  1.1148 +  }
  1.1149 +  const nsStyleDisplay* parentDisp = parentStyleContext->StyleDisplay();
  1.1150 +  return parentDisp->mChildPerspective.GetUnit() == eStyleUnit_Coord;
  1.1151 +}
  1.1152 +
  1.1153 +bool
  1.1154 +nsIFrame::ChildrenHavePerspective() const
  1.1155 +{
  1.1156 +  return StyleDisplay()->HasPerspectiveStyle();
  1.1157 +}
  1.1158 +
  1.1159 +nsRect
  1.1160 +nsIFrame::GetContentRectRelativeToSelf() const
  1.1161 +{
  1.1162 +  nsMargin bp(GetUsedBorderAndPadding());
  1.1163 +  ApplySkipSides(bp);
  1.1164 +  nsRect r(0, 0, mRect.width, mRect.height);
  1.1165 +  r.Deflate(bp);
  1.1166 +  return r;
  1.1167 +}
  1.1168 +
  1.1169 +nsRect
  1.1170 +nsIFrame::GetContentRect() const
  1.1171 +{
  1.1172 +  return GetContentRectRelativeToSelf() + GetPosition();
  1.1173 +}
  1.1174 +
  1.1175 +bool
  1.1176 +nsIFrame::ComputeBorderRadii(const nsStyleCorners& aBorderRadius,
  1.1177 +                             const nsSize& aFrameSize,
  1.1178 +                             const nsSize& aBorderArea,
  1.1179 +                             int aSkipSides,
  1.1180 +                             nscoord aRadii[8])
  1.1181 +{
  1.1182 +  // Percentages are relative to whichever side they're on.
  1.1183 +  NS_FOR_CSS_HALF_CORNERS(i) {
  1.1184 +    const nsStyleCoord c = aBorderRadius.Get(i);
  1.1185 +    nscoord axis =
  1.1186 +      NS_HALF_CORNER_IS_X(i) ? aFrameSize.width : aFrameSize.height;
  1.1187 +
  1.1188 +    if (c.IsCoordPercentCalcUnit()) {
  1.1189 +      aRadii[i] = nsRuleNode::ComputeCoordPercentCalc(c, axis);
  1.1190 +      if (aRadii[i] < 0) {
  1.1191 +        // clamp calc()
  1.1192 +        aRadii[i] = 0;
  1.1193 +      }
  1.1194 +    } else {
  1.1195 +      NS_NOTREACHED("ComputeBorderRadii: bad unit");
  1.1196 +      aRadii[i] = 0;
  1.1197 +    }
  1.1198 +  }
  1.1199 +
  1.1200 +  if (aSkipSides & (1 << NS_SIDE_TOP)) {
  1.1201 +    aRadii[NS_CORNER_TOP_LEFT_X] = 0;
  1.1202 +    aRadii[NS_CORNER_TOP_LEFT_Y] = 0;
  1.1203 +    aRadii[NS_CORNER_TOP_RIGHT_X] = 0;
  1.1204 +    aRadii[NS_CORNER_TOP_RIGHT_Y] = 0;
  1.1205 +  }
  1.1206 +
  1.1207 +  if (aSkipSides & (1 << NS_SIDE_RIGHT)) {
  1.1208 +    aRadii[NS_CORNER_TOP_RIGHT_X] = 0;
  1.1209 +    aRadii[NS_CORNER_TOP_RIGHT_Y] = 0;
  1.1210 +    aRadii[NS_CORNER_BOTTOM_RIGHT_X] = 0;
  1.1211 +    aRadii[NS_CORNER_BOTTOM_RIGHT_Y] = 0;
  1.1212 +  }
  1.1213 +
  1.1214 +  if (aSkipSides & (1 << NS_SIDE_BOTTOM)) {
  1.1215 +    aRadii[NS_CORNER_BOTTOM_RIGHT_X] = 0;
  1.1216 +    aRadii[NS_CORNER_BOTTOM_RIGHT_Y] = 0;
  1.1217 +    aRadii[NS_CORNER_BOTTOM_LEFT_X] = 0;
  1.1218 +    aRadii[NS_CORNER_BOTTOM_LEFT_Y] = 0;
  1.1219 +  }
  1.1220 +
  1.1221 +  if (aSkipSides & (1 << NS_SIDE_LEFT)) {
  1.1222 +    aRadii[NS_CORNER_BOTTOM_LEFT_X] = 0;
  1.1223 +    aRadii[NS_CORNER_BOTTOM_LEFT_Y] = 0;
  1.1224 +    aRadii[NS_CORNER_TOP_LEFT_X] = 0;
  1.1225 +    aRadii[NS_CORNER_TOP_LEFT_Y] = 0;
  1.1226 +  }
  1.1227 +
  1.1228 +  // css3-background specifies this algorithm for reducing
  1.1229 +  // corner radii when they are too big.
  1.1230 +  bool haveRadius = false;
  1.1231 +  double ratio = 1.0f;
  1.1232 +  NS_FOR_CSS_SIDES(side) {
  1.1233 +    uint32_t hc1 = NS_SIDE_TO_HALF_CORNER(side, false, true);
  1.1234 +    uint32_t hc2 = NS_SIDE_TO_HALF_CORNER(side, true, true);
  1.1235 +    nscoord length =
  1.1236 +      NS_SIDE_IS_VERTICAL(side) ? aBorderArea.height : aBorderArea.width;
  1.1237 +    nscoord sum = aRadii[hc1] + aRadii[hc2];
  1.1238 +    if (sum)
  1.1239 +      haveRadius = true;
  1.1240 +
  1.1241 +    // avoid floating point division in the normal case
  1.1242 +    if (length < sum)
  1.1243 +      ratio = std::min(ratio, double(length)/sum);
  1.1244 +  }
  1.1245 +  if (ratio < 1.0) {
  1.1246 +    NS_FOR_CSS_HALF_CORNERS(corner) {
  1.1247 +      aRadii[corner] *= ratio;
  1.1248 +    }
  1.1249 +  }
  1.1250 +
  1.1251 +  return haveRadius;
  1.1252 +}
  1.1253 +
  1.1254 +/* static */ void
  1.1255 +nsIFrame::InsetBorderRadii(nscoord aRadii[8], const nsMargin &aOffsets)
  1.1256 +{
  1.1257 +  NS_FOR_CSS_SIDES(side) {
  1.1258 +    nscoord offset = aOffsets.Side(side);
  1.1259 +    uint32_t hc1 = NS_SIDE_TO_HALF_CORNER(side, false, false);
  1.1260 +    uint32_t hc2 = NS_SIDE_TO_HALF_CORNER(side, true, false);
  1.1261 +    aRadii[hc1] = std::max(0, aRadii[hc1] - offset);
  1.1262 +    aRadii[hc2] = std::max(0, aRadii[hc2] - offset);
  1.1263 +  }
  1.1264 +}
  1.1265 +
  1.1266 +/* static */ void
  1.1267 +nsIFrame::OutsetBorderRadii(nscoord aRadii[8], const nsMargin &aOffsets)
  1.1268 +{
  1.1269 +  NS_FOR_CSS_SIDES(side) {
  1.1270 +    nscoord offset = aOffsets.Side(side);
  1.1271 +    uint32_t hc1 = NS_SIDE_TO_HALF_CORNER(side, false, false);
  1.1272 +    uint32_t hc2 = NS_SIDE_TO_HALF_CORNER(side, true, false);
  1.1273 +    if (aRadii[hc1] > 0)
  1.1274 +      aRadii[hc1] += offset;
  1.1275 +    if (aRadii[hc2] > 0)
  1.1276 +      aRadii[hc2] += offset;
  1.1277 +  }
  1.1278 +}
  1.1279 +
  1.1280 +/* virtual */ bool
  1.1281 +nsIFrame::GetBorderRadii(nscoord aRadii[8]) const
  1.1282 +{
  1.1283 +  if (IsThemed()) {
  1.1284 +    // When we're themed, the native theme code draws the border and
  1.1285 +    // background, and therefore it doesn't make sense to tell other
  1.1286 +    // code that's interested in border-radius that we have any radii.
  1.1287 +    //
  1.1288 +    // In an ideal world, we might have a way for the them to tell us an
  1.1289 +    // border radius, but since we don't, we're better off assuming
  1.1290 +    // zero.
  1.1291 +    NS_FOR_CSS_HALF_CORNERS(corner) {
  1.1292 +      aRadii[corner] = 0;
  1.1293 +    }
  1.1294 +    return false;
  1.1295 +  }
  1.1296 +  nsSize size = GetSize();
  1.1297 +  return ComputeBorderRadii(StyleBorder()->mBorderRadius, size, size,
  1.1298 +                            GetSkipSides(), aRadii);
  1.1299 +}
  1.1300 +
  1.1301 +bool
  1.1302 +nsIFrame::GetPaddingBoxBorderRadii(nscoord aRadii[8]) const
  1.1303 +{
  1.1304 +  if (!GetBorderRadii(aRadii))
  1.1305 +    return false;
  1.1306 +  InsetBorderRadii(aRadii, GetUsedBorder());
  1.1307 +  NS_FOR_CSS_HALF_CORNERS(corner) {
  1.1308 +    if (aRadii[corner])
  1.1309 +      return true;
  1.1310 +  }
  1.1311 +  return false;
  1.1312 +}
  1.1313 +
  1.1314 +bool
  1.1315 +nsIFrame::GetContentBoxBorderRadii(nscoord aRadii[8]) const
  1.1316 +{
  1.1317 +  if (!GetBorderRadii(aRadii))
  1.1318 +    return false;
  1.1319 +  InsetBorderRadii(aRadii, GetUsedBorderAndPadding());
  1.1320 +  NS_FOR_CSS_HALF_CORNERS(corner) {
  1.1321 +    if (aRadii[corner])
  1.1322 +      return true;
  1.1323 +  }
  1.1324 +  return false;
  1.1325 +}
  1.1326 +
  1.1327 +nsStyleContext*
  1.1328 +nsFrame::GetAdditionalStyleContext(int32_t aIndex) const
  1.1329 +{
  1.1330 +  NS_PRECONDITION(aIndex >= 0, "invalid index number");
  1.1331 +  return nullptr;
  1.1332 +}
  1.1333 +
  1.1334 +void
  1.1335 +nsFrame::SetAdditionalStyleContext(int32_t aIndex, 
  1.1336 +                                   nsStyleContext* aStyleContext)
  1.1337 +{
  1.1338 +  NS_PRECONDITION(aIndex >= 0, "invalid index number");
  1.1339 +}
  1.1340 +
  1.1341 +nscoord
  1.1342 +nsFrame::GetBaseline() const
  1.1343 +{
  1.1344 +  NS_ASSERTION(!NS_SUBTREE_DIRTY(this),
  1.1345 +               "frame must not be dirty");
  1.1346 +  // Default to the bottom margin edge, per CSS2.1's definition of the
  1.1347 +  // 'baseline' value of 'vertical-align'.
  1.1348 +  return mRect.height + GetUsedMargin().bottom;
  1.1349 +}
  1.1350 +
  1.1351 +const nsFrameList&
  1.1352 +nsFrame::GetChildList(ChildListID aListID) const
  1.1353 +{
  1.1354 +  if (IsAbsoluteContainer() &&
  1.1355 +      aListID == GetAbsoluteListID()) {
  1.1356 +    return GetAbsoluteContainingBlock()->GetChildList();
  1.1357 +  } else {
  1.1358 +    return nsFrameList::EmptyList();
  1.1359 +  }
  1.1360 +}
  1.1361 +
  1.1362 +void
  1.1363 +nsFrame::GetChildLists(nsTArray<ChildList>* aLists) const
  1.1364 +{
  1.1365 +  if (IsAbsoluteContainer()) {
  1.1366 +    nsFrameList absoluteList = GetAbsoluteContainingBlock()->GetChildList();
  1.1367 +    absoluteList.AppendIfNonempty(aLists, GetAbsoluteListID());
  1.1368 +  }
  1.1369 +}
  1.1370 +
  1.1371 +void
  1.1372 +nsIFrame::GetCrossDocChildLists(nsTArray<ChildList>* aLists)
  1.1373 +{
  1.1374 +  nsSubDocumentFrame* subdocumentFrame = do_QueryFrame(this);
  1.1375 +  if (subdocumentFrame) {
  1.1376 +    // Descend into the subdocument
  1.1377 +    nsIFrame* root = subdocumentFrame->GetSubdocumentRootFrame();
  1.1378 +    if (root) {
  1.1379 +      aLists->AppendElement(nsIFrame::ChildList(
  1.1380 +        nsFrameList(root, nsLayoutUtils::GetLastSibling(root)),
  1.1381 +        nsIFrame::kPrincipalList));
  1.1382 +    }
  1.1383 +  }
  1.1384 +
  1.1385 +  GetChildLists(aLists);
  1.1386 +}
  1.1387 +
  1.1388 +static nsIFrame*
  1.1389 +GetActiveSelectionFrame(nsPresContext* aPresContext, nsIFrame* aFrame)
  1.1390 +{
  1.1391 +  nsIContent* capturingContent = nsIPresShell::GetCapturingContent();
  1.1392 +  if (capturingContent) {
  1.1393 +    nsIFrame* activeFrame = aPresContext->GetPrimaryFrameFor(capturingContent);
  1.1394 +    return activeFrame ? activeFrame : aFrame;
  1.1395 +  }
  1.1396 +
  1.1397 +  return aFrame;
  1.1398 +}
  1.1399 +
  1.1400 +int16_t
  1.1401 +nsFrame::DisplaySelection(nsPresContext* aPresContext, bool isOkToTurnOn)
  1.1402 +{
  1.1403 +  int16_t selType = nsISelectionController::SELECTION_OFF;
  1.1404 +
  1.1405 +  nsCOMPtr<nsISelectionController> selCon;
  1.1406 +  nsresult result = GetSelectionController(aPresContext, getter_AddRefs(selCon));
  1.1407 +  if (NS_SUCCEEDED(result) && selCon) {
  1.1408 +    result = selCon->GetDisplaySelection(&selType);
  1.1409 +    if (NS_SUCCEEDED(result) && (selType != nsISelectionController::SELECTION_OFF)) {
  1.1410 +      // Check whether style allows selection.
  1.1411 +      bool selectable;
  1.1412 +      IsSelectable(&selectable, nullptr);
  1.1413 +      if (!selectable) {
  1.1414 +        selType = nsISelectionController::SELECTION_OFF;
  1.1415 +        isOkToTurnOn = false;
  1.1416 +      }
  1.1417 +    }
  1.1418 +    if (isOkToTurnOn && (selType == nsISelectionController::SELECTION_OFF)) {
  1.1419 +      selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON);
  1.1420 +      selType = nsISelectionController::SELECTION_ON;
  1.1421 +    }
  1.1422 +  }
  1.1423 +  return selType;
  1.1424 +}
  1.1425 +
  1.1426 +class nsDisplaySelectionOverlay : public nsDisplayItem {
  1.1427 +public:
  1.1428 +  nsDisplaySelectionOverlay(nsDisplayListBuilder* aBuilder,
  1.1429 +                            nsFrame* aFrame, int16_t aSelectionValue)
  1.1430 +    : nsDisplayItem(aBuilder, aFrame), mSelectionValue(aSelectionValue) {
  1.1431 +    MOZ_COUNT_CTOR(nsDisplaySelectionOverlay);
  1.1432 +  }
  1.1433 +#ifdef NS_BUILD_REFCNT_LOGGING
  1.1434 +  virtual ~nsDisplaySelectionOverlay() {
  1.1435 +    MOZ_COUNT_DTOR(nsDisplaySelectionOverlay);
  1.1436 +  }
  1.1437 +#endif
  1.1438 +
  1.1439 +  virtual void Paint(nsDisplayListBuilder* aBuilder,
  1.1440 +                     nsRenderingContext* aCtx) MOZ_OVERRIDE;
  1.1441 +  NS_DISPLAY_DECL_NAME("SelectionOverlay", TYPE_SELECTION_OVERLAY)
  1.1442 +private:
  1.1443 +  int16_t mSelectionValue;
  1.1444 +};
  1.1445 +
  1.1446 +void nsDisplaySelectionOverlay::Paint(nsDisplayListBuilder* aBuilder,
  1.1447 +                                      nsRenderingContext* aCtx)
  1.1448 +{
  1.1449 +  LookAndFeel::ColorID colorID;
  1.1450 +  if (mSelectionValue == nsISelectionController::SELECTION_ON) {
  1.1451 +    colorID = LookAndFeel::eColorID_TextSelectBackground;
  1.1452 +  } else if (mSelectionValue == nsISelectionController::SELECTION_ATTENTION) {
  1.1453 +    colorID = LookAndFeel::eColorID_TextSelectBackgroundAttention;
  1.1454 +  } else {
  1.1455 +    colorID = LookAndFeel::eColorID_TextSelectBackgroundDisabled;
  1.1456 +  }
  1.1457 +
  1.1458 +  nscolor color = LookAndFeel::GetColor(colorID, NS_RGB(255, 255, 255));
  1.1459 +
  1.1460 +  gfxRGBA c(color);
  1.1461 +  c.a = .5;
  1.1462 +
  1.1463 +  gfxContext *ctx = aCtx->ThebesContext();
  1.1464 +  ctx->SetColor(c);
  1.1465 +
  1.1466 +  nsIntRect pxRect =
  1.1467 +    mVisibleRect.ToOutsidePixels(mFrame->PresContext()->AppUnitsPerDevPixel());
  1.1468 +  ctx->NewPath();
  1.1469 +  ctx->Rectangle(gfxRect(pxRect.x, pxRect.y, pxRect.width, pxRect.height), true);
  1.1470 +  ctx->Fill();
  1.1471 +}
  1.1472 +
  1.1473 +/********************************************************
  1.1474 +* Refreshes each content's frame
  1.1475 +*********************************************************/
  1.1476 +
  1.1477 +void
  1.1478 +nsFrame::DisplaySelectionOverlay(nsDisplayListBuilder*   aBuilder,
  1.1479 +                                 nsDisplayList*          aList,
  1.1480 +                                 uint16_t                aContentType)
  1.1481 +{
  1.1482 +  if (!IsSelected() || !IsVisibleForPainting(aBuilder))
  1.1483 +    return;
  1.1484 +    
  1.1485 +  nsPresContext* presContext = PresContext();
  1.1486 +  nsIPresShell *shell = presContext->PresShell();
  1.1487 +  if (!shell)
  1.1488 +    return;
  1.1489 +
  1.1490 +  int16_t displaySelection = shell->GetSelectionFlags();
  1.1491 +  if (!(displaySelection & aContentType))
  1.1492 +    return;
  1.1493 +
  1.1494 +  const nsFrameSelection* frameSelection = GetConstFrameSelection();
  1.1495 +  int16_t selectionValue = frameSelection->GetDisplaySelection();
  1.1496 +
  1.1497 +  if (selectionValue <= nsISelectionController::SELECTION_HIDDEN)
  1.1498 +    return; // selection is hidden or off
  1.1499 +
  1.1500 +  nsIContent *newContent = mContent->GetParent();
  1.1501 +
  1.1502 +  //check to see if we are anonymous content
  1.1503 +  int32_t offset = 0;
  1.1504 +  if (newContent) {
  1.1505 +    // XXXbz there has GOT to be a better way of determining this!
  1.1506 +    offset = newContent->IndexOf(mContent);
  1.1507 +  }
  1.1508 +
  1.1509 +  SelectionDetails *details;
  1.1510 +  //look up to see what selection(s) are on this frame
  1.1511 +  details = frameSelection->LookUpSelection(newContent, offset, 1, false);
  1.1512 +  if (!details)
  1.1513 +    return;
  1.1514 +  
  1.1515 +  bool normal = false;
  1.1516 +  while (details) {
  1.1517 +    if (details->mType == nsISelectionController::SELECTION_NORMAL) {
  1.1518 +      normal = true;
  1.1519 +    }
  1.1520 +    SelectionDetails *next = details->mNext;
  1.1521 +    delete details;
  1.1522 +    details = next;
  1.1523 +  }
  1.1524 +
  1.1525 +  if (!normal && aContentType == nsISelectionDisplay::DISPLAY_IMAGES) {
  1.1526 +    // Don't overlay an image if it's not in the primary selection.
  1.1527 +    return;
  1.1528 +  }
  1.1529 +
  1.1530 +  aList->AppendNewToTop(new (aBuilder)
  1.1531 +    nsDisplaySelectionOverlay(aBuilder, this, selectionValue));
  1.1532 +}
  1.1533 +
  1.1534 +void
  1.1535 +nsFrame::DisplayOutlineUnconditional(nsDisplayListBuilder*   aBuilder,
  1.1536 +                                     const nsDisplayListSet& aLists)
  1.1537 +{
  1.1538 +  if (StyleOutline()->GetOutlineStyle() == NS_STYLE_BORDER_STYLE_NONE)
  1.1539 +    return;
  1.1540 +
  1.1541 +  aLists.Outlines()->AppendNewToTop(
  1.1542 +    new (aBuilder) nsDisplayOutline(aBuilder, this));
  1.1543 +}
  1.1544 +
  1.1545 +void
  1.1546 +nsFrame::DisplayOutline(nsDisplayListBuilder*   aBuilder,
  1.1547 +                        const nsDisplayListSet& aLists)
  1.1548 +{
  1.1549 +  if (!IsVisibleForPainting(aBuilder))
  1.1550 +    return;
  1.1551 +
  1.1552 +  DisplayOutlineUnconditional(aBuilder, aLists);
  1.1553 +}
  1.1554 +
  1.1555 +void
  1.1556 +nsIFrame::DisplayCaret(nsDisplayListBuilder* aBuilder,
  1.1557 +                       const nsRect& aDirtyRect, nsDisplayList* aList)
  1.1558 +{
  1.1559 +  if (!IsVisibleForPainting(aBuilder))
  1.1560 +    return;
  1.1561 +
  1.1562 +  aList->AppendNewToTop(
  1.1563 +    new (aBuilder) nsDisplayCaret(aBuilder, this, aBuilder->GetCaret()));
  1.1564 +}
  1.1565 +
  1.1566 +nscolor
  1.1567 +nsIFrame::GetCaretColorAt(int32_t aOffset)
  1.1568 +{
  1.1569 +  nscolor color = NS_RGB(0, 0, 0);
  1.1570 +  if (nsLayoutUtils::GetNativeTextColor(this, color))
  1.1571 +    return color;
  1.1572 +
  1.1573 +  // Use CSS text color.
  1.1574 +  return StyleColor()->mColor;
  1.1575 +}
  1.1576 +
  1.1577 +bool
  1.1578 +nsFrame::DisplayBackgroundUnconditional(nsDisplayListBuilder* aBuilder,
  1.1579 +                                        const nsDisplayListSet& aLists,
  1.1580 +                                        bool aForceBackground)
  1.1581 +{
  1.1582 +  // Here we don't try to detect background propagation. Frames that might
  1.1583 +  // receive a propagated background should just set aForceBackground to
  1.1584 +  // true.
  1.1585 +  if (aBuilder->IsForEventDelivery() || aForceBackground ||
  1.1586 +      !StyleBackground()->IsTransparent() || StyleDisplay()->mAppearance) {
  1.1587 +    return nsDisplayBackgroundImage::AppendBackgroundItemsToTop(
  1.1588 +        aBuilder, this, aLists.BorderBackground());
  1.1589 +  }
  1.1590 +  return false;
  1.1591 +}
  1.1592 +
  1.1593 +void
  1.1594 +nsFrame::DisplayBorderBackgroundOutline(nsDisplayListBuilder*   aBuilder,
  1.1595 +                                        const nsDisplayListSet& aLists,
  1.1596 +                                        bool                    aForceBackground)
  1.1597 +{
  1.1598 +  // The visibility check belongs here since child elements have the
  1.1599 +  // opportunity to override the visibility property and display even if
  1.1600 +  // their parent is hidden.
  1.1601 +  if (!IsVisibleForPainting(aBuilder))
  1.1602 +    return;
  1.1603 +
  1.1604 +  nsCSSShadowArray* shadows = StyleBorder()->mBoxShadow;
  1.1605 +  if (shadows && shadows->HasShadowWithInset(false)) {
  1.1606 +    aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
  1.1607 +      nsDisplayBoxShadowOuter(aBuilder, this));
  1.1608 +  }
  1.1609 +
  1.1610 +  bool bgIsThemed = DisplayBackgroundUnconditional(aBuilder, aLists,
  1.1611 +                                                   aForceBackground);
  1.1612 +
  1.1613 +  if (shadows && shadows->HasShadowWithInset(true)) {
  1.1614 +    aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
  1.1615 +      nsDisplayBoxShadowInner(aBuilder, this));
  1.1616 +  }
  1.1617 +
  1.1618 +  // If there's a themed background, we should not create a border item.
  1.1619 +  // It won't be rendered.
  1.1620 +  if (!bgIsThemed && StyleBorder()->HasBorder()) {
  1.1621 +    aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
  1.1622 +      nsDisplayBorder(aBuilder, this));
  1.1623 +  }
  1.1624 +
  1.1625 +  DisplayOutlineUnconditional(aBuilder, aLists);
  1.1626 +}
  1.1627 +
  1.1628 +inline static bool IsSVGContentWithCSSClip(const nsIFrame *aFrame)
  1.1629 +{
  1.1630 +  // The CSS spec says that the 'clip' property only applies to absolutely
  1.1631 +  // positioned elements, whereas the SVG spec says that it applies to SVG
  1.1632 +  // elements regardless of the value of the 'position' property. Here we obey
  1.1633 +  // the CSS spec for outer-<svg> (since that's what we generally do), but
  1.1634 +  // obey the SVG spec for other SVG elements to which 'clip' applies.
  1.1635 +  nsIAtom *tag = aFrame->GetContent()->Tag();
  1.1636 +  return (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) &&
  1.1637 +    (tag == nsGkAtoms::svg || tag == nsGkAtoms::foreignObject);
  1.1638 +}
  1.1639 +
  1.1640 +bool
  1.1641 +nsIFrame::GetClipPropClipRect(const nsStyleDisplay* aDisp, nsRect* aRect,
  1.1642 +                              const nsSize& aSize) const
  1.1643 +{
  1.1644 +  NS_PRECONDITION(aRect, "Must have aRect out parameter");
  1.1645 +
  1.1646 +  if (!(aDisp->mClipFlags & NS_STYLE_CLIP_RECT) ||
  1.1647 +      !(aDisp->IsAbsolutelyPositioned(this) || IsSVGContentWithCSSClip(this))) {
  1.1648 +    return false;
  1.1649 +  }
  1.1650 +
  1.1651 +  *aRect = aDisp->mClip;
  1.1652 +  if (NS_STYLE_CLIP_RIGHT_AUTO & aDisp->mClipFlags) {
  1.1653 +    aRect->width = aSize.width - aRect->x;
  1.1654 +  }
  1.1655 +  if (NS_STYLE_CLIP_BOTTOM_AUTO & aDisp->mClipFlags) {
  1.1656 +    aRect->height = aSize.height - aRect->y;
  1.1657 +  }
  1.1658 +  return true;
  1.1659 +}
  1.1660 +
  1.1661 +/**
  1.1662 + * If the CSS 'clip' property applies to this frame, set it up
  1.1663 + * in aBuilder->ClipState() to clip all content descendants. Returns true
  1.1664 + * if the property applies, and if so also returns the clip rect (relative
  1.1665 + * to aFrame) in *aRect.
  1.1666 + */
  1.1667 +static bool
  1.1668 +ApplyClipPropClipping(nsDisplayListBuilder* aBuilder,
  1.1669 +                      const nsIFrame* aFrame,
  1.1670 +                      const nsStyleDisplay* aDisp,
  1.1671 +                      nsRect* aRect,
  1.1672 +                      DisplayListClipState::AutoSaveRestore& aClipState)
  1.1673 +{
  1.1674 +  if (!aFrame->GetClipPropClipRect(aDisp, aRect, aFrame->GetSize()))
  1.1675 +    return false;
  1.1676 +
  1.1677 +  nsRect clipRect = *aRect + aBuilder->ToReferenceFrame(aFrame);
  1.1678 +  aClipState.ClipContentDescendants(clipRect);
  1.1679 +  return true;
  1.1680 +}
  1.1681 +
  1.1682 +/**
  1.1683 + * If the CSS 'overflow' property applies to this frame, and is not
  1.1684 + * handled by constructing a dedicated nsHTML/XULScrollFrame, set up clipping
  1.1685 + * for that overflow in aBuilder->ClipState() to clip all containing-block
  1.1686 + * descendants.
  1.1687 + */
  1.1688 +static void
  1.1689 +ApplyOverflowClipping(nsDisplayListBuilder* aBuilder,
  1.1690 +                      const nsIFrame* aFrame,
  1.1691 +                      const nsStyleDisplay* aDisp,
  1.1692 +                      DisplayListClipState::AutoClipMultiple& aClipState)
  1.1693 +{
  1.1694 +  // Only -moz-hidden-unscrollable is handled here (and 'hidden' for table
  1.1695 +  // frames, and any non-visible value for blocks in a paginated context).
  1.1696 +  // We allow -moz-hidden-unscrollable to apply to any kind of frame. This
  1.1697 +  // is required by comboboxes which make their display text (an inline frame)
  1.1698 +  // have clipping.
  1.1699 +  if (!nsFrame::ShouldApplyOverflowClipping(aFrame, aDisp)) {
  1.1700 +    return;
  1.1701 +  }
  1.1702 +  nsRect clipRect;
  1.1703 +  bool haveRadii = false;
  1.1704 +  nscoord radii[8];
  1.1705 +  if (aFrame->StyleDisplay()->mOverflowClipBox ==
  1.1706 +        NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX) {
  1.1707 +    clipRect = aFrame->GetPaddingRectRelativeToSelf() +
  1.1708 +      aBuilder->ToReferenceFrame(aFrame);
  1.1709 +    haveRadii = aFrame->GetPaddingBoxBorderRadii(radii);
  1.1710 +  } else {
  1.1711 +    clipRect = aFrame->GetContentRectRelativeToSelf() +
  1.1712 +      aBuilder->ToReferenceFrame(aFrame);
  1.1713 +    // XXX border-radius
  1.1714 +  }
  1.1715 +  aClipState.ClipContainingBlockDescendantsExtra(clipRect, haveRadii ? radii : nullptr);
  1.1716 +}
  1.1717 +
  1.1718 +#ifdef DEBUG
  1.1719 +static void PaintDebugBorder(nsIFrame* aFrame, nsRenderingContext* aCtx,
  1.1720 +     const nsRect& aDirtyRect, nsPoint aPt) {
  1.1721 +  nsRect r(aPt, aFrame->GetSize());
  1.1722 +  if (aFrame->HasView()) {
  1.1723 +    aCtx->SetColor(NS_RGB(0,0,255));
  1.1724 +  } else {
  1.1725 +    aCtx->SetColor(NS_RGB(255,0,0));
  1.1726 +  }
  1.1727 +  aCtx->DrawRect(r);
  1.1728 +}
  1.1729 +
  1.1730 +static void PaintEventTargetBorder(nsIFrame* aFrame, nsRenderingContext* aCtx,
  1.1731 +     const nsRect& aDirtyRect, nsPoint aPt) {
  1.1732 +  nsRect r(aPt, aFrame->GetSize());
  1.1733 +  aCtx->SetColor(NS_RGB(128,0,128));
  1.1734 +  aCtx->DrawRect(r);
  1.1735 +}
  1.1736 +
  1.1737 +static void
  1.1738 +DisplayDebugBorders(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
  1.1739 +                    const nsDisplayListSet& aLists) {
  1.1740 +  // Draw a border around the child
  1.1741 +  // REVIEW: From nsContainerFrame::PaintChild
  1.1742 +  if (nsFrame::GetShowFrameBorders() && !aFrame->GetRect().IsEmpty()) {
  1.1743 +    aLists.Outlines()->AppendNewToTop(new (aBuilder)
  1.1744 +        nsDisplayGeneric(aBuilder, aFrame, PaintDebugBorder, "DebugBorder",
  1.1745 +                         nsDisplayItem::TYPE_DEBUG_BORDER));
  1.1746 +  }
  1.1747 +  // Draw a border around the current event target
  1.1748 +  if (nsFrame::GetShowEventTargetFrameBorder() &&
  1.1749 +      aFrame->PresContext()->PresShell()->GetDrawEventTargetFrame() == aFrame) {
  1.1750 +    aLists.Outlines()->AppendNewToTop(new (aBuilder)
  1.1751 +        nsDisplayGeneric(aBuilder, aFrame, PaintEventTargetBorder, "EventTargetBorder",
  1.1752 +                         nsDisplayItem::TYPE_EVENT_TARGET_BORDER));
  1.1753 +  }
  1.1754 +}
  1.1755 +#endif
  1.1756 +
  1.1757 +static nsresult
  1.1758 +WrapPreserve3DListInternal(nsIFrame* aFrame, nsDisplayListBuilder *aBuilder, nsDisplayList *aList, nsDisplayList *aOutput, uint32_t& aIndex, nsDisplayList* aTemp)
  1.1759 +{
  1.1760 +  if (aIndex > nsDisplayTransform::INDEX_MAX) {
  1.1761 +    return NS_OK;
  1.1762 +  }
  1.1763 +
  1.1764 +  nsresult rv = NS_OK;
  1.1765 +  while (nsDisplayItem *item = aList->RemoveBottom()) {
  1.1766 +    nsIFrame *childFrame = item->Frame();
  1.1767 +
  1.1768 +    // We accumulate sequential items that aren't transforms into the 'temp' list
  1.1769 +    // and then flush this list into aOutput by wrapping the whole lot with a single
  1.1770 +    // nsDisplayTransform.
  1.1771 +
  1.1772 +    if (childFrame->GetParent() &&
  1.1773 +        (childFrame->GetParent()->Preserves3DChildren() || childFrame == aFrame)) {
  1.1774 +      switch (item->GetType()) {
  1.1775 +        case nsDisplayItem::TYPE_TRANSFORM: {
  1.1776 +          if (!aTemp->IsEmpty()) {
  1.1777 +            aOutput->AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, aFrame, aTemp, aIndex++));
  1.1778 +          }
  1.1779 +          // Override item's clipping with our current clip state (if any). Since we're
  1.1780 +          // bubbling up a preserve-3d transformed child to a preserve-3d parent,
  1.1781 +          // we can be sure the child doesn't have clip state of its own.
  1.1782 +          NS_ASSERTION(!item->GetClip().HasClip(), "Unexpected clip on item");
  1.1783 +          const DisplayItemClip* clip = aBuilder->ClipState().GetCurrentCombinedClip(aBuilder);
  1.1784 +          if (clip) {
  1.1785 +            item->SetClip(aBuilder, *clip);
  1.1786 +          }
  1.1787 +          aOutput->AppendToTop(item);
  1.1788 +          break;
  1.1789 +        }
  1.1790 +        case nsDisplayItem::TYPE_WRAP_LIST: {
  1.1791 +          nsDisplayWrapList *list = static_cast<nsDisplayWrapList*>(item);
  1.1792 +          rv = WrapPreserve3DListInternal(aFrame, aBuilder,
  1.1793 +              list->GetChildren(), aOutput, aIndex, aTemp);
  1.1794 +          list->~nsDisplayWrapList();
  1.1795 +          break;
  1.1796 +        }
  1.1797 +        case nsDisplayItem::TYPE_OPACITY: {
  1.1798 +          if (!aTemp->IsEmpty()) {
  1.1799 +            aOutput->AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, aFrame, aTemp, aIndex++));
  1.1800 +          }
  1.1801 +          nsDisplayOpacity *opacity = static_cast<nsDisplayOpacity*>(item);
  1.1802 +          nsDisplayList output;
  1.1803 +          // Call GetChildren, not GetSameCoordinateSystemChildren, because
  1.1804 +          // the preserve-3d children of 'opacity' are temporarily not in the
  1.1805 +          // same coordinate system as the opacity --- until this wrapping is done.
  1.1806 +          rv = WrapPreserve3DListInternal(aFrame, aBuilder,
  1.1807 +              opacity->GetChildren(), &output, aIndex, aTemp);
  1.1808 +          if (!aTemp->IsEmpty()) {
  1.1809 +            output.AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, aFrame, aTemp, aIndex++));
  1.1810 +          }
  1.1811 +          opacity->GetChildren()->AppendToTop(&output);
  1.1812 +          opacity->UpdateBounds(aBuilder);
  1.1813 +          aOutput->AppendToTop(item);
  1.1814 +          break;
  1.1815 +        }
  1.1816 +        default: {
  1.1817 +          if (childFrame->StyleDisplay()->BackfaceIsHidden()) {
  1.1818 +            if (!aTemp->IsEmpty()) {
  1.1819 +              aOutput->AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, aFrame, aTemp, aIndex++));
  1.1820 +            }
  1.1821 +
  1.1822 +            aOutput->AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, childFrame, item, aIndex++));
  1.1823 +          } else {
  1.1824 +            aTemp->AppendToTop(item);
  1.1825 +          }
  1.1826 +          break;
  1.1827 +        }
  1.1828 +      } 
  1.1829 +    } else {
  1.1830 +      aTemp->AppendToTop(item);
  1.1831 +    }
  1.1832 + 
  1.1833 +    if (NS_FAILED(rv) || !item || aIndex > nsDisplayTransform::INDEX_MAX)
  1.1834 +      return rv;
  1.1835 +  }
  1.1836 +    
  1.1837 +  return NS_OK;
  1.1838 +}
  1.1839 +
  1.1840 +static bool
  1.1841 +IsScrollFrameActive(nsIScrollableFrame* aScrollableFrame)
  1.1842 +{
  1.1843 +  return aScrollableFrame && aScrollableFrame->IsScrollingActive();
  1.1844 +}
  1.1845 +
  1.1846 +static nsresult
  1.1847 +WrapPreserve3DList(nsIFrame* aFrame, nsDisplayListBuilder* aBuilder, nsDisplayList *aList)
  1.1848 +{
  1.1849 +  uint32_t index = 0;
  1.1850 +  nsDisplayList temp;
  1.1851 +  nsDisplayList output;
  1.1852 +  nsresult rv = WrapPreserve3DListInternal(aFrame, aBuilder, aList, &output, index, &temp);
  1.1853 +
  1.1854 +  if (!temp.IsEmpty()) {
  1.1855 +    output.AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, aFrame, &temp, index++));
  1.1856 +  }
  1.1857 +
  1.1858 +  aList->AppendToTop(&output);
  1.1859 +  return rv;
  1.1860 +}
  1.1861 +
  1.1862 +class AutoSaveRestoreBlendMode
  1.1863 +{
  1.1864 +  nsDisplayListBuilder& mBuilder;
  1.1865 +  bool                  AutoResetContainsBlendMode;
  1.1866 +public:
  1.1867 +  AutoSaveRestoreBlendMode(nsDisplayListBuilder& aBuilder)
  1.1868 +    : mBuilder(aBuilder),
  1.1869 +      AutoResetContainsBlendMode(aBuilder.ContainsBlendMode()) {
  1.1870 +  }
  1.1871 +
  1.1872 +  ~AutoSaveRestoreBlendMode() {
  1.1873 +    mBuilder.SetContainsBlendMode(AutoResetContainsBlendMode);
  1.1874 +  }
  1.1875 +};
  1.1876 +
  1.1877 +static void
  1.1878 +CheckForTouchEventHandler(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
  1.1879 +{
  1.1880 +  nsIContent* content = aFrame->GetContent();
  1.1881 +  if (!content) {
  1.1882 +    return;
  1.1883 +  }
  1.1884 +  EventListenerManager* elm = nsContentUtils::GetExistingListenerManagerForNode(content);
  1.1885 +  if (!elm) {
  1.1886 +    return;
  1.1887 +  }
  1.1888 +  if (elm->HasListenersFor(nsGkAtoms::ontouchstart) ||
  1.1889 +      elm->HasListenersFor(nsGkAtoms::ontouchmove)) {
  1.1890 +    aBuilder->SetAncestorHasTouchEventHandler(true);
  1.1891 +  }
  1.1892 +}
  1.1893 +
  1.1894 +void
  1.1895 +nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
  1.1896 +                                             const nsRect&         aDirtyRect,
  1.1897 +                                             nsDisplayList*        aList) {
  1.1898 +  if (GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE)
  1.1899 +    return;
  1.1900 +
  1.1901 +  // Replaced elements have their visibility handled here, because
  1.1902 +  // they're visually atomic
  1.1903 +  if (IsFrameOfType(eReplaced) && !IsVisibleForPainting(aBuilder))
  1.1904 +    return;
  1.1905 +
  1.1906 +  const nsStyleDisplay* disp = StyleDisplay();
  1.1907 +  // We can stop right away if this is a zero-opacity stacking context and
  1.1908 +  // we're painting, and we're not animating opacity. Don't do this
  1.1909 +  // if we're going to compute plugin geometry, since opacity-0 plugins
  1.1910 +  // need to have display items built for them.
  1.1911 +  if (disp->mOpacity == 0.0 && aBuilder->IsForPainting() &&
  1.1912 +      !aBuilder->WillComputePluginGeometry() &&
  1.1913 +      !(disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_OPACITY) &&
  1.1914 +      !nsLayoutUtils::HasAnimations(mContent, eCSSProperty_opacity)) {
  1.1915 +    return;
  1.1916 +  }
  1.1917 +
  1.1918 +  nsRect dirtyRect = aDirtyRect;
  1.1919 +
  1.1920 +  bool inTransform = aBuilder->IsInTransform();
  1.1921 +  bool isTransformed = IsTransformed();
  1.1922 +  // reset blend mode so we can keep track if this stacking context needs have
  1.1923 +  // a nsDisplayBlendContainer. Set the blend mode back when the routine exits
  1.1924 +  // so we keep track if the parent stacking context needs a container too.
  1.1925 +  AutoSaveRestoreBlendMode autoRestoreBlendMode(*aBuilder);
  1.1926 +  aBuilder->SetContainsBlendMode(false);
  1.1927 + 
  1.1928 +  if (isTransformed) {
  1.1929 +    const nsRect overflow = GetVisualOverflowRectRelativeToSelf();
  1.1930 +    if (aBuilder->IsForPainting() &&
  1.1931 +        nsDisplayTransform::ShouldPrerenderTransformedContent(aBuilder, this)) {
  1.1932 +      dirtyRect = overflow;
  1.1933 +    } else {
  1.1934 +      if (overflow.IsEmpty() && !Preserves3DChildren()) {
  1.1935 +        return;
  1.1936 +      }
  1.1937 +
  1.1938 +      nsPoint offset = aBuilder->ToReferenceFrame(this);
  1.1939 +      dirtyRect += offset;
  1.1940 +
  1.1941 +      nsRect untransformedDirtyRect;
  1.1942 +      if (nsDisplayTransform::UntransformRect(dirtyRect, overflow, this, offset, &untransformedDirtyRect)) {
  1.1943 +        dirtyRect = untransformedDirtyRect;
  1.1944 +      } else {
  1.1945 +        NS_WARNING("Unable to untransform dirty rect!");
  1.1946 +        // This should only happen if the transform is singular, in which case nothing is visible anyway
  1.1947 +        dirtyRect.SetEmpty();
  1.1948 +      }
  1.1949 +    }
  1.1950 +    inTransform = true;
  1.1951 +  }
  1.1952 +
  1.1953 +  bool useOpacity = HasVisualOpacity() && !nsSVGUtils::CanOptimizeOpacity(this);
  1.1954 +  bool useBlendMode = disp->mMixBlendMode != NS_STYLE_BLEND_NORMAL;
  1.1955 +  bool usingSVGEffects = nsSVGIntegrationUtils::UsingEffectsForFrame(this);
  1.1956 +  bool useStickyPosition = disp->mPosition == NS_STYLE_POSITION_STICKY &&
  1.1957 +    IsScrollFrameActive(nsLayoutUtils::GetNearestScrollableFrame(GetParent(),
  1.1958 +                        nsLayoutUtils::SCROLLABLE_SAME_DOC |
  1.1959 +                        nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN));
  1.1960 +
  1.1961 +  DisplayListClipState::AutoSaveRestore clipState(aBuilder);
  1.1962 +
  1.1963 +  if (isTransformed || useOpacity || useBlendMode || usingSVGEffects || useStickyPosition) {
  1.1964 +    // We don't need to pass ancestor clipping down to our children;
  1.1965 +    // everything goes inside a display item's child list, and the display
  1.1966 +    // item itself will be clipped.
  1.1967 +    // For transforms we also need to clear ancestor clipping because it's
  1.1968 +    // relative to the wrong display item reference frame anyway.
  1.1969 +    clipState.Clear();
  1.1970 +  }
  1.1971 +
  1.1972 +  nsDisplayListCollection set;
  1.1973 +  {    
  1.1974 +    nsDisplayListBuilder::AutoBuildingDisplayList rootSetter(aBuilder, true);
  1.1975 +    DisplayListClipState::AutoSaveRestore nestedClipState(aBuilder);
  1.1976 +    nsDisplayListBuilder::AutoInTransformSetter
  1.1977 +      inTransformSetter(aBuilder, inTransform);
  1.1978 +    CheckForTouchEventHandler(aBuilder, this);
  1.1979 +
  1.1980 +    if (usingSVGEffects) {
  1.1981 +      dirtyRect =
  1.1982 +        nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(this, dirtyRect);
  1.1983 +    }
  1.1984 +
  1.1985 +    nsRect clipPropClip;
  1.1986 +    if (ApplyClipPropClipping(aBuilder, this, disp, &clipPropClip,
  1.1987 +                              nestedClipState)) {
  1.1988 +      dirtyRect.IntersectRect(dirtyRect, clipPropClip);
  1.1989 +    }
  1.1990 +
  1.1991 +    MarkAbsoluteFramesForDisplayList(aBuilder, dirtyRect);
  1.1992 +
  1.1993 +    // Preserve3DChildren() also guarantees that applyAbsPosClipping and usingSVGEffects are false
  1.1994 +    // We only modify the preserve-3d rect if we are the top of a preserve-3d heirarchy
  1.1995 +    if (Preserves3DChildren()) {
  1.1996 +      aBuilder->MarkPreserve3DFramesForDisplayList(this, aDirtyRect);
  1.1997 +    }
  1.1998 +
  1.1999 +    if (aBuilder->IsBuildingLayerEventRegions()) {
  1.2000 +      nsDisplayLayerEventRegions* eventRegions =
  1.2001 +        new (aBuilder) nsDisplayLayerEventRegions(aBuilder, this);
  1.2002 +      aBuilder->SetLayerEventRegions(eventRegions);
  1.2003 +      set.BorderBackground()->AppendNewToTop(eventRegions);
  1.2004 +    }
  1.2005 +    BuildDisplayList(aBuilder, dirtyRect, set);
  1.2006 +  }
  1.2007 +
  1.2008 +  if (aBuilder->IsBackgroundOnly()) {
  1.2009 +    set.BlockBorderBackgrounds()->DeleteAll();
  1.2010 +    set.Floats()->DeleteAll();
  1.2011 +    set.Content()->DeleteAll();
  1.2012 +    set.PositionedDescendants()->DeleteAll();
  1.2013 +    set.Outlines()->DeleteAll();
  1.2014 +  }
  1.2015 +  
  1.2016 +  // This z-order sort also sorts secondarily by content order. We need to do
  1.2017 +  // this so that boxes produced by the same element are placed together
  1.2018 +  // in the sort. Consider a position:relative inline element that breaks
  1.2019 +  // across lines and has absolutely positioned children; all the abs-pos
  1.2020 +  // children should be z-ordered after all the boxes for the position:relative
  1.2021 +  // element itself.
  1.2022 +  set.PositionedDescendants()->SortByZOrder(aBuilder, GetContent());
  1.2023 +  
  1.2024 +  nsDisplayList resultList;
  1.2025 +  // Now follow the rules of http://www.w3.org/TR/CSS21/zindex.html
  1.2026 +  // 1,2: backgrounds and borders
  1.2027 +  resultList.AppendToTop(set.BorderBackground());
  1.2028 +  // 3: negative z-index children.
  1.2029 +  for (;;) {
  1.2030 +    nsDisplayItem* item = set.PositionedDescendants()->GetBottom();
  1.2031 +    if (item && item->ZIndex() < 0) {
  1.2032 +      set.PositionedDescendants()->RemoveBottom();
  1.2033 +      resultList.AppendToTop(item);
  1.2034 +      continue;
  1.2035 +    }
  1.2036 +    break;
  1.2037 +  }
  1.2038 +  // 4: block backgrounds
  1.2039 +  resultList.AppendToTop(set.BlockBorderBackgrounds());
  1.2040 +  // 5: floats
  1.2041 +  resultList.AppendToTop(set.Floats());
  1.2042 +  // 7: general content
  1.2043 +  resultList.AppendToTop(set.Content());
  1.2044 +  // 7.5: outlines, in content tree order. We need to sort by content order
  1.2045 +  // because an element with outline that breaks and has children with outline
  1.2046 +  // might have placed child outline items between its own outline items.
  1.2047 +  // The element's outline items need to all come before any child outline
  1.2048 +  // items.
  1.2049 +  nsIContent* content = GetContent();
  1.2050 +  if (!content) {
  1.2051 +    content = PresContext()->Document()->GetRootElement();
  1.2052 +  }
  1.2053 +  if (content) {
  1.2054 +    set.Outlines()->SortByContentOrder(aBuilder, content);
  1.2055 +  }
  1.2056 +#ifdef DEBUG
  1.2057 +  DisplayDebugBorders(aBuilder, this, set);
  1.2058 +#endif
  1.2059 +  resultList.AppendToTop(set.Outlines());
  1.2060 +  // 8, 9: non-negative z-index children
  1.2061 +  resultList.AppendToTop(set.PositionedDescendants());
  1.2062 +
  1.2063 +  if (!isTransformed) {
  1.2064 +    // Restore saved clip state now so that any display items we create below
  1.2065 +    // are clipped properly.
  1.2066 +    clipState.Restore();
  1.2067 +  }
  1.2068 +
  1.2069 +  /* If there are any SVG effects, wrap the list up in an SVG effects item
  1.2070 +   * (which also handles CSS group opacity). Note that we create an SVG effects
  1.2071 +   * item even if resultList is empty, since a filter can produce graphical
  1.2072 +   * output even if the element being filtered wouldn't otherwise do so.
  1.2073 +   */
  1.2074 +  if (usingSVGEffects) {
  1.2075 +    /* List now emptied, so add the new list to the top. */
  1.2076 +    resultList.AppendNewToTop(
  1.2077 +        new (aBuilder) nsDisplaySVGEffects(aBuilder, this, &resultList));
  1.2078 +  }
  1.2079 +  /* Else, if the list is non-empty and there is CSS group opacity without SVG
  1.2080 +   * effects, wrap it up in an opacity item.
  1.2081 +   */
  1.2082 +  else if (useOpacity && !resultList.IsEmpty()) {
  1.2083 +    resultList.AppendNewToTop(
  1.2084 +        new (aBuilder) nsDisplayOpacity(aBuilder, this, &resultList));
  1.2085 +  }
  1.2086 +  /* If we have sticky positioning, wrap it in a sticky position item.
  1.2087 +   */
  1.2088 +  if (useStickyPosition) {
  1.2089 +    resultList.AppendNewToTop(
  1.2090 +        new (aBuilder) nsDisplayStickyPosition(aBuilder, this, &resultList));
  1.2091 +  }
  1.2092 +
  1.2093 +  /* If we're going to apply a transformation and don't have preserve-3d set, wrap 
  1.2094 +   * everything in an nsDisplayTransform. If there's nothing in the list, don't add 
  1.2095 +   * anything.
  1.2096 +   *
  1.2097 +   * For the preserve-3d case we want to individually wrap every child in the list with
  1.2098 +   * a separate nsDisplayTransform instead. When the child is already an nsDisplayTransform,
  1.2099 +   * we can skip this step, as the computed transform will already include our own.
  1.2100 +   *
  1.2101 +   * We also traverse into sublists created by nsDisplayWrapList or nsDisplayOpacity, so that
  1.2102 +   * we find all the correct children.
  1.2103 +   */
  1.2104 +  if (isTransformed && !resultList.IsEmpty()) {
  1.2105 +    // Restore clip state now so nsDisplayTransform is clipped properly.
  1.2106 +    clipState.Restore();
  1.2107 +
  1.2108 +    if (Preserves3DChildren()) {
  1.2109 +      WrapPreserve3DList(this, aBuilder, &resultList);
  1.2110 +    } else {
  1.2111 +      resultList.AppendNewToTop(
  1.2112 +        new (aBuilder) nsDisplayTransform(aBuilder, this, &resultList));
  1.2113 +    }
  1.2114 +  }
  1.2115 +
  1.2116 +  /* If adding both a nsDisplayBlendContainer and a nsDisplayMixBlendMode to the
  1.2117 +   * same list, the nsDisplayBlendContainer should be added first. This only
  1.2118 +   * happens when the element creating this stacking context has mix-blend-mode
  1.2119 +   * and also contains a child which has mix-blend-mode.
  1.2120 +   * The nsDisplayBlendContainer must be added to the list first, so it does not
  1.2121 +   * isolate the containing element blending as well.
  1.2122 +   */
  1.2123 +
  1.2124 +  if (aBuilder->ContainsBlendMode()) {
  1.2125 +      resultList.AppendNewToTop(
  1.2126 +        new (aBuilder) nsDisplayBlendContainer(aBuilder, this, &resultList));
  1.2127 +  }
  1.2128 +
  1.2129 +  /* If there's blending, wrap up the list in a blend-mode item. Note
  1.2130 +   * that opacity can be applied before blending as the blend color is
  1.2131 +   * not affected by foreground opacity (only background alpha).
  1.2132 +   */
  1.2133 +
  1.2134 +  if (useBlendMode && !resultList.IsEmpty()) {
  1.2135 +    resultList.AppendNewToTop(
  1.2136 +        new (aBuilder) nsDisplayMixBlendMode(aBuilder, this, &resultList));
  1.2137 +  }
  1.2138 +
  1.2139 +  CreateOwnLayerIfNeeded(aBuilder, &resultList);
  1.2140 +
  1.2141 +  aList->AppendToTop(&resultList);
  1.2142 +}
  1.2143 +
  1.2144 +static nsDisplayItem*
  1.2145 +WrapInWrapList(nsDisplayListBuilder* aBuilder,
  1.2146 +               nsIFrame* aFrame, nsDisplayList* aList)
  1.2147 +{
  1.2148 +  nsDisplayItem* item = aList->GetBottom();
  1.2149 +  if (!item || item->GetAbove() || item->Frame() != aFrame) {
  1.2150 +    return new (aBuilder) nsDisplayWrapList(aBuilder, aFrame, aList);
  1.2151 +  }
  1.2152 +  aList->RemoveBottom();
  1.2153 +  return item;
  1.2154 +}
  1.2155 +
  1.2156 +void
  1.2157 +nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder*   aBuilder,
  1.2158 +                                   nsIFrame*               aChild,
  1.2159 +                                   const nsRect&           aDirtyRect,
  1.2160 +                                   const nsDisplayListSet& aLists,
  1.2161 +                                   uint32_t                aFlags) {
  1.2162 +  // If painting is restricted to just the background of the top level frame,
  1.2163 +  // then we have nothing to do here.
  1.2164 +  if (aBuilder->IsBackgroundOnly())
  1.2165 +    return;
  1.2166 +
  1.2167 +  nsIFrame* child = aChild;
  1.2168 +  if (child->GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE)
  1.2169 +    return;
  1.2170 +  
  1.2171 +  bool isSVG = (child->GetStateBits() & NS_FRAME_SVG_LAYOUT);
  1.2172 +
  1.2173 +  // true if this is a real or pseudo stacking context
  1.2174 +  bool pseudoStackingContext =
  1.2175 +    (aFlags & DISPLAY_CHILD_FORCE_PSEUDO_STACKING_CONTEXT) != 0;
  1.2176 +  if (!isSVG &&
  1.2177 +      (aFlags & DISPLAY_CHILD_INLINE) &&
  1.2178 +      !child->IsFrameOfType(eLineParticipant)) {
  1.2179 +    // child is a non-inline frame in an inline context, i.e.,
  1.2180 +    // it acts like inline-block or inline-table. Therefore it is a
  1.2181 +    // pseudo-stacking-context.
  1.2182 +    pseudoStackingContext = true;
  1.2183 +  }
  1.2184 +
  1.2185 +  // dirty rect in child-relative coordinates
  1.2186 +  nsRect dirty = aDirtyRect - child->GetOffsetTo(this);
  1.2187 +
  1.2188 +  nsIAtom* childType = child->GetType();
  1.2189 +  nsDisplayListBuilder::OutOfFlowDisplayData* savedOutOfFlowData = nullptr;
  1.2190 +  if (childType == nsGkAtoms::placeholderFrame) {
  1.2191 +    nsPlaceholderFrame* placeholder = static_cast<nsPlaceholderFrame*>(child);
  1.2192 +    child = placeholder->GetOutOfFlowFrame();
  1.2193 +    NS_ASSERTION(child, "No out of flow frame?");
  1.2194 +    // If 'child' is a pushed float then it's owned by a block that's not an
  1.2195 +    // ancestor of the placeholder, and it will be painted by that block and
  1.2196 +    // should not be painted through the placeholder.
  1.2197 +    if (!child || nsLayoutUtils::IsPopup(child) ||
  1.2198 +        (child->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT))
  1.2199 +      return;
  1.2200 +    // Make sure that any attempt to use childType below is disappointed. We
  1.2201 +    // could call GetType again but since we don't currently need it, let's
  1.2202 +    // avoid the virtual call.
  1.2203 +    childType = nullptr;
  1.2204 +    // Recheck NS_FRAME_TOO_DEEP_IN_FRAME_TREE
  1.2205 +    if (child->GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE)
  1.2206 +      return;
  1.2207 +    savedOutOfFlowData = static_cast<nsDisplayListBuilder::OutOfFlowDisplayData*>
  1.2208 +      (child->Properties().Get(nsDisplayListBuilder::OutOfFlowDisplayDataProperty()));
  1.2209 +    if (savedOutOfFlowData) {
  1.2210 +      dirty = savedOutOfFlowData->mDirtyRect;
  1.2211 +    } else {
  1.2212 +      // The out-of-flow frame did not intersect the dirty area. We may still
  1.2213 +      // need to traverse into it, since it may contain placeholders we need
  1.2214 +      // to enter to reach other out-of-flow frames that are visible.
  1.2215 +      dirty.SetEmpty();
  1.2216 +    }
  1.2217 +    pseudoStackingContext = true;
  1.2218 +  }
  1.2219 +  if (child->Preserves3D()) {
  1.2220 +    nsRect* savedDirty = static_cast<nsRect*>
  1.2221 +      (child->Properties().Get(nsDisplayListBuilder::Preserve3DDirtyRectProperty()));
  1.2222 +    if (savedDirty) {
  1.2223 +      dirty = *savedDirty;
  1.2224 +    } else {
  1.2225 +      dirty.SetEmpty();
  1.2226 +    }
  1.2227 +  }
  1.2228 +
  1.2229 +  NS_ASSERTION(childType != nsGkAtoms::placeholderFrame,
  1.2230 +               "Should have dealt with placeholders already");
  1.2231 +  if (aBuilder->GetSelectedFramesOnly() &&
  1.2232 +      child->IsLeaf() &&
  1.2233 +      !aChild->IsSelected()) {
  1.2234 +    return;
  1.2235 +  }
  1.2236 +
  1.2237 +  if (aBuilder->GetIncludeAllOutOfFlows() &&
  1.2238 +      (child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
  1.2239 +    dirty = child->GetVisualOverflowRect();
  1.2240 +  } else if (!(child->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO)) {
  1.2241 +    // No need to descend into child to catch placeholders for visible
  1.2242 +    // positioned stuff. So see if we can short-circuit frame traversal here.
  1.2243 +
  1.2244 +    // We can stop if child's frame subtree's intersection with the
  1.2245 +    // dirty area is empty.
  1.2246 +    // If the child is a scrollframe that we want to ignore, then we need
  1.2247 +    // to descend into it because its scrolled child may intersect the dirty
  1.2248 +    // area even if the scrollframe itself doesn't.
  1.2249 +    // There are cases where the "ignore scroll frame" on the builder is not set
  1.2250 +    // correctly, and so we additionally want to catch cases where the child is
  1.2251 +    // a root scrollframe and we are ignoring scrolling on the viewport.
  1.2252 +    nsIPresShell* shell = PresContext()->PresShell();
  1.2253 +    bool keepDescending = child == aBuilder->GetIgnoreScrollFrame() ||
  1.2254 +        (shell->IgnoringViewportScrolling() && child == shell->GetRootScrollFrame());
  1.2255 +    if (!keepDescending) {
  1.2256 +      nsRect childDirty;
  1.2257 +      if (!childDirty.IntersectRect(dirty, child->GetVisualOverflowRect()))
  1.2258 +        return;
  1.2259 +      // Usually we could set dirty to childDirty now but there's no
  1.2260 +      // benefit, and it can be confusing. It can especially confuse
  1.2261 +      // situations where we're going to ignore a scrollframe's clipping;
  1.2262 +      // we wouldn't want to clip the dirty area to the scrollframe's
  1.2263 +      // bounds in that case.
  1.2264 +    }
  1.2265 +  }
  1.2266 +
  1.2267 +  // XXX need to have inline-block and inline-table set pseudoStackingContext
  1.2268 +  
  1.2269 +  const nsStyleDisplay* ourDisp = StyleDisplay();
  1.2270 +  // REVIEW: Taken from nsBoxFrame::Paint
  1.2271 +  // Don't paint our children if the theme object is a leaf.
  1.2272 +  if (IsThemed(ourDisp) &&
  1.2273 +      !PresContext()->GetTheme()->WidgetIsContainer(ourDisp->mAppearance))
  1.2274 +    return;
  1.2275 +
  1.2276 +  // Child is composited if it's transformed, partially transparent, or has
  1.2277 +  // SVG effects or a blend mode..
  1.2278 +  const nsStyleDisplay* disp = child->StyleDisplay();
  1.2279 +  const nsStylePosition* pos = child->StylePosition();
  1.2280 +  bool isVisuallyAtomic = child->HasOpacity()
  1.2281 +    || child->IsTransformed()
  1.2282 +    // strictly speaking, 'perspective' doesn't require visual atomicity,
  1.2283 +    // but the spec says it acts like the rest of these
  1.2284 +    || disp->mChildPerspective.GetUnit() == eStyleUnit_Coord
  1.2285 +    || disp->mMixBlendMode != NS_STYLE_BLEND_NORMAL
  1.2286 +    || nsSVGIntegrationUtils::UsingEffectsForFrame(child);
  1.2287 +
  1.2288 +  bool isPositioned = disp->IsPositioned(child);
  1.2289 +  bool isStackingContext =
  1.2290 +    (isPositioned && (disp->mPosition == NS_STYLE_POSITION_STICKY ||
  1.2291 +                      pos->mZIndex.GetUnit() == eStyleUnit_Integer)) ||
  1.2292 +     (disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_STACKING_CONTEXT) ||
  1.2293 +     isVisuallyAtomic || (aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT);
  1.2294 +
  1.2295 +  if (isVisuallyAtomic || isPositioned || (!isSVG && disp->IsFloating(child)) ||
  1.2296 +      ((disp->mClipFlags & NS_STYLE_CLIP_RECT) &&
  1.2297 +       IsSVGContentWithCSSClip(child)) ||
  1.2298 +       (disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_STACKING_CONTEXT) ||
  1.2299 +      (aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT)) {
  1.2300 +    // If you change this, also change IsPseudoStackingContextFromStyle()
  1.2301 +    pseudoStackingContext = true;
  1.2302 +  }
  1.2303 +  NS_ASSERTION(!isStackingContext || pseudoStackingContext,
  1.2304 +               "Stacking contexts must also be pseudo-stacking-contexts");
  1.2305 +
  1.2306 +  bool isInFixedPos = aBuilder->IsInFixedPos() ||
  1.2307 +                        (isPositioned &&
  1.2308 +                         disp->mPosition == NS_STYLE_POSITION_FIXED &&
  1.2309 +                         nsLayoutUtils::IsReallyFixedPos(child));
  1.2310 +  nsDisplayListBuilder::AutoInFixedPosSetter
  1.2311 +    buildingInFixedPos(aBuilder, isInFixedPos);
  1.2312 +
  1.2313 +  nsDisplayListBuilder::AutoBuildingDisplayList
  1.2314 +    buildingForChild(aBuilder, child, pseudoStackingContext);
  1.2315 +  DisplayListClipState::AutoClipMultiple clipState(aBuilder);
  1.2316 +  CheckForTouchEventHandler(aBuilder, child);
  1.2317 +
  1.2318 +  if (savedOutOfFlowData) {
  1.2319 +    clipState.SetClipForContainingBlockDescendants(
  1.2320 +      &savedOutOfFlowData->mContainingBlockClip);
  1.2321 +  }
  1.2322 +
  1.2323 +  // Setup clipping for the parent's overflow:-moz-hidden-unscrollable,
  1.2324 +  // or overflow:hidden on elements that don't support scrolling (and therefore
  1.2325 +  // don't create nsHTML/XULScrollFrame). This clipping needs to not clip
  1.2326 +  // anything directly rendered by the parent, only the rendering of its
  1.2327 +  // children.
  1.2328 +  // Don't use overflowClip to restrict the dirty rect, since some of the
  1.2329 +  // descendants may not be clipped by it. Even if we end up with unnecessary
  1.2330 +  // display items, they'll be pruned during ComputeVisibility.
  1.2331 +  nsIFrame* parent = child->GetParent();
  1.2332 +  const nsStyleDisplay* parentDisp =
  1.2333 +    parent == this ? ourDisp : parent->StyleDisplay();
  1.2334 +  ApplyOverflowClipping(aBuilder, parent, parentDisp, clipState);
  1.2335 +
  1.2336 +  nsDisplayList list;
  1.2337 +  nsDisplayList extraPositionedDescendants;
  1.2338 +  if (isStackingContext) {
  1.2339 +    if (disp->mMixBlendMode != NS_STYLE_BLEND_NORMAL) {
  1.2340 +      aBuilder->SetContainsBlendMode(true);
  1.2341 +    }
  1.2342 +    // True stacking context.
  1.2343 +    // For stacking contexts, BuildDisplayListForStackingContext handles
  1.2344 +    // clipping and MarkAbsoluteFramesForDisplayList.
  1.2345 +    child->BuildDisplayListForStackingContext(aBuilder, dirty, &list);
  1.2346 +    aBuilder->DisplayCaret(child, dirty, &list);
  1.2347 +  } else {
  1.2348 +    nsRect clipRect;
  1.2349 +    if (ApplyClipPropClipping(aBuilder, child, disp, &clipRect, clipState)) {
  1.2350 +      // clipRect is in builder-reference-frame coordinates,
  1.2351 +      // dirty/clippedDirtyRect are in child coordinates
  1.2352 +      dirty.IntersectRect(dirty, clipRect);
  1.2353 +    }
  1.2354 +
  1.2355 +    child->MarkAbsoluteFramesForDisplayList(aBuilder, dirty);
  1.2356 +
  1.2357 +    if (!pseudoStackingContext) {
  1.2358 +      // THIS IS THE COMMON CASE.
  1.2359 +      // Not a pseudo or real stacking context. Do the simple thing and
  1.2360 +      // return early.
  1.2361 +      nsDisplayLayerEventRegions* eventRegions = aBuilder->GetLayerEventRegions();
  1.2362 +      if (eventRegions) {
  1.2363 +        eventRegions->AddFrame(aBuilder, child);
  1.2364 +      }
  1.2365 +      child->BuildDisplayList(aBuilder, dirty, aLists);
  1.2366 +      aBuilder->DisplayCaret(child, dirty, aLists.Content());
  1.2367 +#ifdef DEBUG
  1.2368 +      DisplayDebugBorders(aBuilder, child, aLists);
  1.2369 +#endif
  1.2370 +      return;
  1.2371 +    }
  1.2372 +
  1.2373 +    // A pseudo-stacking context (e.g., a positioned element with z-index auto).
  1.2374 +    // We allow positioned descendants of the child to escape to our parent
  1.2375 +    // stacking context's positioned descendant list, because they might be
  1.2376 +    // z-index:non-auto
  1.2377 +    nsDisplayListCollection pseudoStack;
  1.2378 +    if (aBuilder->IsBuildingLayerEventRegions()) {
  1.2379 +      nsDisplayLayerEventRegions* eventRegions =
  1.2380 +        new (aBuilder) nsDisplayLayerEventRegions(aBuilder, this);
  1.2381 +      aBuilder->SetLayerEventRegions(eventRegions);
  1.2382 +      pseudoStack.BorderBackground()->AppendNewToTop(eventRegions);
  1.2383 +    }
  1.2384 +    child->BuildDisplayList(aBuilder, dirty, pseudoStack);
  1.2385 +    aBuilder->DisplayCaret(child, dirty, pseudoStack.Content());
  1.2386 +
  1.2387 +    list.AppendToTop(pseudoStack.BorderBackground());
  1.2388 +    list.AppendToTop(pseudoStack.BlockBorderBackgrounds());
  1.2389 +    list.AppendToTop(pseudoStack.Floats());
  1.2390 +    list.AppendToTop(pseudoStack.Content());
  1.2391 +    list.AppendToTop(pseudoStack.Outlines());
  1.2392 +    extraPositionedDescendants.AppendToTop(pseudoStack.PositionedDescendants());
  1.2393 +#ifdef DEBUG
  1.2394 +    DisplayDebugBorders(aBuilder, child, aLists);
  1.2395 +#endif
  1.2396 +  }
  1.2397 +    
  1.2398 +  // Clear clip rect for the construction of the items below. Since we're
  1.2399 +  // clipping all their contents, they themselves don't need to be clipped.
  1.2400 +  clipState.Clear();
  1.2401 +
  1.2402 +  if (isPositioned || isVisuallyAtomic ||
  1.2403 +      (aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT)) {
  1.2404 +    // Genuine stacking contexts, and positioned pseudo-stacking-contexts,
  1.2405 +    // go in this level.
  1.2406 +    if (!list.IsEmpty()) {
  1.2407 +      nsDisplayItem* item = WrapInWrapList(aBuilder, child, &list);
  1.2408 +      if (isSVG) {
  1.2409 +        aLists.Content()->AppendNewToTop(item);
  1.2410 +      } else {
  1.2411 +        aLists.PositionedDescendants()->AppendNewToTop(item);
  1.2412 +      }
  1.2413 +    }
  1.2414 +  } else if (!isSVG && disp->IsFloating(child)) {
  1.2415 +    if (!list.IsEmpty()) {
  1.2416 +      aLists.Floats()->AppendNewToTop(WrapInWrapList(aBuilder, child, &list));
  1.2417 +    }
  1.2418 +  } else {
  1.2419 +    aLists.Content()->AppendToTop(&list);
  1.2420 +  }
  1.2421 +  // We delay placing the positioned descendants of positioned frames to here,
  1.2422 +  // because in the absence of z-index this is the correct order for them.
  1.2423 +  // This doesn't affect correctness because the positioned descendants list
  1.2424 +  // is sorted by z-order and content in BuildDisplayListForStackingContext,
  1.2425 +  // but it means that sort routine needs to do less work.
  1.2426 +  aLists.PositionedDescendants()->AppendToTop(&extraPositionedDescendants);
  1.2427 +}
  1.2428 +
  1.2429 +void
  1.2430 +nsIFrame::MarkAbsoluteFramesForDisplayList(nsDisplayListBuilder* aBuilder,
  1.2431 +                                           const nsRect& aDirtyRect)
  1.2432 +{
  1.2433 +  if (IsAbsoluteContainer()) {
  1.2434 +    aBuilder->MarkFramesForDisplayList(this, GetAbsoluteContainingBlock()->GetChildList(), aDirtyRect);
  1.2435 +  }
  1.2436 +}
  1.2437 +
  1.2438 +nsresult  
  1.2439 +nsFrame::GetContentForEvent(WidgetEvent* aEvent,
  1.2440 +                            nsIContent** aContent)
  1.2441 +{
  1.2442 +  nsIFrame* f = nsLayoutUtils::GetNonGeneratedAncestor(this);
  1.2443 +  *aContent = f->GetContent();
  1.2444 +  NS_IF_ADDREF(*aContent);
  1.2445 +  return NS_OK;
  1.2446 +}
  1.2447 +
  1.2448 +void
  1.2449 +nsFrame::FireDOMEvent(const nsAString& aDOMEventName, nsIContent *aContent)
  1.2450 +{
  1.2451 +  nsIContent* target = aContent ? aContent : mContent;
  1.2452 +
  1.2453 +  if (target) {
  1.2454 +    nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
  1.2455 +      new AsyncEventDispatcher(target, aDOMEventName, true, false);
  1.2456 +    DebugOnly<nsresult> rv = asyncDispatcher->PostDOMEvent();
  1.2457 +    NS_ASSERTION(NS_SUCCEEDED(rv), "AsyncEventDispatcher failed to dispatch");
  1.2458 +  }
  1.2459 +}
  1.2460 +
  1.2461 +nsresult
  1.2462 +nsFrame::HandleEvent(nsPresContext* aPresContext, 
  1.2463 +                     WidgetGUIEvent* aEvent,
  1.2464 +                     nsEventStatus* aEventStatus)
  1.2465 +{
  1.2466 +
  1.2467 +  if (aEvent->message == NS_MOUSE_MOVE) {
  1.2468 +    // XXX If the second argument of HandleDrag() is WidgetMouseEvent,
  1.2469 +    //     the implementation becomes simpler.
  1.2470 +    return HandleDrag(aPresContext, aEvent, aEventStatus);
  1.2471 +  }
  1.2472 +
  1.2473 +  if ((aEvent->eventStructType == NS_MOUSE_EVENT &&
  1.2474 +       aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton) ||
  1.2475 +      aEvent->eventStructType == NS_TOUCH_EVENT) {
  1.2476 +    if (aEvent->message == NS_MOUSE_BUTTON_DOWN || aEvent->message == NS_TOUCH_START) {
  1.2477 +      HandlePress(aPresContext, aEvent, aEventStatus);
  1.2478 +    } else if (aEvent->message == NS_MOUSE_BUTTON_UP || aEvent->message == NS_TOUCH_END) {
  1.2479 +      HandleRelease(aPresContext, aEvent, aEventStatus);
  1.2480 +    }
  1.2481 +  }
  1.2482 +  return NS_OK;
  1.2483 +}
  1.2484 +
  1.2485 +NS_IMETHODIMP
  1.2486 +nsFrame::GetDataForTableSelection(const nsFrameSelection* aFrameSelection,
  1.2487 +                                  nsIPresShell* aPresShell,
  1.2488 +                                  WidgetMouseEvent* aMouseEvent, 
  1.2489 +                                  nsIContent** aParentContent,
  1.2490 +                                  int32_t* aContentOffset,
  1.2491 +                                  int32_t* aTarget)
  1.2492 +{
  1.2493 +  if (!aFrameSelection || !aPresShell || !aMouseEvent || !aParentContent || !aContentOffset || !aTarget)
  1.2494 +    return NS_ERROR_NULL_POINTER;
  1.2495 +
  1.2496 +  *aParentContent = nullptr;
  1.2497 +  *aContentOffset = 0;
  1.2498 +  *aTarget = 0;
  1.2499 +
  1.2500 +  int16_t displaySelection = aPresShell->GetSelectionFlags();
  1.2501 +
  1.2502 +  bool selectingTableCells = aFrameSelection->GetTableCellSelection();
  1.2503 +
  1.2504 +  // DISPLAY_ALL means we're in an editor.
  1.2505 +  // If already in cell selection mode, 
  1.2506 +  //  continue selecting with mouse drag or end on mouse up,
  1.2507 +  //  or when using shift key to extend block of cells
  1.2508 +  //  (Mouse down does normal selection unless Ctrl/Cmd is pressed)
  1.2509 +  bool doTableSelection =
  1.2510 +     displaySelection == nsISelectionDisplay::DISPLAY_ALL && selectingTableCells &&
  1.2511 +     (aMouseEvent->message == NS_MOUSE_MOVE ||
  1.2512 +      (aMouseEvent->message == NS_MOUSE_BUTTON_UP &&
  1.2513 +       aMouseEvent->button == WidgetMouseEvent::eLeftButton) ||
  1.2514 +      aMouseEvent->IsShift());
  1.2515 +
  1.2516 +  if (!doTableSelection)
  1.2517 +  {  
  1.2518 +    // In Browser, special 'table selection' key must be pressed for table selection
  1.2519 +    // or when just Shift is pressed and we're already in table/cell selection mode
  1.2520 +#ifdef XP_MACOSX
  1.2521 +    doTableSelection = aMouseEvent->IsMeta() || (aMouseEvent->IsShift() && selectingTableCells);
  1.2522 +#else
  1.2523 +    doTableSelection = aMouseEvent->IsControl() || (aMouseEvent->IsShift() && selectingTableCells);
  1.2524 +#endif
  1.2525 +  }
  1.2526 +  if (!doTableSelection) 
  1.2527 +    return NS_OK;
  1.2528 +
  1.2529 +  // Get the cell frame or table frame (or parent) of the current content node
  1.2530 +  nsIFrame *frame = this;
  1.2531 +  bool foundCell = false;
  1.2532 +  bool foundTable = false;
  1.2533 +
  1.2534 +  // Get the limiting node to stop parent frame search
  1.2535 +  nsIContent* limiter = aFrameSelection->GetLimiter();
  1.2536 +
  1.2537 +  // If our content node is an ancestor of the limiting node,
  1.2538 +  // we should stop the search right now.
  1.2539 +  if (limiter && nsContentUtils::ContentIsDescendantOf(limiter, GetContent()))
  1.2540 +    return NS_OK;
  1.2541 +
  1.2542 +  //We don't initiate row/col selection from here now,
  1.2543 +  //  but we may in future
  1.2544 +  //bool selectColumn = false;
  1.2545 +  //bool selectRow = false;
  1.2546 +  
  1.2547 +  while (frame)
  1.2548 +  {
  1.2549 +    // Check for a table cell by querying to a known CellFrame interface
  1.2550 +    nsITableCellLayout *cellElement = do_QueryFrame(frame);
  1.2551 +    if (cellElement)
  1.2552 +    {
  1.2553 +      foundCell = true;
  1.2554 +      //TODO: If we want to use proximity to top or left border
  1.2555 +      //      for row and column selection, this is the place to do it
  1.2556 +      break;
  1.2557 +    }
  1.2558 +    else
  1.2559 +    {
  1.2560 +      // If not a cell, check for table
  1.2561 +      // This will happen when starting frame is the table or child of a table,
  1.2562 +      //  such as a row (we were inbetween cells or in table border)
  1.2563 +      nsTableOuterFrame *tableFrame = do_QueryFrame(frame);
  1.2564 +      if (tableFrame)
  1.2565 +      {
  1.2566 +        foundTable = true;
  1.2567 +        //TODO: How can we select row when along left table edge
  1.2568 +        //  or select column when along top edge?
  1.2569 +        break;
  1.2570 +      } else {
  1.2571 +        frame = frame->GetParent();
  1.2572 +        // Stop if we have hit the selection's limiting content node
  1.2573 +        if (frame && frame->GetContent() == limiter)
  1.2574 +          break;
  1.2575 +      }
  1.2576 +    }
  1.2577 +  }
  1.2578 +  // We aren't in a cell or table
  1.2579 +  if (!foundCell && !foundTable) return NS_OK;
  1.2580 +
  1.2581 +  nsIContent* tableOrCellContent = frame->GetContent();
  1.2582 +  if (!tableOrCellContent) return NS_ERROR_FAILURE;
  1.2583 +
  1.2584 +  nsCOMPtr<nsIContent> parentContent = tableOrCellContent->GetParent();
  1.2585 +  if (!parentContent) return NS_ERROR_FAILURE;
  1.2586 +
  1.2587 +  int32_t offset = parentContent->IndexOf(tableOrCellContent);
  1.2588 +  // Not likely?
  1.2589 +  if (offset < 0) return NS_ERROR_FAILURE;
  1.2590 +
  1.2591 +  // Everything is OK -- set the return values
  1.2592 +  *aParentContent = parentContent;
  1.2593 +  NS_ADDREF(*aParentContent);
  1.2594 +
  1.2595 +  *aContentOffset = offset;
  1.2596 +
  1.2597 +#if 0
  1.2598 +  if (selectRow)
  1.2599 +    *aTarget = nsISelectionPrivate::TABLESELECTION_ROW;
  1.2600 +  else if (selectColumn)
  1.2601 +    *aTarget = nsISelectionPrivate::TABLESELECTION_COLUMN;
  1.2602 +  else 
  1.2603 +#endif
  1.2604 +  if (foundCell)
  1.2605 +    *aTarget = nsISelectionPrivate::TABLESELECTION_CELL;
  1.2606 +  else if (foundTable)
  1.2607 +    *aTarget = nsISelectionPrivate::TABLESELECTION_TABLE;
  1.2608 +
  1.2609 +  return NS_OK;
  1.2610 +}
  1.2611 +
  1.2612 +nsresult
  1.2613 +nsFrame::IsSelectable(bool* aSelectable, uint8_t* aSelectStyle) const
  1.2614 +{
  1.2615 +  if (!aSelectable) //it's ok if aSelectStyle is null
  1.2616 +    return NS_ERROR_NULL_POINTER;
  1.2617 +
  1.2618 +  // Like 'visibility', we must check all the parents: if a parent
  1.2619 +  // is not selectable, none of its children is selectable.
  1.2620 +  //
  1.2621 +  // The -moz-all value acts similarly: if a frame has 'user-select:-moz-all',
  1.2622 +  // all its children are selectable, even those with 'user-select:none'.
  1.2623 +  //
  1.2624 +  // As a result, if 'none' and '-moz-all' are not present in the frame hierarchy,
  1.2625 +  // aSelectStyle returns the first style that is not AUTO. If these values
  1.2626 +  // are present in the frame hierarchy, aSelectStyle returns the style of the
  1.2627 +  // topmost parent that has either 'none' or '-moz-all'.
  1.2628 +  //
  1.2629 +  // For instance, if the frame hierarchy is:
  1.2630 +  //    AUTO     -> _MOZ_ALL -> NONE -> TEXT,     the returned value is _MOZ_ALL
  1.2631 +  //    TEXT     -> NONE     -> AUTO -> _MOZ_ALL, the returned value is TEXT
  1.2632 +  //    _MOZ_ALL -> TEXT     -> AUTO -> AUTO,     the returned value is _MOZ_ALL
  1.2633 +  //    AUTO     -> CELL     -> TEXT -> AUTO,     the returned value is TEXT
  1.2634 +  //
  1.2635 +  uint8_t selectStyle  = NS_STYLE_USER_SELECT_AUTO;
  1.2636 +  nsIFrame* frame      = const_cast<nsFrame*>(this);
  1.2637 +
  1.2638 +  while (frame) {
  1.2639 +    const nsStyleUIReset* userinterface = frame->StyleUIReset();
  1.2640 +    switch (userinterface->mUserSelect) {
  1.2641 +      case NS_STYLE_USER_SELECT_ALL:
  1.2642 +      case NS_STYLE_USER_SELECT_MOZ_ALL:
  1.2643 +        // override the previous values
  1.2644 +        selectStyle = userinterface->mUserSelect;
  1.2645 +        break;
  1.2646 +      default:
  1.2647 +        // otherwise return the first value which is not 'auto'
  1.2648 +        if (selectStyle == NS_STYLE_USER_SELECT_AUTO) {
  1.2649 +          selectStyle = userinterface->mUserSelect;
  1.2650 +        }
  1.2651 +        break;
  1.2652 +    }
  1.2653 +    frame = frame->GetParent();
  1.2654 +  }
  1.2655 +
  1.2656 +  // convert internal values to standard values
  1.2657 +  if (selectStyle == NS_STYLE_USER_SELECT_AUTO)
  1.2658 +    selectStyle = NS_STYLE_USER_SELECT_TEXT;
  1.2659 +  else
  1.2660 +  if (selectStyle == NS_STYLE_USER_SELECT_MOZ_ALL)
  1.2661 +    selectStyle = NS_STYLE_USER_SELECT_ALL;
  1.2662 +
  1.2663 +  // return stuff
  1.2664 +  if (aSelectStyle)
  1.2665 +    *aSelectStyle = selectStyle;
  1.2666 +  if (mState & NS_FRAME_GENERATED_CONTENT)
  1.2667 +    *aSelectable = false;
  1.2668 +  else
  1.2669 +    *aSelectable = (selectStyle != NS_STYLE_USER_SELECT_NONE);
  1.2670 +  return NS_OK;
  1.2671 +}
  1.2672 +
  1.2673 +/**
  1.2674 +  * Handles the Mouse Press Event for the frame
  1.2675 + */
  1.2676 +NS_IMETHODIMP
  1.2677 +nsFrame::HandlePress(nsPresContext* aPresContext, 
  1.2678 +                     WidgetGUIEvent* aEvent,
  1.2679 +                     nsEventStatus* aEventStatus)
  1.2680 +{
  1.2681 +  NS_ENSURE_ARG_POINTER(aEventStatus);
  1.2682 +  if (nsEventStatus_eConsumeNoDefault == *aEventStatus) {
  1.2683 +    return NS_OK;
  1.2684 +  }
  1.2685 +
  1.2686 +  NS_ENSURE_ARG_POINTER(aEvent);
  1.2687 +  if (aEvent->eventStructType == NS_TOUCH_EVENT) {
  1.2688 +    return NS_OK;
  1.2689 +  }
  1.2690 +
  1.2691 +  //We often get out of sync state issues with mousedown events that
  1.2692 +  //get interrupted by alerts/dialogs.
  1.2693 +  //Check with the ESM to see if we should process this one
  1.2694 +  if (!aPresContext->EventStateManager()->EventStatusOK(aEvent)) 
  1.2695 +    return NS_OK;
  1.2696 +
  1.2697 +  nsresult rv;
  1.2698 +  nsIPresShell *shell = aPresContext->GetPresShell();
  1.2699 +  if (!shell)
  1.2700 +    return NS_ERROR_FAILURE;
  1.2701 +
  1.2702 +  // if we are in Navigator and the click is in a draggable node, we don't want
  1.2703 +  // to start selection because we don't want to interfere with a potential
  1.2704 +  // drag of said node and steal all its glory.
  1.2705 +  int16_t isEditor = shell->GetSelectionFlags();
  1.2706 +  //weaaak. only the editor can display frame selection not just text and images
  1.2707 +  isEditor = isEditor == nsISelectionDisplay::DISPLAY_ALL;
  1.2708 +
  1.2709 +  WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
  1.2710 +
  1.2711 +  if (!mouseEvent->IsAlt()) {
  1.2712 +    for (nsIContent* content = mContent; content;
  1.2713 +         content = content->GetParent()) {
  1.2714 +      if (nsContentUtils::ContentIsDraggable(content) &&
  1.2715 +          !content->IsEditable()) {
  1.2716 +        // coordinate stuff is the fix for bug #55921
  1.2717 +        if ((mRect - GetPosition()).Contains(
  1.2718 +              nsLayoutUtils::GetEventCoordinatesRelativeTo(mouseEvent, this))) {
  1.2719 +          return NS_OK;
  1.2720 +        }
  1.2721 +      }
  1.2722 +    }
  1.2723 +  }
  1.2724 +
  1.2725 +  // check whether style allows selection
  1.2726 +  // if not, don't tell selection the mouse event even occurred.  
  1.2727 +  bool    selectable;
  1.2728 +  uint8_t selectStyle;
  1.2729 +  rv = IsSelectable(&selectable, &selectStyle);
  1.2730 +  if (NS_FAILED(rv)) return rv;
  1.2731 +  
  1.2732 +  // check for select: none
  1.2733 +  if (!selectable)
  1.2734 +    return NS_OK;
  1.2735 +
  1.2736 +  // When implementing NS_STYLE_USER_SELECT_ELEMENT, NS_STYLE_USER_SELECT_ELEMENTS and
  1.2737 +  // NS_STYLE_USER_SELECT_TOGGLE, need to change this logic
  1.2738 +  bool useFrameSelection = (selectStyle == NS_STYLE_USER_SELECT_TEXT);
  1.2739 +
  1.2740 +  // If the mouse is dragged outside the nearest enclosing scrollable area
  1.2741 +  // while making a selection, the area will be scrolled. To do this, capture
  1.2742 +  // the mouse on the nearest scrollable frame. If there isn't a scrollable
  1.2743 +  // frame, or something else is already capturing the mouse, there's no
  1.2744 +  // reason to capture.
  1.2745 +  bool hasCapturedContent = false;
  1.2746 +  if (!nsIPresShell::GetCapturingContent()) {
  1.2747 +    nsIScrollableFrame* scrollFrame =
  1.2748 +      nsLayoutUtils::GetNearestScrollableFrame(this,
  1.2749 +        nsLayoutUtils::SCROLLABLE_SAME_DOC |
  1.2750 +        nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN);
  1.2751 +    if (scrollFrame) {
  1.2752 +      nsIFrame* capturingFrame = do_QueryFrame(scrollFrame);
  1.2753 +      nsIPresShell::SetCapturingContent(capturingFrame->GetContent(),
  1.2754 +                                        CAPTURE_IGNOREALLOWED);
  1.2755 +      hasCapturedContent = true;
  1.2756 +    }
  1.2757 +  }
  1.2758 +
  1.2759 +  // XXX This is screwy; it really should use the selection frame, not the
  1.2760 +  // event frame
  1.2761 +  const nsFrameSelection* frameselection = nullptr;
  1.2762 +  if (useFrameSelection)
  1.2763 +    frameselection = GetConstFrameSelection();
  1.2764 +  else
  1.2765 +    frameselection = shell->ConstFrameSelection();
  1.2766 +
  1.2767 +  if (!frameselection || frameselection->GetDisplaySelection() == nsISelectionController::SELECTION_OFF)
  1.2768 +    return NS_OK;//nothing to do we cannot affect selection from here
  1.2769 +
  1.2770 +#ifdef XP_MACOSX
  1.2771 +  if (mouseEvent->IsControl())
  1.2772 +    return NS_OK;//short circuit. hard coded for mac due to time restraints.
  1.2773 +  bool control = mouseEvent->IsMeta();
  1.2774 +#else
  1.2775 +  bool control = mouseEvent->IsControl();
  1.2776 +#endif
  1.2777 +
  1.2778 +  nsRefPtr<nsFrameSelection> fc = const_cast<nsFrameSelection*>(frameselection);
  1.2779 +  if (mouseEvent->clickCount > 1) {
  1.2780 +    // These methods aren't const but can't actually delete anything,
  1.2781 +    // so no need for nsWeakFrame.
  1.2782 +    fc->SetMouseDownState(true);
  1.2783 +    fc->SetMouseDoubleDown(true);
  1.2784 +    return HandleMultiplePress(aPresContext, mouseEvent, aEventStatus, control);
  1.2785 +  }
  1.2786 +
  1.2787 +  nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(mouseEvent, this);
  1.2788 +  ContentOffsets offsets = GetContentOffsetsFromPoint(pt, SKIP_HIDDEN);
  1.2789 +
  1.2790 +  if (!offsets.content)
  1.2791 +    return NS_ERROR_FAILURE;
  1.2792 +
  1.2793 +  // On touchables devices, touch the screen is usually a pan action,
  1.2794 +  // so let's reposition the caret if needed but do not select text
  1.2795 +  // if the touch did not happen over an editable element.  Otherwise,
  1.2796 +  // let the user move the caret by tapping and dragging.
  1.2797 +  if (!offsets.content->IsEditable() &&
  1.2798 +      Preferences::GetBool("browser.ignoreNativeFrameTextSelection", false)) {
  1.2799 +    // On touchables devices, mouse events are generated if the gesture is a tap.
  1.2800 +    // Such events are never going to generate a drag action, so let's release
  1.2801 +    // captured content if any.
  1.2802 +    if (hasCapturedContent) {
  1.2803 +      nsIPresShell::SetCapturingContent(nullptr, 0);
  1.2804 +    }
  1.2805 +
  1.2806 +    return fc->HandleClick(offsets.content, offsets.StartOffset(),
  1.2807 +                           offsets.EndOffset(), false, false,
  1.2808 +                           offsets.associateWithNext);
  1.2809 +  }
  1.2810 +
  1.2811 +  // Let Ctrl/Cmd+mouse down do table selection instead of drag initiation
  1.2812 +  nsCOMPtr<nsIContent>parentContent;
  1.2813 +  int32_t  contentOffset;
  1.2814 +  int32_t target;
  1.2815 +  rv = GetDataForTableSelection(frameselection, shell, mouseEvent,
  1.2816 +                                getter_AddRefs(parentContent), &contentOffset,
  1.2817 +                                &target);
  1.2818 +  if (NS_SUCCEEDED(rv) && parentContent)
  1.2819 +  {
  1.2820 +    fc->SetMouseDownState(true);
  1.2821 +    return fc->HandleTableSelection(parentContent, contentOffset, target,
  1.2822 +                                    mouseEvent);
  1.2823 +  }
  1.2824 +
  1.2825 +  fc->SetDelayedCaretData(0);
  1.2826 +
  1.2827 +  // Check if any part of this frame is selected, and if the
  1.2828 +  // user clicked inside the selected region. If so, we delay
  1.2829 +  // starting a new selection since the user may be trying to
  1.2830 +  // drag the selected region to some other app.
  1.2831 +
  1.2832 +  SelectionDetails *details = 0;
  1.2833 +  if (GetContent()->IsSelectionDescendant())
  1.2834 +  {
  1.2835 +    bool inSelection = false;
  1.2836 +    details = frameselection->LookUpSelection(offsets.content, 0,
  1.2837 +        offsets.EndOffset(), false);
  1.2838 +
  1.2839 +    //
  1.2840 +    // If there are any details, check to see if the user clicked
  1.2841 +    // within any selected region of the frame.
  1.2842 +    //
  1.2843 +
  1.2844 +    SelectionDetails *curDetail = details;
  1.2845 +
  1.2846 +    while (curDetail)
  1.2847 +    {
  1.2848 +      //
  1.2849 +      // If the user clicked inside a selection, then just
  1.2850 +      // return without doing anything. We will handle placing
  1.2851 +      // the caret later on when the mouse is released. We ignore
  1.2852 +      // the spellcheck, find and url formatting selections.
  1.2853 +      //
  1.2854 +      if (curDetail->mType != nsISelectionController::SELECTION_SPELLCHECK &&
  1.2855 +          curDetail->mType != nsISelectionController::SELECTION_FIND &&
  1.2856 +          curDetail->mType != nsISelectionController::SELECTION_URLSECONDARY &&
  1.2857 +          curDetail->mStart <= offsets.StartOffset() &&
  1.2858 +          offsets.EndOffset() <= curDetail->mEnd)
  1.2859 +      {
  1.2860 +        inSelection = true;
  1.2861 +      }
  1.2862 +
  1.2863 +      SelectionDetails *nextDetail = curDetail->mNext;
  1.2864 +      delete curDetail;
  1.2865 +      curDetail = nextDetail;
  1.2866 +    }
  1.2867 +
  1.2868 +    if (inSelection) {
  1.2869 +      fc->SetMouseDownState(false);
  1.2870 +      fc->SetDelayedCaretData(mouseEvent);
  1.2871 +      return NS_OK;
  1.2872 +    }
  1.2873 +  }
  1.2874 +
  1.2875 +  fc->SetMouseDownState(true);
  1.2876 +
  1.2877 +  // Do not touch any nsFrame members after this point without adding
  1.2878 +  // weakFrame checks.
  1.2879 +  rv = fc->HandleClick(offsets.content, offsets.StartOffset(),
  1.2880 +                       offsets.EndOffset(), mouseEvent->IsShift(), control,
  1.2881 +                       offsets.associateWithNext);
  1.2882 +
  1.2883 +  if (NS_FAILED(rv))
  1.2884 +    return rv;
  1.2885 +
  1.2886 +  if (offsets.offset != offsets.secondaryOffset)
  1.2887 +    fc->MaintainSelection();
  1.2888 +
  1.2889 +  if (isEditor && !mouseEvent->IsShift() &&
  1.2890 +      (offsets.EndOffset() - offsets.StartOffset()) == 1)
  1.2891 +  {
  1.2892 +    // A single node is selected and we aren't extending an existing
  1.2893 +    // selection, which means the user clicked directly on an object (either
  1.2894 +    // -moz-user-select: all or a non-text node without children).
  1.2895 +    // Therefore, disable selection extension during mouse moves.
  1.2896 +    // XXX This is a bit hacky; shouldn't editor be able to deal with this?
  1.2897 +    fc->SetMouseDownState(false);
  1.2898 +  }
  1.2899 +
  1.2900 +  return rv;
  1.2901 +}
  1.2902 +
  1.2903 +/*
  1.2904 + * SelectByTypeAtPoint
  1.2905 + *
  1.2906 + * Search for selectable content at point and attempt to select
  1.2907 + * based on the start and end selection behaviours.
  1.2908 + *
  1.2909 + * @param aPresContext Presentation context
  1.2910 + * @param aPoint Point at which selection will occur. Coordinates
  1.2911 + * should be relaitve to this frame.
  1.2912 + * @param aBeginAmountType, aEndAmountType Selection behavior, see
  1.2913 + * nsIFrame for definitions.
  1.2914 + * @param aSelectFlags Selection flags defined in nsFame.h.
  1.2915 + * @return success or failure at finding suitable content to select.
  1.2916 + */
  1.2917 +nsresult
  1.2918 +nsFrame::SelectByTypeAtPoint(nsPresContext* aPresContext,
  1.2919 +                             const nsPoint& aPoint,
  1.2920 +                             nsSelectionAmount aBeginAmountType,
  1.2921 +                             nsSelectionAmount aEndAmountType,
  1.2922 +                             uint32_t aSelectFlags)
  1.2923 +{
  1.2924 +  NS_ENSURE_ARG_POINTER(aPresContext);
  1.2925 +
  1.2926 +  // No point in selecting if selection is turned off
  1.2927 +  if (DisplaySelection(aPresContext) == nsISelectionController::SELECTION_OFF)
  1.2928 +    return NS_OK;
  1.2929 +
  1.2930 +  ContentOffsets offsets = GetContentOffsetsFromPoint(aPoint, SKIP_HIDDEN);
  1.2931 +  if (!offsets.content)
  1.2932 +    return NS_ERROR_FAILURE;
  1.2933 +
  1.2934 +  int32_t offset;
  1.2935 +  const nsFrameSelection* frameSelection =
  1.2936 +    PresContext()->GetPresShell()->ConstFrameSelection();
  1.2937 +  nsIFrame* theFrame = frameSelection->
  1.2938 +    GetFrameForNodeOffset(offsets.content, offsets.offset,
  1.2939 +                          nsFrameSelection::HINT(offsets.associateWithNext),
  1.2940 +                          &offset);
  1.2941 +  if (!theFrame)
  1.2942 +    return NS_ERROR_FAILURE;
  1.2943 +
  1.2944 +  nsFrame* frame = static_cast<nsFrame*>(theFrame);
  1.2945 +  return frame->PeekBackwardAndForward(aBeginAmountType, aEndAmountType, 
  1.2946 +                                       offset, aPresContext,
  1.2947 +                                       aBeginAmountType != eSelectWord,
  1.2948 +                                       aSelectFlags);
  1.2949 +}
  1.2950 +
  1.2951 +/**
  1.2952 +  * Multiple Mouse Press -- line or paragraph selection -- for the frame.
  1.2953 +  * Wouldn't it be nice if this didn't have to be hardwired into Frame code?
  1.2954 + */
  1.2955 +NS_IMETHODIMP
  1.2956 +nsFrame::HandleMultiplePress(nsPresContext* aPresContext,
  1.2957 +                             WidgetGUIEvent* aEvent,
  1.2958 +                             nsEventStatus* aEventStatus,
  1.2959 +                             bool aControlHeld)
  1.2960 +{
  1.2961 +  NS_ENSURE_ARG_POINTER(aEvent);
  1.2962 +  NS_ENSURE_ARG_POINTER(aEventStatus);
  1.2963 +
  1.2964 +  if (nsEventStatus_eConsumeNoDefault == *aEventStatus ||
  1.2965 +      DisplaySelection(aPresContext) == nsISelectionController::SELECTION_OFF) {
  1.2966 +    return NS_OK;
  1.2967 +  }
  1.2968 +
  1.2969 +  // Find out whether we're doing line or paragraph selection.
  1.2970 +  // If browser.triple_click_selects_paragraph is true, triple-click selects paragraph.
  1.2971 +  // Otherwise, triple-click selects line, and quadruple-click selects paragraph
  1.2972 +  // (on platforms that support quadruple-click).
  1.2973 +  nsSelectionAmount beginAmount, endAmount;
  1.2974 +  WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
  1.2975 +  if (!mouseEvent) {
  1.2976 +    return NS_OK;
  1.2977 +  }
  1.2978 +
  1.2979 +  if (mouseEvent->clickCount == 4) {
  1.2980 +    beginAmount = endAmount = eSelectParagraph;
  1.2981 +  } else if (mouseEvent->clickCount == 3) {
  1.2982 +    if (Preferences::GetBool("browser.triple_click_selects_paragraph")) {
  1.2983 +      beginAmount = endAmount = eSelectParagraph;
  1.2984 +    } else {
  1.2985 +      beginAmount = eSelectBeginLine;
  1.2986 +      endAmount = eSelectEndLine;
  1.2987 +    }
  1.2988 +  } else if (mouseEvent->clickCount == 2) {
  1.2989 +    // We only want inline frames; PeekBackwardAndForward dislikes blocks
  1.2990 +    beginAmount = endAmount = eSelectWord;
  1.2991 +  } else {
  1.2992 +    return NS_OK;
  1.2993 +  }
  1.2994 +
  1.2995 +  nsPoint relPoint =
  1.2996 +    nsLayoutUtils::GetEventCoordinatesRelativeTo(mouseEvent, this);
  1.2997 +  return SelectByTypeAtPoint(aPresContext, relPoint, beginAmount, endAmount,
  1.2998 +                             (aControlHeld ? SELECT_ACCUMULATE : 0));
  1.2999 +}
  1.3000 +
  1.3001 +nsresult
  1.3002 +nsFrame::PeekBackwardAndForward(nsSelectionAmount aAmountBack,
  1.3003 +                                nsSelectionAmount aAmountForward,
  1.3004 +                                int32_t aStartPos,
  1.3005 +                                nsPresContext* aPresContext,
  1.3006 +                                bool aJumpLines,
  1.3007 +                                uint32_t aSelectFlags)
  1.3008 +{
  1.3009 +  nsIFrame* baseFrame = this;
  1.3010 +  int32_t baseOffset = aStartPos;
  1.3011 +  nsresult rv;
  1.3012 +
  1.3013 +  if (aAmountBack == eSelectWord) {
  1.3014 +    // To avoid selecting the previous word when at start of word,
  1.3015 +    // first move one character forward.
  1.3016 +    nsPeekOffsetStruct pos(eSelectCharacter,
  1.3017 +                           eDirNext,
  1.3018 +                           aStartPos,
  1.3019 +                           0,
  1.3020 +                           aJumpLines,
  1.3021 +                           true,  //limit on scrolled views
  1.3022 +                           false,
  1.3023 +                           false);
  1.3024 +    rv = PeekOffset(&pos);
  1.3025 +    if (NS_SUCCEEDED(rv)) {
  1.3026 +      baseFrame = pos.mResultFrame;
  1.3027 +      baseOffset = pos.mContentOffset;
  1.3028 +    }
  1.3029 +  }
  1.3030 +
  1.3031 +  // Use peek offset one way then the other:
  1.3032 +  nsPeekOffsetStruct startpos(aAmountBack,
  1.3033 +                              eDirPrevious,
  1.3034 +                              baseOffset,
  1.3035 +                              0,
  1.3036 +                              aJumpLines,
  1.3037 +                              true,  //limit on scrolled views
  1.3038 +                              false,
  1.3039 +                              false);
  1.3040 +  rv = baseFrame->PeekOffset(&startpos);
  1.3041 +  if (NS_FAILED(rv))
  1.3042 +    return rv;
  1.3043 +
  1.3044 +  nsPeekOffsetStruct endpos(aAmountForward,
  1.3045 +                            eDirNext,
  1.3046 +                            aStartPos,
  1.3047 +                            0,
  1.3048 +                            aJumpLines,
  1.3049 +                            true,  //limit on scrolled views
  1.3050 +                            false,
  1.3051 +                            false);
  1.3052 +  rv = PeekOffset(&endpos);
  1.3053 +  if (NS_FAILED(rv))
  1.3054 +    return rv;
  1.3055 +
  1.3056 +  // Keep frameSelection alive.
  1.3057 +  nsRefPtr<nsFrameSelection> frameSelection = GetFrameSelection();
  1.3058 +
  1.3059 +  rv = frameSelection->HandleClick(startpos.mResultContent,
  1.3060 +                                   startpos.mContentOffset, startpos.mContentOffset,
  1.3061 +                                   false, (aSelectFlags & SELECT_ACCUMULATE),
  1.3062 +                                   nsFrameSelection::HINTRIGHT);
  1.3063 +  if (NS_FAILED(rv))
  1.3064 +    return rv;
  1.3065 +
  1.3066 +  rv = frameSelection->HandleClick(endpos.mResultContent,
  1.3067 +                                   endpos.mContentOffset, endpos.mContentOffset,
  1.3068 +                                   true, false,
  1.3069 +                                   nsFrameSelection::HINTLEFT);
  1.3070 +  if (NS_FAILED(rv))
  1.3071 +    return rv;
  1.3072 +
  1.3073 +  // maintain selection
  1.3074 +  return frameSelection->MaintainSelection(aAmountBack);
  1.3075 +}
  1.3076 +
  1.3077 +NS_IMETHODIMP nsFrame::HandleDrag(nsPresContext* aPresContext, 
  1.3078 +                                  WidgetGUIEvent* aEvent,
  1.3079 +                                  nsEventStatus* aEventStatus)
  1.3080 +{
  1.3081 +  MOZ_ASSERT(aEvent->eventStructType == NS_MOUSE_EVENT, "HandleDrag can only handle mouse event");
  1.3082 +
  1.3083 +  bool selectable;
  1.3084 +  IsSelectable(&selectable, nullptr);
  1.3085 +
  1.3086 +  // XXX Do we really need to exclude non-selectable content here?
  1.3087 +  // GetContentOffsetsFromPoint can handle it just fine, although some
  1.3088 +  // other stuff might not like it.
  1.3089 +  if (!selectable)
  1.3090 +    return NS_OK;
  1.3091 +  if (DisplaySelection(aPresContext) == nsISelectionController::SELECTION_OFF) {
  1.3092 +    return NS_OK;
  1.3093 +  }
  1.3094 +  nsIPresShell *presShell = aPresContext->PresShell();
  1.3095 +
  1.3096 +  nsRefPtr<nsFrameSelection> frameselection = GetFrameSelection();
  1.3097 +  bool mouseDown = frameselection->GetMouseDownState();
  1.3098 +  if (!mouseDown)
  1.3099 +    return NS_OK;
  1.3100 +
  1.3101 +  frameselection->StopAutoScrollTimer();
  1.3102 +
  1.3103 +  // Check if we are dragging in a table cell
  1.3104 +  nsCOMPtr<nsIContent> parentContent;
  1.3105 +  int32_t contentOffset;
  1.3106 +  int32_t target;
  1.3107 +  WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
  1.3108 +  nsresult result;
  1.3109 +  result = GetDataForTableSelection(frameselection, presShell, mouseEvent,
  1.3110 +                                    getter_AddRefs(parentContent),
  1.3111 +                                    &contentOffset, &target);      
  1.3112 +
  1.3113 +  nsWeakFrame weakThis = this;
  1.3114 +  if (NS_SUCCEEDED(result) && parentContent) {
  1.3115 +    frameselection->HandleTableSelection(parentContent, contentOffset, target,
  1.3116 +                                         mouseEvent);
  1.3117 +  } else {
  1.3118 +    nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(mouseEvent, this);
  1.3119 +    frameselection->HandleDrag(this, pt);
  1.3120 +  }
  1.3121 +
  1.3122 +  // The frameselection object notifies selection listeners synchronously above
  1.3123 +  // which might have killed us.
  1.3124 +  if (!weakThis.IsAlive()) {
  1.3125 +    return NS_OK;
  1.3126 +  }
  1.3127 +
  1.3128 +  // get the nearest scrollframe
  1.3129 +  nsIScrollableFrame* scrollFrame =
  1.3130 +    nsLayoutUtils::GetNearestScrollableFrame(this,
  1.3131 +        nsLayoutUtils::SCROLLABLE_SAME_DOC |
  1.3132 +        nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN);
  1.3133 +
  1.3134 +  if (scrollFrame) {
  1.3135 +    nsIFrame* capturingFrame = scrollFrame->GetScrolledFrame();
  1.3136 +    if (capturingFrame) {
  1.3137 +      nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(mouseEvent,
  1.3138 +                                                                capturingFrame);
  1.3139 +      frameselection->StartAutoScrollTimer(capturingFrame, pt, 30);
  1.3140 +    }
  1.3141 +  }
  1.3142 +
  1.3143 +  return NS_OK;
  1.3144 +}
  1.3145 +
  1.3146 +/**
  1.3147 + * This static method handles part of the nsFrame::HandleRelease in a way
  1.3148 + * which doesn't rely on the nsFrame object to stay alive.
  1.3149 + */
  1.3150 +static nsresult
  1.3151 +HandleFrameSelection(nsFrameSelection*         aFrameSelection,
  1.3152 +                     nsIFrame::ContentOffsets& aOffsets,
  1.3153 +                     bool                      aHandleTableSel,
  1.3154 +                     int32_t                   aContentOffsetForTableSel,
  1.3155 +                     int32_t                   aTargetForTableSel,
  1.3156 +                     nsIContent*               aParentContentForTableSel,
  1.3157 +                     WidgetGUIEvent*           aEvent,
  1.3158 +                     nsEventStatus*            aEventStatus)
  1.3159 +{
  1.3160 +  if (!aFrameSelection) {
  1.3161 +    return NS_OK;
  1.3162 +  }
  1.3163 +
  1.3164 +  nsresult rv = NS_OK;
  1.3165 +
  1.3166 +  if (nsEventStatus_eConsumeNoDefault != *aEventStatus) {
  1.3167 +    if (!aHandleTableSel) {
  1.3168 +      if (!aOffsets.content || !aFrameSelection->HasDelayedCaretData()) {
  1.3169 +        return NS_ERROR_FAILURE;
  1.3170 +      }
  1.3171 +
  1.3172 +      // We are doing this to simulate what we would have done on HandlePress.
  1.3173 +      // We didn't do it there to give the user an opportunity to drag
  1.3174 +      // the text, but since they didn't drag, we want to place the
  1.3175 +      // caret.
  1.3176 +      // However, we'll use the mouse position from the release, since:
  1.3177 +      //  * it's easier
  1.3178 +      //  * that's the normal click position to use (although really, in
  1.3179 +      //    the normal case, small movements that don't count as a drag
  1.3180 +      //    can do selection)
  1.3181 +      aFrameSelection->SetMouseDownState(true);
  1.3182 +
  1.3183 +      rv = aFrameSelection->HandleClick(aOffsets.content,
  1.3184 +                                        aOffsets.StartOffset(),
  1.3185 +                                        aOffsets.EndOffset(),
  1.3186 +                                        aFrameSelection->IsShiftDownInDelayedCaretData(),
  1.3187 +                                        false,
  1.3188 +                                        aOffsets.associateWithNext);
  1.3189 +      if (NS_FAILED(rv)) {
  1.3190 +        return rv;
  1.3191 +      }
  1.3192 +    } else if (aParentContentForTableSel) {
  1.3193 +      aFrameSelection->SetMouseDownState(false);
  1.3194 +      rv = aFrameSelection->HandleTableSelection(
  1.3195 +                              aParentContentForTableSel,
  1.3196 +                              aContentOffsetForTableSel,
  1.3197 +                              aTargetForTableSel,
  1.3198 +                              aEvent->AsMouseEvent());
  1.3199 +      if (NS_FAILED(rv)) {
  1.3200 +        return rv;
  1.3201 +      }
  1.3202 +    }
  1.3203 +    aFrameSelection->SetDelayedCaretData(0);
  1.3204 +  }
  1.3205 +
  1.3206 +  aFrameSelection->SetMouseDownState(false);
  1.3207 +  aFrameSelection->StopAutoScrollTimer();
  1.3208 +
  1.3209 +  return NS_OK;
  1.3210 +}
  1.3211 +
  1.3212 +NS_IMETHODIMP nsFrame::HandleRelease(nsPresContext* aPresContext,
  1.3213 +                                     WidgetGUIEvent* aEvent,
  1.3214 +                                     nsEventStatus* aEventStatus)
  1.3215 +{
  1.3216 +  if (aEvent->eventStructType != NS_MOUSE_EVENT) {
  1.3217 +    return NS_OK;
  1.3218 +  }
  1.3219 +
  1.3220 +  nsIFrame* activeFrame = GetActiveSelectionFrame(aPresContext, this);
  1.3221 +
  1.3222 +  nsCOMPtr<nsIContent> captureContent = nsIPresShell::GetCapturingContent();
  1.3223 +
  1.3224 +  // We can unconditionally stop capturing because
  1.3225 +  // we should never be capturing when the mouse button is up
  1.3226 +  nsIPresShell::SetCapturingContent(nullptr, 0);
  1.3227 +
  1.3228 +  bool selectionOff =
  1.3229 +    (DisplaySelection(aPresContext) == nsISelectionController::SELECTION_OFF);
  1.3230 +
  1.3231 +  nsRefPtr<nsFrameSelection> frameselection;
  1.3232 +  ContentOffsets offsets;
  1.3233 +  nsCOMPtr<nsIContent> parentContent;
  1.3234 +  int32_t contentOffsetForTableSel = 0;
  1.3235 +  int32_t targetForTableSel = 0;
  1.3236 +  bool handleTableSelection = true;
  1.3237 +
  1.3238 +  if (!selectionOff) {
  1.3239 +    frameselection = GetFrameSelection();
  1.3240 +    if (nsEventStatus_eConsumeNoDefault != *aEventStatus && frameselection) {
  1.3241 +      // Check if the frameselection recorded the mouse going down.
  1.3242 +      // If not, the user must have clicked in a part of the selection.
  1.3243 +      // Place the caret before continuing!
  1.3244 +
  1.3245 +      bool mouseDown = frameselection->GetMouseDownState();
  1.3246 +
  1.3247 +      if (!mouseDown && frameselection->HasDelayedCaretData() &&
  1.3248 +          frameselection->GetClickCountInDelayedCaretData() < 2) {
  1.3249 +        nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this);
  1.3250 +        offsets = GetContentOffsetsFromPoint(pt, SKIP_HIDDEN);
  1.3251 +        handleTableSelection = false;
  1.3252 +      } else {
  1.3253 +        GetDataForTableSelection(frameselection, PresContext()->PresShell(),
  1.3254 +                                 aEvent->AsMouseEvent(),
  1.3255 +                                 getter_AddRefs(parentContent),
  1.3256 +                                 &contentOffsetForTableSel,
  1.3257 +                                 &targetForTableSel);
  1.3258 +      }
  1.3259 +    }
  1.3260 +  }
  1.3261 +
  1.3262 +  // We might be capturing in some other document and the event just happened to
  1.3263 +  // trickle down here. Make sure that document's frame selection is notified.
  1.3264 +  // Note, this may cause the current nsFrame object to be deleted, bug 336592.
  1.3265 +  nsRefPtr<nsFrameSelection> frameSelection;
  1.3266 +  if (activeFrame != this &&
  1.3267 +      static_cast<nsFrame*>(activeFrame)->DisplaySelection(activeFrame->PresContext())
  1.3268 +        != nsISelectionController::SELECTION_OFF) {
  1.3269 +      frameSelection = activeFrame->GetFrameSelection();
  1.3270 +  }
  1.3271 +
  1.3272 +  // Also check the selection of the capturing content which might be in a
  1.3273 +  // different document.
  1.3274 +  if (!frameSelection && captureContent) {
  1.3275 +    nsIDocument* doc = captureContent->GetCurrentDoc();
  1.3276 +    if (doc) {
  1.3277 +      nsIPresShell* capturingShell = doc->GetShell();
  1.3278 +      if (capturingShell && capturingShell != PresContext()->GetPresShell()) {
  1.3279 +        frameSelection = capturingShell->FrameSelection();
  1.3280 +      }
  1.3281 +    }
  1.3282 +  }
  1.3283 +
  1.3284 +  if (frameSelection) {
  1.3285 +    frameSelection->SetMouseDownState(false);
  1.3286 +    frameSelection->StopAutoScrollTimer();
  1.3287 +  }
  1.3288 +
  1.3289 +  // Do not call any methods of the current object after this point!!!
  1.3290 +  // The object is perhaps dead!
  1.3291 +
  1.3292 +  return selectionOff
  1.3293 +    ? NS_OK
  1.3294 +    : HandleFrameSelection(frameselection, offsets, handleTableSelection,
  1.3295 +                           contentOffsetForTableSel, targetForTableSel,
  1.3296 +                           parentContent, aEvent, aEventStatus);
  1.3297 +}
  1.3298 +
  1.3299 +struct MOZ_STACK_CLASS FrameContentRange {
  1.3300 +  FrameContentRange(nsIContent* aContent, int32_t aStart, int32_t aEnd) :
  1.3301 +    content(aContent), start(aStart), end(aEnd) { }
  1.3302 +  nsCOMPtr<nsIContent> content;
  1.3303 +  int32_t start;
  1.3304 +  int32_t end;
  1.3305 +};
  1.3306 +
  1.3307 +// Retrieve the content offsets of a frame
  1.3308 +static FrameContentRange GetRangeForFrame(nsIFrame* aFrame) {
  1.3309 +  nsCOMPtr<nsIContent> content, parent;
  1.3310 +  content = aFrame->GetContent();
  1.3311 +  if (!content) {
  1.3312 +    NS_WARNING("Frame has no content");
  1.3313 +    return FrameContentRange(nullptr, -1, -1);
  1.3314 +  }
  1.3315 +  nsIAtom* type = aFrame->GetType();
  1.3316 +  if (type == nsGkAtoms::textFrame) {
  1.3317 +    int32_t offset, offsetEnd;
  1.3318 +    aFrame->GetOffsets(offset, offsetEnd);
  1.3319 +    return FrameContentRange(content, offset, offsetEnd);
  1.3320 +  }
  1.3321 +  if (type == nsGkAtoms::brFrame) {
  1.3322 +    parent = content->GetParent();
  1.3323 +    int32_t beginOffset = parent->IndexOf(content);
  1.3324 +    return FrameContentRange(parent, beginOffset, beginOffset);
  1.3325 +  }
  1.3326 +  // Loop to deal with anonymous content, which has no index; this loop
  1.3327 +  // probably won't run more than twice under normal conditions
  1.3328 +  do {
  1.3329 +    parent  = content->GetParent();
  1.3330 +    if (parent) {
  1.3331 +      int32_t beginOffset = parent->IndexOf(content);
  1.3332 +      if (beginOffset >= 0)
  1.3333 +        return FrameContentRange(parent, beginOffset, beginOffset + 1);
  1.3334 +      content = parent;
  1.3335 +    }
  1.3336 +  } while (parent);
  1.3337 +
  1.3338 +  // The root content node must act differently
  1.3339 +  return FrameContentRange(content, 0, content->GetChildCount());
  1.3340 +}
  1.3341 +
  1.3342 +// The FrameTarget represents the closest frame to a point that can be selected
  1.3343 +// The frame is the frame represented, frameEdge says whether one end of the
  1.3344 +// frame is the result (in which case different handling is needed), and
  1.3345 +// afterFrame says which end is repersented if frameEdge is true
  1.3346 +struct FrameTarget {
  1.3347 +  FrameTarget(nsIFrame* aFrame, bool aFrameEdge, bool aAfterFrame,
  1.3348 +              bool aEmptyBlock = false) :
  1.3349 +    frame(aFrame), frameEdge(aFrameEdge), afterFrame(aAfterFrame),
  1.3350 +    emptyBlock(aEmptyBlock) { }
  1.3351 +  static FrameTarget Null() {
  1.3352 +    return FrameTarget(nullptr, false, false);
  1.3353 +  }
  1.3354 +  bool IsNull() {
  1.3355 +    return !frame;
  1.3356 +  }
  1.3357 +  nsIFrame* frame;
  1.3358 +  bool frameEdge;
  1.3359 +  bool afterFrame;
  1.3360 +  bool emptyBlock;
  1.3361 +};
  1.3362 +
  1.3363 +// See function implementation for information
  1.3364 +static FrameTarget GetSelectionClosestFrame(nsIFrame* aFrame, nsPoint aPoint,
  1.3365 +                                            uint32_t aFlags);
  1.3366 +
  1.3367 +static bool SelfIsSelectable(nsIFrame* aFrame, uint32_t aFlags)
  1.3368 +{
  1.3369 +  if ((aFlags & nsIFrame::SKIP_HIDDEN) &&
  1.3370 +      !aFrame->StyleVisibility()->IsVisible()) {
  1.3371 +    return false;
  1.3372 +  }
  1.3373 +  return !aFrame->IsGeneratedContentFrame() &&
  1.3374 +    aFrame->StyleUIReset()->mUserSelect != NS_STYLE_USER_SELECT_NONE;
  1.3375 +}
  1.3376 +
  1.3377 +static bool SelectionDescendToKids(nsIFrame* aFrame) {
  1.3378 +  uint8_t style = aFrame->StyleUIReset()->mUserSelect;
  1.3379 +  nsIFrame* parent = aFrame->GetParent();
  1.3380 +  // If we are only near (not directly over) then don't traverse
  1.3381 +  // frames with independent selection (e.g. text and list controls)
  1.3382 +  // unless we're already inside such a frame (see bug 268497).  Note that this
  1.3383 +  // prevents any of the users of this method from entering form controls.
  1.3384 +  // XXX We might want some way to allow using the up-arrow to go into a form
  1.3385 +  // control, but the focus didn't work right anyway; it'd probably be enough
  1.3386 +  // if the left and right arrows could enter textboxes (which I don't believe
  1.3387 +  // they can at the moment)
  1.3388 +  return !aFrame->IsGeneratedContentFrame() &&
  1.3389 +         style != NS_STYLE_USER_SELECT_ALL  &&
  1.3390 +         style != NS_STYLE_USER_SELECT_NONE &&
  1.3391 +         ((parent->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION) ||
  1.3392 +          !(aFrame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION));
  1.3393 +}
  1.3394 +
  1.3395 +static FrameTarget GetSelectionClosestFrameForChild(nsIFrame* aChild,
  1.3396 +                                                    nsPoint aPoint,
  1.3397 +                                                    uint32_t aFlags)
  1.3398 +{
  1.3399 +  nsIFrame* parent = aChild->GetParent();
  1.3400 +  if (SelectionDescendToKids(aChild)) {
  1.3401 +    nsPoint pt = aPoint - aChild->GetOffsetTo(parent);
  1.3402 +    return GetSelectionClosestFrame(aChild, pt, aFlags);
  1.3403 +  }
  1.3404 +  return FrameTarget(aChild, false, false);
  1.3405 +}
  1.3406 +
  1.3407 +// When the cursor needs to be at the beginning of a block, it shouldn't be
  1.3408 +// before the first child.  A click on a block whose first child is a block
  1.3409 +// should put the cursor in the child.  The cursor shouldn't be between the
  1.3410 +// blocks, because that's not where it's expected.
  1.3411 +// Note that this method is guaranteed to succeed.
  1.3412 +static FrameTarget DrillDownToSelectionFrame(nsIFrame* aFrame,
  1.3413 +                                             bool aEndFrame, uint32_t aFlags) {
  1.3414 +  if (SelectionDescendToKids(aFrame)) {
  1.3415 +    nsIFrame* result = nullptr;
  1.3416 +    nsIFrame *frame = aFrame->GetFirstPrincipalChild();
  1.3417 +    if (!aEndFrame) {
  1.3418 +      while (frame && (!SelfIsSelectable(frame, aFlags) ||
  1.3419 +                        frame->IsEmpty()))
  1.3420 +        frame = frame->GetNextSibling();
  1.3421 +      if (frame)
  1.3422 +        result = frame;
  1.3423 +    } else {
  1.3424 +      // Because the frame tree is singly linked, to find the last frame,
  1.3425 +      // we have to iterate through all the frames
  1.3426 +      // XXX I have a feeling this could be slow for long blocks, although
  1.3427 +      //     I can't find any slowdowns
  1.3428 +      while (frame) {
  1.3429 +        if (!frame->IsEmpty() && SelfIsSelectable(frame, aFlags))
  1.3430 +          result = frame;
  1.3431 +        frame = frame->GetNextSibling();
  1.3432 +      }
  1.3433 +    }
  1.3434 +    if (result)
  1.3435 +      return DrillDownToSelectionFrame(result, aEndFrame, aFlags);
  1.3436 +  }
  1.3437 +  // If the current frame has no targetable children, target the current frame
  1.3438 +  return FrameTarget(aFrame, true, aEndFrame);
  1.3439 +}
  1.3440 +
  1.3441 +// This method finds the closest valid FrameTarget on a given line; if there is
  1.3442 +// no valid FrameTarget on the line, it returns a null FrameTarget
  1.3443 +static FrameTarget GetSelectionClosestFrameForLine(
  1.3444 +                      nsBlockFrame* aParent,
  1.3445 +                      nsBlockFrame::line_iterator aLine,
  1.3446 +                      nsPoint aPoint,
  1.3447 +                      uint32_t aFlags)
  1.3448 +{
  1.3449 +  nsIFrame *frame = aLine->mFirstChild;
  1.3450 +  // Account for end of lines (any iterator from the block is valid)
  1.3451 +  if (aLine == aParent->end_lines())
  1.3452 +    return DrillDownToSelectionFrame(aParent, true, aFlags);
  1.3453 +  nsIFrame *closestFromIStart = nullptr, *closestFromIEnd = nullptr;
  1.3454 +  nscoord closestIStart = aLine->IStart(), closestIEnd = aLine->IEnd();
  1.3455 +  WritingMode wm = aLine->mWritingMode;
  1.3456 +  LogicalPoint pt(wm, aPoint, aLine->mContainerWidth);
  1.3457 +  for (int32_t n = aLine->GetChildCount(); n;
  1.3458 +       --n, frame = frame->GetNextSibling()) {
  1.3459 +    if (!SelfIsSelectable(frame, aFlags) || frame->IsEmpty())
  1.3460 +      continue;
  1.3461 +    LogicalRect frameRect = LogicalRect(wm, frame->GetRect(),
  1.3462 +                                        aLine->mContainerWidth);
  1.3463 +    if (pt.I(wm) >= frameRect.IStart(wm)) {
  1.3464 +      if (pt.I(wm) < frameRect.IEnd(wm)) {
  1.3465 +        return GetSelectionClosestFrameForChild(frame, aPoint, aFlags);
  1.3466 +      }
  1.3467 +      if (frameRect.IEnd(wm) >= closestIStart) {
  1.3468 +        closestFromIStart = frame;
  1.3469 +        closestIStart = frameRect.IEnd(wm);
  1.3470 +      }
  1.3471 +    } else {
  1.3472 +      if (frameRect.IStart(wm) <= closestIEnd) {
  1.3473 +        closestFromIEnd = frame;
  1.3474 +        closestIEnd = frameRect.IStart(wm);
  1.3475 +      }
  1.3476 +    }
  1.3477 +  }
  1.3478 +  if (!closestFromIStart && !closestFromIEnd) {
  1.3479 +    // We should only get here if there are no selectable frames on a line
  1.3480 +    // XXX Do we need more elaborate handling here?
  1.3481 +    return FrameTarget::Null();
  1.3482 +  }
  1.3483 +  if (closestFromIStart &&
  1.3484 +      (!closestFromIEnd ||
  1.3485 +       (abs(pt.I(wm) - closestIStart) <= abs(pt.I(wm) - closestIEnd)))) {
  1.3486 +    return GetSelectionClosestFrameForChild(closestFromIStart, aPoint,
  1.3487 +                                            aFlags);
  1.3488 +  }
  1.3489 +  return GetSelectionClosestFrameForChild(closestFromIEnd, aPoint, aFlags);
  1.3490 +}
  1.3491 +
  1.3492 +// This method is for the special handling we do for block frames; they're
  1.3493 +// special because they represent paragraphs and because they are organized
  1.3494 +// into lines, which have bounds that are not stored elsewhere in the
  1.3495 +// frame tree.  Returns a null FrameTarget for frames which are not
  1.3496 +// blocks or blocks with no lines except editable one.
  1.3497 +static FrameTarget GetSelectionClosestFrameForBlock(nsIFrame* aFrame,
  1.3498 +                                                    nsPoint aPoint,
  1.3499 +                                                    uint32_t aFlags)
  1.3500 +{
  1.3501 +  nsBlockFrame* bf = nsLayoutUtils::GetAsBlock(aFrame); // used only for QI
  1.3502 +  if (!bf)
  1.3503 +    return FrameTarget::Null();
  1.3504 +
  1.3505 +  // This code searches for the correct line
  1.3506 +  nsBlockFrame::line_iterator firstLine = bf->begin_lines();
  1.3507 +  nsBlockFrame::line_iterator end = bf->end_lines();
  1.3508 +  if (firstLine == end) {
  1.3509 +    nsIContent *blockContent = aFrame->GetContent();
  1.3510 +    if (blockContent) {
  1.3511 +      // Return with empty flag true.
  1.3512 +      return FrameTarget(aFrame, false, false, true);
  1.3513 +    }
  1.3514 +    return FrameTarget::Null();
  1.3515 +  }
  1.3516 +  nsBlockFrame::line_iterator curLine = firstLine;
  1.3517 +  nsBlockFrame::line_iterator closestLine = end;
  1.3518 +  // Convert aPoint into a LogicalPoint in the writing-mode of this block
  1.3519 +  WritingMode wm = curLine->mWritingMode;
  1.3520 +  LogicalPoint pt(wm, aPoint, curLine->mContainerWidth);
  1.3521 +  while (curLine != end) {
  1.3522 +    // Check to see if our point lies within the line's block-direction bounds
  1.3523 +    nscoord BCoord = pt.B(wm) - curLine->BStart();
  1.3524 +    nscoord BSize = curLine->BSize();
  1.3525 +    if (BCoord >= 0 && BCoord < BSize) {
  1.3526 +      closestLine = curLine;
  1.3527 +      break; // We found the line; stop looking
  1.3528 +    }
  1.3529 +    if (BCoord < 0)
  1.3530 +      break;
  1.3531 +    ++curLine;
  1.3532 +  }
  1.3533 +
  1.3534 +  if (closestLine == end) {
  1.3535 +    nsBlockFrame::line_iterator prevLine = curLine.prev();
  1.3536 +    nsBlockFrame::line_iterator nextLine = curLine;
  1.3537 +    // Avoid empty lines
  1.3538 +    while (nextLine != end && nextLine->IsEmpty())
  1.3539 +      ++nextLine;
  1.3540 +    while (prevLine != end && prevLine->IsEmpty())
  1.3541 +      --prevLine;
  1.3542 +
  1.3543 +    // This hidden pref dictates whether a point above or below all lines comes
  1.3544 +    // up with a line or the beginning or end of the frame; 0 on Windows,
  1.3545 +    // 1 on other platforms by default at the writing of this code
  1.3546 +    int32_t dragOutOfFrame =
  1.3547 +      Preferences::GetInt("browser.drag_out_of_frame_style");
  1.3548 +
  1.3549 +    if (prevLine == end) {
  1.3550 +      if (dragOutOfFrame == 1 || nextLine == end)
  1.3551 +        return DrillDownToSelectionFrame(aFrame, false, aFlags);
  1.3552 +      closestLine = nextLine;
  1.3553 +    } else if (nextLine == end) {
  1.3554 +      if (dragOutOfFrame == 1)
  1.3555 +        return DrillDownToSelectionFrame(aFrame, true, aFlags);
  1.3556 +      closestLine = prevLine;
  1.3557 +    } else { // Figure out which line is closer
  1.3558 +      if (pt.B(wm) - prevLine->BEnd() < nextLine->BStart() - pt.B(wm))
  1.3559 +        closestLine = prevLine;
  1.3560 +      else
  1.3561 +        closestLine = nextLine;
  1.3562 +    }
  1.3563 +  }
  1.3564 +
  1.3565 +  do {
  1.3566 +    FrameTarget target = GetSelectionClosestFrameForLine(bf, closestLine,
  1.3567 +                                                         aPoint, aFlags);
  1.3568 +    if (!target.IsNull())
  1.3569 +      return target;
  1.3570 +    ++closestLine;
  1.3571 +  } while (closestLine != end);
  1.3572 +  // Fall back to just targeting the last targetable place
  1.3573 +  return DrillDownToSelectionFrame(aFrame, true, aFlags);
  1.3574 +}
  1.3575 +
  1.3576 +// GetSelectionClosestFrame is the helper function that calculates the closest
  1.3577 +// frame to the given point.
  1.3578 +// It doesn't completely account for offset styles, so needs to be used in
  1.3579 +// restricted environments.
  1.3580 +// Cannot handle overlapping frames correctly, so it should receive the output
  1.3581 +// of GetFrameForPoint
  1.3582 +// Guaranteed to return a valid FrameTarget
  1.3583 +static FrameTarget GetSelectionClosestFrame(nsIFrame* aFrame, nsPoint aPoint,
  1.3584 +                                            uint32_t aFlags)
  1.3585 +{
  1.3586 +  {
  1.3587 +    // Handle blocks; if the frame isn't a block, the method fails
  1.3588 +    FrameTarget target = GetSelectionClosestFrameForBlock(aFrame, aPoint, aFlags);
  1.3589 +    if (!target.IsNull())
  1.3590 +      return target;
  1.3591 +  }
  1.3592 +
  1.3593 +  nsIFrame *kid = aFrame->GetFirstPrincipalChild();
  1.3594 +
  1.3595 +  if (kid) {
  1.3596 +    // Go through all the child frames to find the closest one
  1.3597 +    nsIFrame::FrameWithDistance closest = { nullptr, nscoord_MAX, nscoord_MAX };
  1.3598 +    for (; kid; kid = kid->GetNextSibling()) {
  1.3599 +      if (!SelfIsSelectable(kid, aFlags) || kid->IsEmpty())
  1.3600 +        continue;
  1.3601 +
  1.3602 +      kid->FindCloserFrameForSelection(aPoint, &closest);
  1.3603 +    }
  1.3604 +    if (closest.mFrame) {
  1.3605 +      if (closest.mFrame->IsSVGText())
  1.3606 +        return FrameTarget(closest.mFrame, false, false);
  1.3607 +      return GetSelectionClosestFrameForChild(closest.mFrame, aPoint, aFlags);
  1.3608 +    }
  1.3609 +  }
  1.3610 +  return FrameTarget(aFrame, false, false);
  1.3611 +}
  1.3612 +
  1.3613 +nsIFrame::ContentOffsets OffsetsForSingleFrame(nsIFrame* aFrame, nsPoint aPoint)
  1.3614 +{
  1.3615 +  nsIFrame::ContentOffsets offsets;
  1.3616 +  FrameContentRange range = GetRangeForFrame(aFrame);
  1.3617 +  offsets.content = range.content;
  1.3618 +  // If there are continuations (meaning it's not one rectangle), this is the
  1.3619 +  // best this function can do
  1.3620 +  if (aFrame->GetNextContinuation() || aFrame->GetPrevContinuation()) {
  1.3621 +    offsets.offset = range.start;
  1.3622 +    offsets.secondaryOffset = range.end;
  1.3623 +    offsets.associateWithNext = true;
  1.3624 +    return offsets;
  1.3625 +  }
  1.3626 +
  1.3627 +  // Figure out whether the offsets should be over, after, or before the frame
  1.3628 +  nsRect rect(nsPoint(0, 0), aFrame->GetSize());
  1.3629 +
  1.3630 +  bool isBlock = aFrame->GetDisplay() != NS_STYLE_DISPLAY_INLINE;
  1.3631 +  bool isRtl = (aFrame->StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL);
  1.3632 +  if ((isBlock && rect.y < aPoint.y) ||
  1.3633 +      (!isBlock && ((isRtl  && rect.x + rect.width / 2 > aPoint.x) || 
  1.3634 +                    (!isRtl && rect.x + rect.width / 2 < aPoint.x)))) {
  1.3635 +    offsets.offset = range.end;
  1.3636 +    if (rect.Contains(aPoint))
  1.3637 +      offsets.secondaryOffset = range.start;
  1.3638 +    else
  1.3639 +      offsets.secondaryOffset = range.end;
  1.3640 +  } else {
  1.3641 +    offsets.offset = range.start;
  1.3642 +    if (rect.Contains(aPoint))
  1.3643 +      offsets.secondaryOffset = range.end;
  1.3644 +    else
  1.3645 +      offsets.secondaryOffset = range.start;
  1.3646 +  }
  1.3647 +  offsets.associateWithNext = (offsets.offset == range.start);
  1.3648 +  return offsets;
  1.3649 +}
  1.3650 +
  1.3651 +static nsIFrame* AdjustFrameForSelectionStyles(nsIFrame* aFrame) {
  1.3652 +  nsIFrame* adjustedFrame = aFrame;
  1.3653 +  for (nsIFrame* frame = aFrame; frame; frame = frame->GetParent())
  1.3654 +  {
  1.3655 +    // These are the conditions that make all children not able to handle
  1.3656 +    // a cursor.
  1.3657 +    if (frame->StyleUIReset()->mUserSelect == NS_STYLE_USER_SELECT_ALL ||
  1.3658 +        frame->IsGeneratedContentFrame()) {
  1.3659 +      adjustedFrame = frame;
  1.3660 +    }
  1.3661 +  }
  1.3662 +  return adjustedFrame;
  1.3663 +}
  1.3664 +
  1.3665 +nsIFrame::ContentOffsets nsIFrame::GetContentOffsetsFromPoint(nsPoint aPoint,
  1.3666 +                                                              uint32_t aFlags)
  1.3667 +{
  1.3668 +  nsIFrame *adjustedFrame;
  1.3669 +  if (aFlags & IGNORE_SELECTION_STYLE) {
  1.3670 +    adjustedFrame = this;
  1.3671 +  }
  1.3672 +  else {
  1.3673 +    // This section of code deals with special selection styles.  Note that
  1.3674 +    // -moz-all exists, even though it doesn't need to be explicitly handled.
  1.3675 +    //
  1.3676 +    // The offset is forced not to end up in generated content; content offsets
  1.3677 +    // cannot represent content outside of the document's content tree.
  1.3678 +
  1.3679 +    adjustedFrame = AdjustFrameForSelectionStyles(this);
  1.3680 +
  1.3681 +    // -moz-user-select: all needs special handling, because clicking on it
  1.3682 +    // should lead to the whole frame being selected
  1.3683 +    if (adjustedFrame && adjustedFrame->StyleUIReset()->mUserSelect ==
  1.3684 +        NS_STYLE_USER_SELECT_ALL) {
  1.3685 +      nsPoint adjustedPoint = aPoint + this->GetOffsetTo(adjustedFrame);
  1.3686 +      return OffsetsForSingleFrame(adjustedFrame, adjustedPoint);
  1.3687 +    }
  1.3688 +
  1.3689 +    // For other cases, try to find a closest frame starting from the parent of
  1.3690 +    // the unselectable frame
  1.3691 +    if (adjustedFrame != this)
  1.3692 +      adjustedFrame = adjustedFrame->GetParent();
  1.3693 +  }
  1.3694 +
  1.3695 +  nsPoint adjustedPoint = aPoint + this->GetOffsetTo(adjustedFrame);
  1.3696 +
  1.3697 +  FrameTarget closest =
  1.3698 +    GetSelectionClosestFrame(adjustedFrame, adjustedPoint, aFlags);
  1.3699 +
  1.3700 +  if (closest.emptyBlock) {
  1.3701 +    ContentOffsets offsets;
  1.3702 +    NS_ASSERTION(closest.frame,
  1.3703 +                 "closest.frame must not be null when it's empty");
  1.3704 +    offsets.content = closest.frame->GetContent();
  1.3705 +    offsets.offset = 0;
  1.3706 +    offsets.secondaryOffset = 0;
  1.3707 +    offsets.associateWithNext = true;
  1.3708 +    return offsets;
  1.3709 +  }
  1.3710 +
  1.3711 +  // If the correct offset is at one end of a frame, use offset-based
  1.3712 +  // calculation method
  1.3713 +  if (closest.frameEdge) {
  1.3714 +    ContentOffsets offsets;
  1.3715 +    FrameContentRange range = GetRangeForFrame(closest.frame);
  1.3716 +    offsets.content = range.content;
  1.3717 +    if (closest.afterFrame)
  1.3718 +      offsets.offset = range.end;
  1.3719 +    else
  1.3720 +      offsets.offset = range.start;
  1.3721 +    offsets.secondaryOffset = offsets.offset;
  1.3722 +    offsets.associateWithNext = (offsets.offset == range.start);
  1.3723 +    return offsets;
  1.3724 +  }
  1.3725 +
  1.3726 +  nsPoint pt;
  1.3727 +  if (closest.frame != this) {
  1.3728 +    if (closest.frame->IsSVGText()) {
  1.3729 +      pt = nsLayoutUtils::TransformAncestorPointToFrame(closest.frame,
  1.3730 +                                                        aPoint, this);
  1.3731 +    } else {
  1.3732 +      pt = aPoint - closest.frame->GetOffsetTo(this);
  1.3733 +    }
  1.3734 +  } else {
  1.3735 +    pt = aPoint;
  1.3736 +  }
  1.3737 +  return static_cast<nsFrame*>(closest.frame)->CalcContentOffsetsFromFramePoint(pt);
  1.3738 +
  1.3739 +  // XXX should I add some kind of offset standardization?
  1.3740 +  // consider <b>xxxxx</b><i>zzzzz</i>; should any click between the last
  1.3741 +  // x and first z put the cursor in the same logical position in addition
  1.3742 +  // to the same visual position?
  1.3743 +}
  1.3744 +
  1.3745 +nsIFrame::ContentOffsets nsFrame::CalcContentOffsetsFromFramePoint(nsPoint aPoint)
  1.3746 +{
  1.3747 +  return OffsetsForSingleFrame(this, aPoint);
  1.3748 +}
  1.3749 +
  1.3750 +void
  1.3751 +nsIFrame::AssociateImage(const nsStyleImage& aImage, nsPresContext* aPresContext)
  1.3752 +{
  1.3753 +  if (aImage.GetType() != eStyleImageType_Image) {
  1.3754 +    return;
  1.3755 +  }
  1.3756 +
  1.3757 +  imgIRequest *req = aImage.GetImageData();
  1.3758 +  mozilla::css::ImageLoader* loader =
  1.3759 +    aPresContext->Document()->StyleImageLoader();
  1.3760 +
  1.3761 +  // If this fails there's not much we can do ...
  1.3762 +  loader->AssociateRequestToFrame(req, this);
  1.3763 +}
  1.3764 +
  1.3765 +nsresult
  1.3766 +nsFrame::GetCursor(const nsPoint& aPoint,
  1.3767 +                   nsIFrame::Cursor& aCursor)
  1.3768 +{
  1.3769 +  FillCursorInformationFromStyle(StyleUserInterface(), aCursor);
  1.3770 +  if (NS_STYLE_CURSOR_AUTO == aCursor.mCursor) {
  1.3771 +    // If this is editable, I-beam cursor is better for most elements.
  1.3772 +    aCursor.mCursor =
  1.3773 +      (mContent && mContent->IsEditable()) ? NS_STYLE_CURSOR_TEXT :
  1.3774 +                                             NS_STYLE_CURSOR_DEFAULT;
  1.3775 +  }
  1.3776 +
  1.3777 +
  1.3778 +  return NS_OK;
  1.3779 +}
  1.3780 +
  1.3781 +// Resize and incremental reflow
  1.3782 +
  1.3783 +/* virtual */ void
  1.3784 +nsFrame::MarkIntrinsicWidthsDirty()
  1.3785 +{
  1.3786 +  // This version is meant only for what used to be box-to-block adaptors.
  1.3787 +  // It should not be called by other derived classes.
  1.3788 +  if (IsBoxWrapped()) {
  1.3789 +    nsBoxLayoutMetrics *metrics = BoxMetrics();
  1.3790 +
  1.3791 +    SizeNeedsRecalc(metrics->mPrefSize);
  1.3792 +    SizeNeedsRecalc(metrics->mMinSize);
  1.3793 +    SizeNeedsRecalc(metrics->mMaxSize);
  1.3794 +    SizeNeedsRecalc(metrics->mBlockPrefSize);
  1.3795 +    SizeNeedsRecalc(metrics->mBlockMinSize);
  1.3796 +    CoordNeedsRecalc(metrics->mFlex);
  1.3797 +    CoordNeedsRecalc(metrics->mAscent);
  1.3798 +  }
  1.3799 +
  1.3800 +  if (GetStateBits() & NS_FRAME_FONT_INFLATION_FLOW_ROOT) {
  1.3801 +    nsFontInflationData::MarkFontInflationDataTextDirty(this);
  1.3802 +  }
  1.3803 +}
  1.3804 +
  1.3805 +/* virtual */ nscoord
  1.3806 +nsFrame::GetMinWidth(nsRenderingContext *aRenderingContext)
  1.3807 +{
  1.3808 +  nscoord result = 0;
  1.3809 +  DISPLAY_MIN_WIDTH(this, result);
  1.3810 +  return result;
  1.3811 +}
  1.3812 +
  1.3813 +/* virtual */ nscoord
  1.3814 +nsFrame::GetPrefWidth(nsRenderingContext *aRenderingContext)
  1.3815 +{
  1.3816 +  nscoord result = 0;
  1.3817 +  DISPLAY_PREF_WIDTH(this, result);
  1.3818 +  return result;
  1.3819 +}
  1.3820 +
  1.3821 +/* virtual */ void
  1.3822 +nsFrame::AddInlineMinWidth(nsRenderingContext *aRenderingContext,
  1.3823 +                           nsIFrame::InlineMinWidthData *aData)
  1.3824 +{
  1.3825 +  NS_ASSERTION(GetParent(), "Must have a parent if we get here!");
  1.3826 +  nsIFrame* parent = GetParent();
  1.3827 +  bool canBreak = !CanContinueTextRun() &&
  1.3828 +    parent->StyleText()->WhiteSpaceCanWrap(parent);
  1.3829 +  
  1.3830 +  if (canBreak)
  1.3831 +    aData->OptionallyBreak(aRenderingContext);
  1.3832 +  aData->trailingWhitespace = 0;
  1.3833 +  aData->skipWhitespace = false;
  1.3834 +  aData->trailingTextFrame = nullptr;
  1.3835 +  aData->currentLine += nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
  1.3836 +                            this, nsLayoutUtils::MIN_WIDTH);
  1.3837 +  aData->atStartOfLine = false;
  1.3838 +  if (canBreak)
  1.3839 +    aData->OptionallyBreak(aRenderingContext);
  1.3840 +}
  1.3841 +
  1.3842 +/* virtual */ void
  1.3843 +nsFrame::AddInlinePrefWidth(nsRenderingContext *aRenderingContext,
  1.3844 +                            nsIFrame::InlinePrefWidthData *aData)
  1.3845 +{
  1.3846 +  aData->trailingWhitespace = 0;
  1.3847 +  aData->skipWhitespace = false;
  1.3848 +  nscoord myPref = nsLayoutUtils::IntrinsicForContainer(aRenderingContext, 
  1.3849 +                       this, nsLayoutUtils::PREF_WIDTH);
  1.3850 +  aData->currentLine = NSCoordSaturatingAdd(aData->currentLine, myPref);
  1.3851 +}
  1.3852 +
  1.3853 +void
  1.3854 +nsIFrame::InlineMinWidthData::ForceBreak(nsRenderingContext *aRenderingContext)
  1.3855 +{
  1.3856 +  currentLine -= trailingWhitespace;
  1.3857 +  prevLines = std::max(prevLines, currentLine);
  1.3858 +  currentLine = trailingWhitespace = 0;
  1.3859 +
  1.3860 +  for (uint32_t i = 0, i_end = floats.Length(); i != i_end; ++i) {
  1.3861 +    nscoord float_min = floats[i].Width();
  1.3862 +    if (float_min > prevLines)
  1.3863 +      prevLines = float_min;
  1.3864 +  }
  1.3865 +  floats.Clear();
  1.3866 +  trailingTextFrame = nullptr;
  1.3867 +  skipWhitespace = true;
  1.3868 +}
  1.3869 +
  1.3870 +void
  1.3871 +nsIFrame::InlineMinWidthData::OptionallyBreak(nsRenderingContext *aRenderingContext,
  1.3872 +                                              nscoord aHyphenWidth)
  1.3873 +{
  1.3874 +  trailingTextFrame = nullptr;
  1.3875 +
  1.3876 +  // If we can fit more content into a smaller width by staying on this
  1.3877 +  // line (because we're still at a negative offset due to negative
  1.3878 +  // text-indent or negative margin), don't break.  Otherwise, do the
  1.3879 +  // same as ForceBreak.  it doesn't really matter when we accumulate
  1.3880 +  // floats.
  1.3881 +  if (currentLine + aHyphenWidth < 0 || atStartOfLine)
  1.3882 +    return;
  1.3883 +  currentLine += aHyphenWidth;
  1.3884 +  ForceBreak(aRenderingContext);
  1.3885 +}
  1.3886 +
  1.3887 +void
  1.3888 +nsIFrame::InlinePrefWidthData::ForceBreak(nsRenderingContext *aRenderingContext)
  1.3889 +{
  1.3890 +  if (floats.Length() != 0) {
  1.3891 +            // preferred widths accumulated for floats that have already
  1.3892 +            // been cleared past
  1.3893 +    nscoord floats_done = 0,
  1.3894 +            // preferred widths accumulated for floats that have not yet
  1.3895 +            // been cleared past
  1.3896 +            floats_cur_left = 0,
  1.3897 +            floats_cur_right = 0;
  1.3898 +
  1.3899 +    for (uint32_t i = 0, i_end = floats.Length(); i != i_end; ++i) {
  1.3900 +      const FloatInfo& floatInfo = floats[i];
  1.3901 +      const nsStyleDisplay *floatDisp = floatInfo.Frame()->StyleDisplay();
  1.3902 +      if (floatDisp->mBreakType == NS_STYLE_CLEAR_LEFT ||
  1.3903 +          floatDisp->mBreakType == NS_STYLE_CLEAR_RIGHT ||
  1.3904 +          floatDisp->mBreakType == NS_STYLE_CLEAR_BOTH) {
  1.3905 +        nscoord floats_cur = NSCoordSaturatingAdd(floats_cur_left,
  1.3906 +                                                  floats_cur_right);
  1.3907 +        if (floats_cur > floats_done)
  1.3908 +          floats_done = floats_cur;
  1.3909 +        if (floatDisp->mBreakType != NS_STYLE_CLEAR_RIGHT)
  1.3910 +          floats_cur_left = 0;
  1.3911 +        if (floatDisp->mBreakType != NS_STYLE_CLEAR_LEFT)
  1.3912 +          floats_cur_right = 0;
  1.3913 +      }
  1.3914 +
  1.3915 +      nscoord &floats_cur = floatDisp->mFloats == NS_STYLE_FLOAT_LEFT
  1.3916 +                              ? floats_cur_left : floats_cur_right;
  1.3917 +      nscoord floatWidth = floatInfo.Width();
  1.3918 +      // Negative-width floats don't change the available space so they
  1.3919 +      // shouldn't change our intrinsic line width either.
  1.3920 +      floats_cur =
  1.3921 +        NSCoordSaturatingAdd(floats_cur, std::max(0, floatWidth));
  1.3922 +    }
  1.3923 +
  1.3924 +    nscoord floats_cur =
  1.3925 +      NSCoordSaturatingAdd(floats_cur_left, floats_cur_right);
  1.3926 +    if (floats_cur > floats_done)
  1.3927 +      floats_done = floats_cur;
  1.3928 +
  1.3929 +    currentLine = NSCoordSaturatingAdd(currentLine, floats_done);
  1.3930 +
  1.3931 +    floats.Clear();
  1.3932 +  }
  1.3933 +
  1.3934 +  currentLine =
  1.3935 +    NSCoordSaturatingSubtract(currentLine, trailingWhitespace, nscoord_MAX);
  1.3936 +  prevLines = std::max(prevLines, currentLine);
  1.3937 +  currentLine = trailingWhitespace = 0;
  1.3938 +  skipWhitespace = true;
  1.3939 +}
  1.3940 +
  1.3941 +static void
  1.3942 +AddCoord(const nsStyleCoord& aStyle,
  1.3943 +         nsRenderingContext* aRenderingContext,
  1.3944 +         nsIFrame* aFrame,
  1.3945 +         nscoord* aCoord, float* aPercent,
  1.3946 +         bool aClampNegativeToZero)
  1.3947 +{
  1.3948 +  switch (aStyle.GetUnit()) {
  1.3949 +    case eStyleUnit_Coord: {
  1.3950 +      NS_ASSERTION(!aClampNegativeToZero || aStyle.GetCoordValue() >= 0,
  1.3951 +                   "unexpected negative value");
  1.3952 +      *aCoord += aStyle.GetCoordValue();
  1.3953 +      return;
  1.3954 +    }
  1.3955 +    case eStyleUnit_Percent: {
  1.3956 +      NS_ASSERTION(!aClampNegativeToZero || aStyle.GetPercentValue() >= 0.0f,
  1.3957 +                   "unexpected negative value");
  1.3958 +      *aPercent += aStyle.GetPercentValue();
  1.3959 +      return;
  1.3960 +    }
  1.3961 +    case eStyleUnit_Calc: {
  1.3962 +      const nsStyleCoord::Calc *calc = aStyle.GetCalcValue();
  1.3963 +      if (aClampNegativeToZero) {
  1.3964 +        // This is far from ideal when one is negative and one is positive.
  1.3965 +        *aCoord += std::max(calc->mLength, 0);
  1.3966 +        *aPercent += std::max(calc->mPercent, 0.0f);
  1.3967 +      } else {
  1.3968 +        *aCoord += calc->mLength;
  1.3969 +        *aPercent += calc->mPercent;
  1.3970 +      }
  1.3971 +      return;
  1.3972 +    }
  1.3973 +    default: {
  1.3974 +      return;
  1.3975 +    }
  1.3976 +  }
  1.3977 +}
  1.3978 +
  1.3979 +/* virtual */ nsIFrame::IntrinsicWidthOffsetData
  1.3980 +nsFrame::IntrinsicWidthOffsets(nsRenderingContext* aRenderingContext)
  1.3981 +{
  1.3982 +  IntrinsicWidthOffsetData result;
  1.3983 +
  1.3984 +  const nsStyleMargin *styleMargin = StyleMargin();
  1.3985 +  AddCoord(styleMargin->mMargin.GetLeft(), aRenderingContext, this,
  1.3986 +           &result.hMargin, &result.hPctMargin, false);
  1.3987 +  AddCoord(styleMargin->mMargin.GetRight(), aRenderingContext, this,
  1.3988 +           &result.hMargin, &result.hPctMargin, false);
  1.3989 +
  1.3990 +  const nsStylePadding *stylePadding = StylePadding();
  1.3991 +  AddCoord(stylePadding->mPadding.GetLeft(), aRenderingContext, this,
  1.3992 +           &result.hPadding, &result.hPctPadding, true);
  1.3993 +  AddCoord(stylePadding->mPadding.GetRight(), aRenderingContext, this,
  1.3994 +           &result.hPadding, &result.hPctPadding, true);
  1.3995 +
  1.3996 +  const nsStyleBorder *styleBorder = StyleBorder();
  1.3997 +  result.hBorder += styleBorder->GetComputedBorderWidth(NS_SIDE_LEFT);
  1.3998 +  result.hBorder += styleBorder->GetComputedBorderWidth(NS_SIDE_RIGHT);
  1.3999 +
  1.4000 +  const nsStyleDisplay *disp = StyleDisplay();
  1.4001 +  if (IsThemed(disp)) {
  1.4002 +    nsPresContext *presContext = PresContext();
  1.4003 +
  1.4004 +    nsIntMargin border;
  1.4005 +    presContext->GetTheme()->GetWidgetBorder(presContext->DeviceContext(),
  1.4006 +                                             this, disp->mAppearance,
  1.4007 +                                             &border);
  1.4008 +    result.hBorder = presContext->DevPixelsToAppUnits(border.LeftRight());
  1.4009 +
  1.4010 +    nsIntMargin padding;
  1.4011 +    if (presContext->GetTheme()->GetWidgetPadding(presContext->DeviceContext(),
  1.4012 +                                                  this, disp->mAppearance,
  1.4013 +                                                  &padding)) {
  1.4014 +      result.hPadding = presContext->DevPixelsToAppUnits(padding.LeftRight());
  1.4015 +      result.hPctPadding = 0;
  1.4016 +    }
  1.4017 +  }
  1.4018 +
  1.4019 +  return result;
  1.4020 +}
  1.4021 +
  1.4022 +/* virtual */ IntrinsicSize
  1.4023 +nsFrame::GetIntrinsicSize()
  1.4024 +{
  1.4025 +  return IntrinsicSize(); // default is width/height set to eStyleUnit_None
  1.4026 +}
  1.4027 +
  1.4028 +/* virtual */ nsSize
  1.4029 +nsFrame::GetIntrinsicRatio()
  1.4030 +{
  1.4031 +  return nsSize(0, 0);
  1.4032 +}
  1.4033 +
  1.4034 +/* virtual */ nsSize
  1.4035 +nsFrame::ComputeSize(nsRenderingContext *aRenderingContext,
  1.4036 +                     nsSize aCBSize, nscoord aAvailableWidth,
  1.4037 +                     nsSize aMargin, nsSize aBorder, nsSize aPadding,
  1.4038 +                     uint32_t aFlags)
  1.4039 +{
  1.4040 +  nsSize result = ComputeAutoSize(aRenderingContext, aCBSize, aAvailableWidth,
  1.4041 +                                  aMargin, aBorder, aPadding,
  1.4042 +                                  aFlags & eShrinkWrap);
  1.4043 +  nsSize boxSizingAdjust(0,0);
  1.4044 +  const nsStylePosition *stylePos = StylePosition();
  1.4045 +
  1.4046 +  switch (stylePos->mBoxSizing) {
  1.4047 +    case NS_STYLE_BOX_SIZING_BORDER:
  1.4048 +      boxSizingAdjust += aBorder;
  1.4049 +      // fall through
  1.4050 +    case NS_STYLE_BOX_SIZING_PADDING:
  1.4051 +      boxSizingAdjust += aPadding;
  1.4052 +  }
  1.4053 +  nscoord boxSizingToMarginEdgeWidth =
  1.4054 +    aMargin.width + aBorder.width + aPadding.width - boxSizingAdjust.width;
  1.4055 +  const nsStyleCoord* widthStyleCoord = &(stylePos->mWidth);
  1.4056 +  const nsStyleCoord* heightStyleCoord = &(stylePos->mHeight);
  1.4057 +
  1.4058 +  bool isFlexItem = IsFlexItem();
  1.4059 +  bool isHorizontalFlexItem = false;
  1.4060 + 
  1.4061 +  if (isFlexItem) {
  1.4062 +    // Flex items use their "flex-basis" property in place of their main-size
  1.4063 +    // property (e.g. "width") for sizing purposes, *unless* they have
  1.4064 +    // "flex-basis:auto", in which case they use their main-size property after
  1.4065 +    // all.
  1.4066 +    uint32_t flexDirection = mParent->StylePosition()->mFlexDirection;
  1.4067 +    isHorizontalFlexItem =
  1.4068 +      flexDirection == NS_STYLE_FLEX_DIRECTION_ROW ||
  1.4069 +      flexDirection == NS_STYLE_FLEX_DIRECTION_ROW_REVERSE;
  1.4070 +
  1.4071 +    // NOTE: The logic here should match the similar chunk for determining
  1.4072 +    // widthStyleCoord and heightStyleCoord in
  1.4073 +    // nsLayoutUtils::ComputeSizeWithIntrinsicDimensions().
  1.4074 +    const nsStyleCoord* flexBasis = &(stylePos->mFlexBasis);
  1.4075 +    if (flexBasis->GetUnit() != eStyleUnit_Auto) {
  1.4076 +      if (isHorizontalFlexItem) {
  1.4077 +        widthStyleCoord = flexBasis;
  1.4078 +      } else {
  1.4079 +        // One caveat for vertical flex items: We don't support enumerated
  1.4080 +        // values (e.g. "max-content") for height properties yet. So, if our
  1.4081 +        // computed flex-basis is an enumerated value, we'll just behave as if
  1.4082 +        // it were "auto", which means "use the main-size property after all"
  1.4083 +        // (which is "height", in this case).
  1.4084 +        // NOTE: Once we support intrinsic sizing keywords for "height",
  1.4085 +        // we should remove this check.
  1.4086 +        if (flexBasis->GetUnit() != eStyleUnit_Enumerated) {
  1.4087 +          heightStyleCoord = flexBasis;
  1.4088 +        }
  1.4089 +      }
  1.4090 +    }
  1.4091 +  }
  1.4092 +
  1.4093 +  // Compute width
  1.4094 +
  1.4095 +  if (widthStyleCoord->GetUnit() != eStyleUnit_Auto) {
  1.4096 +    result.width =
  1.4097 +      nsLayoutUtils::ComputeWidthValue(aRenderingContext, this,
  1.4098 +        aCBSize.width, boxSizingAdjust.width, boxSizingToMarginEdgeWidth,
  1.4099 +        *widthStyleCoord);
  1.4100 +  }
  1.4101 +
  1.4102 +  // Flex items ignore their min & max sizing properties in their
  1.4103 +  // flex container's main-axis.  (Those properties get applied later in
  1.4104 +  // the flexbox algorithm.)
  1.4105 +  if (stylePos->mMaxWidth.GetUnit() != eStyleUnit_None &&
  1.4106 +      !(isFlexItem && isHorizontalFlexItem)) {
  1.4107 +    nscoord maxWidth =
  1.4108 +      nsLayoutUtils::ComputeWidthValue(aRenderingContext, this,
  1.4109 +        aCBSize.width, boxSizingAdjust.width, boxSizingToMarginEdgeWidth,
  1.4110 +        stylePos->mMaxWidth);
  1.4111 +    result.width = std::min(maxWidth, result.width);
  1.4112 +  }
  1.4113 +
  1.4114 +  nscoord minWidth;
  1.4115 +  if (!(isFlexItem && isHorizontalFlexItem)) {
  1.4116 +    minWidth =
  1.4117 +      nsLayoutUtils::ComputeWidthValue(aRenderingContext, this,
  1.4118 +        aCBSize.width, boxSizingAdjust.width, boxSizingToMarginEdgeWidth,
  1.4119 +        stylePos->mMinWidth);
  1.4120 +  } else {
  1.4121 +    minWidth = 0;
  1.4122 +  }
  1.4123 +  result.width = std::max(minWidth, result.width);
  1.4124 +
  1.4125 +  // Compute height
  1.4126 +  // (but not if we're auto-height or if we recieved the "eUseAutoHeight"
  1.4127 +  // flag -- then, we'll just stick with the height that we already calculated
  1.4128 +  // in the initial ComputeAutoSize() call.)
  1.4129 +  if (!nsLayoutUtils::IsAutoHeight(*heightStyleCoord, aCBSize.height) &&
  1.4130 +      !(aFlags & nsIFrame::eUseAutoHeight)) {
  1.4131 +    result.height =
  1.4132 +      nsLayoutUtils::ComputeHeightValue(aCBSize.height, 
  1.4133 +                                        boxSizingAdjust.height,
  1.4134 +                                        *heightStyleCoord);
  1.4135 +  }
  1.4136 +
  1.4137 +  if (result.height != NS_UNCONSTRAINEDSIZE) {
  1.4138 +    if (!nsLayoutUtils::IsAutoHeight(stylePos->mMaxHeight, aCBSize.height) &&
  1.4139 +        !(isFlexItem && !isHorizontalFlexItem)) {
  1.4140 +      nscoord maxHeight =
  1.4141 +        nsLayoutUtils::ComputeHeightValue(aCBSize.height, 
  1.4142 +                                          boxSizingAdjust.height,
  1.4143 +                                          stylePos->mMaxHeight);
  1.4144 +      result.height = std::min(maxHeight, result.height);
  1.4145 +    }
  1.4146 +
  1.4147 +    if (!nsLayoutUtils::IsAutoHeight(stylePos->mMinHeight, aCBSize.height) &&
  1.4148 +        !(isFlexItem && !isHorizontalFlexItem)) {
  1.4149 +      nscoord minHeight =
  1.4150 +        nsLayoutUtils::ComputeHeightValue(aCBSize.height, 
  1.4151 +                                          boxSizingAdjust.height, 
  1.4152 +                                          stylePos->mMinHeight);
  1.4153 +      result.height = std::max(minHeight, result.height);
  1.4154 +    }
  1.4155 +  }
  1.4156 +
  1.4157 +  const nsStyleDisplay *disp = StyleDisplay();
  1.4158 +  if (IsThemed(disp)) {
  1.4159 +    nsIntSize widget(0, 0);
  1.4160 +    bool canOverride = true;
  1.4161 +    nsPresContext *presContext = PresContext();
  1.4162 +    presContext->GetTheme()->
  1.4163 +      GetMinimumWidgetSize(aRenderingContext, this, disp->mAppearance,
  1.4164 +                           &widget, &canOverride);
  1.4165 +
  1.4166 +    nsSize size;
  1.4167 +    size.width = presContext->DevPixelsToAppUnits(widget.width);
  1.4168 +    size.height = presContext->DevPixelsToAppUnits(widget.height);
  1.4169 +
  1.4170 +    // GMWS() returns border-box; we need content-box
  1.4171 +    size.width -= aBorder.width + aPadding.width;
  1.4172 +    size.height -= aBorder.height + aPadding.height;
  1.4173 +
  1.4174 +    if (size.height > result.height || !canOverride)
  1.4175 +      result.height = size.height;
  1.4176 +    if (size.width > result.width || !canOverride)
  1.4177 +      result.width = size.width;
  1.4178 +  }
  1.4179 +
  1.4180 +  result.width = std::max(0, result.width);
  1.4181 +  result.height = std::max(0, result.height);
  1.4182 +
  1.4183 +  return result;
  1.4184 +}
  1.4185 +
  1.4186 +nsRect
  1.4187 +nsIFrame::ComputeTightBounds(gfxContext* aContext) const
  1.4188 +{
  1.4189 +  return GetVisualOverflowRect();
  1.4190 +}
  1.4191 +
  1.4192 +nsRect
  1.4193 +nsFrame::ComputeSimpleTightBounds(gfxContext* aContext) const
  1.4194 +{
  1.4195 +  if (StyleOutline()->GetOutlineStyle() != NS_STYLE_BORDER_STYLE_NONE ||
  1.4196 +      StyleBorder()->HasBorder() || !StyleBackground()->IsTransparent() ||
  1.4197 +      StyleDisplay()->mAppearance) {
  1.4198 +    // Not necessarily tight, due to clipping, negative
  1.4199 +    // outline-offset, and lots of other issues, but that's OK
  1.4200 +    return GetVisualOverflowRect();
  1.4201 +  }
  1.4202 +
  1.4203 +  nsRect r(0, 0, 0, 0);
  1.4204 +  ChildListIterator lists(this);
  1.4205 +  for (; !lists.IsDone(); lists.Next()) {
  1.4206 +    nsFrameList::Enumerator childFrames(lists.CurrentList());
  1.4207 +    for (; !childFrames.AtEnd(); childFrames.Next()) {
  1.4208 +      nsIFrame* child = childFrames.get();
  1.4209 +      r.UnionRect(r, child->ComputeTightBounds(aContext) + child->GetPosition());
  1.4210 +    }
  1.4211 +  }
  1.4212 +  return r;
  1.4213 +}
  1.4214 +
  1.4215 +/* virtual */ nsresult
  1.4216 +nsIFrame::GetPrefWidthTightBounds(nsRenderingContext* aContext,
  1.4217 +                                  nscoord* aX,
  1.4218 +                                  nscoord* aXMost)
  1.4219 +{
  1.4220 +  return NS_ERROR_NOT_IMPLEMENTED;
  1.4221 +}
  1.4222 +
  1.4223 +/* virtual */ nsSize
  1.4224 +nsFrame::ComputeAutoSize(nsRenderingContext *aRenderingContext,
  1.4225 +                         nsSize aCBSize, nscoord aAvailableWidth,
  1.4226 +                         nsSize aMargin, nsSize aBorder, nsSize aPadding,
  1.4227 +                         bool aShrinkWrap)
  1.4228 +{
  1.4229 +  // Use basic shrink-wrapping as a default implementation.
  1.4230 +  nsSize result(0xdeadbeef, NS_UNCONSTRAINEDSIZE);
  1.4231 +
  1.4232 +  // don't bother setting it if the result won't be used
  1.4233 +  if (StylePosition()->mWidth.GetUnit() == eStyleUnit_Auto) {
  1.4234 +    nscoord availBased = aAvailableWidth - aMargin.width - aBorder.width -
  1.4235 +                         aPadding.width;
  1.4236 +    result.width = ShrinkWidthToFit(aRenderingContext, availBased);
  1.4237 +  }
  1.4238 +  return result;
  1.4239 +}
  1.4240 +
  1.4241 +nscoord
  1.4242 +nsFrame::ShrinkWidthToFit(nsRenderingContext *aRenderingContext,
  1.4243 +                          nscoord aWidthInCB)
  1.4244 +{
  1.4245 +  // If we're a container for font size inflation, then shrink
  1.4246 +  // wrapping inside of us should not apply font size inflation.
  1.4247 +  AutoMaybeDisableFontInflation an(this);
  1.4248 +
  1.4249 +  nscoord result;
  1.4250 +  nscoord minWidth = GetMinWidth(aRenderingContext);
  1.4251 +  if (minWidth > aWidthInCB) {
  1.4252 +    result = minWidth;
  1.4253 +  } else {
  1.4254 +    nscoord prefWidth = GetPrefWidth(aRenderingContext);
  1.4255 +    if (prefWidth > aWidthInCB) {
  1.4256 +      result = aWidthInCB;
  1.4257 +    } else {
  1.4258 +      result = prefWidth;
  1.4259 +    }
  1.4260 +  }
  1.4261 +  return result;
  1.4262 +}
  1.4263 +
  1.4264 +nsresult
  1.4265 +nsFrame::WillReflow(nsPresContext* aPresContext)
  1.4266 +{
  1.4267 +#ifdef DEBUG_dbaron_off
  1.4268 +  // bug 81268
  1.4269 +  NS_ASSERTION(!(mState & NS_FRAME_IN_REFLOW),
  1.4270 +               "nsFrame::WillReflow: frame is already in reflow");
  1.4271 +#endif
  1.4272 +
  1.4273 +  NS_FRAME_TRACE_MSG(NS_FRAME_TRACE_CALLS,
  1.4274 +                     ("WillReflow: oldState=%x", mState));
  1.4275 +  mState |= NS_FRAME_IN_REFLOW;
  1.4276 +  return NS_OK;
  1.4277 +}
  1.4278 +
  1.4279 +nsresult
  1.4280 +nsFrame::DidReflow(nsPresContext*           aPresContext,
  1.4281 +                   const nsHTMLReflowState*  aReflowState,
  1.4282 +                   nsDidReflowStatus         aStatus)
  1.4283 +{
  1.4284 +  NS_FRAME_TRACE_MSG(NS_FRAME_TRACE_CALLS,
  1.4285 +                     ("nsFrame::DidReflow: aStatus=%d", static_cast<uint32_t>(aStatus)));
  1.4286 +
  1.4287 +  nsSVGEffects::InvalidateDirectRenderingObservers(this, nsSVGEffects::INVALIDATE_REFLOW);
  1.4288 +
  1.4289 +  if (nsDidReflowStatus::FINISHED == aStatus) {
  1.4290 +    mState &= ~(NS_FRAME_IN_REFLOW | NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY |
  1.4291 +                NS_FRAME_HAS_DIRTY_CHILDREN);
  1.4292 +  }
  1.4293 +
  1.4294 +  // Notify the percent height observer if there is a percent height.
  1.4295 +  // The observer may be able to initiate another reflow with a computed
  1.4296 +  // height. This happens in the case where a table cell has no computed
  1.4297 +  // height but can fabricate one when the cell height is known.
  1.4298 +  if (aReflowState && aReflowState->mPercentHeightObserver &&
  1.4299 +      !GetPrevInFlow()) {
  1.4300 +    const nsStyleCoord &height = aReflowState->mStylePosition->mHeight;
  1.4301 +    if (height.HasPercent()) {
  1.4302 +      aReflowState->mPercentHeightObserver->NotifyPercentHeight(*aReflowState);
  1.4303 +    }
  1.4304 +  }
  1.4305 +
  1.4306 +  return NS_OK;
  1.4307 +}
  1.4308 +
  1.4309 +void
  1.4310 +nsFrame::FinishReflowWithAbsoluteFrames(nsPresContext*           aPresContext,
  1.4311 +                                        nsHTMLReflowMetrics&     aDesiredSize,
  1.4312 +                                        const nsHTMLReflowState& aReflowState,
  1.4313 +                                        nsReflowStatus&          aStatus,
  1.4314 +                                        bool                     aConstrainHeight)
  1.4315 +{
  1.4316 +  ReflowAbsoluteFrames(aPresContext, aDesiredSize, aReflowState, aStatus, aConstrainHeight);
  1.4317 +
  1.4318 +  FinishAndStoreOverflow(&aDesiredSize);
  1.4319 +}
  1.4320 +
  1.4321 +void
  1.4322 +nsFrame::ReflowAbsoluteFrames(nsPresContext*           aPresContext,
  1.4323 +                              nsHTMLReflowMetrics&     aDesiredSize,
  1.4324 +                              const nsHTMLReflowState& aReflowState,
  1.4325 +                              nsReflowStatus&          aStatus,
  1.4326 +                              bool                     aConstrainHeight)
  1.4327 +{
  1.4328 +  if (HasAbsolutelyPositionedChildren()) {
  1.4329 +    nsAbsoluteContainingBlock* absoluteContainer = GetAbsoluteContainingBlock();
  1.4330 +
  1.4331 +    // Let the absolutely positioned container reflow any absolutely positioned
  1.4332 +    // child frames that need to be reflowed
  1.4333 +
  1.4334 +    // The containing block for the abs pos kids is formed by our padding edge.
  1.4335 +    nsMargin computedBorder =
  1.4336 +      aReflowState.ComputedPhysicalBorderPadding() - aReflowState.ComputedPhysicalPadding();
  1.4337 +    nscoord containingBlockWidth =
  1.4338 +      aDesiredSize.Width() - computedBorder.LeftRight();
  1.4339 +    nscoord containingBlockHeight =
  1.4340 +      aDesiredSize.Height() - computedBorder.TopBottom();
  1.4341 +
  1.4342 +    nsContainerFrame* container = do_QueryFrame(this);
  1.4343 +    NS_ASSERTION(container, "Abs-pos children only supported on container frames for now");
  1.4344 +
  1.4345 +    nsRect containingBlock(0, 0, containingBlockWidth, containingBlockHeight);
  1.4346 +    absoluteContainer->Reflow(container, aPresContext, aReflowState, aStatus,
  1.4347 +                              containingBlock,
  1.4348 +                              aConstrainHeight, true, true, // XXX could be optimized
  1.4349 +                              &aDesiredSize.mOverflowAreas);
  1.4350 +  }
  1.4351 +}
  1.4352 +
  1.4353 +/* virtual */ bool
  1.4354 +nsFrame::CanContinueTextRun() const
  1.4355 +{
  1.4356 +  // By default, a frame will *not* allow a text run to be continued
  1.4357 +  // through it.
  1.4358 +  return false;
  1.4359 +}
  1.4360 +
  1.4361 +nsresult
  1.4362 +nsFrame::Reflow(nsPresContext*          aPresContext,
  1.4363 +                nsHTMLReflowMetrics&     aDesiredSize,
  1.4364 +                const nsHTMLReflowState& aReflowState,
  1.4365 +                nsReflowStatus&          aStatus)
  1.4366 +{
  1.4367 +  DO_GLOBAL_REFLOW_COUNT("nsFrame");
  1.4368 +  aDesiredSize.Width() = 0;
  1.4369 +  aDesiredSize.Height() = 0;
  1.4370 +  aStatus = NS_FRAME_COMPLETE;
  1.4371 +  NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
  1.4372 +  return NS_OK;
  1.4373 +}
  1.4374 +
  1.4375 +nsresult
  1.4376 +nsFrame::CharacterDataChanged(CharacterDataChangeInfo* aInfo)
  1.4377 +{
  1.4378 +  NS_NOTREACHED("should only be called for text frames");
  1.4379 +  return NS_OK;
  1.4380 +}
  1.4381 +
  1.4382 +nsresult
  1.4383 +nsFrame::AttributeChanged(int32_t         aNameSpaceID,
  1.4384 +                          nsIAtom*        aAttribute,
  1.4385 +                          int32_t         aModType)
  1.4386 +{
  1.4387 +  return NS_OK;
  1.4388 +}
  1.4389 +
  1.4390 +// Flow member functions
  1.4391 +
  1.4392 +nsSplittableType
  1.4393 +nsFrame::GetSplittableType() const
  1.4394 +{
  1.4395 +  return NS_FRAME_NOT_SPLITTABLE;
  1.4396 +}
  1.4397 +
  1.4398 +nsIFrame* nsFrame::GetPrevContinuation() const
  1.4399 +{
  1.4400 +  return nullptr;
  1.4401 +}
  1.4402 +
  1.4403 +void
  1.4404 +nsFrame::SetPrevContinuation(nsIFrame* aPrevContinuation)
  1.4405 +{
  1.4406 +  MOZ_ASSERT(false, "not splittable");
  1.4407 +}
  1.4408 +
  1.4409 +nsIFrame* nsFrame::GetNextContinuation() const
  1.4410 +{
  1.4411 +  return nullptr;
  1.4412 +}
  1.4413 +
  1.4414 +void
  1.4415 +nsFrame::SetNextContinuation(nsIFrame*)
  1.4416 +{
  1.4417 +  MOZ_ASSERT(false, "not splittable");
  1.4418 +}
  1.4419 +
  1.4420 +nsIFrame* nsFrame::GetPrevInFlowVirtual() const
  1.4421 +{
  1.4422 +  return nullptr;
  1.4423 +}
  1.4424 +
  1.4425 +void
  1.4426 +nsFrame::SetPrevInFlow(nsIFrame* aPrevInFlow)
  1.4427 +{
  1.4428 +  MOZ_ASSERT(false, "not splittable");
  1.4429 +}
  1.4430 +
  1.4431 +nsIFrame* nsFrame::GetNextInFlowVirtual() const
  1.4432 +{
  1.4433 +  return nullptr;
  1.4434 +}
  1.4435 +
  1.4436 +void
  1.4437 +nsFrame::SetNextInFlow(nsIFrame*)
  1.4438 +{
  1.4439 +  MOZ_ASSERT(false, "not splittable");
  1.4440 +}
  1.4441 +
  1.4442 +nsIFrame* nsIFrame::GetTailContinuation()
  1.4443 +{
  1.4444 +  nsIFrame* frame = this;
  1.4445 +  while (frame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
  1.4446 +    frame = frame->GetPrevContinuation();
  1.4447 +    NS_ASSERTION(frame, "first continuation can't be overflow container");
  1.4448 +  }
  1.4449 +  for (nsIFrame* next = frame->GetNextContinuation();
  1.4450 +       next && !(next->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER);
  1.4451 +       next = frame->GetNextContinuation())  {
  1.4452 +    frame = next;
  1.4453 +  }
  1.4454 +  NS_POSTCONDITION(frame, "illegal state in continuation chain.");
  1.4455 +  return frame;
  1.4456 +}
  1.4457 +
  1.4458 +NS_DECLARE_FRAME_PROPERTY(ViewProperty, nullptr)
  1.4459 +
  1.4460 +// Associated view object
  1.4461 +nsView*
  1.4462 +nsIFrame::GetView() const
  1.4463 +{
  1.4464 +  // Check the frame state bit and see if the frame has a view
  1.4465 +  if (!(GetStateBits() & NS_FRAME_HAS_VIEW))
  1.4466 +    return nullptr;
  1.4467 +
  1.4468 +  // Check for a property on the frame
  1.4469 +  void* value = Properties().Get(ViewProperty());
  1.4470 +  NS_ASSERTION(value, "frame state bit was set but frame has no view");
  1.4471 +  return static_cast<nsView*>(value);
  1.4472 +}
  1.4473 +
  1.4474 +/* virtual */ nsView*
  1.4475 +nsIFrame::GetViewExternal() const
  1.4476 +{
  1.4477 +  return GetView();
  1.4478 +}
  1.4479 +
  1.4480 +nsresult
  1.4481 +nsIFrame::SetView(nsView* aView)
  1.4482 +{
  1.4483 +  if (aView) {
  1.4484 +    aView->SetFrame(this);
  1.4485 +
  1.4486 +#ifdef DEBUG
  1.4487 +    nsIAtom* frameType = GetType();
  1.4488 +    NS_ASSERTION(frameType == nsGkAtoms::scrollFrame ||
  1.4489 +                 frameType == nsGkAtoms::subDocumentFrame ||
  1.4490 +                 frameType == nsGkAtoms::listControlFrame ||
  1.4491 +                 frameType == nsGkAtoms::objectFrame ||
  1.4492 +                 frameType == nsGkAtoms::viewportFrame ||
  1.4493 +                 frameType == nsGkAtoms::menuPopupFrame,
  1.4494 +                 "Only specific frame types can have an nsView");
  1.4495 +#endif
  1.4496 +
  1.4497 +    // Set a property on the frame
  1.4498 +    Properties().Set(ViewProperty(), aView);
  1.4499 +
  1.4500 +    // Set the frame state bit that says the frame has a view
  1.4501 +    AddStateBits(NS_FRAME_HAS_VIEW);
  1.4502 +
  1.4503 +    // Let all of the ancestors know they have a descendant with a view.
  1.4504 +    for (nsIFrame* f = GetParent();
  1.4505 +         f && !(f->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW);
  1.4506 +         f = f->GetParent())
  1.4507 +      f->AddStateBits(NS_FRAME_HAS_CHILD_WITH_VIEW);
  1.4508 +  }
  1.4509 +
  1.4510 +  return NS_OK;
  1.4511 +}
  1.4512 +
  1.4513 +nsIFrame* nsIFrame::GetAncestorWithViewExternal() const
  1.4514 +{
  1.4515 +  return GetAncestorWithView();
  1.4516 +}
  1.4517 +
  1.4518 +// Find the first geometric parent that has a view
  1.4519 +nsIFrame* nsIFrame::GetAncestorWithView() const
  1.4520 +{
  1.4521 +  for (nsIFrame* f = mParent; nullptr != f; f = f->GetParent()) {
  1.4522 +    if (f->HasView()) {
  1.4523 +      return f;
  1.4524 +    }
  1.4525 +  }
  1.4526 +  return nullptr;
  1.4527 +}
  1.4528 +
  1.4529 +// virtual
  1.4530 +nsPoint nsIFrame::GetOffsetToExternal(const nsIFrame* aOther) const
  1.4531 +{
  1.4532 +  return GetOffsetTo(aOther);
  1.4533 +}
  1.4534 +
  1.4535 +nsPoint nsIFrame::GetOffsetTo(const nsIFrame* aOther) const
  1.4536 +{
  1.4537 +  NS_PRECONDITION(aOther,
  1.4538 +                  "Must have frame for destination coordinate system!");
  1.4539 +
  1.4540 +  NS_ASSERTION(PresContext() == aOther->PresContext(),
  1.4541 +               "GetOffsetTo called on frames in different documents");
  1.4542 +
  1.4543 +  nsPoint offset(0, 0);
  1.4544 +  const nsIFrame* f;
  1.4545 +  for (f = this; f != aOther && f; f = f->GetParent()) {
  1.4546 +    offset += f->GetPosition();
  1.4547 +  }
  1.4548 +
  1.4549 +  if (f != aOther) {
  1.4550 +    // Looks like aOther wasn't an ancestor of |this|.  So now we have
  1.4551 +    // the root-frame-relative position of |this| in |offset|.  Convert back
  1.4552 +    // to the coordinates of aOther
  1.4553 +    while (aOther) {
  1.4554 +      offset -= aOther->GetPosition();
  1.4555 +      aOther = aOther->GetParent();
  1.4556 +    }
  1.4557 +  }
  1.4558 +
  1.4559 +  return offset;
  1.4560 +}
  1.4561 +
  1.4562 +nsPoint nsIFrame::GetOffsetToCrossDoc(const nsIFrame* aOther) const
  1.4563 +{
  1.4564 +  return GetOffsetToCrossDoc(aOther, PresContext()->AppUnitsPerDevPixel());
  1.4565 +}
  1.4566 +
  1.4567 +nsPoint
  1.4568 +nsIFrame::GetOffsetToCrossDoc(const nsIFrame* aOther, const int32_t aAPD) const
  1.4569 +{
  1.4570 +  NS_PRECONDITION(aOther,
  1.4571 +                  "Must have frame for destination coordinate system!");
  1.4572 +  NS_ASSERTION(PresContext()->GetRootPresContext() ==
  1.4573 +                 aOther->PresContext()->GetRootPresContext(),
  1.4574 +               "trying to get the offset between frames in different document "
  1.4575 +               "hierarchies?");
  1.4576 +  if (PresContext()->GetRootPresContext() !=
  1.4577 +        aOther->PresContext()->GetRootPresContext()) {
  1.4578 +    // crash right away, we are almost certainly going to crash anyway.
  1.4579 +    NS_RUNTIMEABORT("trying to get the offset between frames in different "
  1.4580 +                    "document hierarchies?");
  1.4581 +  }
  1.4582 +
  1.4583 +  const nsIFrame* root = nullptr;
  1.4584 +  // offset will hold the final offset
  1.4585 +  // docOffset holds the currently accumulated offset at the current APD, it
  1.4586 +  // will be converted and added to offset when the current APD changes.
  1.4587 +  nsPoint offset(0, 0), docOffset(0, 0);
  1.4588 +  const nsIFrame* f = this;
  1.4589 +  int32_t currAPD = PresContext()->AppUnitsPerDevPixel();
  1.4590 +  while (f && f != aOther) {
  1.4591 +    docOffset += f->GetPosition();
  1.4592 +    nsIFrame* parent = f->GetParent();
  1.4593 +    if (parent) {
  1.4594 +      f = parent;
  1.4595 +    } else {
  1.4596 +      nsPoint newOffset(0, 0);
  1.4597 +      root = f;
  1.4598 +      f = nsLayoutUtils::GetCrossDocParentFrame(f, &newOffset);
  1.4599 +      int32_t newAPD = f ? f->PresContext()->AppUnitsPerDevPixel() : 0;
  1.4600 +      if (!f || newAPD != currAPD) {
  1.4601 +        // Convert docOffset to the right APD and add it to offset.
  1.4602 +        offset += docOffset.ConvertAppUnits(currAPD, aAPD);
  1.4603 +        docOffset.x = docOffset.y = 0;
  1.4604 +      }
  1.4605 +      currAPD = newAPD;
  1.4606 +      docOffset += newOffset;
  1.4607 +    }
  1.4608 +  }
  1.4609 +  if (f == aOther) {
  1.4610 +    offset += docOffset.ConvertAppUnits(currAPD, aAPD);
  1.4611 +  } else {
  1.4612 +    // Looks like aOther wasn't an ancestor of |this|.  So now we have
  1.4613 +    // the root-document-relative position of |this| in |offset|. Subtract the
  1.4614 +    // root-document-relative position of |aOther| from |offset|.
  1.4615 +    // This call won't try to recurse again because root is an ancestor of
  1.4616 +    // aOther.
  1.4617 +    nsPoint negOffset = aOther->GetOffsetToCrossDoc(root, aAPD);
  1.4618 +    offset -= negOffset;
  1.4619 +  }
  1.4620 +
  1.4621 +  return offset;
  1.4622 +}
  1.4623 +
  1.4624 +// virtual
  1.4625 +nsIntRect nsIFrame::GetScreenRectExternal() const
  1.4626 +{
  1.4627 +  return GetScreenRect();
  1.4628 +}
  1.4629 +
  1.4630 +nsIntRect nsIFrame::GetScreenRect() const
  1.4631 +{
  1.4632 +  return GetScreenRectInAppUnits().ToNearestPixels(PresContext()->AppUnitsPerCSSPixel());
  1.4633 +}
  1.4634 +
  1.4635 +// virtual
  1.4636 +nsRect nsIFrame::GetScreenRectInAppUnitsExternal() const
  1.4637 +{
  1.4638 +  return GetScreenRectInAppUnits();
  1.4639 +}
  1.4640 +
  1.4641 +nsRect nsIFrame::GetScreenRectInAppUnits() const
  1.4642 +{
  1.4643 +  nsPresContext* presContext = PresContext();
  1.4644 +  nsIFrame* rootFrame =
  1.4645 +    presContext->PresShell()->FrameManager()->GetRootFrame();
  1.4646 +  nsPoint rootScreenPos(0, 0);
  1.4647 +  nsPoint rootFrameOffsetInParent(0, 0);
  1.4648 +  nsIFrame* rootFrameParent =
  1.4649 +    nsLayoutUtils::GetCrossDocParentFrame(rootFrame, &rootFrameOffsetInParent);
  1.4650 +  if (rootFrameParent) {
  1.4651 +    nsRect parentScreenRectAppUnits = rootFrameParent->GetScreenRectInAppUnits();
  1.4652 +    nsPresContext* parentPresContext = rootFrameParent->PresContext();
  1.4653 +    double parentScale = double(presContext->AppUnitsPerDevPixel())/
  1.4654 +        parentPresContext->AppUnitsPerDevPixel();
  1.4655 +    nsPoint rootPt = parentScreenRectAppUnits.TopLeft() + rootFrameOffsetInParent;
  1.4656 +    rootScreenPos.x = NS_round(parentScale*rootPt.x);
  1.4657 +    rootScreenPos.y = NS_round(parentScale*rootPt.y);
  1.4658 +  } else {
  1.4659 +    nsCOMPtr<nsIWidget> rootWidget;
  1.4660 +    presContext->PresShell()->GetViewManager()->GetRootWidget(getter_AddRefs(rootWidget));
  1.4661 +    if (rootWidget) {
  1.4662 +      nsIntPoint rootDevPx = rootWidget->WidgetToScreenOffset();
  1.4663 +      rootScreenPos.x = presContext->DevPixelsToAppUnits(rootDevPx.x);
  1.4664 +      rootScreenPos.y = presContext->DevPixelsToAppUnits(rootDevPx.y);
  1.4665 +    }
  1.4666 +  }
  1.4667 +
  1.4668 +  return nsRect(rootScreenPos + GetOffsetTo(rootFrame), GetSize());
  1.4669 +}
  1.4670 +
  1.4671 +// Returns the offset from this frame to the closest geometric parent that
  1.4672 +// has a view. Also returns the containing view or null in case of error
  1.4673 +void
  1.4674 +nsIFrame::GetOffsetFromView(nsPoint& aOffset, nsView** aView) const
  1.4675 +{
  1.4676 +  NS_PRECONDITION(nullptr != aView, "null OUT parameter pointer");
  1.4677 +  nsIFrame* frame = const_cast<nsIFrame*>(this);
  1.4678 +
  1.4679 +  *aView = nullptr;
  1.4680 +  aOffset.MoveTo(0, 0);
  1.4681 +  do {
  1.4682 +    aOffset += frame->GetPosition();
  1.4683 +    frame = frame->GetParent();
  1.4684 +  } while (frame && !frame->HasView());
  1.4685 +
  1.4686 +  if (frame) {
  1.4687 +    *aView = frame->GetView();
  1.4688 +  }
  1.4689 +}
  1.4690 +
  1.4691 +nsIWidget*
  1.4692 +nsIFrame::GetNearestWidget() const
  1.4693 +{
  1.4694 +  return GetClosestView()->GetNearestWidget(nullptr);
  1.4695 +}
  1.4696 +
  1.4697 +nsIWidget*
  1.4698 +nsIFrame::GetNearestWidget(nsPoint& aOffset) const
  1.4699 +{
  1.4700 +  nsPoint offsetToView;
  1.4701 +  nsPoint offsetToWidget;
  1.4702 +  nsIWidget* widget =
  1.4703 +    GetClosestView(&offsetToView)->GetNearestWidget(&offsetToWidget);
  1.4704 +  aOffset = offsetToView + offsetToWidget;
  1.4705 +  return widget;
  1.4706 +}
  1.4707 +
  1.4708 +nsIAtom*
  1.4709 +nsFrame::GetType() const
  1.4710 +{
  1.4711 +  return nullptr;
  1.4712 +}
  1.4713 +
  1.4714 +bool
  1.4715 +nsIFrame::IsLeaf() const
  1.4716 +{
  1.4717 +  return true;
  1.4718 +}
  1.4719 +
  1.4720 +gfx3DMatrix
  1.4721 +nsIFrame::GetTransformMatrix(const nsIFrame* aStopAtAncestor,
  1.4722 +                             nsIFrame** aOutAncestor)
  1.4723 +{
  1.4724 +  NS_PRECONDITION(aOutAncestor, "Need a place to put the ancestor!");
  1.4725 +
  1.4726 +  /* If we're transformed, we want to hand back the combination
  1.4727 +   * transform/translate matrix that will apply our current transform, then
  1.4728 +   * shift us to our parent.
  1.4729 +   */
  1.4730 +  if (IsTransformed()) {
  1.4731 +    /* Compute the delta to the parent, which we need because we are converting
  1.4732 +     * coordinates to our parent.
  1.4733 +     */
  1.4734 +    NS_ASSERTION(nsLayoutUtils::GetCrossDocParentFrame(this),
  1.4735 +                 "Cannot transform the viewport frame!");
  1.4736 +    int32_t scaleFactor = PresContext()->AppUnitsPerDevPixel();
  1.4737 +
  1.4738 +    gfx3DMatrix result =
  1.4739 +      nsDisplayTransform::GetResultingTransformMatrix(this, nsPoint(0, 0), scaleFactor, nullptr, aOutAncestor);
  1.4740 +    // XXXjwatt: seems like this will double count offsets in the face of preserve-3d:
  1.4741 +    nsPoint delta = GetOffsetToCrossDoc(*aOutAncestor);
  1.4742 +    /* Combine the raw transform with a translation to our parent. */
  1.4743 +    result *= gfx3DMatrix::Translation
  1.4744 +      (NSAppUnitsToFloatPixels(delta.x, scaleFactor),
  1.4745 +       NSAppUnitsToFloatPixels(delta.y, scaleFactor),
  1.4746 +       0.0f);
  1.4747 +    return result;
  1.4748 +  }
  1.4749 +
  1.4750 +  if (nsLayoutUtils::IsPopup(this) &&
  1.4751 +      GetType() == nsGkAtoms::listControlFrame) {
  1.4752 +    nsPresContext* presContext = PresContext();
  1.4753 +    nsIFrame* docRootFrame = presContext->PresShell()->GetRootFrame();
  1.4754 +
  1.4755 +    // Compute a matrix that transforms from the popup widget to the toplevel
  1.4756 +    // widget. We use the widgets because they're the simplest and most
  1.4757 +    // accurate approach --- this should work no matter how the widget position
  1.4758 +    // was chosen.
  1.4759 +    nsIWidget* widget = GetView()->GetWidget();
  1.4760 +    nsPresContext* rootPresContext = PresContext()->GetRootPresContext();
  1.4761 +    // Maybe the widget hasn't been created yet? Popups without widgets are
  1.4762 +    // treated as regular frames. That should work since they'll be rendered
  1.4763 +    // as part of the page if they're rendered at all.
  1.4764 +    if (widget && rootPresContext) {
  1.4765 +      nsIWidget* toplevel = rootPresContext->GetNearestWidget();
  1.4766 +      if (toplevel) {
  1.4767 +        nsIntRect screenBounds;
  1.4768 +        widget->GetClientBounds(screenBounds);
  1.4769 +        nsIntRect toplevelScreenBounds;
  1.4770 +        toplevel->GetClientBounds(toplevelScreenBounds);
  1.4771 +        nsIntPoint translation = screenBounds.TopLeft() - toplevelScreenBounds.TopLeft();
  1.4772 +
  1.4773 +        gfx3DMatrix transformToTop;
  1.4774 +        transformToTop._41 = translation.x;
  1.4775 +        transformToTop._42 = translation.y;
  1.4776 +
  1.4777 +        *aOutAncestor = docRootFrame;
  1.4778 +        gfx3DMatrix docRootTransformToTop =
  1.4779 +          nsLayoutUtils::GetTransformToAncestor(docRootFrame, nullptr);
  1.4780 +        if (docRootTransformToTop.IsSingular()) {
  1.4781 +          NS_WARNING("Containing document is invisible, we can't compute a valid transform");
  1.4782 +        } else {
  1.4783 +          gfx3DMatrix topToDocRootTransform = docRootTransformToTop.Inverse();
  1.4784 +          return transformToTop*topToDocRootTransform;
  1.4785 +        }
  1.4786 +      }
  1.4787 +    }
  1.4788 +  }
  1.4789 +
  1.4790 +  *aOutAncestor = nsLayoutUtils::GetCrossDocParentFrame(this);
  1.4791 +
  1.4792 +  /* Otherwise, we're not transformed.  In that case, we'll walk up the frame
  1.4793 +   * tree until we either hit the root frame or something that may be
  1.4794 +   * transformed.  We'll then change coordinates into that frame, since we're
  1.4795 +   * guaranteed that nothing in-between can be transformed.  First, however,
  1.4796 +   * we have to check to see if we have a parent.  If not, we'll set the
  1.4797 +   * outparam to null (indicating that there's nothing left) and will hand back
  1.4798 +   * the identity matrix.
  1.4799 +   */
  1.4800 +  if (!*aOutAncestor)
  1.4801 +    return gfx3DMatrix();
  1.4802 +  
  1.4803 +  /* Keep iterating while the frame can't possibly be transformed. */
  1.4804 +  while (!(*aOutAncestor)->IsTransformed() &&
  1.4805 +         !nsLayoutUtils::IsPopup(*aOutAncestor) &&
  1.4806 +         *aOutAncestor != aStopAtAncestor) {
  1.4807 +    /* If no parent, stop iterating.  Otherwise, update the ancestor. */
  1.4808 +    nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(*aOutAncestor);
  1.4809 +    if (!parent)
  1.4810 +      break;
  1.4811 +
  1.4812 +    *aOutAncestor = parent;
  1.4813 +  }
  1.4814 +
  1.4815 +  NS_ASSERTION(*aOutAncestor, "Somehow ended up with a null ancestor...?");
  1.4816 +
  1.4817 +  /* Translate from this frame to our ancestor, if it exists.  That's the
  1.4818 +   * entire transform, so we're done.
  1.4819 +   */
  1.4820 +  nsPoint delta = GetOffsetToCrossDoc(*aOutAncestor);
  1.4821 +  int32_t scaleFactor = PresContext()->AppUnitsPerDevPixel();
  1.4822 +  return gfx3DMatrix().Translation
  1.4823 +    (NSAppUnitsToFloatPixels(delta.x, scaleFactor),
  1.4824 +     NSAppUnitsToFloatPixels(delta.y, scaleFactor),
  1.4825 +     0.0f);
  1.4826 +}
  1.4827 +
  1.4828 +static void InvalidateFrameInternal(nsIFrame *aFrame, bool aHasDisplayItem = true)
  1.4829 +{
  1.4830 +  if (aHasDisplayItem) {
  1.4831 +    aFrame->AddStateBits(NS_FRAME_NEEDS_PAINT);
  1.4832 +  }
  1.4833 +  nsSVGEffects::InvalidateDirectRenderingObservers(aFrame);
  1.4834 +  bool needsSchedulePaint = false;
  1.4835 +  if (nsLayoutUtils::IsPopup(aFrame)) {
  1.4836 +    needsSchedulePaint = true;
  1.4837 +  } else {
  1.4838 +    nsIFrame *parent = nsLayoutUtils::GetCrossDocParentFrame(aFrame);
  1.4839 +    while (parent && !parent->HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT)) {
  1.4840 +      if (aHasDisplayItem) {
  1.4841 +        parent->AddStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT);
  1.4842 +      }
  1.4843 +      nsSVGEffects::InvalidateDirectRenderingObservers(parent);
  1.4844 +
  1.4845 +      // If we're inside a popup, then we need to make sure that we
  1.4846 +      // call schedule paint so that the NS_FRAME_UPDATE_LAYER_TREE
  1.4847 +      // flag gets added to the popup display root frame.
  1.4848 +      if (nsLayoutUtils::IsPopup(parent)) {
  1.4849 +        needsSchedulePaint = true;
  1.4850 +        break;
  1.4851 +      }
  1.4852 +      parent = nsLayoutUtils::GetCrossDocParentFrame(parent);
  1.4853 +    }
  1.4854 +    if (!parent) {
  1.4855 +      needsSchedulePaint = true;
  1.4856 +    }
  1.4857 +  }
  1.4858 +  if (!aHasDisplayItem) {
  1.4859 +    return;
  1.4860 +  }
  1.4861 +  if (needsSchedulePaint) {
  1.4862 +    aFrame->SchedulePaint();
  1.4863 +  }
  1.4864 +  if (aFrame->HasAnyStateBits(NS_FRAME_HAS_INVALID_RECT)) {
  1.4865 +    aFrame->Properties().Delete(nsIFrame::InvalidationRect());
  1.4866 +    aFrame->RemoveStateBits(NS_FRAME_HAS_INVALID_RECT);
  1.4867 +  }
  1.4868 +}
  1.4869 +
  1.4870 +void
  1.4871 +nsIFrame::InvalidateFrameSubtree(uint32_t aDisplayItemKey)
  1.4872 +{
  1.4873 +  bool hasDisplayItem = 
  1.4874 +    !aDisplayItemKey || FrameLayerBuilder::HasRetainedDataFor(this, aDisplayItemKey);
  1.4875 +  InvalidateFrame(aDisplayItemKey);
  1.4876 +
  1.4877 +  if (HasAnyStateBits(NS_FRAME_ALL_DESCENDANTS_NEED_PAINT) || !hasDisplayItem) {
  1.4878 +    return;
  1.4879 +  }
  1.4880 +
  1.4881 +  AddStateBits(NS_FRAME_ALL_DESCENDANTS_NEED_PAINT);
  1.4882 +  
  1.4883 +  nsAutoTArray<nsIFrame::ChildList,4> childListArray;
  1.4884 +  GetCrossDocChildLists(&childListArray);
  1.4885 +
  1.4886 +  nsIFrame::ChildListArrayIterator lists(childListArray);
  1.4887 +  for (; !lists.IsDone(); lists.Next()) {
  1.4888 +    nsFrameList::Enumerator childFrames(lists.CurrentList());
  1.4889 +    for (; !childFrames.AtEnd(); childFrames.Next()) {
  1.4890 +      childFrames.get()->InvalidateFrameSubtree();
  1.4891 +    }
  1.4892 +  }
  1.4893 +}
  1.4894 +
  1.4895 +void
  1.4896 +nsIFrame::ClearInvalidationStateBits()
  1.4897 +{
  1.4898 +  if (HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT)) {
  1.4899 +    nsAutoTArray<nsIFrame::ChildList,4> childListArray;
  1.4900 +    GetCrossDocChildLists(&childListArray);
  1.4901 +
  1.4902 +    nsIFrame::ChildListArrayIterator lists(childListArray);
  1.4903 +    for (; !lists.IsDone(); lists.Next()) {
  1.4904 +      nsFrameList::Enumerator childFrames(lists.CurrentList());
  1.4905 +      for (; !childFrames.AtEnd(); childFrames.Next()) {
  1.4906 +        childFrames.get()->ClearInvalidationStateBits();
  1.4907 +      }
  1.4908 +    }
  1.4909 +  }
  1.4910 +
  1.4911 +  RemoveStateBits(NS_FRAME_NEEDS_PAINT | 
  1.4912 +                  NS_FRAME_DESCENDANT_NEEDS_PAINT | 
  1.4913 +                  NS_FRAME_ALL_DESCENDANTS_NEED_PAINT);
  1.4914 +}
  1.4915 +
  1.4916 +void
  1.4917 +nsIFrame::InvalidateFrame(uint32_t aDisplayItemKey)
  1.4918 +{
  1.4919 +  bool hasDisplayItem = 
  1.4920 +    !aDisplayItemKey || FrameLayerBuilder::HasRetainedDataFor(this, aDisplayItemKey);
  1.4921 +  InvalidateFrameInternal(this, hasDisplayItem);
  1.4922 +}
  1.4923 +
  1.4924 +void
  1.4925 +nsIFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey)
  1.4926 +{
  1.4927 +  bool hasDisplayItem = 
  1.4928 +    !aDisplayItemKey || FrameLayerBuilder::HasRetainedDataFor(this, aDisplayItemKey);
  1.4929 +  bool alreadyInvalid = false;
  1.4930 +  if (!HasAnyStateBits(NS_FRAME_NEEDS_PAINT)) {
  1.4931 +    InvalidateFrameInternal(this, hasDisplayItem);
  1.4932 +  } else {
  1.4933 +    alreadyInvalid = true;
  1.4934 +  } 
  1.4935 +
  1.4936 +  if (!hasDisplayItem) {
  1.4937 +    return;
  1.4938 +  }
  1.4939 +
  1.4940 +  nsRect *rect = static_cast<nsRect*>(Properties().Get(InvalidationRect()));
  1.4941 +  if (!rect) {
  1.4942 +    if (alreadyInvalid) {
  1.4943 +      return;
  1.4944 +    }
  1.4945 +    rect = new nsRect();
  1.4946 +    Properties().Set(InvalidationRect(), rect);
  1.4947 +    AddStateBits(NS_FRAME_HAS_INVALID_RECT);
  1.4948 +  }
  1.4949 +
  1.4950 +  *rect = rect->Union(aRect);
  1.4951 +}
  1.4952 +
  1.4953 +/*static*/ uint8_t nsIFrame::sLayerIsPrerenderedDataKey;
  1.4954 +
  1.4955 +bool
  1.4956 +nsIFrame::TryUpdateTransformOnly(Layer** aLayerResult)
  1.4957 +{
  1.4958 +  Layer* layer = FrameLayerBuilder::GetDedicatedLayer(
  1.4959 +    this, nsDisplayItem::TYPE_TRANSFORM);
  1.4960 +  if (!layer || !layer->HasUserData(LayerIsPrerenderedDataKey())) {
  1.4961 +    // If this layer isn't prerendered or we clip composites to our OS
  1.4962 +    // window, then we can't correctly optimize to an empty
  1.4963 +    // transaction in general.
  1.4964 +    return false;
  1.4965 +  }
  1.4966 +
  1.4967 +  gfx3DMatrix transform3d;
  1.4968 +  if (!nsLayoutUtils::GetLayerTransformForFrame(this, &transform3d)) {
  1.4969 +    // We're not able to compute a layer transform that we know would
  1.4970 +    // be used at the next layers transaction, so we can't only update
  1.4971 +    // the transform and will need to schedule an invalidating paint.
  1.4972 +    return false;
  1.4973 +  }
  1.4974 +  gfxMatrix transform;
  1.4975 +  gfx::Matrix previousTransform;
  1.4976 +  // FIXME/bug 796690 and 796705: in general, changes to 3D
  1.4977 +  // transforms, or transform changes to properties other than
  1.4978 +  // translation, may lead us to choose a different rendering
  1.4979 +  // resolution for our layer.  So if the transform is 3D or has a
  1.4980 +  // non-translation change, bail and schedule an invalidating paint.
  1.4981 +  // (We can often do better than this, for example for scale-down
  1.4982 +  // changes.)
  1.4983 + static const gfx::Float kError = 0.0001f;
  1.4984 +  if (!transform3d.Is2D(&transform) ||
  1.4985 +      !layer->GetBaseTransform().Is2D(&previousTransform) ||
  1.4986 +      !gfx::FuzzyEqual(transform.xx, previousTransform._11, kError) ||
  1.4987 +      !gfx::FuzzyEqual(transform.yy, previousTransform._22, kError) ||
  1.4988 +      !gfx::FuzzyEqual(transform.xy, previousTransform._21, kError) ||
  1.4989 +      !gfx::FuzzyEqual(transform.yx, previousTransform._12, kError)) {
  1.4990 +    return false;
  1.4991 +  }
  1.4992 +  gfx::Matrix4x4 matrix;
  1.4993 +  gfx::ToMatrix4x4(transform3d, matrix);
  1.4994 +  layer->SetBaseTransformForNextTransaction(matrix);
  1.4995 +  *aLayerResult = layer;
  1.4996 +  return true;
  1.4997 +}
  1.4998 +
  1.4999 +bool 
  1.5000 +nsIFrame::IsInvalid(nsRect& aRect)
  1.5001 +{
  1.5002 +  if (!HasAnyStateBits(NS_FRAME_NEEDS_PAINT)) {
  1.5003 +    return false;
  1.5004 +  }
  1.5005 +  
  1.5006 +  if (HasAnyStateBits(NS_FRAME_HAS_INVALID_RECT)) {
  1.5007 +    nsRect *rect = static_cast<nsRect*>(Properties().Get(InvalidationRect()));
  1.5008 +    NS_ASSERTION(rect, "Must have an invalid rect if NS_FRAME_HAS_INVALID_RECT is set!");
  1.5009 +    aRect = *rect;
  1.5010 +  } else {
  1.5011 +    aRect.SetEmpty();
  1.5012 +  }
  1.5013 +  return true;
  1.5014 +}
  1.5015 +
  1.5016 +void
  1.5017 +nsIFrame::SchedulePaint(PaintType aType)
  1.5018 +{
  1.5019 +  nsIFrame *displayRoot = nsLayoutUtils::GetDisplayRootFrame(this);
  1.5020 +  nsPresContext *pres = displayRoot->PresContext()->GetRootPresContext();
  1.5021 +
  1.5022 +  // No need to schedule a paint for an external document since they aren't
  1.5023 +  // painted directly.
  1.5024 +  if (!pres || (pres->Document() && pres->Document()->IsResourceDoc())) {
  1.5025 +    return;
  1.5026 +  }
  1.5027 +  if (!pres->GetContainerWeak()) {
  1.5028 +    NS_WARNING("Shouldn't call SchedulePaint in a detached pres context");
  1.5029 +    return;
  1.5030 +  }
  1.5031 +
  1.5032 +  pres->PresShell()->ScheduleViewManagerFlush(aType == PAINT_DELAYED_COMPRESS ?
  1.5033 +                                              nsIPresShell::PAINT_DELAYED_COMPRESS :
  1.5034 +                                              nsIPresShell::PAINT_DEFAULT);
  1.5035 +
  1.5036 +  if (aType == PAINT_DELAYED_COMPRESS) {
  1.5037 +    return;
  1.5038 +  }
  1.5039 +
  1.5040 +  if (aType == PAINT_DEFAULT) {
  1.5041 +    displayRoot->AddStateBits(NS_FRAME_UPDATE_LAYER_TREE);
  1.5042 +  }
  1.5043 +  nsIPresShell* shell = PresContext()->PresShell();
  1.5044 +  if (shell) {
  1.5045 +    shell->AddInvalidateHiddenPresShellObserver(pres->RefreshDriver());
  1.5046 +  }
  1.5047 +}
  1.5048 +
  1.5049 +Layer*
  1.5050 +nsIFrame::InvalidateLayer(uint32_t aDisplayItemKey,
  1.5051 +                          const nsIntRect* aDamageRect,
  1.5052 +                          uint32_t aFlags /* = 0 */)
  1.5053 +{
  1.5054 +  NS_ASSERTION(aDisplayItemKey > 0, "Need a key");
  1.5055 +
  1.5056 +  Layer* layer = FrameLayerBuilder::GetDedicatedLayer(this, aDisplayItemKey);
  1.5057 +
  1.5058 +  // If the layer is being updated asynchronously, and it's being forwarded
  1.5059 +  // to a compositor, then we don't need to invalidate.
  1.5060 +  if ((aFlags & UPDATE_IS_ASYNC) && layer &&
  1.5061 +      layer->Manager()->GetBackendType() == LayersBackend::LAYERS_CLIENT) {
  1.5062 +    return layer;
  1.5063 +  }
  1.5064 +
  1.5065 +  if (aDamageRect && aDamageRect->IsEmpty()) {
  1.5066 +    return layer;
  1.5067 +  }
  1.5068 +
  1.5069 +  if (!layer) {
  1.5070 +    // Plugins can transition from not rendering anything to rendering,
  1.5071 +    // and still only call this. So always invalidate, with specifying
  1.5072 +    // the display item type just in case.
  1.5073 +    //
  1.5074 +    // In the bug 930056, dialer app startup but not shown on the
  1.5075 +    // screen because sometimes we don't have any retainned data
  1.5076 +    // for remote type displayitem and thus Repaint event is not
  1.5077 +    // triggered. So, always invalidate here as well.
  1.5078 +    if (aDisplayItemKey == nsDisplayItem::TYPE_PLUGIN ||
  1.5079 +        aDisplayItemKey == nsDisplayItem::TYPE_REMOTE) {
  1.5080 +      InvalidateFrame();
  1.5081 +    } else {
  1.5082 +      InvalidateFrame(aDisplayItemKey);
  1.5083 +    }
  1.5084 +    return nullptr;
  1.5085 +  }
  1.5086 +
  1.5087 +  if (aDamageRect) {
  1.5088 +    layer->AddInvalidRect(*aDamageRect);
  1.5089 +  } else {
  1.5090 +    layer->SetInvalidRectToVisibleRegion();
  1.5091 +  }
  1.5092 +
  1.5093 +  SchedulePaint(PAINT_COMPOSITE_ONLY);
  1.5094 +  return layer;
  1.5095 +}
  1.5096 +
  1.5097 +static nsRect
  1.5098 +ComputeEffectsRect(nsIFrame* aFrame, const nsRect& aOverflowRect,
  1.5099 +                   const nsSize& aNewSize)
  1.5100 +{
  1.5101 +  nsRect r = aOverflowRect;
  1.5102 +
  1.5103 +  if (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) {
  1.5104 +    // For SVG frames, we only need to account for filters.
  1.5105 +    // TODO: We could also take account of clipPath and mask to reduce the
  1.5106 +    // visual overflow, but that's not essential.
  1.5107 +    if (aFrame->StyleSVGReset()->HasFilters()) {
  1.5108 +      aFrame->Properties().
  1.5109 +        Set(nsIFrame::PreEffectsBBoxProperty(), new nsRect(r));
  1.5110 +      r = nsSVGUtils::GetPostFilterVisualOverflowRect(aFrame, aOverflowRect);
  1.5111 +    }
  1.5112 +    return r;
  1.5113 +  }
  1.5114 +
  1.5115 +  // box-shadow
  1.5116 +  r.UnionRect(r, nsLayoutUtils::GetBoxShadowRectForFrame(aFrame, aNewSize));
  1.5117 +
  1.5118 +  // border-image-outset.
  1.5119 +  // We need to include border-image-outset because it can cause the
  1.5120 +  // border image to be drawn beyond the border box.
  1.5121 +
  1.5122 +  // (1) It's important we not check whether there's a border-image
  1.5123 +  //     since the style hint for a change in border image doesn't cause
  1.5124 +  //     reflow, and that's probably more important than optimizing the
  1.5125 +  //     overflow areas for the silly case of border-image-outset without
  1.5126 +  //     border-image
  1.5127 +  // (2) It's important that we not check whether the border-image
  1.5128 +  //     is actually loaded, since that would require us to reflow when
  1.5129 +  //     the image loads.
  1.5130 +  const nsStyleBorder* styleBorder = aFrame->StyleBorder();
  1.5131 +  nsMargin outsetMargin = styleBorder->GetImageOutset();
  1.5132 +
  1.5133 +  if (outsetMargin != nsMargin(0, 0, 0, 0)) {
  1.5134 +    nsRect outsetRect(nsPoint(0, 0), aNewSize);
  1.5135 +    outsetRect.Inflate(outsetMargin);
  1.5136 +    r.UnionRect(r, outsetRect);
  1.5137 +  }
  1.5138 +
  1.5139 +  // Note that we don't remove the outlineInnerRect if a frame loses outline
  1.5140 +  // style. That would require an extra property lookup for every frame,
  1.5141 +  // or a new frame state bit to track whether a property had been stored,
  1.5142 +  // or something like that. It's not worth doing that here. At most it's
  1.5143 +  // only one heap-allocated rect per frame and it will be cleaned up when
  1.5144 +  // the frame dies.
  1.5145 +
  1.5146 +  if (nsSVGIntegrationUtils::UsingEffectsForFrame(aFrame)) {
  1.5147 +    aFrame->Properties().
  1.5148 +      Set(nsIFrame::PreEffectsBBoxProperty(), new nsRect(r));
  1.5149 +    r = nsSVGIntegrationUtils::ComputePostEffectsVisualOverflowRect(aFrame, r);
  1.5150 +  }
  1.5151 +
  1.5152 +  return r;
  1.5153 +}
  1.5154 +
  1.5155 +void
  1.5156 +nsIFrame::MovePositionBy(const nsPoint& aTranslation)
  1.5157 +{
  1.5158 +  nsPoint position = GetNormalPosition() + aTranslation;
  1.5159 +
  1.5160 +  const nsMargin* computedOffsets = nullptr;
  1.5161 +  if (IsRelativelyPositioned()) {
  1.5162 +    computedOffsets = static_cast<nsMargin*>
  1.5163 +      (Properties().Get(nsIFrame::ComputedOffsetProperty()));
  1.5164 +  }
  1.5165 +  nsHTMLReflowState::ApplyRelativePositioning(this, computedOffsets ?
  1.5166 +                                              *computedOffsets : nsMargin(),
  1.5167 +                                              &position);
  1.5168 +  NS_ASSERTION(StyleDisplay()->mPosition == NS_STYLE_POSITION_STICKY ||
  1.5169 +               GetPosition() + aTranslation == position,
  1.5170 +               "MovePositionBy should always lead to the movement "
  1.5171 +               "specified, unless the frame is position:sticky");
  1.5172 +  SetPosition(position);
  1.5173 +}
  1.5174 +
  1.5175 +nsPoint
  1.5176 +nsIFrame::GetNormalPosition() const
  1.5177 +{
  1.5178 +  // It might be faster to first check
  1.5179 +  // StyleDisplay()->IsRelativelyPositionedStyle().
  1.5180 +  nsPoint* normalPosition = static_cast<nsPoint*>
  1.5181 +    (Properties().Get(NormalPositionProperty()));
  1.5182 +  if (normalPosition) {
  1.5183 +    return *normalPosition;
  1.5184 +  }
  1.5185 +  return GetPosition();
  1.5186 +}
  1.5187 +
  1.5188 +nsRect
  1.5189 +nsIFrame::GetOverflowRect(nsOverflowType aType) const
  1.5190 +{
  1.5191 +  NS_ABORT_IF_FALSE(aType == eVisualOverflow || aType == eScrollableOverflow,
  1.5192 +                    "unexpected type");
  1.5193 +
  1.5194 +  // Note that in some cases the overflow area might not have been
  1.5195 +  // updated (yet) to reflect any outline set on the frame or the area
  1.5196 +  // of child frames. That's OK because any reflow that updates these
  1.5197 +  // areas will invalidate the appropriate area, so any (mis)uses of
  1.5198 +  // this method will be fixed up.
  1.5199 +
  1.5200 +  if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) {
  1.5201 +    // there is an overflow rect, and it's not stored as deltas but as
  1.5202 +    // a separately-allocated rect
  1.5203 +    return static_cast<nsOverflowAreas*>(const_cast<nsIFrame*>(this)->
  1.5204 +             GetOverflowAreasProperty())->Overflow(aType);
  1.5205 +  }
  1.5206 +
  1.5207 +  if (aType == eVisualOverflow &&
  1.5208 +      mOverflow.mType != NS_FRAME_OVERFLOW_NONE) {
  1.5209 +    return GetVisualOverflowFromDeltas();
  1.5210 +  }
  1.5211 +
  1.5212 +  return nsRect(nsPoint(0, 0), GetSize());
  1.5213 +}
  1.5214 +
  1.5215 +nsOverflowAreas
  1.5216 +nsIFrame::GetOverflowAreas() const
  1.5217 +{
  1.5218 +  if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) {
  1.5219 +    // there is an overflow rect, and it's not stored as deltas but as
  1.5220 +    // a separately-allocated rect
  1.5221 +    return *const_cast<nsIFrame*>(this)->GetOverflowAreasProperty();
  1.5222 +  }
  1.5223 +
  1.5224 +  return nsOverflowAreas(GetVisualOverflowFromDeltas(),
  1.5225 +                         nsRect(nsPoint(0, 0), GetSize()));
  1.5226 +}
  1.5227 +
  1.5228 +nsOverflowAreas
  1.5229 +nsIFrame::GetOverflowAreasRelativeToSelf() const
  1.5230 +{
  1.5231 +  if (IsTransformed()) {
  1.5232 +    nsOverflowAreas* preTransformOverflows = static_cast<nsOverflowAreas*>
  1.5233 +      (Properties().Get(PreTransformOverflowAreasProperty()));
  1.5234 +    if (preTransformOverflows) {
  1.5235 +      return nsOverflowAreas(preTransformOverflows->VisualOverflow(),
  1.5236 +                             preTransformOverflows->ScrollableOverflow());
  1.5237 +    }
  1.5238 +  }
  1.5239 +  return nsOverflowAreas(GetVisualOverflowRect(),
  1.5240 +                         GetScrollableOverflowRect());
  1.5241 +}
  1.5242 +
  1.5243 +nsRect
  1.5244 +nsIFrame::GetScrollableOverflowRectRelativeToParent() const
  1.5245 +{
  1.5246 +  return GetScrollableOverflowRect() + mRect.TopLeft();
  1.5247 +}
  1.5248 +
  1.5249 +nsRect
  1.5250 +nsIFrame::GetScrollableOverflowRectRelativeToSelf() const
  1.5251 +{
  1.5252 +  if (IsTransformed()) {
  1.5253 +    nsOverflowAreas* preTransformOverflows = static_cast<nsOverflowAreas*>
  1.5254 +      (Properties().Get(PreTransformOverflowAreasProperty()));
  1.5255 +    if (preTransformOverflows)
  1.5256 +      return preTransformOverflows->ScrollableOverflow();
  1.5257 +  }
  1.5258 +  return GetScrollableOverflowRect();
  1.5259 +}
  1.5260 +
  1.5261 +nsRect
  1.5262 +nsIFrame::GetVisualOverflowRectRelativeToSelf() const
  1.5263 +{
  1.5264 +  if (IsTransformed()) {
  1.5265 +    nsOverflowAreas* preTransformOverflows = static_cast<nsOverflowAreas*>
  1.5266 +      (Properties().Get(PreTransformOverflowAreasProperty()));
  1.5267 +    if (preTransformOverflows)
  1.5268 +      return preTransformOverflows->VisualOverflow();
  1.5269 +  }
  1.5270 +  return GetVisualOverflowRect();
  1.5271 +}
  1.5272 +
  1.5273 +nsRect
  1.5274 +nsIFrame::GetPreEffectsVisualOverflowRect() const
  1.5275 +{
  1.5276 +  nsRect* r = static_cast<nsRect*>
  1.5277 +    (Properties().Get(nsIFrame::PreEffectsBBoxProperty()));
  1.5278 +  return r ? *r : GetVisualOverflowRectRelativeToSelf();
  1.5279 +}
  1.5280 +
  1.5281 +inline static bool
  1.5282 +FrameMaintainsOverflow(nsIFrame* aFrame)
  1.5283 +{
  1.5284 +  return (aFrame->GetStateBits() &
  1.5285 +          (NS_FRAME_SVG_LAYOUT | NS_FRAME_IS_NONDISPLAY)) !=
  1.5286 +         (NS_FRAME_SVG_LAYOUT | NS_FRAME_IS_NONDISPLAY);
  1.5287 +}
  1.5288 +
  1.5289 +/* virtual */ bool
  1.5290 +nsFrame::UpdateOverflow()
  1.5291 +{
  1.5292 +  MOZ_ASSERT(FrameMaintainsOverflow(this),
  1.5293 +             "Non-display SVG do not maintain visual overflow rects");
  1.5294 +
  1.5295 +  nsRect rect(nsPoint(0, 0), GetSize());
  1.5296 +  nsOverflowAreas overflowAreas(rect, rect);
  1.5297 +
  1.5298 +  if (!DoesClipChildren() &&
  1.5299 +      !(IsCollapsed() && (IsBoxFrame() || IsBoxWrapped()))) {
  1.5300 +    nsLayoutUtils::UnionChildOverflow(this, overflowAreas);
  1.5301 +  }
  1.5302 +
  1.5303 +  if (FinishAndStoreOverflow(overflowAreas, GetSize())) {
  1.5304 +    nsView* view = GetView();
  1.5305 +    if (view) {
  1.5306 +      uint32_t flags = 0;
  1.5307 +      GetLayoutFlags(flags);
  1.5308 +
  1.5309 +      if ((flags & NS_FRAME_NO_SIZE_VIEW) == 0) {
  1.5310 +        // Make sure the frame's view is properly sized.
  1.5311 +        nsViewManager* vm = view->GetViewManager();
  1.5312 +        vm->ResizeView(view, overflowAreas.VisualOverflow(), true);
  1.5313 +      }
  1.5314 +    }
  1.5315 +
  1.5316 +    return true;
  1.5317 +  }
  1.5318 +
  1.5319 +  return false;
  1.5320 +}
  1.5321 +
  1.5322 +// Define the MAX_FRAME_DEPTH to be the ContentSink's MAX_REFLOW_DEPTH plus
  1.5323 +// 4 for the frames above the document's frames: 
  1.5324 +//  the Viewport, GFXScroll, ScrollPort, and Canvas
  1.5325 +#define MAX_FRAME_DEPTH (MAX_REFLOW_DEPTH+4)
  1.5326 +
  1.5327 +bool
  1.5328 +nsFrame::IsFrameTreeTooDeep(const nsHTMLReflowState& aReflowState,
  1.5329 +                            nsHTMLReflowMetrics& aMetrics,
  1.5330 +                            nsReflowStatus& aStatus)
  1.5331 +{
  1.5332 +  if (aReflowState.mReflowDepth >  MAX_FRAME_DEPTH) {
  1.5333 +    NS_WARNING("frame tree too deep; setting zero size and returning");
  1.5334 +    mState |= NS_FRAME_TOO_DEEP_IN_FRAME_TREE;
  1.5335 +    ClearOverflowRects();
  1.5336 +    aMetrics.Width() = 0;
  1.5337 +    aMetrics.Height() = 0;
  1.5338 +    aMetrics.SetTopAscent(0);
  1.5339 +    aMetrics.mCarriedOutBottomMargin.Zero();
  1.5340 +    aMetrics.mOverflowAreas.Clear();
  1.5341 +
  1.5342 +    if (GetNextInFlow()) {
  1.5343 +      // Reflow depth might vary between reflows, so we might have
  1.5344 +      // successfully reflowed and split this frame before.  If so, we
  1.5345 +      // shouldn't delete its continuations.
  1.5346 +      aStatus = NS_FRAME_NOT_COMPLETE;
  1.5347 +    } else {
  1.5348 +      aStatus = NS_FRAME_COMPLETE;
  1.5349 +    }
  1.5350 +
  1.5351 +    return true;
  1.5352 +  }
  1.5353 +  mState &= ~NS_FRAME_TOO_DEEP_IN_FRAME_TREE;
  1.5354 +  return false;
  1.5355 +}
  1.5356 +
  1.5357 +bool
  1.5358 +nsIFrame::IsBlockWrapper() const
  1.5359 +{
  1.5360 +  nsIAtom *pseudoType = StyleContext()->GetPseudo();
  1.5361 +  return (pseudoType == nsCSSAnonBoxes::mozAnonymousBlock ||
  1.5362 +          pseudoType == nsCSSAnonBoxes::mozAnonymousPositionedBlock ||
  1.5363 +          pseudoType == nsCSSAnonBoxes::buttonContent ||
  1.5364 +          pseudoType == nsCSSAnonBoxes::cellContent);
  1.5365 +}
  1.5366 +
  1.5367 +static nsIFrame*
  1.5368 +GetNearestBlockContainer(nsIFrame* frame)
  1.5369 +{
  1.5370 +  // The block wrappers we use to wrap blocks inside inlines aren't
  1.5371 +  // described in the CSS spec.  We need to make them not be containing
  1.5372 +  // blocks.
  1.5373 +  // Since the parent of such a block is either a normal block or
  1.5374 +  // another such pseudo, this shouldn't cause anything bad to happen.
  1.5375 +  // Also the anonymous blocks inside table cells are not containing blocks.
  1.5376 +  while (frame->IsFrameOfType(nsIFrame::eLineParticipant) ||
  1.5377 +         frame->IsBlockWrapper() ||
  1.5378 +         // Table rows are not containing blocks either
  1.5379 +         frame->GetType() == nsGkAtoms::tableRowFrame) {
  1.5380 +    frame = frame->GetParent();
  1.5381 +    NS_ASSERTION(frame, "How come we got to the root frame without seeing a containing block?");
  1.5382 +  }
  1.5383 +  return frame;
  1.5384 +}
  1.5385 +
  1.5386 +nsIFrame*
  1.5387 +nsIFrame::GetContainingBlock() const
  1.5388 +{
  1.5389 +  // MathML frames might have absolute positioning style, but they would
  1.5390 +  // still be in-flow.  So we have to check to make sure that the frame
  1.5391 +  // is really out-of-flow too.
  1.5392 +  if (IsAbsolutelyPositioned() &&
  1.5393 +      (GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
  1.5394 +    return GetParent(); // the parent is always the containing block
  1.5395 +  }
  1.5396 +  return GetNearestBlockContainer(GetParent());
  1.5397 +}
  1.5398 +
  1.5399 +#ifdef DEBUG_FRAME_DUMP
  1.5400 +
  1.5401 +int32_t nsFrame::ContentIndexInContainer(const nsIFrame* aFrame)
  1.5402 +{
  1.5403 +  int32_t result = -1;
  1.5404 +
  1.5405 +  nsIContent* content = aFrame->GetContent();
  1.5406 +  if (content) {
  1.5407 +    nsIContent* parentContent = content->GetParent();
  1.5408 +    if (parentContent) {
  1.5409 +      result = parentContent->IndexOf(content);
  1.5410 +    }
  1.5411 +  }
  1.5412 +
  1.5413 +  return result;
  1.5414 +}
  1.5415 +
  1.5416 +/**
  1.5417 + * List a frame tree to stderr. Meant to be called from gdb.
  1.5418 + */
  1.5419 +void
  1.5420 +DebugListFrameTree(nsIFrame* aFrame)
  1.5421 +{
  1.5422 +  ((nsFrame*)aFrame)->List(stderr);
  1.5423 +}
  1.5424 +
  1.5425 +void
  1.5426 +nsIFrame::ListTag(nsACString& aTo) const
  1.5427 +{
  1.5428 +  ListTag(aTo, this);
  1.5429 +}
  1.5430 +
  1.5431 +/* static */
  1.5432 +void
  1.5433 +nsIFrame::ListTag(nsACString& aTo, const nsIFrame* aFrame) {
  1.5434 +  nsAutoString tmp;
  1.5435 +  aFrame->GetFrameName(tmp);
  1.5436 +  aTo += NS_ConvertUTF16toUTF8(tmp).get();
  1.5437 +  aTo += nsPrintfCString("@%p", static_cast<const void*>(aFrame));
  1.5438 +}
  1.5439 +
  1.5440 +// Debugging
  1.5441 +void
  1.5442 +nsIFrame::ListGeneric(nsACString& aTo, const char* aPrefix, uint32_t aFlags) const
  1.5443 +{
  1.5444 +  aTo =+ aPrefix;
  1.5445 +  ListTag(aTo);
  1.5446 +  if (HasView()) {
  1.5447 +    aTo += nsPrintfCString(" [view=%p]", static_cast<void*>(GetView()));
  1.5448 +  }
  1.5449 +  if (GetNextSibling()) {
  1.5450 +    aTo += nsPrintfCString(" next=%p", static_cast<void*>(GetNextSibling()));
  1.5451 +  }
  1.5452 +  if (GetPrevContinuation()) {
  1.5453 +    bool fluid = GetPrevInFlow() == GetPrevContinuation();
  1.5454 +    aTo += nsPrintfCString(" prev-%s=%p", fluid?"in-flow":"continuation",
  1.5455 +            static_cast<void*>(GetPrevContinuation()));
  1.5456 +  }
  1.5457 +  if (GetNextContinuation()) {
  1.5458 +    bool fluid = GetNextInFlow() == GetNextContinuation();
  1.5459 +    aTo += nsPrintfCString(" next-%s=%p", fluid?"in-flow":"continuation",
  1.5460 +            static_cast<void*>(GetNextContinuation()));
  1.5461 +  }
  1.5462 +  void* IBsibling = Properties().Get(IBSplitSibling());
  1.5463 +  if (IBsibling) {
  1.5464 +    aTo += nsPrintfCString(" IBSplitSibling=%p", IBsibling);
  1.5465 +  }
  1.5466 +  void* IBprevsibling = Properties().Get(IBSplitPrevSibling());
  1.5467 +  if (IBprevsibling) {
  1.5468 +    aTo += nsPrintfCString(" IBSplitPrevSibling=%p", IBprevsibling);
  1.5469 +  }
  1.5470 +  aTo += nsPrintfCString(" {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height);
  1.5471 +  nsIFrame* f = const_cast<nsIFrame*>(this);
  1.5472 +  if (f->HasOverflowAreas()) {
  1.5473 +    nsRect vo = f->GetVisualOverflowRect();
  1.5474 +    if (!vo.IsEqualEdges(mRect)) {
  1.5475 +      aTo += nsPrintfCString(" vis-overflow=%d,%d,%d,%d", vo.x, vo.y, vo.width, vo.height);
  1.5476 +    }
  1.5477 +    nsRect so = f->GetScrollableOverflowRect();
  1.5478 +    if (!so.IsEqualEdges(mRect)) {
  1.5479 +      aTo += nsPrintfCString(" scr-overflow=%d,%d,%d,%d", so.x, so.y, so.width, so.height);
  1.5480 +    }
  1.5481 +  }
  1.5482 +  if (0 != mState) {
  1.5483 +    aTo += nsPrintfCString(" [state=%016llx]", (unsigned long long)mState);
  1.5484 +  }
  1.5485 +  if (IsTransformed()) {
  1.5486 +    aTo += nsPrintfCString(" transformed");
  1.5487 +  }
  1.5488 +  if (ChildrenHavePerspective()) {
  1.5489 +    aTo += nsPrintfCString(" perspective");
  1.5490 +  }
  1.5491 +  if (Preserves3DChildren()) {
  1.5492 +    aTo += nsPrintfCString(" preserves-3d-children");
  1.5493 +  }
  1.5494 +  if (Preserves3D()) {
  1.5495 +    aTo += nsPrintfCString(" preserves-3d");
  1.5496 +  }
  1.5497 +  if (mContent) {
  1.5498 +    aTo += nsPrintfCString(" [content=%p]", static_cast<void*>(mContent));
  1.5499 +  }
  1.5500 +  aTo += nsPrintfCString(" [sc=%p", static_cast<void*>(mStyleContext));
  1.5501 +  if (mStyleContext) {
  1.5502 +    nsIAtom* pseudoTag = mStyleContext->GetPseudo();
  1.5503 +    if (pseudoTag) {
  1.5504 +      nsAutoString atomString;
  1.5505 +      pseudoTag->ToString(atomString);
  1.5506 +      aTo += nsPrintfCString("%s", NS_LossyConvertUTF16toASCII(atomString).get());
  1.5507 +    }
  1.5508 +    if (mParent && mStyleContext->GetParent() != mParent->StyleContext()) {
  1.5509 +      aTo += nsPrintfCString(",parent=%p", mStyleContext->GetParent());
  1.5510 +    }
  1.5511 +  }
  1.5512 +  aTo += "]";
  1.5513 +}
  1.5514 +
  1.5515 +void
  1.5516 +nsIFrame::List(FILE* out, const char* aPrefix, uint32_t aFlags) const
  1.5517 +{
  1.5518 +  nsCString str;
  1.5519 +  ListGeneric(str, aPrefix, aFlags);
  1.5520 +  fprintf_stderr(out, "%s\n", str.get());
  1.5521 +}
  1.5522 +
  1.5523 +nsresult
  1.5524 +nsFrame::GetFrameName(nsAString& aResult) const
  1.5525 +{
  1.5526 +  return MakeFrameName(NS_LITERAL_STRING("Frame"), aResult);
  1.5527 +}
  1.5528 +
  1.5529 +nsresult
  1.5530 +nsFrame::MakeFrameName(const nsAString& aType, nsAString& aResult) const
  1.5531 +{
  1.5532 +  aResult = aType;
  1.5533 +  if (mContent && !mContent->IsNodeOfType(nsINode::eTEXT)) {
  1.5534 +    nsAutoString buf;
  1.5535 +    mContent->Tag()->ToString(buf);
  1.5536 +    if (GetType() == nsGkAtoms::subDocumentFrame) {
  1.5537 +      nsAutoString src;
  1.5538 +      mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::src, src);
  1.5539 +      buf.Append(NS_LITERAL_STRING(" src=") + src);
  1.5540 +    }
  1.5541 +    aResult.Append(NS_LITERAL_STRING("(") + buf + NS_LITERAL_STRING(")"));
  1.5542 +  }
  1.5543 +  char buf[40];
  1.5544 +  PR_snprintf(buf, sizeof(buf), "(%d)", ContentIndexInContainer(this));
  1.5545 +  AppendASCIItoUTF16(buf, aResult);
  1.5546 +  return NS_OK;
  1.5547 +}
  1.5548 +
  1.5549 +void
  1.5550 +nsIFrame::DumpFrameTree()
  1.5551 +{
  1.5552 +  RootFrameList(PresContext(), stderr);
  1.5553 +}
  1.5554 +
  1.5555 +void
  1.5556 +nsIFrame::DumpFrameTreeLimited()
  1.5557 +{
  1.5558 +  List(stderr);
  1.5559 +}
  1.5560 +
  1.5561 +void
  1.5562 +nsIFrame::RootFrameList(nsPresContext* aPresContext, FILE* out, const char* aPrefix)
  1.5563 +{
  1.5564 +  if (!aPresContext || !out)
  1.5565 +    return;
  1.5566 +
  1.5567 +  nsIPresShell *shell = aPresContext->GetPresShell();
  1.5568 +  if (shell) {
  1.5569 +    nsIFrame* frame = shell->FrameManager()->GetRootFrame();
  1.5570 +    if(frame) {
  1.5571 +      frame->List(out, aPrefix);
  1.5572 +    }
  1.5573 +  }
  1.5574 +}
  1.5575 +#endif
  1.5576 +
  1.5577 +#ifdef DEBUG
  1.5578 +nsFrameState
  1.5579 +nsFrame::GetDebugStateBits() const
  1.5580 +{
  1.5581 +  // We'll ignore these flags for the purposes of comparing frame state:
  1.5582 +  //
  1.5583 +  //   NS_FRAME_EXTERNAL_REFERENCE
  1.5584 +  //     because this is set by the event state manager or the
  1.5585 +  //     caret code when a frame is focused. Depending on whether
  1.5586 +  //     or not the regression tests are run as the focused window
  1.5587 +  //     will make this value vary randomly.
  1.5588 +#define IRRELEVANT_FRAME_STATE_FLAGS NS_FRAME_EXTERNAL_REFERENCE
  1.5589 +
  1.5590 +#define FRAME_STATE_MASK (~(IRRELEVANT_FRAME_STATE_FLAGS))
  1.5591 +
  1.5592 +  return GetStateBits() & FRAME_STATE_MASK;
  1.5593 +}
  1.5594 +
  1.5595 +void
  1.5596 +nsFrame::XMLQuote(nsString& aString)
  1.5597 +{
  1.5598 +  int32_t i, len = aString.Length();
  1.5599 +  for (i = 0; i < len; i++) {
  1.5600 +    char16_t ch = aString.CharAt(i);
  1.5601 +    if (ch == '<') {
  1.5602 +      nsAutoString tmp(NS_LITERAL_STRING("&lt;"));
  1.5603 +      aString.Cut(i, 1);
  1.5604 +      aString.Insert(tmp, i);
  1.5605 +      len += 3;
  1.5606 +      i += 3;
  1.5607 +    }
  1.5608 +    else if (ch == '>') {
  1.5609 +      nsAutoString tmp(NS_LITERAL_STRING("&gt;"));
  1.5610 +      aString.Cut(i, 1);
  1.5611 +      aString.Insert(tmp, i);
  1.5612 +      len += 3;
  1.5613 +      i += 3;
  1.5614 +    }
  1.5615 +    else if (ch == '\"') {
  1.5616 +      nsAutoString tmp(NS_LITERAL_STRING("&quot;"));
  1.5617 +      aString.Cut(i, 1);
  1.5618 +      aString.Insert(tmp, i);
  1.5619 +      len += 5;
  1.5620 +      i += 5;
  1.5621 +    }
  1.5622 +  }
  1.5623 +}
  1.5624 +#endif
  1.5625 +
  1.5626 +bool
  1.5627 +nsIFrame::IsVisibleForPainting(nsDisplayListBuilder* aBuilder) {
  1.5628 +  if (!StyleVisibility()->IsVisible())
  1.5629 +    return false;
  1.5630 +  nsISelection* sel = aBuilder->GetBoundingSelection();
  1.5631 +  return !sel || IsVisibleInSelection(sel);
  1.5632 +}
  1.5633 +
  1.5634 +bool
  1.5635 +nsIFrame::IsVisibleForPainting() {
  1.5636 +  if (!StyleVisibility()->IsVisible())
  1.5637 +    return false;
  1.5638 +
  1.5639 +  nsPresContext* pc = PresContext();
  1.5640 +  if (!pc->IsRenderingOnlySelection())
  1.5641 +    return true;
  1.5642 +
  1.5643 +  nsCOMPtr<nsISelectionController> selcon(do_QueryInterface(pc->PresShell()));
  1.5644 +  if (selcon) {
  1.5645 +    nsCOMPtr<nsISelection> sel;
  1.5646 +    selcon->GetSelection(nsISelectionController::SELECTION_NORMAL,
  1.5647 +                         getter_AddRefs(sel));
  1.5648 +    if (sel)
  1.5649 +      return IsVisibleInSelection(sel);
  1.5650 +  }
  1.5651 +  return true;
  1.5652 +}
  1.5653 +
  1.5654 +bool
  1.5655 +nsIFrame::IsVisibleInSelection(nsDisplayListBuilder* aBuilder) {
  1.5656 +  nsISelection* sel = aBuilder->GetBoundingSelection();
  1.5657 +  return !sel || IsVisibleInSelection(sel);
  1.5658 +}
  1.5659 +
  1.5660 +bool
  1.5661 +nsIFrame::IsVisibleOrCollapsedForPainting(nsDisplayListBuilder* aBuilder) {
  1.5662 +  if (!StyleVisibility()->IsVisibleOrCollapsed())
  1.5663 +    return false;
  1.5664 +  nsISelection* sel = aBuilder->GetBoundingSelection();
  1.5665 +  return !sel || IsVisibleInSelection(sel);
  1.5666 +}
  1.5667 +
  1.5668 +bool
  1.5669 +nsIFrame::IsVisibleInSelection(nsISelection* aSelection)
  1.5670 +{
  1.5671 +  if (!GetContent() || !GetContent()->IsSelectionDescendant()) {
  1.5672 +    return false;
  1.5673 +  }
  1.5674 +  
  1.5675 +  nsCOMPtr<nsIDOMNode> node(do_QueryInterface(mContent));
  1.5676 +  bool vis;
  1.5677 +  nsresult rv = aSelection->ContainsNode(node, true, &vis);
  1.5678 +  return NS_FAILED(rv) || vis;
  1.5679 +}
  1.5680 +
  1.5681 +/* virtual */ bool
  1.5682 +nsFrame::IsEmpty()
  1.5683 +{
  1.5684 +  return false;
  1.5685 +}
  1.5686 +
  1.5687 +bool
  1.5688 +nsIFrame::CachedIsEmpty()
  1.5689 +{
  1.5690 +  NS_PRECONDITION(!(GetStateBits() & NS_FRAME_IS_DIRTY),
  1.5691 +                  "Must only be called on reflowed lines");
  1.5692 +  return IsEmpty();
  1.5693 +}
  1.5694 +
  1.5695 +/* virtual */ bool
  1.5696 +nsFrame::IsSelfEmpty()
  1.5697 +{
  1.5698 +  return false;
  1.5699 +}
  1.5700 +
  1.5701 +nsresult
  1.5702 +nsFrame::GetSelectionController(nsPresContext *aPresContext, nsISelectionController **aSelCon)
  1.5703 +{
  1.5704 +  if (!aPresContext || !aSelCon)
  1.5705 +    return NS_ERROR_INVALID_ARG;
  1.5706 +
  1.5707 +  nsIFrame *frame = this;
  1.5708 +  while (frame && (frame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION)) {
  1.5709 +    nsITextControlFrame *tcf = do_QueryFrame(frame);
  1.5710 +    if (tcf) {
  1.5711 +      return tcf->GetOwnedSelectionController(aSelCon);
  1.5712 +    }
  1.5713 +    frame = frame->GetParent();
  1.5714 +  }
  1.5715 +
  1.5716 +  return CallQueryInterface(aPresContext->GetPresShell(), aSelCon);
  1.5717 +}
  1.5718 +
  1.5719 +already_AddRefed<nsFrameSelection>
  1.5720 +nsIFrame::GetFrameSelection()
  1.5721 +{
  1.5722 +  nsRefPtr<nsFrameSelection> fs =
  1.5723 +    const_cast<nsFrameSelection*>(GetConstFrameSelection());
  1.5724 +  return fs.forget();
  1.5725 +}
  1.5726 +
  1.5727 +const nsFrameSelection*
  1.5728 +nsIFrame::GetConstFrameSelection() const
  1.5729 +{
  1.5730 +  nsIFrame* frame = const_cast<nsIFrame*>(this);
  1.5731 +  while (frame && (frame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION)) {
  1.5732 +    nsITextControlFrame* tcf = do_QueryFrame(frame);
  1.5733 +    if (tcf) {
  1.5734 +      return tcf->GetOwnedFrameSelection();
  1.5735 +    }
  1.5736 +    frame = frame->GetParent();
  1.5737 +  }
  1.5738 +
  1.5739 +  return PresContext()->PresShell()->ConstFrameSelection();
  1.5740 +}
  1.5741 +
  1.5742 +#ifdef DEBUG
  1.5743 +nsresult
  1.5744 +nsFrame::DumpRegressionData(nsPresContext* aPresContext, FILE* out, int32_t aIndent)
  1.5745 +{
  1.5746 +  IndentBy(out, aIndent);
  1.5747 +  fprintf(out, "<frame va=\"%p\" type=\"", (void*)this);
  1.5748 +  nsAutoString name;
  1.5749 +  GetFrameName(name);
  1.5750 +  XMLQuote(name);
  1.5751 +  fputs(NS_LossyConvertUTF16toASCII(name).get(), out);
  1.5752 +  fprintf(out, "\" state=\"%016llx\" parent=\"%p\">\n",
  1.5753 +          (unsigned long long)GetDebugStateBits(), (void*)mParent);
  1.5754 +
  1.5755 +  aIndent++;
  1.5756 +  DumpBaseRegressionData(aPresContext, out, aIndent);
  1.5757 +  aIndent--;
  1.5758 +
  1.5759 +  IndentBy(out, aIndent);
  1.5760 +  fprintf(out, "</frame>\n");
  1.5761 +
  1.5762 +  return NS_OK;
  1.5763 +}
  1.5764 +
  1.5765 +void
  1.5766 +nsFrame::DumpBaseRegressionData(nsPresContext* aPresContext, FILE* out, int32_t aIndent)
  1.5767 +{
  1.5768 +  if (GetNextSibling()) {
  1.5769 +    IndentBy(out, aIndent);
  1.5770 +    fprintf(out, "<next-sibling va=\"%p\"/>\n", (void*)GetNextSibling());
  1.5771 +  }
  1.5772 +
  1.5773 +  if (HasView()) {
  1.5774 +    IndentBy(out, aIndent);
  1.5775 +    fprintf(out, "<view va=\"%p\">\n", (void*)GetView());
  1.5776 +    aIndent++;
  1.5777 +    // XXX add in code to dump out view state too...
  1.5778 +    aIndent--;
  1.5779 +    IndentBy(out, aIndent);
  1.5780 +    fprintf(out, "</view>\n");
  1.5781 +  }
  1.5782 +
  1.5783 +  IndentBy(out, aIndent);
  1.5784 +  fprintf(out, "<bbox x=\"%d\" y=\"%d\" w=\"%d\" h=\"%d\"/>\n",
  1.5785 +          mRect.x, mRect.y, mRect.width, mRect.height);
  1.5786 +
  1.5787 +  // Now dump all of the children on all of the child lists
  1.5788 +  ChildListIterator lists(this);
  1.5789 +  for (; !lists.IsDone(); lists.Next()) {
  1.5790 +    IndentBy(out, aIndent);
  1.5791 +    if (lists.CurrentID() != kPrincipalList) {
  1.5792 +      fprintf(out, "<child-list name=\"%s\">\n", mozilla::layout::ChildListName(lists.CurrentID()));
  1.5793 +    }
  1.5794 +    else {
  1.5795 +      fprintf(out, "<child-list>\n");
  1.5796 +    }
  1.5797 +    aIndent++;
  1.5798 +    nsFrameList::Enumerator childFrames(lists.CurrentList());
  1.5799 +    for (; !childFrames.AtEnd(); childFrames.Next()) {
  1.5800 +      nsIFrame* kid = childFrames.get();
  1.5801 +      kid->DumpRegressionData(aPresContext, out, aIndent);
  1.5802 +    }
  1.5803 +    aIndent--;
  1.5804 +    IndentBy(out, aIndent);
  1.5805 +    fprintf(out, "</child-list>\n");
  1.5806 +  }
  1.5807 +}
  1.5808 +#endif
  1.5809 +
  1.5810 +bool
  1.5811 +nsIFrame::IsFrameSelected() const
  1.5812 +{
  1.5813 +  NS_ASSERTION(!GetContent() || GetContent()->IsSelectionDescendant(),
  1.5814 +               "use the public IsSelected() instead");
  1.5815 +  return nsRange::IsNodeSelected(GetContent(), 0,
  1.5816 +                                 GetContent()->GetChildCount());
  1.5817 +}
  1.5818 +
  1.5819 +nsresult
  1.5820 +nsFrame::GetPointFromOffset(int32_t inOffset, nsPoint* outPoint)
  1.5821 +{
  1.5822 +  NS_PRECONDITION(outPoint != nullptr, "Null parameter");
  1.5823 +  nsRect contentRect = GetContentRect() - GetPosition();
  1.5824 +  nsPoint pt = contentRect.TopLeft();
  1.5825 +  if (mContent)
  1.5826 +  {
  1.5827 +    nsIContent* newContent = mContent->GetParent();
  1.5828 +    if (newContent){
  1.5829 +      int32_t newOffset = newContent->IndexOf(mContent);
  1.5830 +
  1.5831 +      bool isRTL = (NS_GET_EMBEDDING_LEVEL(this) & 1) == 1;
  1.5832 +      if ((!isRTL && inOffset > newOffset) ||
  1.5833 +          (isRTL && inOffset <= newOffset)) {
  1.5834 +        pt = contentRect.TopRight();
  1.5835 +      }
  1.5836 +    }
  1.5837 +  }
  1.5838 +  *outPoint = pt;
  1.5839 +  return NS_OK;
  1.5840 +}
  1.5841 +
  1.5842 +nsresult
  1.5843 +nsFrame::GetChildFrameContainingOffset(int32_t inContentOffset, bool inHint, int32_t* outFrameContentOffset, nsIFrame **outChildFrame)
  1.5844 +{
  1.5845 +  NS_PRECONDITION(outChildFrame && outFrameContentOffset, "Null parameter");
  1.5846 +  *outFrameContentOffset = (int32_t)inHint;
  1.5847 +  //the best frame to reflect any given offset would be a visible frame if possible
  1.5848 +  //i.e. we are looking for a valid frame to place the blinking caret 
  1.5849 +  nsRect rect = GetRect();
  1.5850 +  if (!rect.width || !rect.height)
  1.5851 +  {
  1.5852 +    //if we have a 0 width or height then lets look for another frame that possibly has
  1.5853 +    //the same content.  If we have no frames in flow then just let us return 'this' frame
  1.5854 +    nsIFrame* nextFlow = GetNextInFlow();
  1.5855 +    if (nextFlow)
  1.5856 +      return nextFlow->GetChildFrameContainingOffset(inContentOffset, inHint, outFrameContentOffset, outChildFrame);
  1.5857 +  }
  1.5858 +  *outChildFrame = this;
  1.5859 +  return NS_OK;
  1.5860 +}
  1.5861 +
  1.5862 +//
  1.5863 +// What I've pieced together about this routine:
  1.5864 +// Starting with a block frame (from which a line frame can be gotten)
  1.5865 +// and a line number, drill down and get the first/last selectable
  1.5866 +// frame on that line, depending on aPos->mDirection.
  1.5867 +// aOutSideLimit != 0 means ignore aLineStart, instead work from
  1.5868 +// the end (if > 0) or beginning (if < 0).
  1.5869 +//
  1.5870 +nsresult
  1.5871 +nsFrame::GetNextPrevLineFromeBlockFrame(nsPresContext* aPresContext,
  1.5872 +                                        nsPeekOffsetStruct *aPos,
  1.5873 +                                        nsIFrame *aBlockFrame, 
  1.5874 +                                        int32_t aLineStart, 
  1.5875 +                                        int8_t aOutSideLimit
  1.5876 +                                        )
  1.5877 +{
  1.5878 +  //magic numbers aLineStart will be -1 for end of block 0 will be start of block
  1.5879 +  if (!aBlockFrame || !aPos)
  1.5880 +    return NS_ERROR_NULL_POINTER;
  1.5881 +
  1.5882 +  aPos->mResultFrame = nullptr;
  1.5883 +  aPos->mResultContent = nullptr;
  1.5884 +  aPos->mAttachForward = (aPos->mDirection == eDirNext);
  1.5885 +
  1.5886 +  nsAutoLineIterator it = aBlockFrame->GetLineIterator();
  1.5887 +  if (!it)
  1.5888 +    return NS_ERROR_FAILURE;
  1.5889 +  int32_t searchingLine = aLineStart;
  1.5890 +  int32_t countLines = it->GetNumLines();
  1.5891 +  if (aOutSideLimit > 0) //start at end
  1.5892 +    searchingLine = countLines;
  1.5893 +  else if (aOutSideLimit <0)//start at beginning
  1.5894 +    searchingLine = -1;//"next" will be 0  
  1.5895 +  else 
  1.5896 +    if ((aPos->mDirection == eDirPrevious && searchingLine == 0) || 
  1.5897 +       (aPos->mDirection == eDirNext && searchingLine >= (countLines -1) )){
  1.5898 +      //we need to jump to new block frame.
  1.5899 +           return NS_ERROR_FAILURE;
  1.5900 +    }
  1.5901 +  int32_t lineFrameCount;
  1.5902 +  nsIFrame *resultFrame = nullptr;
  1.5903 +  nsIFrame *farStoppingFrame = nullptr; //we keep searching until we find a "this" frame then we go to next line
  1.5904 +  nsIFrame *nearStoppingFrame = nullptr; //if we are backing up from edge, stop here
  1.5905 +  nsIFrame *firstFrame;
  1.5906 +  nsIFrame *lastFrame;
  1.5907 +  nsRect  rect;
  1.5908 +  bool isBeforeFirstFrame, isAfterLastFrame;
  1.5909 +  bool found = false;
  1.5910 +
  1.5911 +  nsresult result = NS_OK;
  1.5912 +  while (!found)
  1.5913 +  {
  1.5914 +    if (aPos->mDirection == eDirPrevious)
  1.5915 +      searchingLine --;
  1.5916 +    else
  1.5917 +      searchingLine ++;
  1.5918 +    if ((aPos->mDirection == eDirPrevious && searchingLine < 0) || 
  1.5919 +       (aPos->mDirection == eDirNext && searchingLine >= countLines ))
  1.5920 +    {
  1.5921 +      //we need to jump to new block frame.
  1.5922 +      return NS_ERROR_FAILURE;
  1.5923 +    }
  1.5924 +    uint32_t lineFlags;
  1.5925 +    result = it->GetLine(searchingLine, &firstFrame, &lineFrameCount,
  1.5926 +                         rect, &lineFlags);
  1.5927 +    if (!lineFrameCount) 
  1.5928 +      continue;
  1.5929 +    if (NS_SUCCEEDED(result)){
  1.5930 +      lastFrame = firstFrame;
  1.5931 +      for (;lineFrameCount > 1;lineFrameCount --){
  1.5932 +        //result = lastFrame->GetNextSibling(&lastFrame, searchingLine);
  1.5933 +        result = it->GetNextSiblingOnLine(lastFrame, searchingLine);
  1.5934 +        if (NS_FAILED(result) || !lastFrame){
  1.5935 +          NS_ERROR("GetLine promised more frames than could be found");
  1.5936 +          return NS_ERROR_FAILURE;
  1.5937 +        }
  1.5938 +      }
  1.5939 +      GetLastLeaf(aPresContext, &lastFrame);
  1.5940 +
  1.5941 +      if (aPos->mDirection == eDirNext){
  1.5942 +        nearStoppingFrame = firstFrame;
  1.5943 +        farStoppingFrame = lastFrame;
  1.5944 +      }
  1.5945 +      else{
  1.5946 +        nearStoppingFrame = lastFrame;
  1.5947 +        farStoppingFrame = firstFrame;
  1.5948 +      }
  1.5949 +      nsPoint offset;
  1.5950 +      nsView * view; //used for call of get offset from view
  1.5951 +      aBlockFrame->GetOffsetFromView(offset,&view);
  1.5952 +      nscoord newDesiredX  = aPos->mDesiredX - offset.x;//get desired x into blockframe coordinates!
  1.5953 +      result = it->FindFrameAt(searchingLine, newDesiredX, &resultFrame, &isBeforeFirstFrame, &isAfterLastFrame);
  1.5954 +      if(NS_FAILED(result))
  1.5955 +        continue;
  1.5956 +    }
  1.5957 +
  1.5958 +    if (NS_SUCCEEDED(result) && resultFrame)
  1.5959 +    {
  1.5960 +      //check to see if this is ANOTHER blockframe inside the other one if so then call into its lines
  1.5961 +      nsAutoLineIterator newIt = resultFrame->GetLineIterator();
  1.5962 +      if (newIt)
  1.5963 +      {
  1.5964 +        aPos->mResultFrame = resultFrame;
  1.5965 +        return NS_OK;
  1.5966 +      }
  1.5967 +      //resultFrame is not a block frame
  1.5968 +      result = NS_ERROR_FAILURE;
  1.5969 +
  1.5970 +      nsCOMPtr<nsIFrameEnumerator> frameTraversal;
  1.5971 +      result = NS_NewFrameTraversal(getter_AddRefs(frameTraversal),
  1.5972 +                                    aPresContext, resultFrame,
  1.5973 +                                    ePostOrder,
  1.5974 +                                    false, // aVisual
  1.5975 +                                    aPos->mScrollViewStop,
  1.5976 +                                    false     // aFollowOOFs
  1.5977 +                                    );
  1.5978 +      if (NS_FAILED(result))
  1.5979 +        return result;
  1.5980 +
  1.5981 +      nsIFrame *storeOldResultFrame = resultFrame;
  1.5982 +      while ( !found ){
  1.5983 +        nsPoint point;
  1.5984 +        point.x = aPos->mDesiredX;
  1.5985 +
  1.5986 +        nsRect tempRect = resultFrame->GetRect();
  1.5987 +        nsPoint offset;
  1.5988 +        nsView * view; //used for call of get offset from view
  1.5989 +        resultFrame->GetOffsetFromView(offset, &view);
  1.5990 +        if (!view) {
  1.5991 +          return NS_ERROR_FAILURE;
  1.5992 +        }
  1.5993 +        point.y = tempRect.height + offset.y;
  1.5994 +
  1.5995 +        //special check. if we allow non-text selection then we can allow a hit location to fall before a table.
  1.5996 +        //otherwise there is no way to get and click signal to fall before a table (it being a line iterator itself)
  1.5997 +        nsIPresShell *shell = aPresContext->GetPresShell();
  1.5998 +        if (!shell)
  1.5999 +          return NS_ERROR_FAILURE;
  1.6000 +        int16_t isEditor = shell->GetSelectionFlags();
  1.6001 +        isEditor = isEditor == nsISelectionDisplay::DISPLAY_ALL;
  1.6002 +        if ( isEditor )
  1.6003 +        {
  1.6004 +          if (resultFrame->GetType() == nsGkAtoms::tableOuterFrame)
  1.6005 +          {
  1.6006 +            if (((point.x - offset.x + tempRect.x)<0) ||  ((point.x - offset.x+ tempRect.x)>tempRect.width))//off left/right side
  1.6007 +            {
  1.6008 +              nsIContent* content = resultFrame->GetContent();
  1.6009 +              if (content)
  1.6010 +              {
  1.6011 +                nsIContent* parent = content->GetParent();
  1.6012 +                if (parent)
  1.6013 +                {
  1.6014 +                  aPos->mResultContent = parent;
  1.6015 +                  aPos->mContentOffset = parent->IndexOf(content);
  1.6016 +                  aPos->mAttachForward = false;
  1.6017 +                  if ((point.x - offset.x+ tempRect.x)>tempRect.width)
  1.6018 +                  {
  1.6019 +                    aPos->mContentOffset++;//go to end of this frame
  1.6020 +                    aPos->mAttachForward = true;
  1.6021 +                  }
  1.6022 +                  //result frame is the result frames parent.
  1.6023 +                  aPos->mResultFrame = resultFrame->GetParent();
  1.6024 +                  return NS_POSITION_BEFORE_TABLE;
  1.6025 +                }
  1.6026 +              }
  1.6027 +            }
  1.6028 +          }
  1.6029 +        }
  1.6030 +
  1.6031 +        if (!resultFrame->HasView())
  1.6032 +        {
  1.6033 +          nsView* view;
  1.6034 +          nsPoint offset;
  1.6035 +          resultFrame->GetOffsetFromView(offset, &view);
  1.6036 +          ContentOffsets offsets =
  1.6037 +              resultFrame->GetContentOffsetsFromPoint(point - offset);
  1.6038 +          aPos->mResultContent = offsets.content;
  1.6039 +          aPos->mContentOffset = offsets.offset;
  1.6040 +          aPos->mAttachForward = offsets.associateWithNext;
  1.6041 +          if (offsets.content)
  1.6042 +          {
  1.6043 +            bool selectable;
  1.6044 +            resultFrame->IsSelectable(&selectable, nullptr);
  1.6045 +            if (selectable)
  1.6046 +            {
  1.6047 +              found = true;
  1.6048 +              break;
  1.6049 +            }
  1.6050 +          }
  1.6051 +        }
  1.6052 +
  1.6053 +        if (aPos->mDirection == eDirPrevious && (resultFrame == farStoppingFrame))
  1.6054 +          break;
  1.6055 +        if (aPos->mDirection == eDirNext && (resultFrame == nearStoppingFrame))
  1.6056 +          break;
  1.6057 +        //always try previous on THAT line if that fails go the other way
  1.6058 +        frameTraversal->Prev();
  1.6059 +        resultFrame = frameTraversal->CurrentItem();
  1.6060 +        if (!resultFrame)
  1.6061 +          return NS_ERROR_FAILURE;
  1.6062 +      }
  1.6063 +
  1.6064 +      if (!found){
  1.6065 +        resultFrame = storeOldResultFrame;
  1.6066 +
  1.6067 +        result = NS_NewFrameTraversal(getter_AddRefs(frameTraversal),
  1.6068 +                                      aPresContext, resultFrame,
  1.6069 +                                      eLeaf,
  1.6070 +                                      false, // aVisual
  1.6071 +                                      aPos->mScrollViewStop,
  1.6072 +                                      false     // aFollowOOFs
  1.6073 +                                      );
  1.6074 +      }
  1.6075 +      while ( !found ){
  1.6076 +        nsPoint point(aPos->mDesiredX, 0);
  1.6077 +        nsView* view;
  1.6078 +        nsPoint offset;
  1.6079 +        resultFrame->GetOffsetFromView(offset, &view);
  1.6080 +        ContentOffsets offsets =
  1.6081 +            resultFrame->GetContentOffsetsFromPoint(point - offset);
  1.6082 +        aPos->mResultContent = offsets.content;
  1.6083 +        aPos->mContentOffset = offsets.offset;
  1.6084 +        aPos->mAttachForward = offsets.associateWithNext;
  1.6085 +        if (offsets.content)
  1.6086 +        {
  1.6087 +          bool selectable;
  1.6088 +          resultFrame->IsSelectable(&selectable, nullptr);
  1.6089 +          if (selectable)
  1.6090 +          {
  1.6091 +            found = true;
  1.6092 +            if (resultFrame == farStoppingFrame)
  1.6093 +              aPos->mAttachForward = false;
  1.6094 +            else
  1.6095 +              aPos->mAttachForward = true;
  1.6096 +            break;
  1.6097 +          }
  1.6098 +        }
  1.6099 +        if (aPos->mDirection == eDirPrevious && (resultFrame == nearStoppingFrame))
  1.6100 +          break;
  1.6101 +        if (aPos->mDirection == eDirNext && (resultFrame == farStoppingFrame))
  1.6102 +          break;
  1.6103 +        //previous didnt work now we try "next"
  1.6104 +        frameTraversal->Next();
  1.6105 +        nsIFrame *tempFrame = frameTraversal->CurrentItem();
  1.6106 +        if (!tempFrame)
  1.6107 +          break;
  1.6108 +        resultFrame = tempFrame;
  1.6109 +      }
  1.6110 +      aPos->mResultFrame = resultFrame;
  1.6111 +    }
  1.6112 +    else {
  1.6113 +        //we need to jump to new block frame.
  1.6114 +      aPos->mAmount = eSelectLine;
  1.6115 +      aPos->mStartOffset = 0;
  1.6116 +      aPos->mAttachForward = !(aPos->mDirection == eDirNext);
  1.6117 +      if (aPos->mDirection == eDirPrevious)
  1.6118 +        aPos->mStartOffset = -1;//start from end
  1.6119 +     return aBlockFrame->PeekOffset(aPos);
  1.6120 +    }
  1.6121 +  }
  1.6122 +  return NS_OK;
  1.6123 +}
  1.6124 +
  1.6125 +nsIFrame::CaretPosition
  1.6126 +nsIFrame::GetExtremeCaretPosition(bool aStart)
  1.6127 +{
  1.6128 +  CaretPosition result;
  1.6129 +
  1.6130 +  FrameTarget targetFrame = DrillDownToSelectionFrame(this, !aStart, 0);
  1.6131 +  FrameContentRange range = GetRangeForFrame(targetFrame.frame);
  1.6132 +  result.mResultContent = range.content;
  1.6133 +  result.mContentOffset = aStart ? range.start : range.end;
  1.6134 +  return result;
  1.6135 +}
  1.6136 +
  1.6137 +// Find the first (or last) descendant of the given frame
  1.6138 +// which is either a block frame or a BRFrame.
  1.6139 +static nsContentAndOffset
  1.6140 +FindBlockFrameOrBR(nsIFrame* aFrame, nsDirection aDirection)
  1.6141 +{
  1.6142 +  nsContentAndOffset result;
  1.6143 +  result.mContent =  nullptr;
  1.6144 +  result.mOffset = 0;
  1.6145 +
  1.6146 +  if (aFrame->IsGeneratedContentFrame())
  1.6147 +    return result;
  1.6148 +
  1.6149 +  // Treat form controls as inline leaves
  1.6150 +  // XXX we really need a way to determine whether a frame is inline-level
  1.6151 +  nsIFormControlFrame* fcf = do_QueryFrame(aFrame);
  1.6152 +  if (fcf)
  1.6153 +    return result;
  1.6154 +  
  1.6155 +  // Check the frame itself
  1.6156 +  // Fall through block-in-inline split frames because their mContent is
  1.6157 +  // the content of the inline frames they were created from. The
  1.6158 +  // first/last child of such frames is the real block frame we're
  1.6159 +  // looking for.
  1.6160 +  if ((nsLayoutUtils::GetAsBlock(aFrame) &&
  1.6161 +       !(aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT)) ||
  1.6162 +      aFrame->GetType() == nsGkAtoms::brFrame) {
  1.6163 +    nsIContent* content = aFrame->GetContent();
  1.6164 +    result.mContent = content->GetParent();
  1.6165 +    // In some cases (bug 310589, bug 370174) we end up here with a null content.
  1.6166 +    // This probably shouldn't ever happen, but since it sometimes does, we want
  1.6167 +    // to avoid crashing here.
  1.6168 +    NS_ASSERTION(result.mContent, "Unexpected orphan content");
  1.6169 +    if (result.mContent)
  1.6170 +      result.mOffset = result.mContent->IndexOf(content) + 
  1.6171 +        (aDirection == eDirPrevious ? 1 : 0);
  1.6172 +    return result;
  1.6173 +  }
  1.6174 +
  1.6175 +  // If this is a preformatted text frame, see if it ends with a newline
  1.6176 +  if (aFrame->HasSignificantTerminalNewline()) {
  1.6177 +    int32_t startOffset, endOffset;
  1.6178 +    aFrame->GetOffsets(startOffset, endOffset);
  1.6179 +    result.mContent = aFrame->GetContent();
  1.6180 +    result.mOffset = endOffset - (aDirection == eDirPrevious ? 0 : 1);
  1.6181 +    return result;
  1.6182 +  }
  1.6183 +
  1.6184 +  // Iterate over children and call ourselves recursively
  1.6185 +  if (aDirection == eDirPrevious) {
  1.6186 +    nsIFrame* child = aFrame->GetLastChild(nsIFrame::kPrincipalList);
  1.6187 +    while(child && !result.mContent) {
  1.6188 +      result = FindBlockFrameOrBR(child, aDirection);
  1.6189 +      child = child->GetPrevSibling();
  1.6190 +    }
  1.6191 +  } else { // eDirNext
  1.6192 +    nsIFrame* child = aFrame->GetFirstPrincipalChild();
  1.6193 +    while(child && !result.mContent) {
  1.6194 +      result = FindBlockFrameOrBR(child, aDirection);
  1.6195 +      child = child->GetNextSibling();
  1.6196 +    }
  1.6197 +  }
  1.6198 +  return result;
  1.6199 +}
  1.6200 +
  1.6201 +nsresult
  1.6202 +nsIFrame::PeekOffsetParagraph(nsPeekOffsetStruct *aPos)
  1.6203 +{
  1.6204 +  nsIFrame* frame = this;
  1.6205 +  nsContentAndOffset blockFrameOrBR;
  1.6206 +  blockFrameOrBR.mContent = nullptr;
  1.6207 +  bool reachedBlockAncestor = false;
  1.6208 +
  1.6209 +  // Go through containing frames until reaching a block frame.
  1.6210 +  // In each step, search the previous (or next) siblings for the closest
  1.6211 +  // "stop frame" (a block frame or a BRFrame).
  1.6212 +  // If found, set it to be the selection boundray and abort.
  1.6213 +  
  1.6214 +  if (aPos->mDirection == eDirPrevious) {
  1.6215 +    while (!reachedBlockAncestor) {
  1.6216 +      nsIFrame* parent = frame->GetParent();
  1.6217 +      // Treat a frame associated with the root content as if it were a block frame.
  1.6218 +      if (!frame->mContent || !frame->mContent->GetParent()) {
  1.6219 +        reachedBlockAncestor = true;
  1.6220 +        break;
  1.6221 +      }
  1.6222 +      nsIFrame* sibling = frame->GetPrevSibling();
  1.6223 +      while (sibling && !blockFrameOrBR.mContent) {
  1.6224 +        blockFrameOrBR = FindBlockFrameOrBR(sibling, eDirPrevious);
  1.6225 +        sibling = sibling->GetPrevSibling();
  1.6226 +      }
  1.6227 +      if (blockFrameOrBR.mContent) {
  1.6228 +        aPos->mResultContent = blockFrameOrBR.mContent;
  1.6229 +        aPos->mContentOffset = blockFrameOrBR.mOffset;
  1.6230 +        break;
  1.6231 +      }
  1.6232 +      frame = parent;
  1.6233 +      reachedBlockAncestor = (nsLayoutUtils::GetAsBlock(frame) != nullptr);
  1.6234 +    }
  1.6235 +    if (reachedBlockAncestor) { // no "stop frame" found
  1.6236 +      aPos->mResultContent = frame->GetContent();
  1.6237 +      aPos->mContentOffset = 0;
  1.6238 +    }
  1.6239 +  } else { // eDirNext
  1.6240 +    while (!reachedBlockAncestor) {
  1.6241 +      nsIFrame* parent = frame->GetParent();
  1.6242 +      // Treat a frame associated with the root content as if it were a block frame.
  1.6243 +      if (!frame->mContent || !frame->mContent->GetParent()) {
  1.6244 +        reachedBlockAncestor = true;
  1.6245 +        break;
  1.6246 +      }
  1.6247 +      nsIFrame* sibling = frame;
  1.6248 +      while (sibling && !blockFrameOrBR.mContent) {
  1.6249 +        blockFrameOrBR = FindBlockFrameOrBR(sibling, eDirNext);
  1.6250 +        sibling = sibling->GetNextSibling();
  1.6251 +      }
  1.6252 +      if (blockFrameOrBR.mContent) {
  1.6253 +        aPos->mResultContent = blockFrameOrBR.mContent;
  1.6254 +        aPos->mContentOffset = blockFrameOrBR.mOffset;
  1.6255 +        break;
  1.6256 +      }
  1.6257 +      frame = parent;
  1.6258 +      reachedBlockAncestor = (nsLayoutUtils::GetAsBlock(frame) != nullptr);
  1.6259 +    }
  1.6260 +    if (reachedBlockAncestor) { // no "stop frame" found
  1.6261 +      aPos->mResultContent = frame->GetContent();
  1.6262 +      if (aPos->mResultContent)
  1.6263 +        aPos->mContentOffset = aPos->mResultContent->GetChildCount();
  1.6264 +    }
  1.6265 +  }
  1.6266 +  return NS_OK;
  1.6267 +}
  1.6268 +
  1.6269 +// Determine movement direction relative to frame
  1.6270 +static bool IsMovingInFrameDirection(nsIFrame* frame, nsDirection aDirection, bool aVisual)
  1.6271 +{
  1.6272 +  bool isReverseDirection = aVisual ?
  1.6273 +    (NS_GET_EMBEDDING_LEVEL(frame) & 1) != (NS_GET_BASE_LEVEL(frame) & 1) : false;
  1.6274 +  return aDirection == (isReverseDirection ? eDirPrevious : eDirNext);
  1.6275 +}
  1.6276 +
  1.6277 +nsresult
  1.6278 +nsIFrame::PeekOffset(nsPeekOffsetStruct* aPos)
  1.6279 +{
  1.6280 +  if (!aPos)
  1.6281 +    return NS_ERROR_NULL_POINTER;
  1.6282 +  nsresult result = NS_ERROR_FAILURE;
  1.6283 +
  1.6284 +  if (mState & NS_FRAME_IS_DIRTY)
  1.6285 +    return NS_ERROR_UNEXPECTED;
  1.6286 +
  1.6287 +  // Translate content offset to be relative to frame
  1.6288 +  FrameContentRange range = GetRangeForFrame(this);
  1.6289 +  int32_t offset = aPos->mStartOffset - range.start;
  1.6290 +  nsIFrame* current = this;
  1.6291 +  
  1.6292 +  switch (aPos->mAmount) {
  1.6293 +    case eSelectCharacter:
  1.6294 +    case eSelectCluster:
  1.6295 +    {
  1.6296 +      bool eatingNonRenderableWS = false;
  1.6297 +      nsIFrame::FrameSearchResult peekSearchState = CONTINUE;
  1.6298 +      bool jumpedLine = false;
  1.6299 +      bool movedOverNonSelectableText = false;
  1.6300 +      
  1.6301 +      while (peekSearchState != FOUND) {
  1.6302 +        bool movingInFrameDirection =
  1.6303 +          IsMovingInFrameDirection(current, aPos->mDirection, aPos->mVisual);
  1.6304 +
  1.6305 +        if (eatingNonRenderableWS)
  1.6306 +          peekSearchState = current->PeekOffsetNoAmount(movingInFrameDirection, &offset); 
  1.6307 +        else
  1.6308 +          peekSearchState = current->PeekOffsetCharacter(movingInFrameDirection, &offset,
  1.6309 +                                              aPos->mAmount == eSelectCluster);
  1.6310 +
  1.6311 +        movedOverNonSelectableText |= (peekSearchState == CONTINUE_UNSELECTABLE);
  1.6312 +
  1.6313 +        if (peekSearchState != FOUND) {
  1.6314 +          result =
  1.6315 +            current->GetFrameFromDirection(aPos->mDirection, aPos->mVisual,
  1.6316 +                                           aPos->mJumpLines, aPos->mScrollViewStop,
  1.6317 +                                           &current, &offset, &jumpedLine);
  1.6318 +          if (NS_FAILED(result))
  1.6319 +            return result;
  1.6320 +
  1.6321 +          // If we jumped lines, it's as if we found a character, but we still need
  1.6322 +          // to eat non-renderable content on the new line.
  1.6323 +          if (jumpedLine)
  1.6324 +            eatingNonRenderableWS = true;
  1.6325 +        }
  1.6326 +
  1.6327 +        // Found frame, but because we moved over non selectable text we want the offset
  1.6328 +        // to be at the frame edge.
  1.6329 +        if (peekSearchState == FOUND && movedOverNonSelectableText)
  1.6330 +        {
  1.6331 +          int32_t start, end;
  1.6332 +          current->GetOffsets(start, end);
  1.6333 +          offset = aPos->mDirection == eDirNext ? 0 : end - start;
  1.6334 +        }
  1.6335 +      }
  1.6336 +
  1.6337 +      // Set outputs
  1.6338 +      range = GetRangeForFrame(current);
  1.6339 +      aPos->mResultFrame = current;
  1.6340 +      aPos->mResultContent = range.content;
  1.6341 +      // Output offset is relative to content, not frame
  1.6342 +      aPos->mContentOffset = offset < 0 ? range.end : range.start + offset;
  1.6343 +      // If we're dealing with a text frame and moving backward positions us at
  1.6344 +      // the end of that line, decrease the offset by one to make sure that
  1.6345 +      // we're placed before the linefeed character on the previous line.
  1.6346 +      if (offset < 0 && jumpedLine &&
  1.6347 +          aPos->mDirection == eDirPrevious &&
  1.6348 +          current->HasSignificantTerminalNewline()) {
  1.6349 +        --aPos->mContentOffset;
  1.6350 +      }
  1.6351 +      
  1.6352 +      break;
  1.6353 +    }
  1.6354 +    case eSelectWordNoSpace:
  1.6355 +      // eSelectWordNoSpace means that we should not be eating any whitespace when
  1.6356 +      // moving to the adjacent word.  This means that we should set aPos->
  1.6357 +      // mWordMovementType to eEndWord if we're moving forwards, and to eStartWord
  1.6358 +      // if we're moving backwards.
  1.6359 +      if (aPos->mDirection == eDirPrevious) {
  1.6360 +        aPos->mWordMovementType = eStartWord;
  1.6361 +      } else {
  1.6362 +        aPos->mWordMovementType = eEndWord;
  1.6363 +      }
  1.6364 +      // Intentionally fall through the eSelectWord case.
  1.6365 +    case eSelectWord:
  1.6366 +    {
  1.6367 +      // wordSelectEatSpace means "are we looking for a boundary between whitespace
  1.6368 +      // and non-whitespace (in the direction we're moving in)".
  1.6369 +      // It is true when moving forward and looking for a beginning of a word, or
  1.6370 +      // when moving backwards and looking for an end of a word.
  1.6371 +      bool wordSelectEatSpace;
  1.6372 +      if (aPos->mWordMovementType != eDefaultBehavior) {
  1.6373 +        // aPos->mWordMovementType possible values:
  1.6374 +        //       eEndWord: eat the space if we're moving backwards
  1.6375 +        //       eStartWord: eat the space if we're moving forwards
  1.6376 +        wordSelectEatSpace = ((aPos->mWordMovementType == eEndWord) == (aPos->mDirection == eDirPrevious));
  1.6377 +      }
  1.6378 +      else {
  1.6379 +        // Use the hidden preference which is based on operating system behavior.
  1.6380 +        // This pref only affects whether moving forward by word should go to the end of this word or start of the next word.
  1.6381 +        // When going backwards, the start of the word is always used, on every operating system.
  1.6382 +        wordSelectEatSpace = aPos->mDirection == eDirNext &&
  1.6383 +          Preferences::GetBool("layout.word_select.eat_space_to_next_word");
  1.6384 +      }
  1.6385 +      
  1.6386 +      // mSawBeforeType means "we already saw characters of the type
  1.6387 +      // before the boundary we're looking for". Examples:
  1.6388 +      // 1. If we're moving forward, looking for a word beginning (i.e. a boundary
  1.6389 +      //    between whitespace and non-whitespace), then eatingWS==true means
  1.6390 +      //    "we already saw some whitespace".
  1.6391 +      // 2. If we're moving backward, looking for a word beginning (i.e. a boundary
  1.6392 +      //    between non-whitespace and whitespace), then eatingWS==true means
  1.6393 +      //    "we already saw some non-whitespace".
  1.6394 +      PeekWordState state;
  1.6395 +      int32_t offsetAdjustment = 0;
  1.6396 +      bool done = false;
  1.6397 +      while (!done) {
  1.6398 +        bool movingInFrameDirection =
  1.6399 +          IsMovingInFrameDirection(current, aPos->mDirection, aPos->mVisual);
  1.6400 +        
  1.6401 +        done = current->PeekOffsetWord(movingInFrameDirection, wordSelectEatSpace,
  1.6402 +                                       aPos->mIsKeyboardSelect, &offset, &state) == FOUND;
  1.6403 +        
  1.6404 +        if (!done) {
  1.6405 +          nsIFrame* nextFrame;
  1.6406 +          int32_t nextFrameOffset;
  1.6407 +          bool jumpedLine;
  1.6408 +          result =
  1.6409 +            current->GetFrameFromDirection(aPos->mDirection, aPos->mVisual,
  1.6410 +                                           aPos->mJumpLines, aPos->mScrollViewStop,
  1.6411 +                                           &nextFrame, &nextFrameOffset, &jumpedLine);
  1.6412 +          // We can't jump lines if we're looking for whitespace following
  1.6413 +          // non-whitespace, and we already encountered non-whitespace.
  1.6414 +          if (NS_FAILED(result) ||
  1.6415 +              (jumpedLine && !wordSelectEatSpace && state.mSawBeforeType)) {
  1.6416 +            done = true;
  1.6417 +            // If we've crossed the line boundary, check to make sure that we
  1.6418 +            // have not consumed a trailing newline as whitesapce if it's significant.
  1.6419 +            if (jumpedLine && wordSelectEatSpace &&
  1.6420 +                current->HasSignificantTerminalNewline()) {
  1.6421 +              offsetAdjustment = -1;
  1.6422 +            }
  1.6423 +          } else {
  1.6424 +            if (jumpedLine) {
  1.6425 +              state.mContext.Truncate();
  1.6426 +            }
  1.6427 +            current = nextFrame;
  1.6428 +            offset = nextFrameOffset;
  1.6429 +            // Jumping a line is equivalent to encountering whitespace
  1.6430 +            if (wordSelectEatSpace && jumpedLine)
  1.6431 +              state.SetSawBeforeType();
  1.6432 +          }
  1.6433 +        }
  1.6434 +      }
  1.6435 +      
  1.6436 +      // Set outputs
  1.6437 +      range = GetRangeForFrame(current);
  1.6438 +      aPos->mResultFrame = current;
  1.6439 +      aPos->mResultContent = range.content;
  1.6440 +      // Output offset is relative to content, not frame
  1.6441 +      aPos->mContentOffset = (offset < 0 ? range.end : range.start + offset) + offsetAdjustment;
  1.6442 +      break;
  1.6443 +    }
  1.6444 +    case eSelectLine :
  1.6445 +    {
  1.6446 +      nsAutoLineIterator iter;
  1.6447 +      nsIFrame *blockFrame = this;
  1.6448 +
  1.6449 +      while (NS_FAILED(result)){
  1.6450 +        int32_t thisLine = nsFrame::GetLineNumber(blockFrame, aPos->mScrollViewStop, &blockFrame);
  1.6451 +        if (thisLine < 0) 
  1.6452 +          return  NS_ERROR_FAILURE;
  1.6453 +        iter = blockFrame->GetLineIterator();
  1.6454 +        NS_ASSERTION(iter, "GetLineNumber() succeeded but no block frame?");
  1.6455 +        result = NS_OK;
  1.6456 +
  1.6457 +        int edgeCase = 0;//no edge case. this should look at thisLine
  1.6458 +        
  1.6459 +        bool doneLooping = false;//tells us when no more block frames hit.
  1.6460 +        //this part will find a frame or a block frame. if it's a block frame
  1.6461 +        //it will "drill down" to find a viable frame or it will return an error.
  1.6462 +        nsIFrame *lastFrame = this;
  1.6463 +        do {
  1.6464 +          result = nsFrame::GetNextPrevLineFromeBlockFrame(PresContext(),
  1.6465 +                                                           aPos, 
  1.6466 +                                                           blockFrame, 
  1.6467 +                                                           thisLine, 
  1.6468 +                                                           edgeCase //start from thisLine
  1.6469 +            );
  1.6470 +          if (NS_SUCCEEDED(result) && (!aPos->mResultFrame || aPos->mResultFrame == lastFrame))//we came back to same spot! keep going
  1.6471 +          {
  1.6472 +            aPos->mResultFrame = nullptr;
  1.6473 +            if (aPos->mDirection == eDirPrevious)
  1.6474 +              thisLine--;
  1.6475 +            else
  1.6476 +              thisLine++;
  1.6477 +          }
  1.6478 +          else //if failure or success with different frame.
  1.6479 +            doneLooping = true; //do not continue with while loop
  1.6480 +
  1.6481 +          lastFrame = aPos->mResultFrame; //set last frame 
  1.6482 +
  1.6483 +          if (NS_SUCCEEDED(result) && aPos->mResultFrame 
  1.6484 +            && blockFrame != aPos->mResultFrame)// make sure block element is not the same as the one we had before
  1.6485 +          {
  1.6486 +/* SPECIAL CHECK FOR TABLE NAVIGATION
  1.6487 +  tables need to navigate also and the frame that supports it is nsTableRowGroupFrame which is INSIDE
  1.6488 +  nsTableOuterFrame.  if we have stumbled onto an nsTableOuter we need to drill into nsTableRowGroup
  1.6489 +  if we hit a header or footer that's ok just go into them,
  1.6490 +*/
  1.6491 +            bool searchTableBool = false;
  1.6492 +            if (aPos->mResultFrame->GetType() == nsGkAtoms::tableOuterFrame ||
  1.6493 +                aPos->mResultFrame->GetType() == nsGkAtoms::tableCellFrame)
  1.6494 +            {
  1.6495 +              nsIFrame *frame = aPos->mResultFrame->GetFirstPrincipalChild();
  1.6496 +              //got the table frame now
  1.6497 +              while(frame) //ok time to drill down to find iterator
  1.6498 +              {
  1.6499 +                iter = frame->GetLineIterator();
  1.6500 +                if (iter)
  1.6501 +                {
  1.6502 +                  aPos->mResultFrame = frame;
  1.6503 +                  searchTableBool = true;
  1.6504 +                  result = NS_OK;
  1.6505 +                  break; //while(frame)
  1.6506 +                }
  1.6507 +                result = NS_ERROR_FAILURE;
  1.6508 +                frame = frame->GetFirstPrincipalChild();
  1.6509 +              }
  1.6510 +            }
  1.6511 +
  1.6512 +            if (!searchTableBool) {
  1.6513 +              iter = aPos->mResultFrame->GetLineIterator();
  1.6514 +              result = iter ? NS_OK : NS_ERROR_FAILURE;
  1.6515 +            }
  1.6516 +            if (NS_SUCCEEDED(result) && iter)//we've struck another block element!
  1.6517 +            {
  1.6518 +              doneLooping = false;
  1.6519 +              if (aPos->mDirection == eDirPrevious)
  1.6520 +                edgeCase = 1;//far edge, search from end backwards
  1.6521 +              else
  1.6522 +                edgeCase = -1;//near edge search from beginning onwards
  1.6523 +              thisLine=0;//this line means nothing now.
  1.6524 +              //everything else means something so keep looking "inside" the block
  1.6525 +              blockFrame = aPos->mResultFrame;
  1.6526 +
  1.6527 +            }
  1.6528 +            else
  1.6529 +            {
  1.6530 +              result = NS_OK;//THIS is to mean that everything is ok to the containing while loop
  1.6531 +              break;
  1.6532 +            }
  1.6533 +          }
  1.6534 +        } while (!doneLooping);
  1.6535 +      }
  1.6536 +      return result;
  1.6537 +    }
  1.6538 +
  1.6539 +    case eSelectParagraph:
  1.6540 +      return PeekOffsetParagraph(aPos);
  1.6541 +
  1.6542 +    case eSelectBeginLine:
  1.6543 +    case eSelectEndLine:
  1.6544 +    {
  1.6545 +      // Adjusted so that the caret can't get confused when content changes
  1.6546 +      nsIFrame* blockFrame = AdjustFrameForSelectionStyles(this);
  1.6547 +      int32_t thisLine = nsFrame::GetLineNumber(blockFrame, aPos->mScrollViewStop, &blockFrame);
  1.6548 +      if (thisLine < 0)
  1.6549 +        return NS_ERROR_FAILURE;
  1.6550 +      nsAutoLineIterator it = blockFrame->GetLineIterator();
  1.6551 +      NS_ASSERTION(it, "GetLineNumber() succeeded but no block frame?");
  1.6552 +
  1.6553 +      int32_t lineFrameCount;
  1.6554 +      nsIFrame *firstFrame;
  1.6555 +      nsRect usedRect;
  1.6556 +      uint32_t lineFlags;
  1.6557 +      nsIFrame* baseFrame = nullptr;
  1.6558 +      bool endOfLine = (eSelectEndLine == aPos->mAmount);
  1.6559 +
  1.6560 +      if (aPos->mVisual && PresContext()->BidiEnabled()) {
  1.6561 +        bool lineIsRTL = it->GetDirection();
  1.6562 +        bool isReordered;
  1.6563 +        nsIFrame *lastFrame;
  1.6564 +        result = it->CheckLineOrder(thisLine, &isReordered, &firstFrame, &lastFrame);
  1.6565 +        baseFrame = endOfLine ? lastFrame : firstFrame;
  1.6566 +        if (baseFrame) {
  1.6567 +          nsBidiLevel embeddingLevel = nsBidiPresUtils::GetFrameEmbeddingLevel(baseFrame);
  1.6568 +          // If the direction of the frame on the edge is opposite to that of the line,
  1.6569 +          // we'll need to drill down to its opposite end, so reverse endOfLine.
  1.6570 +          if ((embeddingLevel & 1) == !lineIsRTL)
  1.6571 +            endOfLine = !endOfLine;
  1.6572 +        }
  1.6573 +      } else {
  1.6574 +        it->GetLine(thisLine, &firstFrame, &lineFrameCount, usedRect, &lineFlags);
  1.6575 +
  1.6576 +        nsIFrame* frame = firstFrame;
  1.6577 +        for (int32_t count = lineFrameCount; count;
  1.6578 +             --count, frame = frame->GetNextSibling()) {
  1.6579 +          if (!frame->IsGeneratedContentFrame()) {
  1.6580 +            baseFrame = frame;
  1.6581 +            if (!endOfLine)
  1.6582 +              break;
  1.6583 +          }
  1.6584 +        }
  1.6585 +      }
  1.6586 +      if (!baseFrame)
  1.6587 +        return NS_ERROR_FAILURE;
  1.6588 +      FrameTarget targetFrame = DrillDownToSelectionFrame(baseFrame,
  1.6589 +                                                          endOfLine, 0);
  1.6590 +      FrameContentRange range = GetRangeForFrame(targetFrame.frame);
  1.6591 +      aPos->mResultContent = range.content;
  1.6592 +      aPos->mContentOffset = endOfLine ? range.end : range.start;
  1.6593 +      if (endOfLine && targetFrame.frame->HasSignificantTerminalNewline()) {
  1.6594 +        // Do not position the caret after the terminating newline if we're
  1.6595 +        // trying to move to the end of line (see bug 596506)
  1.6596 +        --aPos->mContentOffset;
  1.6597 +      }
  1.6598 +      aPos->mResultFrame = targetFrame.frame;
  1.6599 +      aPos->mAttachForward = (aPos->mContentOffset == range.start);
  1.6600 +      if (!range.content)
  1.6601 +        return NS_ERROR_FAILURE;
  1.6602 +      return NS_OK;
  1.6603 +    }
  1.6604 +
  1.6605 +    default: 
  1.6606 +    {
  1.6607 +      NS_ASSERTION(false, "Invalid amount");
  1.6608 +      return NS_ERROR_FAILURE;
  1.6609 +    }
  1.6610 +  }
  1.6611 +  return NS_OK;
  1.6612 +}
  1.6613 +
  1.6614 +nsIFrame::FrameSearchResult
  1.6615 +nsFrame::PeekOffsetNoAmount(bool aForward, int32_t* aOffset)
  1.6616 +{
  1.6617 +  NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
  1.6618 +  // Sure, we can stop right here.
  1.6619 +  return FOUND;
  1.6620 +}
  1.6621 +
  1.6622 +nsIFrame::FrameSearchResult
  1.6623 +nsFrame::PeekOffsetCharacter(bool aForward, int32_t* aOffset,
  1.6624 +                             bool aRespectClusters)
  1.6625 +{
  1.6626 +  NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
  1.6627 +  int32_t startOffset = *aOffset;
  1.6628 +  // A negative offset means "end of frame", which in our case means offset 1.
  1.6629 +  if (startOffset < 0)
  1.6630 +    startOffset = 1;
  1.6631 +  if (aForward == (startOffset == 0)) {
  1.6632 +    // We're before the frame and moving forward, or after it and moving backwards:
  1.6633 +    // skip to the other side and we're done.
  1.6634 +    *aOffset = 1 - startOffset;
  1.6635 +    return FOUND;
  1.6636 +  }
  1.6637 +  return CONTINUE;
  1.6638 +}
  1.6639 +
  1.6640 +nsIFrame::FrameSearchResult
  1.6641 +nsFrame::PeekOffsetWord(bool aForward, bool aWordSelectEatSpace, bool aIsKeyboardSelect,
  1.6642 +                        int32_t* aOffset, PeekWordState* aState)
  1.6643 +{
  1.6644 +  NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
  1.6645 +  int32_t startOffset = *aOffset;
  1.6646 +  // This isn't text, so truncate the context
  1.6647 +  aState->mContext.Truncate();
  1.6648 +  if (startOffset < 0)
  1.6649 +    startOffset = 1;
  1.6650 +  if (aForward == (startOffset == 0)) {
  1.6651 +    // We're before the frame and moving forward, or after it and moving backwards.
  1.6652 +    // If we're looking for non-whitespace, we found it (without skipping this frame).
  1.6653 +    if (!aState->mAtStart) {
  1.6654 +      if (aState->mLastCharWasPunctuation) {
  1.6655 +        // We're not punctuation, so this is a punctuation boundary.
  1.6656 +        if (BreakWordBetweenPunctuation(aState, aForward, false, false, aIsKeyboardSelect))
  1.6657 +          return FOUND;
  1.6658 +      } else {
  1.6659 +        // This is not a punctuation boundary.
  1.6660 +        if (aWordSelectEatSpace && aState->mSawBeforeType)
  1.6661 +          return FOUND;
  1.6662 +      }
  1.6663 +    }
  1.6664 +    // Otherwise skip to the other side and note that we encountered non-whitespace.
  1.6665 +    *aOffset = 1 - startOffset;
  1.6666 +    aState->Update(false, // not punctuation
  1.6667 +                   false     // not whitespace
  1.6668 +                   );
  1.6669 +    if (!aWordSelectEatSpace)
  1.6670 +      aState->SetSawBeforeType();
  1.6671 +  }
  1.6672 +  return CONTINUE;
  1.6673 +}
  1.6674 +
  1.6675 +bool
  1.6676 +nsFrame::BreakWordBetweenPunctuation(const PeekWordState* aState,
  1.6677 +                                     bool aForward,
  1.6678 +                                     bool aPunctAfter, bool aWhitespaceAfter,
  1.6679 +                                     bool aIsKeyboardSelect)
  1.6680 +{
  1.6681 +  NS_ASSERTION(aPunctAfter != aState->mLastCharWasPunctuation,
  1.6682 +               "Call this only at punctuation boundaries");
  1.6683 +  if (aState->mLastCharWasWhitespace) {
  1.6684 +    // We always stop between whitespace and punctuation
  1.6685 +    return true;
  1.6686 +  }
  1.6687 +  if (!Preferences::GetBool("layout.word_select.stop_at_punctuation")) {
  1.6688 +    // When this pref is false, we never stop at a punctuation boundary unless
  1.6689 +    // it's followed by whitespace (in the relevant direction).
  1.6690 +    return aWhitespaceAfter;
  1.6691 +  }
  1.6692 +  if (!aIsKeyboardSelect) {
  1.6693 +    // mouse caret movement (e.g. word selection) always stops at every punctuation boundary
  1.6694 +    return true;
  1.6695 +  }
  1.6696 +  bool afterPunct = aForward ? aState->mLastCharWasPunctuation : aPunctAfter;
  1.6697 +  if (!afterPunct) {
  1.6698 +    // keyboard caret movement only stops after punctuation (in content order)
  1.6699 +    return false;
  1.6700 +  }
  1.6701 +  // Stop only if we've seen some non-punctuation since the last whitespace;
  1.6702 +  // don't stop after punctuation that follows whitespace.
  1.6703 +  return aState->mSeenNonPunctuationSinceWhitespace;
  1.6704 +}
  1.6705 +
  1.6706 +nsresult
  1.6707 +nsFrame::CheckVisibility(nsPresContext* , int32_t , int32_t , bool , bool *, bool *)
  1.6708 +{
  1.6709 +  return NS_ERROR_NOT_IMPLEMENTED;
  1.6710 +}
  1.6711 +
  1.6712 +
  1.6713 +int32_t
  1.6714 +nsFrame::GetLineNumber(nsIFrame *aFrame, bool aLockScroll, nsIFrame** aContainingBlock)
  1.6715 +{
  1.6716 +  NS_ASSERTION(aFrame, "null aFrame");
  1.6717 +  nsFrameManager* frameManager = aFrame->PresContext()->FrameManager();
  1.6718 +  nsIFrame *blockFrame = aFrame;
  1.6719 +  nsIFrame *thisBlock;
  1.6720 +  nsAutoLineIterator it;
  1.6721 +  nsresult result = NS_ERROR_FAILURE;
  1.6722 +  while (NS_FAILED(result) && blockFrame)
  1.6723 +  {
  1.6724 +    thisBlock = blockFrame;
  1.6725 +    if (thisBlock->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
  1.6726 +      //if we are searching for a frame that is not in flow we will not find it. 
  1.6727 +      //we must instead look for its placeholder
  1.6728 +      if (thisBlock->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
  1.6729 +        // abspos continuations don't have placeholders, get the fif
  1.6730 +        thisBlock = thisBlock->FirstInFlow();
  1.6731 +      }
  1.6732 +      thisBlock = frameManager->GetPlaceholderFrameFor(thisBlock);
  1.6733 +      if (!thisBlock)
  1.6734 +        return -1;
  1.6735 +    }  
  1.6736 +    blockFrame = thisBlock->GetParent();
  1.6737 +    result = NS_OK;
  1.6738 +    if (blockFrame) {
  1.6739 +      if (aLockScroll && blockFrame->GetType() == nsGkAtoms::scrollFrame)
  1.6740 +        return -1;
  1.6741 +      it = blockFrame->GetLineIterator();
  1.6742 +      if (!it)
  1.6743 +        result = NS_ERROR_FAILURE;
  1.6744 +    }
  1.6745 +  }
  1.6746 +  if (!blockFrame || !it)
  1.6747 +    return -1;
  1.6748 +
  1.6749 +  if (aContainingBlock)
  1.6750 +    *aContainingBlock = blockFrame;
  1.6751 +  return it->FindLineContaining(thisBlock);
  1.6752 +}
  1.6753 +
  1.6754 +nsresult
  1.6755 +nsIFrame::GetFrameFromDirection(nsDirection aDirection, bool aVisual,
  1.6756 +                                bool aJumpLines, bool aScrollViewStop, 
  1.6757 +                                nsIFrame** aOutFrame, int32_t* aOutOffset, bool* aOutJumpedLine)
  1.6758 +{
  1.6759 +  nsresult result;
  1.6760 +
  1.6761 +  if (!aOutFrame || !aOutOffset || !aOutJumpedLine)
  1.6762 +    return NS_ERROR_NULL_POINTER;
  1.6763 +  
  1.6764 +  nsPresContext* presContext = PresContext();
  1.6765 +  *aOutFrame = nullptr;
  1.6766 +  *aOutOffset = 0;
  1.6767 +  *aOutJumpedLine = false;
  1.6768 +
  1.6769 +  // Find the prev/next selectable frame
  1.6770 +  bool selectable = false;
  1.6771 +  nsIFrame *traversedFrame = this;
  1.6772 +  while (!selectable) {
  1.6773 +    nsIFrame *blockFrame;
  1.6774 +    
  1.6775 +    int32_t thisLine = nsFrame::GetLineNumber(traversedFrame, aScrollViewStop, &blockFrame);
  1.6776 +    if (thisLine < 0)
  1.6777 +      return NS_ERROR_FAILURE;
  1.6778 +
  1.6779 +    nsAutoLineIterator it = blockFrame->GetLineIterator();
  1.6780 +    NS_ASSERTION(it, "GetLineNumber() succeeded but no block frame?");
  1.6781 +
  1.6782 +    bool atLineEdge;
  1.6783 +    nsIFrame *firstFrame;
  1.6784 +    nsIFrame *lastFrame;
  1.6785 +    if (aVisual && presContext->BidiEnabled()) {
  1.6786 +      bool lineIsRTL = it->GetDirection();
  1.6787 +      bool isReordered;
  1.6788 +      result = it->CheckLineOrder(thisLine, &isReordered, &firstFrame, &lastFrame);
  1.6789 +      nsIFrame** framePtr = aDirection == eDirPrevious ? &firstFrame : &lastFrame;
  1.6790 +      if (*framePtr) {
  1.6791 +        nsBidiLevel embeddingLevel = nsBidiPresUtils::GetFrameEmbeddingLevel(*framePtr);
  1.6792 +        if ((((embeddingLevel & 1) && lineIsRTL) || (!(embeddingLevel & 1) && !lineIsRTL)) ==
  1.6793 +            (aDirection == eDirPrevious)) {
  1.6794 +          nsFrame::GetFirstLeaf(presContext, framePtr);
  1.6795 +        } else {
  1.6796 +          nsFrame::GetLastLeaf(presContext, framePtr);
  1.6797 +        }
  1.6798 +        atLineEdge = *framePtr == traversedFrame;
  1.6799 +      } else {
  1.6800 +        atLineEdge = true;
  1.6801 +      }
  1.6802 +    } else {
  1.6803 +      nsRect  nonUsedRect;
  1.6804 +      int32_t lineFrameCount;
  1.6805 +      uint32_t lineFlags;
  1.6806 +      result = it->GetLine(thisLine, &firstFrame, &lineFrameCount,nonUsedRect,
  1.6807 +                           &lineFlags);
  1.6808 +      if (NS_FAILED(result))
  1.6809 +        return result;
  1.6810 +
  1.6811 +      if (aDirection == eDirPrevious) {
  1.6812 +        nsFrame::GetFirstLeaf(presContext, &firstFrame);
  1.6813 +        atLineEdge = firstFrame == traversedFrame;
  1.6814 +      } else { // eDirNext
  1.6815 +        lastFrame = firstFrame;
  1.6816 +        for (;lineFrameCount > 1;lineFrameCount --){
  1.6817 +          result = it->GetNextSiblingOnLine(lastFrame, thisLine);
  1.6818 +          if (NS_FAILED(result) || !lastFrame){
  1.6819 +            NS_ERROR("should not be reached nsFrame");
  1.6820 +            return NS_ERROR_FAILURE;
  1.6821 +          }
  1.6822 +        }
  1.6823 +        nsFrame::GetLastLeaf(presContext, &lastFrame);
  1.6824 +        atLineEdge = lastFrame == traversedFrame;
  1.6825 +      }
  1.6826 +    }
  1.6827 +
  1.6828 +    if (atLineEdge) {
  1.6829 +      *aOutJumpedLine = true;
  1.6830 +      if (!aJumpLines)
  1.6831 +        return NS_ERROR_FAILURE; //we are done. cannot jump lines
  1.6832 +    }
  1.6833 +
  1.6834 +    nsCOMPtr<nsIFrameEnumerator> frameTraversal;
  1.6835 +    result = NS_NewFrameTraversal(getter_AddRefs(frameTraversal),
  1.6836 +                                  presContext, traversedFrame,
  1.6837 +                                  eLeaf,
  1.6838 +                                  aVisual && presContext->BidiEnabled(),
  1.6839 +                                  aScrollViewStop,
  1.6840 +                                  true     // aFollowOOFs
  1.6841 +                                  );
  1.6842 +    if (NS_FAILED(result))
  1.6843 +      return result;
  1.6844 +
  1.6845 +    if (aDirection == eDirNext)
  1.6846 +      frameTraversal->Next();
  1.6847 +    else
  1.6848 +      frameTraversal->Prev();
  1.6849 +
  1.6850 +    traversedFrame = frameTraversal->CurrentItem();
  1.6851 +    if (!traversedFrame)
  1.6852 +      return NS_ERROR_FAILURE;
  1.6853 +    traversedFrame->IsSelectable(&selectable, nullptr);
  1.6854 +  } // while (!selectable)
  1.6855 +
  1.6856 +  *aOutOffset = (aDirection == eDirNext) ? 0 : -1;
  1.6857 +
  1.6858 +  if (aVisual) {
  1.6859 +    uint8_t newLevel = NS_GET_EMBEDDING_LEVEL(traversedFrame);
  1.6860 +    uint8_t newBaseLevel = NS_GET_BASE_LEVEL(traversedFrame);
  1.6861 +    if ((newLevel & 1) != (newBaseLevel & 1)) // The new frame is reverse-direction, go to the other end
  1.6862 +      *aOutOffset = -1 - *aOutOffset;
  1.6863 +  }
  1.6864 +  *aOutFrame = traversedFrame;
  1.6865 +  return NS_OK;
  1.6866 +}
  1.6867 +
  1.6868 +nsView* nsIFrame::GetClosestView(nsPoint* aOffset) const
  1.6869 +{
  1.6870 +  nsPoint offset(0,0);
  1.6871 +  for (const nsIFrame *f = this; f; f = f->GetParent()) {
  1.6872 +    if (f->HasView()) {
  1.6873 +      if (aOffset)
  1.6874 +        *aOffset = offset;
  1.6875 +      return f->GetView();
  1.6876 +    }
  1.6877 +    offset += f->GetPosition();
  1.6878 +  }
  1.6879 +
  1.6880 +  NS_NOTREACHED("No view on any parent?  How did that happen?");
  1.6881 +  return nullptr;
  1.6882 +}
  1.6883 +
  1.6884 +
  1.6885 +/* virtual */ void
  1.6886 +nsFrame::ChildIsDirty(nsIFrame* aChild)
  1.6887 +{
  1.6888 +  NS_NOTREACHED("should never be called on a frame that doesn't inherit from "
  1.6889 +                "nsContainerFrame");
  1.6890 +}
  1.6891 +
  1.6892 +
  1.6893 +#ifdef ACCESSIBILITY
  1.6894 +a11y::AccType
  1.6895 +nsFrame::AccessibleType()
  1.6896 +{
  1.6897 +  return a11y::eNoType;
  1.6898 +}
  1.6899 +#endif
  1.6900 +
  1.6901 +NS_DECLARE_FRAME_PROPERTY(OverflowAreasProperty,
  1.6902 +                          nsIFrame::DestroyOverflowAreas)
  1.6903 +
  1.6904 +bool
  1.6905 +nsIFrame::ClearOverflowRects()
  1.6906 +{
  1.6907 +  if (mOverflow.mType == NS_FRAME_OVERFLOW_NONE) {
  1.6908 +    return false;
  1.6909 +  }
  1.6910 +  if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) {
  1.6911 +    Properties().Delete(OverflowAreasProperty());
  1.6912 +  }
  1.6913 +  mOverflow.mType = NS_FRAME_OVERFLOW_NONE;
  1.6914 +  return true;
  1.6915 +}
  1.6916 +
  1.6917 +/** Create or retrieve the previously stored overflow area, if the frame does 
  1.6918 + * not overflow and no creation is required return nullptr.
  1.6919 + * @return pointer to the overflow area rectangle 
  1.6920 + */
  1.6921 +nsOverflowAreas*
  1.6922 +nsIFrame::GetOverflowAreasProperty()
  1.6923 +{
  1.6924 +  FrameProperties props = Properties();
  1.6925 +  nsOverflowAreas *overflow =
  1.6926 +    static_cast<nsOverflowAreas*>(props.Get(OverflowAreasProperty()));
  1.6927 +
  1.6928 +  if (overflow) {
  1.6929 +    return overflow; // the property already exists
  1.6930 +  }
  1.6931 +
  1.6932 +  // The property isn't set yet, so allocate a new rect, set the property,
  1.6933 +  // and return the newly allocated rect
  1.6934 +  overflow = new nsOverflowAreas;
  1.6935 +  props.Set(OverflowAreasProperty(), overflow);
  1.6936 +  return overflow;
  1.6937 +}
  1.6938 +
  1.6939 +/** Set the overflowArea rect, storing it as deltas or a separate rect
  1.6940 + * depending on its size in relation to the primary frame rect.
  1.6941 + */
  1.6942 +bool
  1.6943 +nsIFrame::SetOverflowAreas(const nsOverflowAreas& aOverflowAreas)
  1.6944 +{
  1.6945 +  if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) {
  1.6946 +    nsOverflowAreas *overflow =
  1.6947 +      static_cast<nsOverflowAreas*>(Properties().Get(OverflowAreasProperty()));
  1.6948 +    bool changed = *overflow != aOverflowAreas;
  1.6949 +    *overflow = aOverflowAreas;
  1.6950 +
  1.6951 +    // Don't bother with converting to the deltas form if we already
  1.6952 +    // have a property.
  1.6953 +    return changed;
  1.6954 +  }
  1.6955 +
  1.6956 +  const nsRect& vis = aOverflowAreas.VisualOverflow();
  1.6957 +  uint32_t l = -vis.x, // left edge: positive delta is leftwards
  1.6958 +           t = -vis.y, // top: positive is upwards
  1.6959 +           r = vis.XMost() - mRect.width, // right: positive is rightwards
  1.6960 +           b = vis.YMost() - mRect.height; // bottom: positive is downwards
  1.6961 +  if (aOverflowAreas.ScrollableOverflow().IsEqualEdges(nsRect(nsPoint(0, 0), GetSize())) &&
  1.6962 +      l <= NS_FRAME_OVERFLOW_DELTA_MAX &&
  1.6963 +      t <= NS_FRAME_OVERFLOW_DELTA_MAX &&
  1.6964 +      r <= NS_FRAME_OVERFLOW_DELTA_MAX &&
  1.6965 +      b <= NS_FRAME_OVERFLOW_DELTA_MAX &&
  1.6966 +      // we have to check these against zero because we *never* want to
  1.6967 +      // set a frame as having no overflow in this function.  This is
  1.6968 +      // because FinishAndStoreOverflow calls this function prior to
  1.6969 +      // SetRect based on whether the overflow areas match aNewSize.
  1.6970 +      // In the case where the overflow areas exactly match mRect but
  1.6971 +      // do not match aNewSize, we need to store overflow in a property
  1.6972 +      // so that our eventual SetRect/SetSize will know that it has to
  1.6973 +      // reset our overflow areas.
  1.6974 +      (l | t | r | b) != 0) {
  1.6975 +    VisualDeltas oldDeltas = mOverflow.mVisualDeltas;
  1.6976 +    // It's a "small" overflow area so we store the deltas for each edge
  1.6977 +    // directly in the frame, rather than allocating a separate rect.
  1.6978 +    // If they're all zero, that's fine; we're setting things to
  1.6979 +    // no-overflow.
  1.6980 +    mOverflow.mVisualDeltas.mLeft   = l;
  1.6981 +    mOverflow.mVisualDeltas.mTop    = t;
  1.6982 +    mOverflow.mVisualDeltas.mRight  = r;
  1.6983 +    mOverflow.mVisualDeltas.mBottom = b;
  1.6984 +    // There was no scrollable overflow before, and there isn't now.
  1.6985 +    return oldDeltas != mOverflow.mVisualDeltas;
  1.6986 +  } else {
  1.6987 +    bool changed = !aOverflowAreas.ScrollableOverflow().IsEqualEdges(nsRect(nsPoint(0, 0), GetSize())) ||
  1.6988 +      !aOverflowAreas.VisualOverflow().IsEqualEdges(GetVisualOverflowFromDeltas());
  1.6989 +
  1.6990 +    // it's a large overflow area that we need to store as a property
  1.6991 +    mOverflow.mType = NS_FRAME_OVERFLOW_LARGE;
  1.6992 +    nsOverflowAreas* overflow = GetOverflowAreasProperty();
  1.6993 +    NS_ASSERTION(overflow, "should have created areas");
  1.6994 +    *overflow = aOverflowAreas;
  1.6995 +    return changed;
  1.6996 +  }
  1.6997 +}
  1.6998 +
  1.6999 +inline bool
  1.7000 +IsInlineFrame(nsIFrame *aFrame)
  1.7001 +{
  1.7002 +  nsIAtom *type = aFrame->GetType();
  1.7003 +  return type == nsGkAtoms::inlineFrame;
  1.7004 +}
  1.7005 +
  1.7006 +/**
  1.7007 + * Compute the union of the border boxes of aFrame and its descendants,
  1.7008 + * in aFrame's coordinate space (if aApplyTransform is false) or its
  1.7009 + * post-transform coordinate space (if aApplyTransform is true).
  1.7010 + */
  1.7011 +static nsRect
  1.7012 +UnionBorderBoxes(nsIFrame* aFrame, bool aApplyTransform,
  1.7013 +                 const nsSize* aSizeOverride = nullptr,
  1.7014 +                 const nsOverflowAreas* aOverflowOverride = nullptr)
  1.7015 +{
  1.7016 +  const nsRect bounds(nsPoint(0, 0),
  1.7017 +                      aSizeOverride ? *aSizeOverride : aFrame->GetSize());
  1.7018 +
  1.7019 +  // Start from our border-box, transformed.  See comment below about
  1.7020 +  // transform of children.
  1.7021 +  nsRect u;
  1.7022 +  bool doTransform = aApplyTransform && aFrame->IsTransformed();
  1.7023 +  if (doTransform) {
  1.7024 +    u = nsDisplayTransform::TransformRect(bounds, aFrame,
  1.7025 +                                          nsPoint(0, 0), &bounds);
  1.7026 +  } else {
  1.7027 +    u = bounds;
  1.7028 +  }
  1.7029 +
  1.7030 +  // Only iterate through the children if the overflow areas suggest
  1.7031 +  // that we might need to, and if the frame doesn't clip its overflow
  1.7032 +  // anyway.
  1.7033 +  if (aOverflowOverride) {
  1.7034 +    if (!doTransform &&
  1.7035 +        bounds.IsEqualEdges(aOverflowOverride->VisualOverflow()) &&
  1.7036 +        bounds.IsEqualEdges(aOverflowOverride->ScrollableOverflow())) {
  1.7037 +      return u;
  1.7038 +    }
  1.7039 +  } else {
  1.7040 +    if (!doTransform &&
  1.7041 +        bounds.IsEqualEdges(aFrame->GetVisualOverflowRect()) &&
  1.7042 +        bounds.IsEqualEdges(aFrame->GetScrollableOverflowRect())) {
  1.7043 +      return u;
  1.7044 +    }
  1.7045 +  }
  1.7046 +  const nsStyleDisplay* disp = aFrame->StyleDisplay();
  1.7047 +  nsIAtom* fType = aFrame->GetType();
  1.7048 +  if (nsFrame::ShouldApplyOverflowClipping(aFrame, disp) ||
  1.7049 +      fType == nsGkAtoms::scrollFrame ||
  1.7050 +      fType == nsGkAtoms::svgOuterSVGFrame) {
  1.7051 +    return u;
  1.7052 +  }
  1.7053 +
  1.7054 +  nsRect clipPropClipRect;
  1.7055 +  bool hasClipPropClip =
  1.7056 +    aFrame->GetClipPropClipRect(disp, &clipPropClipRect, bounds.Size());
  1.7057 +
  1.7058 +  // Iterate over all children except pop-ups.
  1.7059 +  const nsIFrame::ChildListIDs skip(nsIFrame::kPopupList |
  1.7060 +                                    nsIFrame::kSelectPopupList);
  1.7061 +  for (nsIFrame::ChildListIterator childLists(aFrame);
  1.7062 +       !childLists.IsDone(); childLists.Next()) {
  1.7063 +    if (skip.Contains(childLists.CurrentID())) {
  1.7064 +      continue;
  1.7065 +    }
  1.7066 +
  1.7067 +    nsFrameList children = childLists.CurrentList();
  1.7068 +    for (nsFrameList::Enumerator e(children); !e.AtEnd(); e.Next()) {
  1.7069 +      nsIFrame* child = e.get();
  1.7070 +      // Note that passing |true| for aApplyTransform when
  1.7071 +      // child->Preserves3D() is incorrect if our aApplyTransform is
  1.7072 +      // false... but the opposite would be as well.  This is because
  1.7073 +      // elements within a preserve-3d scene are always transformed up
  1.7074 +      // to the top of the scene.  This means we don't have a
  1.7075 +      // mechanism for getting a transform up to an intermediate point
  1.7076 +      // within the scene.  We choose to over-transform rather than
  1.7077 +      // under-transform because this is consistent with other
  1.7078 +      // overflow areas.
  1.7079 +      nsRect childRect = UnionBorderBoxes(child, true) +
  1.7080 +                         child->GetPosition();
  1.7081 +
  1.7082 +      if (hasClipPropClip) {
  1.7083 +        // Intersect with the clip before transforming.
  1.7084 +        childRect.IntersectRect(childRect, clipPropClipRect);
  1.7085 +      }
  1.7086 +
  1.7087 +      // Note that we transform each child separately according to
  1.7088 +      // aFrame's transform, and then union, which gives a different
  1.7089 +      // (smaller) result from unioning and then transforming the
  1.7090 +      // union.  This doesn't match the way we handle overflow areas
  1.7091 +      // with 2-D transforms, though it does match the way we handle
  1.7092 +      // overflow areas in preserve-3d 3-D scenes.
  1.7093 +      if (doTransform && !child->Preserves3D()) {
  1.7094 +        childRect = nsDisplayTransform::TransformRect(childRect, aFrame,
  1.7095 +                                                      nsPoint(0, 0), &bounds);
  1.7096 +      }
  1.7097 +      u.UnionRectEdges(u, childRect);
  1.7098 +    }
  1.7099 +  }
  1.7100 +
  1.7101 +  return u;
  1.7102 +}
  1.7103 +
  1.7104 +static void
  1.7105 +ComputeAndIncludeOutlineArea(nsIFrame* aFrame, nsOverflowAreas& aOverflowAreas,
  1.7106 +                             const nsSize& aNewSize)
  1.7107 +{
  1.7108 +  const nsStyleOutline* outline = aFrame->StyleOutline();
  1.7109 +  if (outline->GetOutlineStyle() == NS_STYLE_BORDER_STYLE_NONE) {
  1.7110 +    return;
  1.7111 +  }
  1.7112 +
  1.7113 +  nscoord width;
  1.7114 +  DebugOnly<bool> result = outline->GetOutlineWidth(width);
  1.7115 +  NS_ASSERTION(result, "GetOutlineWidth had no cached outline width");
  1.7116 +  if (width <= 0) {
  1.7117 +    return;
  1.7118 +  }
  1.7119 +
  1.7120 +  // When the outline property is set on :-moz-anonymous-block or
  1.7121 +  // :-moz-anonymous-positioned-block pseudo-elements, it inherited
  1.7122 +  // that outline from the inline that was broken because it
  1.7123 +  // contained a block.  In that case, we don't want a really wide
  1.7124 +  // outline if the block inside the inline is narrow, so union the
  1.7125 +  // actual contents of the anonymous blocks.
  1.7126 +  nsIFrame *frameForArea = aFrame;
  1.7127 +  do {
  1.7128 +    nsIAtom *pseudoType = frameForArea->StyleContext()->GetPseudo();
  1.7129 +    if (pseudoType != nsCSSAnonBoxes::mozAnonymousBlock &&
  1.7130 +        pseudoType != nsCSSAnonBoxes::mozAnonymousPositionedBlock)
  1.7131 +      break;
  1.7132 +    // If we're done, we really want it and all its later siblings.
  1.7133 +    frameForArea = frameForArea->GetFirstPrincipalChild();
  1.7134 +    NS_ASSERTION(frameForArea, "anonymous block with no children?");
  1.7135 +  } while (frameForArea);
  1.7136 +
  1.7137 +  // Find the union of the border boxes of all descendants, or in
  1.7138 +  // the block-in-inline case, all descendants we care about.
  1.7139 +  //
  1.7140 +  // Note that the interesting perspective-related cases are taken
  1.7141 +  // care of by the code that handles those issues for overflow
  1.7142 +  // calling FinishAndStoreOverflow again, which in turn calls this
  1.7143 +  // function again.  We still need to deal with preserve-3d a bit.
  1.7144 +  nsRect innerRect;
  1.7145 +  if (frameForArea == aFrame) {
  1.7146 +    innerRect = UnionBorderBoxes(aFrame, false, &aNewSize, &aOverflowAreas);
  1.7147 +  } else {
  1.7148 +    for (; frameForArea; frameForArea = frameForArea->GetNextSibling()) {
  1.7149 +      nsRect r(UnionBorderBoxes(frameForArea, true));
  1.7150 +
  1.7151 +      // Adjust for offsets transforms up to aFrame's pre-transform
  1.7152 +      // (i.e., normal) coordinate space; see comments in
  1.7153 +      // UnionBorderBoxes for some of the subtlety here.
  1.7154 +      for (nsIFrame *f = frameForArea, *parent = f->GetParent();
  1.7155 +           /* see middle of loop */;
  1.7156 +           f = parent, parent = f->GetParent()) {
  1.7157 +        r += f->GetPosition();
  1.7158 +        if (parent == aFrame) {
  1.7159 +          break;
  1.7160 +        }
  1.7161 +        if (parent->IsTransformed() && !f->Preserves3D()) {
  1.7162 +          r = nsDisplayTransform::TransformRect(r, parent, nsPoint(0, 0));
  1.7163 +        }
  1.7164 +      }
  1.7165 +
  1.7166 +      innerRect.UnionRect(innerRect, r);
  1.7167 +    }
  1.7168 +  }
  1.7169 +
  1.7170 +  aFrame->Properties().Set(nsIFrame::OutlineInnerRectProperty(),
  1.7171 +                           new nsRect(innerRect));
  1.7172 +
  1.7173 +  nscoord offset = outline->mOutlineOffset;
  1.7174 +  nscoord inflateBy = std::max(width + offset, 0);
  1.7175 +
  1.7176 +  // Keep this code (and the storing of properties just above) in
  1.7177 +  // sync with GetOutlineInnerRect in nsCSSRendering.cpp.
  1.7178 +  nsRect outerRect(innerRect);
  1.7179 +  outerRect.Inflate(inflateBy, inflateBy);
  1.7180 +
  1.7181 +  nsRect& vo = aOverflowAreas.VisualOverflow();
  1.7182 +  vo.UnionRectEdges(vo, outerRect);
  1.7183 +}
  1.7184 +
  1.7185 +bool
  1.7186 +nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
  1.7187 +                                 nsSize aNewSize, nsSize* aOldSize)
  1.7188 +{
  1.7189 +  NS_ASSERTION(FrameMaintainsOverflow(this),
  1.7190 +               "Don't call - overflow rects not maintained on these SVG frames");
  1.7191 +
  1.7192 +  nsRect bounds(nsPoint(0, 0), aNewSize);
  1.7193 +  // Store the passed in overflow area if we are a preserve-3d frame or we have
  1.7194 +  // a transform, and it's not just the frame bounds.
  1.7195 +  if (Preserves3D() || HasPerspective() || IsTransformed()) {
  1.7196 +    if (!aOverflowAreas.VisualOverflow().IsEqualEdges(bounds) ||
  1.7197 +        !aOverflowAreas.ScrollableOverflow().IsEqualEdges(bounds)) {
  1.7198 +
  1.7199 +      nsOverflowAreas* initial =
  1.7200 +        static_cast<nsOverflowAreas*>(Properties().Get(nsIFrame::InitialOverflowProperty()));
  1.7201 +      if (!initial) {
  1.7202 +        Properties().Set(nsIFrame::InitialOverflowProperty(),
  1.7203 +                         new nsOverflowAreas(aOverflowAreas));
  1.7204 +      } else if (initial != &aOverflowAreas) {
  1.7205 +        *initial = aOverflowAreas;
  1.7206 +      }
  1.7207 +    }
  1.7208 +#ifdef DEBUG
  1.7209 +    Properties().Set(nsIFrame::DebugInitialOverflowPropertyApplied(), nullptr);
  1.7210 +#endif
  1.7211 +  } else {
  1.7212 +#ifdef DEBUG
  1.7213 +  Properties().Delete(nsIFrame::DebugInitialOverflowPropertyApplied());
  1.7214 +#endif
  1.7215 +  }
  1.7216 +
  1.7217 +  // This is now called FinishAndStoreOverflow() instead of 
  1.7218 +  // StoreOverflow() because frame-generic ways of adding overflow
  1.7219 +  // can happen here, e.g. CSS2 outline and native theme.
  1.7220 +  // If the overflow area width or height is nscoord_MAX, then a
  1.7221 +  // saturating union may have encounted an overflow, so the overflow may not
  1.7222 +  // contain the frame border-box. Don't warn in that case.
  1.7223 +  // Don't warn for SVG either, since SVG doesn't need the overflow area
  1.7224 +  // to contain the frame bounds.
  1.7225 +  NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
  1.7226 +    DebugOnly<nsRect*> r = &aOverflowAreas.Overflow(otype);
  1.7227 +    NS_ASSERTION(aNewSize.width == 0 || aNewSize.height == 0 ||
  1.7228 +                 r->width == nscoord_MAX || r->height == nscoord_MAX ||
  1.7229 +                 (mState & NS_FRAME_SVG_LAYOUT) ||
  1.7230 +                 r->Contains(nsRect(nsPoint(0,0), aNewSize)),
  1.7231 +                 "Computed overflow area must contain frame bounds");
  1.7232 +  }
  1.7233 +
  1.7234 +  // If we clip our children, clear accumulated overflow area. The
  1.7235 +  // children are actually clipped to the padding-box, but since the
  1.7236 +  // overflow area should include the entire border-box, just set it to
  1.7237 +  // the border-box here.
  1.7238 +  const nsStyleDisplay* disp = StyleDisplay();
  1.7239 +  NS_ASSERTION((disp->mOverflowY == NS_STYLE_OVERFLOW_CLIP) ==
  1.7240 +               (disp->mOverflowX == NS_STYLE_OVERFLOW_CLIP),
  1.7241 +               "If one overflow is clip, the other should be too");
  1.7242 +  if (nsFrame::ShouldApplyOverflowClipping(this, disp)) {
  1.7243 +    // The contents are actually clipped to the padding area 
  1.7244 +    aOverflowAreas.SetAllTo(bounds);
  1.7245 +  }
  1.7246 +
  1.7247 +  // Overflow area must always include the frame's top-left and bottom-right,
  1.7248 +  // even if the frame rect is empty (so we can scroll to those positions).
  1.7249 +  // Pending a real fix for bug 426879, don't do this for inline frames
  1.7250 +  // with zero width.
  1.7251 +  // Do not do this for SVG either, since it will usually massively increase
  1.7252 +  // the area unnecessarily.
  1.7253 +  if ((aNewSize.width != 0 || !IsInlineFrame(this)) &&
  1.7254 +      !(GetStateBits() & NS_FRAME_SVG_LAYOUT)) {
  1.7255 +    NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
  1.7256 +      nsRect& o = aOverflowAreas.Overflow(otype);
  1.7257 +      o.UnionRectEdges(o, bounds);
  1.7258 +    }
  1.7259 +  }
  1.7260 +
  1.7261 +  // Note that NS_STYLE_OVERFLOW_CLIP doesn't clip the frame background,
  1.7262 +  // so we add theme background overflow here so it's not clipped.
  1.7263 +  if (!IsBoxWrapped() && IsThemed(disp)) {
  1.7264 +    nsRect r(bounds);
  1.7265 +    nsPresContext *presContext = PresContext();
  1.7266 +    if (presContext->GetTheme()->
  1.7267 +          GetWidgetOverflow(presContext->DeviceContext(), this,
  1.7268 +                            disp->mAppearance, &r)) {
  1.7269 +      nsRect& vo = aOverflowAreas.VisualOverflow();
  1.7270 +      vo.UnionRectEdges(vo, r);
  1.7271 +    }
  1.7272 +  }
  1.7273 +
  1.7274 +  ComputeAndIncludeOutlineArea(this, aOverflowAreas, aNewSize);
  1.7275 +
  1.7276 +  // Nothing in here should affect scrollable overflow.
  1.7277 +  aOverflowAreas.VisualOverflow() =
  1.7278 +    ComputeEffectsRect(this, aOverflowAreas.VisualOverflow(), aNewSize);
  1.7279 +
  1.7280 +  // Absolute position clipping
  1.7281 +  nsRect clipPropClipRect;
  1.7282 +  bool hasClipPropClip = GetClipPropClipRect(disp, &clipPropClipRect, aNewSize);
  1.7283 +  if (hasClipPropClip) {
  1.7284 +    NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
  1.7285 +      nsRect& o = aOverflowAreas.Overflow(otype);
  1.7286 +      o.IntersectRect(o, clipPropClipRect);
  1.7287 +    }
  1.7288 +  }
  1.7289 +
  1.7290 +  /* If we're transformed, transform the overflow rect by the current transformation. */
  1.7291 +  bool hasTransform = IsTransformed();
  1.7292 +  nsSize oldSize = aOldSize ? *aOldSize : mRect.Size();
  1.7293 +  bool sizeChanged = (oldSize != aNewSize);
  1.7294 +  if (hasTransform) {
  1.7295 +    Properties().Set(nsIFrame::PreTransformOverflowAreasProperty(),
  1.7296 +                     new nsOverflowAreas(aOverflowAreas));
  1.7297 +    /* Since our size might not actually have been computed yet, we need to make sure that we use the
  1.7298 +     * correct dimensions by overriding the stored bounding rectangle with the value the caller has
  1.7299 +     * ensured us we'll use.
  1.7300 +     */
  1.7301 +    nsRect newBounds(nsPoint(0, 0), aNewSize);
  1.7302 +    // Transform affects both overflow areas.
  1.7303 +    NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
  1.7304 +      nsRect& o = aOverflowAreas.Overflow(otype);
  1.7305 +      o = nsDisplayTransform::TransformRect(o, this, nsPoint(0, 0), &newBounds);
  1.7306 +    }
  1.7307 +    if (Preserves3DChildren()) {
  1.7308 +      ComputePreserve3DChildrenOverflow(aOverflowAreas, newBounds);
  1.7309 +    } else if (sizeChanged && ChildrenHavePerspective()) {
  1.7310 +      RecomputePerspectiveChildrenOverflow(this->StyleContext(), &newBounds);
  1.7311 +    }
  1.7312 +  } else {
  1.7313 +    Properties().Delete(nsIFrame::PreTransformOverflowAreasProperty());
  1.7314 +    if (ChildrenHavePerspective() && sizeChanged) {
  1.7315 +      nsRect newBounds(nsPoint(0, 0), aNewSize);
  1.7316 +      RecomputePerspectiveChildrenOverflow(this->StyleContext(), &newBounds);
  1.7317 +    }
  1.7318 +  }
  1.7319 +
  1.7320 +  bool anyOverflowChanged;
  1.7321 +  if (aOverflowAreas != nsOverflowAreas(bounds, bounds)) {
  1.7322 +    anyOverflowChanged = SetOverflowAreas(aOverflowAreas);
  1.7323 +  } else {
  1.7324 +    anyOverflowChanged = ClearOverflowRects();
  1.7325 +  }
  1.7326 +
  1.7327 +  if (anyOverflowChanged) {
  1.7328 +    nsSVGEffects::InvalidateDirectRenderingObservers(this);
  1.7329 +  }
  1.7330 +  return anyOverflowChanged;
  1.7331 +}
  1.7332 +
  1.7333 +void
  1.7334 +nsIFrame::RecomputePerspectiveChildrenOverflow(const nsStyleContext* aStartStyle, const nsRect* aBounds)
  1.7335 +{
  1.7336 +  // Children may check our size when getting our transform, make sure it's valid.
  1.7337 +  nsSize oldSize = GetSize();
  1.7338 +  if (aBounds) {
  1.7339 +    SetSize(aBounds->Size());
  1.7340 +  }
  1.7341 +  nsIFrame::ChildListIterator lists(this);
  1.7342 +  for (; !lists.IsDone(); lists.Next()) {
  1.7343 +    nsFrameList::Enumerator childFrames(lists.CurrentList());
  1.7344 +    for (; !childFrames.AtEnd(); childFrames.Next()) {
  1.7345 +      nsIFrame* child = childFrames.get();
  1.7346 +      if (!FrameMaintainsOverflow(child)) {
  1.7347 +        continue; // frame does not maintain overflow rects
  1.7348 +      }
  1.7349 +      if (child->HasPerspective()) {
  1.7350 +        nsOverflowAreas* overflow = 
  1.7351 +          static_cast<nsOverflowAreas*>(child->Properties().Get(nsIFrame::InitialOverflowProperty()));
  1.7352 +        nsRect bounds(nsPoint(0, 0), child->GetSize());
  1.7353 +        if (overflow) {
  1.7354 +          nsOverflowAreas overflowCopy = *overflow;
  1.7355 +          child->FinishAndStoreOverflow(overflowCopy, bounds.Size());
  1.7356 +        } else {
  1.7357 +          nsOverflowAreas boundsOverflow;
  1.7358 +          boundsOverflow.SetAllTo(bounds);
  1.7359 +          child->FinishAndStoreOverflow(boundsOverflow, bounds.Size());
  1.7360 +        }
  1.7361 +      } else if (child->StyleContext()->GetParent() == aStartStyle ||
  1.7362 +                 child->StyleContext() == aStartStyle) {
  1.7363 +        // If a frame is using perspective, then the size used to compute
  1.7364 +        // perspective-origin is the size of the frame belonging to its parent
  1.7365 +        // style context. We must find any descendant frames using our size
  1.7366 +        // (by recurse into frames with the same style context, or a direct
  1.7367 +        // child style context) to update their overflow rects too.
  1.7368 +        child->RecomputePerspectiveChildrenOverflow(aStartStyle, nullptr);
  1.7369 +      }
  1.7370 +    }
  1.7371 +  }
  1.7372 +  // Restore our old size just in case something depends on this elesewhere.
  1.7373 +  SetSize(oldSize);
  1.7374 +}
  1.7375 +
  1.7376 +/* The overflow rects for leaf nodes in a preserve-3d hierarchy depends on
  1.7377 + * the mRect value for their parents (since we use their transform, and transform
  1.7378 + * depends on this for transform-origin etc). These weren't necessarily correct
  1.7379 + * when we reflowed initially, so walk over all preserve-3d children and repeat the
  1.7380 + * overflow calculation.
  1.7381 + */
  1.7382 +static void
  1.7383 +RecomputePreserve3DChildrenOverflow(nsIFrame* aFrame, const nsRect* aBounds)
  1.7384 +{
  1.7385 +  // Children may check our size when getting our transform, make sure it's valid.
  1.7386 +  nsSize oldSize = aFrame->GetSize();
  1.7387 +  if (aBounds) {
  1.7388 +    aFrame->SetSize(aBounds->Size());
  1.7389 +  }
  1.7390 +  nsIFrame::ChildListIterator lists(aFrame);
  1.7391 +  for (; !lists.IsDone(); lists.Next()) {
  1.7392 +    nsFrameList::Enumerator childFrames(lists.CurrentList());
  1.7393 +    for (; !childFrames.AtEnd(); childFrames.Next()) {
  1.7394 +      nsIFrame* child = childFrames.get();
  1.7395 +      if (!FrameMaintainsOverflow(child)) {
  1.7396 +        continue; // frame does not maintain overflow rects
  1.7397 +      }
  1.7398 +      if (child->Preserves3DChildren()) {
  1.7399 +        RecomputePreserve3DChildrenOverflow(child, nullptr);
  1.7400 +      } else if (child->Preserves3D()) {
  1.7401 +        nsOverflowAreas* overflow = 
  1.7402 +          static_cast<nsOverflowAreas*>(child->Properties().Get(nsIFrame::InitialOverflowProperty()));
  1.7403 +        nsRect bounds(nsPoint(0, 0), child->GetSize());
  1.7404 +        if (overflow) {
  1.7405 +          nsOverflowAreas overflowCopy = *overflow;
  1.7406 +          child->FinishAndStoreOverflow(overflowCopy, bounds.Size());
  1.7407 +        } else {
  1.7408 +          nsOverflowAreas boundsOverflow;
  1.7409 +          boundsOverflow.SetAllTo(bounds);
  1.7410 +          child->FinishAndStoreOverflow(boundsOverflow, bounds.Size());
  1.7411 +        }
  1.7412 +      }
  1.7413 +    }
  1.7414 +  }
  1.7415 +  // Restore our old size just in case something depends on this elesewhere.
  1.7416 +  aFrame->SetSize(oldSize);
  1.7417 + 
  1.7418 +  // Only repeat computing our overflow in recursive calls since the initial caller is still
  1.7419 +  // in the middle of doing this and we don't want an infinite loop.
  1.7420 +  if (!aBounds) {
  1.7421 +    nsOverflowAreas* overflow = 
  1.7422 +      static_cast<nsOverflowAreas*>(aFrame->Properties().Get(nsIFrame::InitialOverflowProperty()));
  1.7423 +    nsRect bounds(nsPoint(0, 0), aFrame->GetSize());
  1.7424 +    if (overflow) {
  1.7425 +      nsOverflowAreas overflowCopy = *overflow;
  1.7426 +      overflowCopy.UnionAllWith(bounds); 
  1.7427 +      aFrame->FinishAndStoreOverflow(overflowCopy, bounds.Size());
  1.7428 +    } else {
  1.7429 +      nsOverflowAreas boundsOverflow;
  1.7430 +      boundsOverflow.SetAllTo(bounds);
  1.7431 +      aFrame->FinishAndStoreOverflow(boundsOverflow, bounds.Size());
  1.7432 +    }
  1.7433 +  }
  1.7434 +}
  1.7435 +
  1.7436 +void
  1.7437 +nsIFrame::ComputePreserve3DChildrenOverflow(nsOverflowAreas& aOverflowAreas, const nsRect& aBounds)
  1.7438 +{
  1.7439 +  // When we are preserving 3d we need to iterate over all children separately.
  1.7440 +  // If the child also preserves 3d then their overflow will already been in our
  1.7441 +  // coordinate space, otherwise we need to transform.
  1.7442 +
  1.7443 +  // If we're the top frame in a preserve 3d chain then we need to recalculate the overflow
  1.7444 +  // areas of all our children since they will have used our size/offset which was invalid at
  1.7445 +  // the time.
  1.7446 +  if (!Preserves3D()) {
  1.7447 +    RecomputePreserve3DChildrenOverflow(this, &aBounds);
  1.7448 +  }
  1.7449 +
  1.7450 +  nsRect childVisual;
  1.7451 +  nsRect childScrollable;
  1.7452 +  nsIFrame::ChildListIterator lists(this);
  1.7453 +  for (; !lists.IsDone(); lists.Next()) {
  1.7454 +    nsFrameList::Enumerator childFrames(lists.CurrentList());
  1.7455 +    for (; !childFrames.AtEnd(); childFrames.Next()) {
  1.7456 +      nsIFrame* child = childFrames.get();
  1.7457 +      nsPoint offset = child->GetPosition();
  1.7458 +      nsRect visual = child->GetVisualOverflowRect();
  1.7459 +      nsRect scrollable = child->GetScrollableOverflowRect();
  1.7460 +      visual.MoveBy(offset);
  1.7461 +      scrollable.MoveBy(offset);
  1.7462 +      if (child->Preserves3D()) {
  1.7463 +        childVisual = childVisual.Union(visual);
  1.7464 +        childScrollable = childScrollable.Union(scrollable);
  1.7465 +      } else {
  1.7466 +        childVisual = 
  1.7467 +          childVisual.Union(nsDisplayTransform::TransformRect(visual, 
  1.7468 +                            this, nsPoint(0,0), &aBounds));
  1.7469 +        childScrollable = 
  1.7470 +          childScrollable.Union(nsDisplayTransform::TransformRect(scrollable,
  1.7471 +                                this, nsPoint(0,0), &aBounds));
  1.7472 +      }
  1.7473 +    }
  1.7474 +  }
  1.7475 +
  1.7476 +  aOverflowAreas.Overflow(eVisualOverflow) = aOverflowAreas.Overflow(eVisualOverflow).Union(childVisual);
  1.7477 +  aOverflowAreas.Overflow(eScrollableOverflow) = aOverflowAreas.Overflow(eScrollableOverflow).Union(childScrollable);
  1.7478 +}
  1.7479 +
  1.7480 +void
  1.7481 +nsFrame::ConsiderChildOverflow(nsOverflowAreas& aOverflowAreas,
  1.7482 +                               nsIFrame* aChildFrame)
  1.7483 +{
  1.7484 +  aOverflowAreas.UnionWith(aChildFrame->GetOverflowAreas() +
  1.7485 +                           aChildFrame->GetPosition());
  1.7486 +}
  1.7487 +
  1.7488 +/**
  1.7489 + * This function takes a frame that is part of a block-in-inline split,
  1.7490 + * and _if_ that frame is an anonymous block created by an ib split it
  1.7491 + * returns the block's preceding inline.  This is needed because the
  1.7492 + * split inline's style context is the parent of the anonymous block's
  1.7493 + * style context.
  1.7494 + *
  1.7495 + * If aFrame is not an anonymous block, null is returned.
  1.7496 + */
  1.7497 +static nsIFrame*
  1.7498 +GetIBSplitSiblingForAnonymousBlock(const nsIFrame* aFrame)
  1.7499 +{
  1.7500 +  NS_PRECONDITION(aFrame, "Must have a non-null frame!");
  1.7501 +  NS_ASSERTION(aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT,
  1.7502 +               "GetIBSplitSibling should only be called on ib-split frames");
  1.7503 +
  1.7504 +  nsIAtom* type = aFrame->StyleContext()->GetPseudo();
  1.7505 +  if (type != nsCSSAnonBoxes::mozAnonymousBlock &&
  1.7506 +      type != nsCSSAnonBoxes::mozAnonymousPositionedBlock) {
  1.7507 +    // it's not an anonymous block
  1.7508 +    return nullptr;
  1.7509 +  }
  1.7510 +
  1.7511 +  // Find the first continuation of the frame.  (Ugh.  This ends up
  1.7512 +  // being O(N^2) when it is called O(N) times.)
  1.7513 +  aFrame = aFrame->FirstContinuation();
  1.7514 +
  1.7515 +  /*
  1.7516 +   * Now look up the nsGkAtoms::IBSplitPrevSibling
  1.7517 +   * property.
  1.7518 +   */
  1.7519 +  nsIFrame *ibSplitSibling = static_cast<nsIFrame*>
  1.7520 +    (aFrame->Properties().Get(nsIFrame::IBSplitPrevSibling()));
  1.7521 +  NS_ASSERTION(ibSplitSibling, "Broken frame tree?");
  1.7522 +  return ibSplitSibling;
  1.7523 +}
  1.7524 +
  1.7525 +/**
  1.7526 + * Get the parent, corrected for the mangled frame tree resulting from
  1.7527 + * having a block within an inline.  The result only differs from the
  1.7528 + * result of |GetParent| when |GetParent| returns an anonymous block
  1.7529 + * that was created for an element that was 'display: inline' because
  1.7530 + * that element contained a block.
  1.7531 + *
  1.7532 + * Also skip anonymous scrolled-content parents; inherit directly from the
  1.7533 + * outer scroll frame.
  1.7534 + */
  1.7535 +static nsIFrame*
  1.7536 +GetCorrectedParent(const nsIFrame* aFrame)
  1.7537 +{
  1.7538 +  nsIFrame *parent = aFrame->GetParent();
  1.7539 +  if (!parent) {
  1.7540 +    return nullptr;
  1.7541 +  }
  1.7542 +
  1.7543 +  // Outer tables are always anon boxes; if we're in here for an outer
  1.7544 +  // table, that actually means its the _inner_ table that wants to
  1.7545 +  // know its parent.  So get the pseudo of the inner in that case.
  1.7546 +  nsIAtom* pseudo = aFrame->StyleContext()->GetPseudo();
  1.7547 +  if (pseudo == nsCSSAnonBoxes::tableOuter) {
  1.7548 +    pseudo = aFrame->GetFirstPrincipalChild()->StyleContext()->GetPseudo();
  1.7549 +  }
  1.7550 +  return nsFrame::CorrectStyleParentFrame(parent, pseudo);
  1.7551 +}
  1.7552 +
  1.7553 +/* static */
  1.7554 +nsIFrame*
  1.7555 +nsFrame::CorrectStyleParentFrame(nsIFrame* aProspectiveParent,
  1.7556 +                                 nsIAtom* aChildPseudo)
  1.7557 +{
  1.7558 +  NS_PRECONDITION(aProspectiveParent, "Must have a prospective parent");
  1.7559 +
  1.7560 +  // Anon boxes are parented to their actual parent already, except
  1.7561 +  // for non-elements.  Those should not be treated as an anon box.
  1.7562 +  if (aChildPseudo && aChildPseudo != nsCSSAnonBoxes::mozNonElement &&
  1.7563 +      nsCSSAnonBoxes::IsAnonBox(aChildPseudo)) {
  1.7564 +    NS_ASSERTION(aChildPseudo != nsCSSAnonBoxes::mozAnonymousBlock &&
  1.7565 +                 aChildPseudo != nsCSSAnonBoxes::mozAnonymousPositionedBlock,
  1.7566 +                 "Should have dealt with kids that have "
  1.7567 +                 "NS_FRAME_PART_OF_IBSPLIT elsewhere");
  1.7568 +    return aProspectiveParent;
  1.7569 +  }
  1.7570 +
  1.7571 +  // Otherwise, walk up out of all anon boxes.  For placeholder frames, walk out
  1.7572 +  // of all pseudo-elements as well.  Otherwise ReparentStyleContext could cause
  1.7573 +  // style data to be out of sync with the frame tree.
  1.7574 +  nsIFrame* parent = aProspectiveParent;
  1.7575 +  do {
  1.7576 +    if (parent->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) {
  1.7577 +      nsIFrame* sibling = GetIBSplitSiblingForAnonymousBlock(parent);
  1.7578 +
  1.7579 +      if (sibling) {
  1.7580 +        // |parent| was a block in an {ib} split; use the inline as
  1.7581 +        // |the style parent.
  1.7582 +        parent = sibling;
  1.7583 +      }
  1.7584 +    }
  1.7585 +      
  1.7586 +    nsIAtom* parentPseudo = parent->StyleContext()->GetPseudo();
  1.7587 +    if (!parentPseudo ||
  1.7588 +        (!nsCSSAnonBoxes::IsAnonBox(parentPseudo) &&
  1.7589 +         // nsPlaceholderFrame pases in nsGkAtoms::placeholderFrame for
  1.7590 +         // aChildPseudo (even though that's not a valid pseudo-type) just to
  1.7591 +         // trigger this behavior of walking up to the nearest non-pseudo
  1.7592 +         // ancestor.
  1.7593 +         aChildPseudo != nsGkAtoms::placeholderFrame)) {
  1.7594 +      return parent;
  1.7595 +    }
  1.7596 +
  1.7597 +    parent = parent->GetParent();
  1.7598 +  } while (parent);
  1.7599 +
  1.7600 +  if (aProspectiveParent->StyleContext()->GetPseudo() ==
  1.7601 +      nsCSSAnonBoxes::viewportScroll) {
  1.7602 +    // aProspectiveParent is the scrollframe for a viewport
  1.7603 +    // and the kids are the anonymous scrollbars
  1.7604 +    return aProspectiveParent;
  1.7605 +  }
  1.7606 +
  1.7607 +  // We can get here if the root element is absolutely positioned.
  1.7608 +  // We can't test for this very accurately, but it can only happen
  1.7609 +  // when the prospective parent is a canvas frame.
  1.7610 +  NS_ASSERTION(aProspectiveParent->GetType() == nsGkAtoms::canvasFrame,
  1.7611 +               "Should have found a parent before this");
  1.7612 +  return nullptr;
  1.7613 +}
  1.7614 +
  1.7615 +nsIFrame*
  1.7616 +nsFrame::DoGetParentStyleContextFrame() const
  1.7617 +{
  1.7618 +  if (mContent && !mContent->GetParent() &&
  1.7619 +      !StyleContext()->GetPseudo()) {
  1.7620 +    // we're a frame for the root.  We have no style context parent.
  1.7621 +    return nullptr;
  1.7622 +  }
  1.7623 +  
  1.7624 +  if (!(mState & NS_FRAME_OUT_OF_FLOW)) {
  1.7625 +    /*
  1.7626 +     * If this frame is an anonymous block created when an inline with a block
  1.7627 +     * inside it got split, then the parent style context is on its preceding
  1.7628 +     * inline. We can get to it using GetIBSplitSiblingForAnonymousBlock.
  1.7629 +     */
  1.7630 +    if (mState & NS_FRAME_PART_OF_IBSPLIT) {
  1.7631 +      nsIFrame* ibSplitSibling = GetIBSplitSiblingForAnonymousBlock(this);
  1.7632 +      if (ibSplitSibling) {
  1.7633 +        return ibSplitSibling;
  1.7634 +      }
  1.7635 +    }
  1.7636 +
  1.7637 +    // If this frame is one of the blocks that split an inline, we must
  1.7638 +    // return the "special" inline parent, i.e., the parent that this
  1.7639 +    // frame would have if we didn't mangle the frame structure.
  1.7640 +    return GetCorrectedParent(this);
  1.7641 +  }
  1.7642 +
  1.7643 +  // We're an out-of-flow frame.  For out-of-flow frames, we must
  1.7644 +  // resolve underneath the placeholder's parent.  The placeholder is
  1.7645 +  // reached from the first-in-flow.
  1.7646 +  nsIFrame* placeholder = PresContext()->FrameManager()->
  1.7647 +                            GetPlaceholderFrameFor(FirstInFlow());
  1.7648 +  if (!placeholder) {
  1.7649 +    NS_NOTREACHED("no placeholder frame for out-of-flow frame");
  1.7650 +    return GetCorrectedParent(this);
  1.7651 +  }
  1.7652 +  return placeholder->GetParentStyleContextFrame();
  1.7653 +}
  1.7654 +
  1.7655 +void
  1.7656 +nsFrame::GetLastLeaf(nsPresContext* aPresContext, nsIFrame **aFrame)
  1.7657 +{
  1.7658 +  if (!aFrame || !*aFrame)
  1.7659 +    return;
  1.7660 +  nsIFrame *child = *aFrame;
  1.7661 +  //if we are a block frame then go for the last line of 'this'
  1.7662 +  while (1){
  1.7663 +    child = child->GetFirstPrincipalChild();
  1.7664 +    if (!child)
  1.7665 +      return;//nothing to do
  1.7666 +    nsIFrame* siblingFrame;
  1.7667 +    nsIContent* content;
  1.7668 +    //ignore anonymous elements, e.g. mozTableAdd* mozTableRemove*
  1.7669 +    //see bug 278197 comment #12 #13 for details
  1.7670 +    while ((siblingFrame = child->GetNextSibling()) &&
  1.7671 +           (content = siblingFrame->GetContent()) &&
  1.7672 +           !content->IsRootOfNativeAnonymousSubtree())
  1.7673 +      child = siblingFrame;
  1.7674 +    *aFrame = child;
  1.7675 +  }
  1.7676 +}
  1.7677 +
  1.7678 +void
  1.7679 +nsFrame::GetFirstLeaf(nsPresContext* aPresContext, nsIFrame **aFrame)
  1.7680 +{
  1.7681 +  if (!aFrame || !*aFrame)
  1.7682 +    return;
  1.7683 +  nsIFrame *child = *aFrame;
  1.7684 +  while (1){
  1.7685 +    child = child->GetFirstPrincipalChild();
  1.7686 +    if (!child)
  1.7687 +      return;//nothing to do
  1.7688 +    *aFrame = child;
  1.7689 +  }
  1.7690 +}
  1.7691 +
  1.7692 +/* virtual */ bool
  1.7693 +nsIFrame::IsFocusable(int32_t *aTabIndex, bool aWithMouse)
  1.7694 +{
  1.7695 +  int32_t tabIndex = -1;
  1.7696 +  if (aTabIndex) {
  1.7697 +    *aTabIndex = -1; // Default for early return is not focusable
  1.7698 +  }
  1.7699 +  bool isFocusable = false;
  1.7700 +
  1.7701 +  if (mContent && mContent->IsElement() && IsVisibleConsideringAncestors()) {
  1.7702 +    const nsStyleUserInterface* ui = StyleUserInterface();
  1.7703 +    if (ui->mUserFocus != NS_STYLE_USER_FOCUS_IGNORE &&
  1.7704 +        ui->mUserFocus != NS_STYLE_USER_FOCUS_NONE) {
  1.7705 +      // Pass in default tabindex of -1 for nonfocusable and 0 for focusable
  1.7706 +      tabIndex = 0;
  1.7707 +    }
  1.7708 +    isFocusable = mContent->IsFocusable(&tabIndex, aWithMouse);
  1.7709 +    if (!isFocusable && !aWithMouse &&
  1.7710 +        GetType() == nsGkAtoms::scrollFrame &&
  1.7711 +        mContent->IsHTML() &&
  1.7712 +        !mContent->IsRootOfNativeAnonymousSubtree() &&
  1.7713 +        mContent->GetParent() &&
  1.7714 +        !mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::tabindex)) {
  1.7715 +      // Elements with scrollable view are focusable with script & tabbable
  1.7716 +      // Otherwise you couldn't scroll them with keyboard, which is
  1.7717 +      // an accessibility issue (e.g. Section 508 rules)
  1.7718 +      // However, we don't make them to be focusable with the mouse,
  1.7719 +      // because the extra focus outlines are considered unnecessarily ugly.
  1.7720 +      // When clicked on, the selection position within the element 
  1.7721 +      // will be enough to make them keyboard scrollable.
  1.7722 +      nsIScrollableFrame *scrollFrame = do_QueryFrame(this);
  1.7723 +      if (scrollFrame &&
  1.7724 +          scrollFrame->GetScrollbarStyles() != ScrollbarStyles(NS_STYLE_OVERFLOW_HIDDEN, NS_STYLE_OVERFLOW_HIDDEN) &&
  1.7725 +          !scrollFrame->GetScrollRange().IsEqualEdges(nsRect(0, 0, 0, 0))) {
  1.7726 +          // Scroll bars will be used for overflow
  1.7727 +          isFocusable = true;
  1.7728 +          tabIndex = 0;
  1.7729 +      }
  1.7730 +    }
  1.7731 +  }
  1.7732 +
  1.7733 +  if (aTabIndex) {
  1.7734 +    *aTabIndex = tabIndex;
  1.7735 +  }
  1.7736 +  return isFocusable;
  1.7737 +}
  1.7738 +
  1.7739 +/**
  1.7740 + * @return true if this text frame ends with a newline character which is
  1.7741 + * treated as preformatted. It should return false if this is not a text frame.
  1.7742 + */
  1.7743 +bool
  1.7744 +nsIFrame::HasSignificantTerminalNewline() const
  1.7745 +{
  1.7746 +  return false;
  1.7747 +}
  1.7748 +
  1.7749 +static uint8_t
  1.7750 +ConvertSVGDominantBaselineToVerticalAlign(uint8_t aDominantBaseline)
  1.7751 +{
  1.7752 +  // Most of these are approximate mappings.
  1.7753 +  switch (aDominantBaseline) {
  1.7754 +  case NS_STYLE_DOMINANT_BASELINE_HANGING:
  1.7755 +  case NS_STYLE_DOMINANT_BASELINE_TEXT_BEFORE_EDGE:
  1.7756 +    return NS_STYLE_VERTICAL_ALIGN_TEXT_TOP;
  1.7757 +  case NS_STYLE_DOMINANT_BASELINE_TEXT_AFTER_EDGE:
  1.7758 +  case NS_STYLE_DOMINANT_BASELINE_IDEOGRAPHIC:
  1.7759 +    return NS_STYLE_VERTICAL_ALIGN_TEXT_BOTTOM;
  1.7760 +  case NS_STYLE_DOMINANT_BASELINE_CENTRAL:
  1.7761 +  case NS_STYLE_DOMINANT_BASELINE_MIDDLE:
  1.7762 +  case NS_STYLE_DOMINANT_BASELINE_MATHEMATICAL:
  1.7763 +    return NS_STYLE_VERTICAL_ALIGN_MIDDLE;
  1.7764 +  case NS_STYLE_DOMINANT_BASELINE_AUTO:
  1.7765 +  case NS_STYLE_DOMINANT_BASELINE_ALPHABETIC:
  1.7766 +    return NS_STYLE_VERTICAL_ALIGN_BASELINE;
  1.7767 +  case NS_STYLE_DOMINANT_BASELINE_USE_SCRIPT:
  1.7768 +  case NS_STYLE_DOMINANT_BASELINE_NO_CHANGE:
  1.7769 +  case NS_STYLE_DOMINANT_BASELINE_RESET_SIZE:
  1.7770 +    // These three should not simply map to 'baseline', but we don't
  1.7771 +    // support the complex baseline model that SVG 1.1 has and which
  1.7772 +    // css3-linebox now defines.
  1.7773 +    return NS_STYLE_VERTICAL_ALIGN_BASELINE;
  1.7774 +  default:
  1.7775 +    NS_NOTREACHED("unexpected aDominantBaseline value");
  1.7776 +    return NS_STYLE_VERTICAL_ALIGN_BASELINE;
  1.7777 +  }
  1.7778 +}
  1.7779 +
  1.7780 +uint8_t
  1.7781 +nsIFrame::VerticalAlignEnum() const
  1.7782 +{
  1.7783 +  if (IsSVGText()) {
  1.7784 +    uint8_t dominantBaseline;
  1.7785 +    for (const nsIFrame* frame = this; frame; frame = frame->GetParent()) {
  1.7786 +      dominantBaseline = frame->StyleSVGReset()->mDominantBaseline;
  1.7787 +      if (dominantBaseline != NS_STYLE_DOMINANT_BASELINE_AUTO ||
  1.7788 +          frame->GetType() == nsGkAtoms::svgTextFrame) {
  1.7789 +        break;
  1.7790 +      }
  1.7791 +    }
  1.7792 +    return ConvertSVGDominantBaselineToVerticalAlign(dominantBaseline);
  1.7793 +  }
  1.7794 +
  1.7795 +  const nsStyleCoord& verticalAlign = StyleTextReset()->mVerticalAlign;
  1.7796 +  if (verticalAlign.GetUnit() == eStyleUnit_Enumerated) {
  1.7797 +    return verticalAlign.GetIntValue();
  1.7798 +  }
  1.7799 +
  1.7800 +  return eInvalidVerticalAlign;
  1.7801 +}
  1.7802 +
  1.7803 +/* static */
  1.7804 +void nsFrame::FillCursorInformationFromStyle(const nsStyleUserInterface* ui,
  1.7805 +                                             nsIFrame::Cursor& aCursor)
  1.7806 +{
  1.7807 +  aCursor.mCursor = ui->mCursor;
  1.7808 +  aCursor.mHaveHotspot = false;
  1.7809 +  aCursor.mHotspotX = aCursor.mHotspotY = 0.0f;
  1.7810 +
  1.7811 +  for (nsCursorImage *item = ui->mCursorArray,
  1.7812 +                 *item_end = ui->mCursorArray + ui->mCursorArrayLength;
  1.7813 +       item < item_end; ++item) {
  1.7814 +    uint32_t status;
  1.7815 +    nsresult rv = item->GetImage()->GetImageStatus(&status);
  1.7816 +    if (NS_SUCCEEDED(rv) && (status & imgIRequest::STATUS_LOAD_COMPLETE)) {
  1.7817 +      // This is the one we want
  1.7818 +      item->GetImage()->GetImage(getter_AddRefs(aCursor.mContainer));
  1.7819 +      aCursor.mHaveHotspot = item->mHaveHotspot;
  1.7820 +      aCursor.mHotspotX = item->mHotspotX;
  1.7821 +      aCursor.mHotspotY = item->mHotspotY;
  1.7822 +      break;
  1.7823 +    }
  1.7824 +  }
  1.7825 +}
  1.7826 +
  1.7827 +NS_IMETHODIMP
  1.7828 +nsFrame::RefreshSizeCache(nsBoxLayoutState& aState)
  1.7829 +{
  1.7830 +  // XXXbz this comment needs some rewriting to make sense in the
  1.7831 +  // post-reflow-branch world.
  1.7832 +  
  1.7833 +  // Ok we need to compute our minimum, preferred, and maximum sizes.
  1.7834 +  // 1) Maximum size. This is easy. Its infinite unless it is overloaded by CSS.
  1.7835 +  // 2) Preferred size. This is a little harder. This is the size the block would be 
  1.7836 +  //      if it were laid out on an infinite canvas. So we can get this by reflowing
  1.7837 +  //      the block with and INTRINSIC width and height. We can also do a nice optimization
  1.7838 +  //      for incremental reflow. If the reflow is incremental then we can pass a flag to 
  1.7839 +  //      have the block compute the preferred width for us! Preferred height can just be
  1.7840 +  //      the minimum height;
  1.7841 +  // 3) Minimum size. This is a toughy. We can pass the block a flag asking for the max element
  1.7842 +  //    size. That would give us the width. Unfortunately you can only ask for a maxElementSize
  1.7843 +  //    during an incremental reflow. So on other reflows we will just have to use 0.
  1.7844 +  //    The min height on the other hand is fairly easy we need to get the largest
  1.7845 +  //    line height. This can be done with the line iterator.
  1.7846 +
  1.7847 +  // if we do have a rendering context
  1.7848 +  nsresult rv = NS_OK;
  1.7849 +  nsRenderingContext* rendContext = aState.GetRenderingContext();
  1.7850 +  if (rendContext) {
  1.7851 +    nsPresContext* presContext = aState.PresContext();
  1.7852 +
  1.7853 +    // If we don't have any HTML constraints and it's a resize, then nothing in the block
  1.7854 +    // could have changed, so no refresh is necessary.
  1.7855 +    nsBoxLayoutMetrics* metrics = BoxMetrics();
  1.7856 +    if (!DoesNeedRecalc(metrics->mBlockPrefSize))
  1.7857 +      return NS_OK;
  1.7858 +
  1.7859 +    // the rect we plan to size to.
  1.7860 +    nsRect rect = GetRect();
  1.7861 +
  1.7862 +    nsMargin bp(0,0,0,0);
  1.7863 +    GetBorderAndPadding(bp);
  1.7864 +
  1.7865 +    {
  1.7866 +      // If we're a container for font size inflation, then shrink
  1.7867 +      // wrapping inside of us should not apply font size inflation.
  1.7868 +      AutoMaybeDisableFontInflation an(this);
  1.7869 +
  1.7870 +      metrics->mBlockPrefSize.width =
  1.7871 +        GetPrefWidth(rendContext) + bp.LeftRight();
  1.7872 +      metrics->mBlockMinSize.width =
  1.7873 +        GetMinWidth(rendContext) + bp.LeftRight();
  1.7874 +    }
  1.7875 +
  1.7876 +    // do the nasty.
  1.7877 +    const WritingMode wm = aState.OuterReflowState() ?
  1.7878 +      aState.OuterReflowState()->GetWritingMode() : GetWritingMode();
  1.7879 +    nsHTMLReflowMetrics desiredSize(wm);
  1.7880 +    rv = BoxReflow(aState, presContext, desiredSize, rendContext,
  1.7881 +                   rect.x, rect.y,
  1.7882 +                   metrics->mBlockPrefSize.width, NS_UNCONSTRAINEDSIZE);
  1.7883 +
  1.7884 +    metrics->mBlockMinSize.height = 0;
  1.7885 +    // ok we need the max ascent of the items on the line. So to do this
  1.7886 +    // ask the block for its line iterator. Get the max ascent.
  1.7887 +    nsAutoLineIterator lines = GetLineIterator();
  1.7888 +    if (lines) 
  1.7889 +    {
  1.7890 +      metrics->mBlockMinSize.height = 0;
  1.7891 +      int count = 0;
  1.7892 +      nsIFrame* firstFrame = nullptr;
  1.7893 +      int32_t framesOnLine;
  1.7894 +      nsRect lineBounds;
  1.7895 +      uint32_t lineFlags;
  1.7896 +
  1.7897 +      do {
  1.7898 +         lines->GetLine(count, &firstFrame, &framesOnLine, lineBounds, &lineFlags);
  1.7899 +
  1.7900 +         if (lineBounds.height > metrics->mBlockMinSize.height)
  1.7901 +           metrics->mBlockMinSize.height = lineBounds.height;
  1.7902 +
  1.7903 +         count++;
  1.7904 +      } while(firstFrame);
  1.7905 +    } else {
  1.7906 +      metrics->mBlockMinSize.height = desiredSize.Height();
  1.7907 +    }
  1.7908 +
  1.7909 +    metrics->mBlockPrefSize.height = metrics->mBlockMinSize.height;
  1.7910 +
  1.7911 +    if (desiredSize.TopAscent() == nsHTMLReflowMetrics::ASK_FOR_BASELINE) {
  1.7912 +      if (!nsLayoutUtils::GetFirstLineBaseline(this, &metrics->mBlockAscent))
  1.7913 +        metrics->mBlockAscent = GetBaseline();
  1.7914 +    } else {
  1.7915 +      metrics->mBlockAscent = desiredSize.TopAscent();
  1.7916 +    }
  1.7917 +
  1.7918 +#ifdef DEBUG_adaptor
  1.7919 +    printf("min=(%d,%d), pref=(%d,%d), ascent=%d\n", metrics->mBlockMinSize.width,
  1.7920 +                                                     metrics->mBlockMinSize.height,
  1.7921 +                                                     metrics->mBlockPrefSize.width,
  1.7922 +                                                     metrics->mBlockPrefSize.height,
  1.7923 +                                                     metrics->mBlockAscent);
  1.7924 +#endif
  1.7925 +  }
  1.7926 +
  1.7927 +  return rv;
  1.7928 +}
  1.7929 +
  1.7930 +/* virtual */ nsILineIterator*
  1.7931 +nsFrame::GetLineIterator()
  1.7932 +{
  1.7933 +  return nullptr;
  1.7934 +}
  1.7935 +
  1.7936 +nsSize
  1.7937 +nsFrame::GetPrefSize(nsBoxLayoutState& aState)
  1.7938 +{
  1.7939 +  nsSize size(0,0);
  1.7940 +  DISPLAY_PREF_SIZE(this, size);
  1.7941 +  // If the size is cached, and there are no HTML constraints that we might
  1.7942 +  // be depending on, then we just return the cached size.
  1.7943 +  nsBoxLayoutMetrics *metrics = BoxMetrics();
  1.7944 +  if (!DoesNeedRecalc(metrics->mPrefSize)) {
  1.7945 +    return metrics->mPrefSize;
  1.7946 +  }
  1.7947 +
  1.7948 +  if (IsCollapsed())
  1.7949 +    return size;
  1.7950 +
  1.7951 +  // get our size in CSS.
  1.7952 +  bool widthSet, heightSet;
  1.7953 +  bool completelyRedefined = nsIFrame::AddCSSPrefSize(this, size, widthSet, heightSet);
  1.7954 +
  1.7955 +  // Refresh our caches with new sizes.
  1.7956 +  if (!completelyRedefined) {
  1.7957 +    RefreshSizeCache(aState);
  1.7958 +    nsSize blockSize = metrics->mBlockPrefSize;
  1.7959 +
  1.7960 +    // notice we don't need to add our borders or padding
  1.7961 +    // in. That's because the block did it for us.
  1.7962 +    if (!widthSet)
  1.7963 +      size.width = blockSize.width;
  1.7964 +    if (!heightSet)
  1.7965 +      size.height = blockSize.height;
  1.7966 +  }
  1.7967 +
  1.7968 +  metrics->mPrefSize = size;
  1.7969 +  return size;
  1.7970 +}
  1.7971 +
  1.7972 +nsSize
  1.7973 +nsFrame::GetMinSize(nsBoxLayoutState& aState)
  1.7974 +{
  1.7975 +  nsSize size(0,0);
  1.7976 +  DISPLAY_MIN_SIZE(this, size);
  1.7977 +  // Don't use the cache if we have HTMLReflowState constraints --- they might have changed
  1.7978 +  nsBoxLayoutMetrics *metrics = BoxMetrics();
  1.7979 +  if (!DoesNeedRecalc(metrics->mMinSize)) {
  1.7980 +    size = metrics->mMinSize;
  1.7981 +    return size;
  1.7982 +  }
  1.7983 +
  1.7984 +  if (IsCollapsed())
  1.7985 +    return size;
  1.7986 +
  1.7987 +  // get our size in CSS.
  1.7988 +  bool widthSet, heightSet;
  1.7989 +  bool completelyRedefined =
  1.7990 +    nsIFrame::AddCSSMinSize(aState, this, size, widthSet, heightSet);
  1.7991 +
  1.7992 +  // Refresh our caches with new sizes.
  1.7993 +  if (!completelyRedefined) {
  1.7994 +    RefreshSizeCache(aState);
  1.7995 +    nsSize blockSize = metrics->mBlockMinSize;
  1.7996 +
  1.7997 +    if (!widthSet)
  1.7998 +      size.width = blockSize.width;
  1.7999 +    if (!heightSet)
  1.8000 +      size.height = blockSize.height;
  1.8001 +  }
  1.8002 +
  1.8003 +  metrics->mMinSize = size;
  1.8004 +  return size;
  1.8005 +}
  1.8006 +
  1.8007 +nsSize
  1.8008 +nsFrame::GetMaxSize(nsBoxLayoutState& aState)
  1.8009 +{
  1.8010 +  nsSize size(NS_INTRINSICSIZE, NS_INTRINSICSIZE);
  1.8011 +  DISPLAY_MAX_SIZE(this, size);
  1.8012 +  // Don't use the cache if we have HTMLReflowState constraints --- they might have changed
  1.8013 +  nsBoxLayoutMetrics *metrics = BoxMetrics();
  1.8014 +  if (!DoesNeedRecalc(metrics->mMaxSize)) {
  1.8015 +    size = metrics->mMaxSize;
  1.8016 +    return size;
  1.8017 +  }
  1.8018 +
  1.8019 +  if (IsCollapsed())
  1.8020 +    return size;
  1.8021 +
  1.8022 +  size = nsBox::GetMaxSize(aState);
  1.8023 +  metrics->mMaxSize = size;
  1.8024 +
  1.8025 +  return size;
  1.8026 +}
  1.8027 +
  1.8028 +nscoord
  1.8029 +nsFrame::GetFlex(nsBoxLayoutState& aState)
  1.8030 +{
  1.8031 +  nsBoxLayoutMetrics *metrics = BoxMetrics();
  1.8032 +  if (!DoesNeedRecalc(metrics->mFlex))
  1.8033 +     return metrics->mFlex;
  1.8034 +
  1.8035 +  metrics->mFlex = nsBox::GetFlex(aState);
  1.8036 +
  1.8037 +  return metrics->mFlex;
  1.8038 +}
  1.8039 +
  1.8040 +nscoord
  1.8041 +nsFrame::GetBoxAscent(nsBoxLayoutState& aState)
  1.8042 +{
  1.8043 +  nsBoxLayoutMetrics *metrics = BoxMetrics();
  1.8044 +  if (!DoesNeedRecalc(metrics->mAscent))
  1.8045 +    return metrics->mAscent;
  1.8046 +
  1.8047 +  if (IsCollapsed()) {
  1.8048 +    metrics->mAscent = 0;
  1.8049 +  } else {
  1.8050 +    // Refresh our caches with new sizes.
  1.8051 +    RefreshSizeCache(aState);
  1.8052 +    metrics->mAscent = metrics->mBlockAscent;
  1.8053 +  }
  1.8054 +
  1.8055 +  return metrics->mAscent;
  1.8056 +}
  1.8057 +
  1.8058 +nsresult
  1.8059 +nsFrame::DoLayout(nsBoxLayoutState& aState)
  1.8060 +{
  1.8061 +  nsRect ourRect(mRect);
  1.8062 +
  1.8063 +  nsRenderingContext* rendContext = aState.GetRenderingContext();
  1.8064 +  nsPresContext* presContext = aState.PresContext();
  1.8065 +  const WritingMode wm = aState.OuterReflowState() ?
  1.8066 +    aState.OuterReflowState()->GetWritingMode() : GetWritingMode();
  1.8067 +  nsHTMLReflowMetrics desiredSize(wm);
  1.8068 +  nsresult rv = NS_OK;
  1.8069 + 
  1.8070 +  if (rendContext) {
  1.8071 +
  1.8072 +    rv = BoxReflow(aState, presContext, desiredSize, rendContext,
  1.8073 +                   ourRect.x, ourRect.y, ourRect.width, ourRect.height);
  1.8074 +
  1.8075 +    if (IsCollapsed()) {
  1.8076 +      SetSize(nsSize(0, 0));
  1.8077 +    } else {
  1.8078 +
  1.8079 +      // if our child needs to be bigger. This might happend with
  1.8080 +      // wrapping text. There is no way to predict its height until we
  1.8081 +      // reflow it. Now that we know the height reshuffle upward.
  1.8082 +      if (desiredSize.Width() > ourRect.width ||
  1.8083 +          desiredSize.Height() > ourRect.height) {
  1.8084 +
  1.8085 +#ifdef DEBUG_GROW
  1.8086 +        DumpBox(stdout);
  1.8087 +        printf(" GREW from (%d,%d) -> (%d,%d)\n",
  1.8088 +               ourRect.width, ourRect.height,
  1.8089 +               desiredSize.Width(), desiredSize.Height());
  1.8090 +#endif
  1.8091 +
  1.8092 +        if (desiredSize.Width() > ourRect.width)
  1.8093 +          ourRect.width = desiredSize.Width();
  1.8094 +
  1.8095 +        if (desiredSize.Height() > ourRect.height)
  1.8096 +          ourRect.height = desiredSize.Height();
  1.8097 +      }
  1.8098 +
  1.8099 +      // ensure our size is what we think is should be. Someone could have
  1.8100 +      // reset the frame to be smaller or something dumb like that. 
  1.8101 +      SetSize(ourRect.Size());
  1.8102 +    }
  1.8103 +  }
  1.8104 +
  1.8105 +  // Should we do this if IsCollapsed() is true?
  1.8106 +  nsSize size(GetSize());
  1.8107 +  desiredSize.Width() = size.width;
  1.8108 +  desiredSize.Height() = size.height;
  1.8109 +  desiredSize.UnionOverflowAreasWithDesiredBounds();
  1.8110 +
  1.8111 +  if (HasAbsolutelyPositionedChildren()) {
  1.8112 +    // Set up a |reflowState| to pass into ReflowAbsoluteFrames
  1.8113 +    nsHTMLReflowState reflowState(aState.PresContext(), this,
  1.8114 +                                  aState.GetRenderingContext(),
  1.8115 +                                  nsSize(size.width, NS_UNCONSTRAINEDSIZE),
  1.8116 +                                  nsHTMLReflowState::DUMMY_PARENT_REFLOW_STATE);
  1.8117 +
  1.8118 +    AddStateBits(NS_FRAME_IN_REFLOW);
  1.8119 +    // Set up a |reflowStatus| to pass into ReflowAbsoluteFrames
  1.8120 +    // (just a dummy value; hopefully that's OK)
  1.8121 +    nsReflowStatus reflowStatus = NS_FRAME_COMPLETE;
  1.8122 +    ReflowAbsoluteFrames(aState.PresContext(), desiredSize,
  1.8123 +                         reflowState, reflowStatus);
  1.8124 +    RemoveStateBits(NS_FRAME_IN_REFLOW);
  1.8125 +  }
  1.8126 +
  1.8127 +  nsSize oldSize(ourRect.Size());
  1.8128 +  FinishAndStoreOverflow(desiredSize.mOverflowAreas, size, &oldSize);
  1.8129 +
  1.8130 +  SyncLayout(aState);
  1.8131 +
  1.8132 +  return rv;
  1.8133 +}
  1.8134 +
  1.8135 +nsresult
  1.8136 +nsFrame::BoxReflow(nsBoxLayoutState&        aState,
  1.8137 +                   nsPresContext*           aPresContext,
  1.8138 +                   nsHTMLReflowMetrics&     aDesiredSize,
  1.8139 +                   nsRenderingContext*     aRenderingContext,
  1.8140 +                   nscoord                  aX,
  1.8141 +                   nscoord                  aY,
  1.8142 +                   nscoord                  aWidth,
  1.8143 +                   nscoord                  aHeight,
  1.8144 +                   bool                     aMoveFrame)
  1.8145 +{
  1.8146 +  DO_GLOBAL_REFLOW_COUNT("nsBoxToBlockAdaptor");
  1.8147 +
  1.8148 +#ifdef DEBUG_REFLOW
  1.8149 +  nsAdaptorAddIndents();
  1.8150 +  printf("Reflowing: ");
  1.8151 +  nsFrame::ListTag(stdout, mFrame);
  1.8152 +  printf("\n");
  1.8153 +  gIndent2++;
  1.8154 +#endif
  1.8155 +
  1.8156 +  nsBoxLayoutMetrics *metrics = BoxMetrics();
  1.8157 +  nsReflowStatus status = NS_FRAME_COMPLETE;
  1.8158 +
  1.8159 +  bool needsReflow = NS_SUBTREE_DIRTY(this);
  1.8160 +
  1.8161 +  // if we don't need a reflow then 
  1.8162 +  // lets see if we are already that size. Yes? then don't even reflow. We are done.
  1.8163 +  if (!needsReflow) {
  1.8164 +      
  1.8165 +      if (aWidth != NS_INTRINSICSIZE && aHeight != NS_INTRINSICSIZE) {
  1.8166 +      
  1.8167 +          // if the new calculated size has a 0 width or a 0 height
  1.8168 +          if ((metrics->mLastSize.width == 0 || metrics->mLastSize.height == 0) && (aWidth == 0 || aHeight == 0)) {
  1.8169 +               needsReflow = false;
  1.8170 +               aDesiredSize.Width() = aWidth; 
  1.8171 +               aDesiredSize.Height() = aHeight; 
  1.8172 +               SetSize(nsSize(aDesiredSize.Width(), aDesiredSize.Height()));
  1.8173 +          } else {
  1.8174 +            aDesiredSize.Width() = metrics->mLastSize.width;
  1.8175 +            aDesiredSize.Height() = metrics->mLastSize.height;
  1.8176 +
  1.8177 +            // remove the margin. The rect of our child does not include it but our calculated size does.
  1.8178 +            // don't reflow if we are already the right size
  1.8179 +            if (metrics->mLastSize.width == aWidth && metrics->mLastSize.height == aHeight)
  1.8180 +                  needsReflow = false;
  1.8181 +            else
  1.8182 +                  needsReflow = true;
  1.8183 +   
  1.8184 +          }
  1.8185 +      } else {
  1.8186 +          // if the width or height are intrinsic alway reflow because
  1.8187 +          // we don't know what it should be.
  1.8188 +         needsReflow = true;
  1.8189 +      }
  1.8190 +  }
  1.8191 +                             
  1.8192 +  // ok now reflow the child into the spacers calculated space
  1.8193 +  if (needsReflow) {
  1.8194 +
  1.8195 +    aDesiredSize.Width() = 0;
  1.8196 +    aDesiredSize.Height() = 0;
  1.8197 +
  1.8198 +    // create a reflow state to tell our child to flow at the given size.
  1.8199 +
  1.8200 +    // Construct a bogus parent reflow state so that there's a usable
  1.8201 +    // containing block reflow state.
  1.8202 +    nsMargin margin(0,0,0,0);
  1.8203 +    GetMargin(margin);
  1.8204 +
  1.8205 +    nsSize parentSize(aWidth, aHeight);
  1.8206 +    if (parentSize.height != NS_INTRINSICSIZE)
  1.8207 +      parentSize.height += margin.TopBottom();
  1.8208 +    if (parentSize.width != NS_INTRINSICSIZE)
  1.8209 +      parentSize.width += margin.LeftRight();
  1.8210 +
  1.8211 +    nsIFrame *parentFrame = GetParent();
  1.8212 +    nsFrameState savedState = parentFrame->GetStateBits();
  1.8213 +    nsHTMLReflowState parentReflowState(aPresContext, parentFrame,
  1.8214 +                                        aRenderingContext,
  1.8215 +                                        parentSize,
  1.8216 +                                        nsHTMLReflowState::DUMMY_PARENT_REFLOW_STATE);
  1.8217 +    parentFrame->RemoveStateBits(~nsFrameState(0));
  1.8218 +    parentFrame->AddStateBits(savedState);
  1.8219 +
  1.8220 +    // This may not do very much useful, but it's probably worth trying.
  1.8221 +    if (parentSize.width != NS_INTRINSICSIZE)
  1.8222 +      parentReflowState.SetComputedWidth(std::max(parentSize.width, 0));
  1.8223 +    if (parentSize.height != NS_INTRINSICSIZE)
  1.8224 +      parentReflowState.SetComputedHeight(std::max(parentSize.height, 0));
  1.8225 +    parentReflowState.ComputedPhysicalMargin().SizeTo(0, 0, 0, 0);
  1.8226 +    // XXX use box methods
  1.8227 +    parentFrame->GetPadding(parentReflowState.ComputedPhysicalPadding());
  1.8228 +    parentFrame->GetBorder(parentReflowState.ComputedPhysicalBorderPadding());
  1.8229 +    parentReflowState.ComputedPhysicalBorderPadding() +=
  1.8230 +      parentReflowState.ComputedPhysicalPadding();
  1.8231 +
  1.8232 +    // Construct the parent chain manually since constructing it normally
  1.8233 +    // messes up dimensions.
  1.8234 +    const nsHTMLReflowState *outerReflowState = aState.OuterReflowState();
  1.8235 +    NS_ASSERTION(!outerReflowState || outerReflowState->frame != this,
  1.8236 +                 "in and out of XUL on a single frame?");
  1.8237 +    const nsHTMLReflowState* parentRS;
  1.8238 +    if (outerReflowState && outerReflowState->frame == parentFrame) {
  1.8239 +      // We're a frame (such as a text control frame) that jumps into
  1.8240 +      // box reflow and then straight out of it on the child frame.
  1.8241 +      // This means we actually have a real parent reflow state.
  1.8242 +      // nsLayoutUtils::InflationMinFontSizeFor used to need this to be
  1.8243 +      // linked up correctly for text control frames, so do so here).
  1.8244 +      parentRS = outerReflowState;
  1.8245 +    } else {
  1.8246 +      parentRS = &parentReflowState;
  1.8247 +    }
  1.8248 +
  1.8249 +    // XXX Is it OK that this reflow state has only one ancestor?
  1.8250 +    // (It used to have a bogus parent, skipping all the boxes).
  1.8251 +    nsSize availSize(aWidth, NS_INTRINSICSIZE);
  1.8252 +    nsHTMLReflowState reflowState(aPresContext, *parentRS, this,
  1.8253 +                                  availSize, -1, -1,
  1.8254 +                                  nsHTMLReflowState::DUMMY_PARENT_REFLOW_STATE);
  1.8255 +
  1.8256 +    // XXX_jwir3: This is somewhat fishy. If this is actually changing the value
  1.8257 +    //            here (which it might be), then we should make sure that it's
  1.8258 +    //            correct the first time around, rather than changing it later.
  1.8259 +    reflowState.mCBReflowState = parentRS;
  1.8260 +
  1.8261 +    reflowState.mReflowDepth = aState.GetReflowDepth();
  1.8262 +
  1.8263 +    // mComputedWidth and mComputedHeight are content-box, not
  1.8264 +    // border-box
  1.8265 +    if (aWidth != NS_INTRINSICSIZE) {
  1.8266 +      nscoord computedWidth =
  1.8267 +        aWidth - reflowState.ComputedPhysicalBorderPadding().LeftRight();
  1.8268 +      computedWidth = std::max(computedWidth, 0);
  1.8269 +      reflowState.SetComputedWidth(computedWidth);
  1.8270 +    }
  1.8271 +
  1.8272 +    // Most child frames of box frames (e.g. subdocument or scroll frames)
  1.8273 +    // need to be constrained to the provided size and overflow as necessary.
  1.8274 +    // The one exception are block frames, because we need to know their
  1.8275 +    // natural height excluding any overflow area which may be caused by
  1.8276 +    // various CSS effects such as shadow or outline.
  1.8277 +    if (!IsFrameOfType(eBlockFrame)) {
  1.8278 +      if (aHeight != NS_INTRINSICSIZE) {
  1.8279 +        nscoord computedHeight =
  1.8280 +          aHeight - reflowState.ComputedPhysicalBorderPadding().TopBottom();
  1.8281 +        computedHeight = std::max(computedHeight, 0);
  1.8282 +        reflowState.SetComputedHeight(computedHeight);
  1.8283 +      } else {
  1.8284 +        reflowState.SetComputedHeight(
  1.8285 +          ComputeSize(aRenderingContext, availSize, availSize.width,
  1.8286 +                      nsSize(reflowState.ComputedPhysicalMargin().LeftRight(),
  1.8287 +                             reflowState.ComputedPhysicalMargin().TopBottom()),
  1.8288 +                      nsSize(reflowState.ComputedPhysicalBorderPadding().LeftRight() -
  1.8289 +                               reflowState.ComputedPhysicalPadding().LeftRight(),
  1.8290 +                             reflowState.ComputedPhysicalBorderPadding().TopBottom() -
  1.8291 +                               reflowState.ComputedPhysicalPadding().TopBottom()),
  1.8292 +                      nsSize(reflowState.ComputedPhysicalPadding().LeftRight(),
  1.8293 +                               reflowState.ComputedPhysicalPadding().TopBottom()),
  1.8294 +                      false).height
  1.8295 +          );
  1.8296 +      }
  1.8297 +    }
  1.8298 +
  1.8299 +    // Box layout calls SetRect before Layout, whereas non-box layout
  1.8300 +    // calls SetRect after Reflow.
  1.8301 +    // XXX Perhaps we should be doing this by twiddling the rect back to
  1.8302 +    // mLastSize before calling Reflow and then switching it back, but
  1.8303 +    // However, mLastSize can also be the size passed to BoxReflow by
  1.8304 +    // RefreshSizeCache, so that doesn't really make sense.
  1.8305 +    if (metrics->mLastSize.width != aWidth) {
  1.8306 +      reflowState.mFlags.mHResize = true;
  1.8307 +
  1.8308 +      // When font size inflation is enabled, a horizontal resize
  1.8309 +      // requires a full reflow.  See nsHTMLReflowState::InitResizeFlags
  1.8310 +      // for more details.
  1.8311 +      if (nsLayoutUtils::FontSizeInflationEnabled(aPresContext)) {
  1.8312 +        AddStateBits(NS_FRAME_IS_DIRTY);
  1.8313 +      }
  1.8314 +    }
  1.8315 +    if (metrics->mLastSize.height != aHeight)
  1.8316 +      reflowState.mFlags.mVResize = true;
  1.8317 +
  1.8318 +    #ifdef DEBUG_REFLOW
  1.8319 +      nsAdaptorAddIndents();
  1.8320 +      printf("Size=(%d,%d)\n",reflowState.ComputedWidth(),
  1.8321 +             reflowState.ComputedHeight());
  1.8322 +      nsAdaptorAddIndents();
  1.8323 +      nsAdaptorPrintReason(reflowState);
  1.8324 +      printf("\n");
  1.8325 +    #endif
  1.8326 +
  1.8327 +       // place the child and reflow
  1.8328 +    WillReflow(aPresContext);
  1.8329 +
  1.8330 +    Reflow(aPresContext, aDesiredSize, reflowState, status);
  1.8331 +
  1.8332 +    NS_ASSERTION(NS_FRAME_IS_COMPLETE(status), "bad status");
  1.8333 +
  1.8334 +    uint32_t layoutFlags = aState.LayoutFlags();
  1.8335 +    nsContainerFrame::FinishReflowChild(this, aPresContext, aDesiredSize,
  1.8336 +                                        &reflowState, aX, aY, layoutFlags | NS_FRAME_NO_MOVE_FRAME);
  1.8337 +
  1.8338 +    // Save the ascent.  (bug 103925)
  1.8339 +    if (IsCollapsed()) {
  1.8340 +      metrics->mAscent = 0;
  1.8341 +    } else {
  1.8342 +      if (aDesiredSize.TopAscent() == nsHTMLReflowMetrics::ASK_FOR_BASELINE) {
  1.8343 +        if (!nsLayoutUtils::GetFirstLineBaseline(this, &metrics->mAscent))
  1.8344 +          metrics->mAscent = GetBaseline();
  1.8345 +      } else
  1.8346 +        metrics->mAscent = aDesiredSize.TopAscent();
  1.8347 +    }
  1.8348 +
  1.8349 +  } else {
  1.8350 +    aDesiredSize.SetTopAscent(metrics->mBlockAscent);
  1.8351 +  }
  1.8352 +
  1.8353 +#ifdef DEBUG_REFLOW
  1.8354 +  if (aHeight != NS_INTRINSICSIZE && aDesiredSize.Height() != aHeight)
  1.8355 +  {
  1.8356 +          nsAdaptorAddIndents();
  1.8357 +          printf("*****got taller!*****\n");
  1.8358 +         
  1.8359 +  }
  1.8360 +  if (aWidth != NS_INTRINSICSIZE && aDesiredSize.Width() != aWidth)
  1.8361 +  {
  1.8362 +          nsAdaptorAddIndents();
  1.8363 +          printf("*****got wider!******\n");
  1.8364 +         
  1.8365 +  }
  1.8366 +#endif
  1.8367 +
  1.8368 +  if (aWidth == NS_INTRINSICSIZE)
  1.8369 +     aWidth = aDesiredSize.Width();
  1.8370 +
  1.8371 +  if (aHeight == NS_INTRINSICSIZE)
  1.8372 +     aHeight = aDesiredSize.Height();
  1.8373 +
  1.8374 +  metrics->mLastSize.width = aDesiredSize.Width();
  1.8375 +  metrics->mLastSize.height = aDesiredSize.Height();
  1.8376 +
  1.8377 +#ifdef DEBUG_REFLOW
  1.8378 +  gIndent2--;
  1.8379 +#endif
  1.8380 +
  1.8381 +  return NS_OK;
  1.8382 +}
  1.8383 +
  1.8384 +static void
  1.8385 +DestroyBoxMetrics(void* aPropertyValue)
  1.8386 +{
  1.8387 +  delete static_cast<nsBoxLayoutMetrics*>(aPropertyValue);
  1.8388 +}
  1.8389 +
  1.8390 +NS_DECLARE_FRAME_PROPERTY(BoxMetricsProperty, DestroyBoxMetrics)
  1.8391 +
  1.8392 +nsBoxLayoutMetrics*
  1.8393 +nsFrame::BoxMetrics() const
  1.8394 +{
  1.8395 +  nsBoxLayoutMetrics* metrics =
  1.8396 +    static_cast<nsBoxLayoutMetrics*>(Properties().Get(BoxMetricsProperty()));
  1.8397 +  NS_ASSERTION(metrics, "A box layout method was called but InitBoxMetrics was never called");
  1.8398 +  return metrics;
  1.8399 +}
  1.8400 +
  1.8401 +/* static */ void
  1.8402 +nsIFrame::AddInPopupStateBitToDescendants(nsIFrame* aFrame)
  1.8403 +{
  1.8404 +  aFrame->AddStateBits(NS_FRAME_IN_POPUP);
  1.8405 +
  1.8406 +  nsAutoTArray<nsIFrame::ChildList,4> childListArray;
  1.8407 +  aFrame->GetCrossDocChildLists(&childListArray);
  1.8408 +
  1.8409 +  nsIFrame::ChildListArrayIterator lists(childListArray);
  1.8410 +  for (; !lists.IsDone(); lists.Next()) {
  1.8411 +    nsFrameList::Enumerator childFrames(lists.CurrentList());
  1.8412 +    for (; !childFrames.AtEnd(); childFrames.Next()) {
  1.8413 +      AddInPopupStateBitToDescendants(childFrames.get());
  1.8414 +    }
  1.8415 +  }
  1.8416 +}
  1.8417 +
  1.8418 +/* static */ void
  1.8419 +nsIFrame::RemoveInPopupStateBitFromDescendants(nsIFrame* aFrame)
  1.8420 +{
  1.8421 +  if (!aFrame->HasAnyStateBits(NS_FRAME_IN_POPUP) ||
  1.8422 +      nsLayoutUtils::IsPopup(aFrame)) {
  1.8423 +    return;
  1.8424 +  }
  1.8425 +
  1.8426 +  aFrame->RemoveStateBits(NS_FRAME_IN_POPUP);
  1.8427 +
  1.8428 +  nsAutoTArray<nsIFrame::ChildList,4> childListArray;
  1.8429 +  aFrame->GetCrossDocChildLists(&childListArray);
  1.8430 +
  1.8431 +  nsIFrame::ChildListArrayIterator lists(childListArray);
  1.8432 +  for (; !lists.IsDone(); lists.Next()) {
  1.8433 +    nsFrameList::Enumerator childFrames(lists.CurrentList());
  1.8434 +    for (; !childFrames.AtEnd(); childFrames.Next()) {
  1.8435 +      RemoveInPopupStateBitFromDescendants(childFrames.get());
  1.8436 +    }
  1.8437 +  }
  1.8438 +}
  1.8439 +
  1.8440 +void
  1.8441 +nsFrame::SetParent(nsIFrame* aParent)
  1.8442 +{
  1.8443 +  bool wasBoxWrapped = IsBoxWrapped();
  1.8444 +  mParent = aParent;
  1.8445 +  if (!wasBoxWrapped && IsBoxWrapped()) {
  1.8446 +    InitBoxMetrics(true);
  1.8447 +  } else if (wasBoxWrapped && !IsBoxWrapped()) {
  1.8448 +    Properties().Delete(BoxMetricsProperty());
  1.8449 +  }
  1.8450 +
  1.8451 +  if (GetStateBits() & (NS_FRAME_HAS_VIEW | NS_FRAME_HAS_CHILD_WITH_VIEW)) {
  1.8452 +    for (nsIFrame* f = aParent;
  1.8453 +         f && !(f->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW);
  1.8454 +         f = f->GetParent()) {
  1.8455 +      f->AddStateBits(NS_FRAME_HAS_CHILD_WITH_VIEW);
  1.8456 +    }
  1.8457 +  }
  1.8458 +  
  1.8459 +  if (HasInvalidFrameInSubtree()) {
  1.8460 +    for (nsIFrame* f = aParent;
  1.8461 +         f && !f->HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT);
  1.8462 +         f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
  1.8463 +      f->AddStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT);
  1.8464 +    }
  1.8465 +  }
  1.8466 +
  1.8467 +  if (aParent->HasAnyStateBits(NS_FRAME_IN_POPUP)) {
  1.8468 +    AddInPopupStateBitToDescendants(this);
  1.8469 +  } else {
  1.8470 +    RemoveInPopupStateBitFromDescendants(this);
  1.8471 +  }
  1.8472 +  
  1.8473 +  // If our new parent only has invalid children, then we just invalidate
  1.8474 +  // ourselves too. This is probably faster than clearing the flag all
  1.8475 +  // the way up the frame tree.
  1.8476 +  if (aParent->HasAnyStateBits(NS_FRAME_ALL_DESCENDANTS_NEED_PAINT)) {
  1.8477 +    InvalidateFrame();
  1.8478 +  }
  1.8479 +}
  1.8480 +
  1.8481 +void
  1.8482 +nsFrame::InitBoxMetrics(bool aClear)
  1.8483 +{
  1.8484 +  FrameProperties props = Properties();
  1.8485 +  if (aClear) {
  1.8486 +    props.Delete(BoxMetricsProperty());
  1.8487 +  }
  1.8488 +
  1.8489 +  nsBoxLayoutMetrics *metrics = new nsBoxLayoutMetrics();
  1.8490 +  props.Set(BoxMetricsProperty(), metrics);
  1.8491 +
  1.8492 +  nsFrame::MarkIntrinsicWidthsDirty();
  1.8493 +  metrics->mBlockAscent = 0;
  1.8494 +  metrics->mLastSize.SizeTo(0, 0);
  1.8495 +}
  1.8496 +
  1.8497 +void
  1.8498 +nsIFrame::CreateOwnLayerIfNeeded(nsDisplayListBuilder* aBuilder, 
  1.8499 +                                 nsDisplayList* aList)
  1.8500 +{
  1.8501 +  if (GetContent() &&
  1.8502 +      GetContent()->IsXUL() &&
  1.8503 +      GetContent()->HasAttr(kNameSpaceID_None, nsGkAtoms::layer)) {
  1.8504 +    aList->AppendNewToTop(new (aBuilder) 
  1.8505 +        nsDisplayOwnLayer(aBuilder, this, aList));
  1.8506 +  }
  1.8507 +}
  1.8508 +
  1.8509 +bool
  1.8510 +nsIFrame::IsSelected() const
  1.8511 +{
  1.8512 +  return (GetContent() && GetContent()->IsSelectionDescendant()) ?
  1.8513 +    IsFrameSelected() : false;
  1.8514 +}
  1.8515 +
  1.8516 +void
  1.8517 +nsIFrame::DestroySurface(void* aPropertyValue)
  1.8518 +{
  1.8519 +  static_cast<gfxASurface*>(aPropertyValue)->Release();
  1.8520 +}
  1.8521 +
  1.8522 +void
  1.8523 +nsIFrame::DestroyDT(void* aPropertyValue)
  1.8524 +{
  1.8525 +  static_cast<mozilla::gfx::DrawTarget*>(aPropertyValue)->Release();
  1.8526 +}
  1.8527 +
  1.8528 +void
  1.8529 +nsIFrame::DestroyRegion(void* aPropertyValue)
  1.8530 +{
  1.8531 +  delete static_cast<nsRegion*>(aPropertyValue);
  1.8532 +}
  1.8533 +
  1.8534 +bool
  1.8535 +nsIFrame::IsPseudoStackingContextFromStyle() {
  1.8536 +  const nsStyleDisplay* disp = StyleDisplay();
  1.8537 +  // If you change this, also change the computation of pseudoStackingContext
  1.8538 +  // in BuildDisplayListForChild()
  1.8539 +  return disp->mOpacity != 1.0f ||
  1.8540 +         disp->IsPositioned(this) ||
  1.8541 +         disp->IsFloating(this) ||
  1.8542 +         (disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_STACKING_CONTEXT);
  1.8543 +}
  1.8544 +
  1.8545 +Element*
  1.8546 +nsIFrame::GetPseudoElement(nsCSSPseudoElements::Type aType)
  1.8547 +{
  1.8548 +  nsIFrame* frame = nullptr;
  1.8549 +
  1.8550 +  if (aType == nsCSSPseudoElements::ePseudo_before) {
  1.8551 +    frame = nsLayoutUtils::GetBeforeFrame(this);
  1.8552 +  } else if (aType == nsCSSPseudoElements::ePseudo_after) {
  1.8553 +    frame = nsLayoutUtils::GetAfterFrame(this);
  1.8554 +  }
  1.8555 +
  1.8556 +  if (frame) {
  1.8557 +    nsIContent* content = frame->GetContent();
  1.8558 +    if (content->IsElement()) {
  1.8559 +      return content->AsElement();
  1.8560 +    }
  1.8561 +  }
  1.8562 +  
  1.8563 +  return nullptr;
  1.8564 +}
  1.8565 +
  1.8566 +nsIFrame::ContentOffsets::ContentOffsets()
  1.8567 +{
  1.8568 +}
  1.8569 +
  1.8570 +nsIFrame::ContentOffsets::ContentOffsets(const ContentOffsets& rhs)
  1.8571 +  : content(rhs.content),
  1.8572 +    offset(rhs.offset),
  1.8573 +    secondaryOffset(rhs.secondaryOffset),
  1.8574 +    associateWithNext(rhs.associateWithNext)
  1.8575 +{
  1.8576 +}
  1.8577 +
  1.8578 +nsIFrame::ContentOffsets::~ContentOffsets()
  1.8579 +{
  1.8580 +}
  1.8581 +
  1.8582 +nsIFrame::CaretPosition::CaretPosition()
  1.8583 +  : mContentOffset(0)
  1.8584 +{
  1.8585 +}
  1.8586 +
  1.8587 +nsIFrame::CaretPosition::~CaretPosition()
  1.8588 +{
  1.8589 +}
  1.8590 +
  1.8591 +// Box layout debugging
  1.8592 +#ifdef DEBUG_REFLOW
  1.8593 +int32_t gIndent2 = 0;
  1.8594 +
  1.8595 +void
  1.8596 +nsAdaptorAddIndents()
  1.8597 +{
  1.8598 +    for(int32_t i=0; i < gIndent2; i++)
  1.8599 +    {
  1.8600 +        printf(" ");
  1.8601 +    }
  1.8602 +}
  1.8603 +
  1.8604 +void
  1.8605 +nsAdaptorPrintReason(nsHTMLReflowState& aReflowState)
  1.8606 +{
  1.8607 +    char* reflowReasonString;
  1.8608 +
  1.8609 +    switch(aReflowState.reason) 
  1.8610 +    {
  1.8611 +        case eReflowReason_Initial:
  1.8612 +          reflowReasonString = "initial";
  1.8613 +          break;
  1.8614 +
  1.8615 +        case eReflowReason_Resize:
  1.8616 +          reflowReasonString = "resize";
  1.8617 +          break;
  1.8618 +        case eReflowReason_Dirty:
  1.8619 +          reflowReasonString = "dirty";
  1.8620 +          break;
  1.8621 +        case eReflowReason_StyleChange:
  1.8622 +          reflowReasonString = "stylechange";
  1.8623 +          break;
  1.8624 +        case eReflowReason_Incremental: 
  1.8625 +        {
  1.8626 +            switch (aReflowState.reflowCommand->Type()) {
  1.8627 +              case eReflowType_StyleChanged:
  1.8628 +                 reflowReasonString = "incremental (StyleChanged)";
  1.8629 +              break;
  1.8630 +              case eReflowType_ReflowDirty:
  1.8631 +                 reflowReasonString = "incremental (ReflowDirty)";
  1.8632 +              break;
  1.8633 +              default:
  1.8634 +                 reflowReasonString = "incremental (Unknown)";
  1.8635 +            }
  1.8636 +        }                             
  1.8637 +        break;
  1.8638 +        default:
  1.8639 +          reflowReasonString = "unknown";
  1.8640 +          break;
  1.8641 +    }
  1.8642 +
  1.8643 +    printf("%s",reflowReasonString);
  1.8644 +}
  1.8645 +
  1.8646 +#endif
  1.8647 +#ifdef DEBUG_LAYOUT
  1.8648 +void
  1.8649 +nsFrame::GetBoxName(nsAutoString& aName)
  1.8650 +{
  1.8651 +  GetFrameName(aName);
  1.8652 +}
  1.8653 +#endif
  1.8654 +
  1.8655 +#ifdef DEBUG
  1.8656 +static void
  1.8657 +GetTagName(nsFrame* aFrame, nsIContent* aContent, int aResultSize,
  1.8658 +           char* aResult)
  1.8659 +{
  1.8660 +  if (aContent) {
  1.8661 +    PR_snprintf(aResult, aResultSize, "%s@%p",
  1.8662 +                nsAtomCString(aContent->Tag()).get(), aFrame);
  1.8663 +  }
  1.8664 +  else {
  1.8665 +    PR_snprintf(aResult, aResultSize, "@%p", aFrame);
  1.8666 +  }
  1.8667 +}
  1.8668 +
  1.8669 +void
  1.8670 +nsFrame::Trace(const char* aMethod, bool aEnter)
  1.8671 +{
  1.8672 +  if (NS_FRAME_LOG_TEST(gLogModule, NS_FRAME_TRACE_CALLS)) {
  1.8673 +    char tagbuf[40];
  1.8674 +    GetTagName(this, mContent, sizeof(tagbuf), tagbuf);
  1.8675 +    PR_LogPrint("%s: %s %s", tagbuf, aEnter ? "enter" : "exit", aMethod);
  1.8676 +  }
  1.8677 +}
  1.8678 +
  1.8679 +void
  1.8680 +nsFrame::Trace(const char* aMethod, bool aEnter, nsReflowStatus aStatus)
  1.8681 +{
  1.8682 +  if (NS_FRAME_LOG_TEST(gLogModule, NS_FRAME_TRACE_CALLS)) {
  1.8683 +    char tagbuf[40];
  1.8684 +    GetTagName(this, mContent, sizeof(tagbuf), tagbuf);
  1.8685 +    PR_LogPrint("%s: %s %s, status=%scomplete%s",
  1.8686 +                tagbuf, aEnter ? "enter" : "exit", aMethod,
  1.8687 +                NS_FRAME_IS_NOT_COMPLETE(aStatus) ? "not" : "",
  1.8688 +                (NS_FRAME_REFLOW_NEXTINFLOW & aStatus) ? "+reflow" : "");
  1.8689 +  }
  1.8690 +}
  1.8691 +
  1.8692 +void
  1.8693 +nsFrame::TraceMsg(const char* aFormatString, ...)
  1.8694 +{
  1.8695 +  if (NS_FRAME_LOG_TEST(gLogModule, NS_FRAME_TRACE_CALLS)) {
  1.8696 +    // Format arguments into a buffer
  1.8697 +    char argbuf[200];
  1.8698 +    va_list ap;
  1.8699 +    va_start(ap, aFormatString);
  1.8700 +    PR_vsnprintf(argbuf, sizeof(argbuf), aFormatString, ap);
  1.8701 +    va_end(ap);
  1.8702 +
  1.8703 +    char tagbuf[40];
  1.8704 +    GetTagName(this, mContent, sizeof(tagbuf), tagbuf);
  1.8705 +    PR_LogPrint("%s: %s", tagbuf, argbuf);
  1.8706 +  }
  1.8707 +}
  1.8708 +
  1.8709 +void
  1.8710 +nsFrame::VerifyDirtyBitSet(const nsFrameList& aFrameList)
  1.8711 +{
  1.8712 +  for (nsFrameList::Enumerator e(aFrameList); !e.AtEnd(); e.Next()) {
  1.8713 +    NS_ASSERTION(e.get()->GetStateBits() & NS_FRAME_IS_DIRTY,
  1.8714 +                 "dirty bit not set");
  1.8715 +  }
  1.8716 +}
  1.8717 +
  1.8718 +// Start Display Reflow
  1.8719 +#ifdef DEBUG
  1.8720 +
  1.8721 +DR_cookie::DR_cookie(nsPresContext*          aPresContext,
  1.8722 +                     nsIFrame*                aFrame, 
  1.8723 +                     const nsHTMLReflowState& aReflowState,
  1.8724 +                     nsHTMLReflowMetrics&     aMetrics,
  1.8725 +                     nsReflowStatus&          aStatus)
  1.8726 +  :mPresContext(aPresContext), mFrame(aFrame), mReflowState(aReflowState), mMetrics(aMetrics), mStatus(aStatus)
  1.8727 +{
  1.8728 +  MOZ_COUNT_CTOR(DR_cookie);
  1.8729 +  mValue = nsFrame::DisplayReflowEnter(aPresContext, mFrame, mReflowState);
  1.8730 +}
  1.8731 +
  1.8732 +DR_cookie::~DR_cookie()
  1.8733 +{
  1.8734 +  MOZ_COUNT_DTOR(DR_cookie);
  1.8735 +  nsFrame::DisplayReflowExit(mPresContext, mFrame, mMetrics, mStatus, mValue);
  1.8736 +}
  1.8737 +
  1.8738 +DR_layout_cookie::DR_layout_cookie(nsIFrame* aFrame)
  1.8739 +  : mFrame(aFrame)
  1.8740 +{
  1.8741 +  MOZ_COUNT_CTOR(DR_layout_cookie);
  1.8742 +  mValue = nsFrame::DisplayLayoutEnter(mFrame);
  1.8743 +}
  1.8744 +
  1.8745 +DR_layout_cookie::~DR_layout_cookie()
  1.8746 +{
  1.8747 +  MOZ_COUNT_DTOR(DR_layout_cookie);
  1.8748 +  nsFrame::DisplayLayoutExit(mFrame, mValue);
  1.8749 +}
  1.8750 +
  1.8751 +DR_intrinsic_width_cookie::DR_intrinsic_width_cookie(
  1.8752 +                     nsIFrame*                aFrame, 
  1.8753 +                     const char*              aType,
  1.8754 +                     nscoord&                 aResult)
  1.8755 +  : mFrame(aFrame)
  1.8756 +  , mType(aType)
  1.8757 +  , mResult(aResult)
  1.8758 +{
  1.8759 +  MOZ_COUNT_CTOR(DR_intrinsic_width_cookie);
  1.8760 +  mValue = nsFrame::DisplayIntrinsicWidthEnter(mFrame, mType);
  1.8761 +}
  1.8762 +
  1.8763 +DR_intrinsic_width_cookie::~DR_intrinsic_width_cookie()
  1.8764 +{
  1.8765 +  MOZ_COUNT_DTOR(DR_intrinsic_width_cookie);
  1.8766 +  nsFrame::DisplayIntrinsicWidthExit(mFrame, mType, mResult, mValue);
  1.8767 +}
  1.8768 +
  1.8769 +DR_intrinsic_size_cookie::DR_intrinsic_size_cookie(
  1.8770 +                     nsIFrame*                aFrame, 
  1.8771 +                     const char*              aType,
  1.8772 +                     nsSize&                  aResult)
  1.8773 +  : mFrame(aFrame)
  1.8774 +  , mType(aType)
  1.8775 +  , mResult(aResult)
  1.8776 +{
  1.8777 +  MOZ_COUNT_CTOR(DR_intrinsic_size_cookie);
  1.8778 +  mValue = nsFrame::DisplayIntrinsicSizeEnter(mFrame, mType);
  1.8779 +}
  1.8780 +
  1.8781 +DR_intrinsic_size_cookie::~DR_intrinsic_size_cookie()
  1.8782 +{
  1.8783 +  MOZ_COUNT_DTOR(DR_intrinsic_size_cookie);
  1.8784 +  nsFrame::DisplayIntrinsicSizeExit(mFrame, mType, mResult, mValue);
  1.8785 +}
  1.8786 +
  1.8787 +DR_init_constraints_cookie::DR_init_constraints_cookie(
  1.8788 +                     nsIFrame*                aFrame,
  1.8789 +                     nsHTMLReflowState*       aState,
  1.8790 +                     nscoord                  aCBWidth,
  1.8791 +                     nscoord                  aCBHeight,
  1.8792 +                     const nsMargin*          aMargin,
  1.8793 +                     const nsMargin*          aPadding)
  1.8794 +  : mFrame(aFrame)
  1.8795 +  , mState(aState)
  1.8796 +{
  1.8797 +  MOZ_COUNT_CTOR(DR_init_constraints_cookie);
  1.8798 +  mValue = nsHTMLReflowState::DisplayInitConstraintsEnter(mFrame, mState,
  1.8799 +                                                          aCBWidth, aCBHeight,
  1.8800 +                                                          aMargin, aPadding);
  1.8801 +}
  1.8802 +
  1.8803 +DR_init_constraints_cookie::~DR_init_constraints_cookie()
  1.8804 +{
  1.8805 +  MOZ_COUNT_DTOR(DR_init_constraints_cookie);
  1.8806 +  nsHTMLReflowState::DisplayInitConstraintsExit(mFrame, mState, mValue);
  1.8807 +}
  1.8808 +
  1.8809 +DR_init_offsets_cookie::DR_init_offsets_cookie(
  1.8810 +                     nsIFrame*                aFrame,
  1.8811 +                     nsCSSOffsetState*        aState,
  1.8812 +                     nscoord                  aHorizontalPercentBasis,
  1.8813 +                     nscoord                  aVerticalPercentBasis,
  1.8814 +                     const nsMargin*          aMargin,
  1.8815 +                     const nsMargin*          aPadding)
  1.8816 +  : mFrame(aFrame)
  1.8817 +  , mState(aState)
  1.8818 +{
  1.8819 +  MOZ_COUNT_CTOR(DR_init_offsets_cookie);
  1.8820 +  mValue = nsCSSOffsetState::DisplayInitOffsetsEnter(mFrame, mState,
  1.8821 +                                                     aHorizontalPercentBasis,
  1.8822 +                                                     aVerticalPercentBasis,
  1.8823 +                                                     aMargin, aPadding);
  1.8824 +}
  1.8825 +
  1.8826 +DR_init_offsets_cookie::~DR_init_offsets_cookie()
  1.8827 +{
  1.8828 +  MOZ_COUNT_DTOR(DR_init_offsets_cookie);
  1.8829 +  nsCSSOffsetState::DisplayInitOffsetsExit(mFrame, mState, mValue);
  1.8830 +}
  1.8831 +
  1.8832 +DR_init_type_cookie::DR_init_type_cookie(
  1.8833 +                     nsIFrame*                aFrame,
  1.8834 +                     nsHTMLReflowState*       aState)
  1.8835 +  : mFrame(aFrame)
  1.8836 +  , mState(aState)
  1.8837 +{
  1.8838 +  MOZ_COUNT_CTOR(DR_init_type_cookie);
  1.8839 +  mValue = nsHTMLReflowState::DisplayInitFrameTypeEnter(mFrame, mState);
  1.8840 +}
  1.8841 +
  1.8842 +DR_init_type_cookie::~DR_init_type_cookie()
  1.8843 +{
  1.8844 +  MOZ_COUNT_DTOR(DR_init_type_cookie);
  1.8845 +  nsHTMLReflowState::DisplayInitFrameTypeExit(mFrame, mState, mValue);
  1.8846 +}
  1.8847 +
  1.8848 +struct DR_FrameTypeInfo;
  1.8849 +struct DR_FrameTreeNode;
  1.8850 +struct DR_Rule;
  1.8851 +
  1.8852 +struct DR_State
  1.8853 +{
  1.8854 +  DR_State();
  1.8855 +  ~DR_State();
  1.8856 +  void Init();
  1.8857 +  void AddFrameTypeInfo(nsIAtom* aFrameType,
  1.8858 +                        const char* aFrameNameAbbrev,
  1.8859 +                        const char* aFrameName);
  1.8860 +  DR_FrameTypeInfo* GetFrameTypeInfo(nsIAtom* aFrameType);
  1.8861 +  DR_FrameTypeInfo* GetFrameTypeInfo(char* aFrameName);
  1.8862 +  void InitFrameTypeTable();
  1.8863 +  DR_FrameTreeNode* CreateTreeNode(nsIFrame*                aFrame,
  1.8864 +                                   const nsHTMLReflowState* aReflowState);
  1.8865 +  void FindMatchingRule(DR_FrameTreeNode& aNode);
  1.8866 +  bool RuleMatches(DR_Rule&          aRule,
  1.8867 +                     DR_FrameTreeNode& aNode);
  1.8868 +  bool GetToken(FILE* aFile,
  1.8869 +                  char* aBuf,
  1.8870 +                  size_t aBufSize);
  1.8871 +  DR_Rule* ParseRule(FILE* aFile);
  1.8872 +  void ParseRulesFile();
  1.8873 +  void AddRule(nsTArray<DR_Rule*>& aRules,
  1.8874 +               DR_Rule&            aRule);
  1.8875 +  bool IsWhiteSpace(int c);
  1.8876 +  bool GetNumber(char*    aBuf, 
  1.8877 +                 int32_t&  aNumber);
  1.8878 +  void PrettyUC(nscoord aSize,
  1.8879 +                char*   aBuf);
  1.8880 +  void PrintMargin(const char* tag, const nsMargin* aMargin);
  1.8881 +  void DisplayFrameTypeInfo(nsIFrame* aFrame,
  1.8882 +                            int32_t   aIndent);
  1.8883 +  void DeleteTreeNode(DR_FrameTreeNode& aNode);
  1.8884 +
  1.8885 +  bool        mInited;
  1.8886 +  bool        mActive;
  1.8887 +  int32_t     mCount;
  1.8888 +  int32_t     mAssert;
  1.8889 +  int32_t     mIndent;
  1.8890 +  bool        mIndentUndisplayedFrames;
  1.8891 +  bool        mDisplayPixelErrors;
  1.8892 +  nsTArray<DR_Rule*>          mWildRules;
  1.8893 +  nsTArray<DR_FrameTypeInfo>  mFrameTypeTable;
  1.8894 +  // reflow specific state
  1.8895 +  nsTArray<DR_FrameTreeNode*> mFrameTreeLeaves;
  1.8896 +};
  1.8897 +
  1.8898 +static DR_State *DR_state; // the one and only DR_State
  1.8899 +
  1.8900 +struct DR_RulePart 
  1.8901 +{
  1.8902 +  DR_RulePart(nsIAtom* aFrameType) : mFrameType(aFrameType), mNext(0) {}
  1.8903 +  void Destroy();
  1.8904 +
  1.8905 +  nsIAtom*     mFrameType;
  1.8906 +  DR_RulePart* mNext;
  1.8907 +};
  1.8908 +
  1.8909 +void DR_RulePart::Destroy()
  1.8910 +{
  1.8911 +  if (mNext) {
  1.8912 +    mNext->Destroy();
  1.8913 +  }
  1.8914 +  delete this;
  1.8915 +}
  1.8916 +
  1.8917 +struct DR_Rule 
  1.8918 +{
  1.8919 +  DR_Rule() : mLength(0), mTarget(nullptr), mDisplay(false) {
  1.8920 +    MOZ_COUNT_CTOR(DR_Rule);
  1.8921 +  }
  1.8922 +  ~DR_Rule() {
  1.8923 +    if (mTarget) mTarget->Destroy();
  1.8924 +    MOZ_COUNT_DTOR(DR_Rule);
  1.8925 +  }
  1.8926 +  void AddPart(nsIAtom* aFrameType);
  1.8927 +
  1.8928 +  uint32_t      mLength;
  1.8929 +  DR_RulePart*  mTarget;
  1.8930 +  bool          mDisplay;
  1.8931 +};
  1.8932 +
  1.8933 +void DR_Rule::AddPart(nsIAtom* aFrameType)
  1.8934 +{
  1.8935 +  DR_RulePart* newPart = new DR_RulePart(aFrameType);
  1.8936 +  newPart->mNext = mTarget;
  1.8937 +  mTarget = newPart;
  1.8938 +  mLength++;
  1.8939 +}
  1.8940 +
  1.8941 +struct DR_FrameTypeInfo
  1.8942 +{
  1.8943 +  DR_FrameTypeInfo(nsIAtom* aFrmeType, const char* aFrameNameAbbrev, const char* aFrameName);
  1.8944 +  ~DR_FrameTypeInfo() { 
  1.8945 +      int32_t numElements;
  1.8946 +      numElements = mRules.Length();
  1.8947 +      for (int32_t i = numElements - 1; i >= 0; i--) {
  1.8948 +        delete mRules.ElementAt(i);
  1.8949 +      }
  1.8950 +   }
  1.8951 +
  1.8952 +  nsIAtom*    mType;
  1.8953 +  char        mNameAbbrev[16];
  1.8954 +  char        mName[32];
  1.8955 +  nsTArray<DR_Rule*> mRules;
  1.8956 +private:
  1.8957 +  DR_FrameTypeInfo& operator=(const DR_FrameTypeInfo&) MOZ_DELETE;
  1.8958 +};
  1.8959 +
  1.8960 +DR_FrameTypeInfo::DR_FrameTypeInfo(nsIAtom* aFrameType, 
  1.8961 +                                   const char* aFrameNameAbbrev, 
  1.8962 +                                   const char* aFrameName)
  1.8963 +{
  1.8964 +  mType = aFrameType;
  1.8965 +  PL_strncpyz(mNameAbbrev, aFrameNameAbbrev, sizeof(mNameAbbrev));
  1.8966 +  PL_strncpyz(mName, aFrameName, sizeof(mName));
  1.8967 +}
  1.8968 +
  1.8969 +struct DR_FrameTreeNode
  1.8970 +{
  1.8971 +  DR_FrameTreeNode(nsIFrame* aFrame, DR_FrameTreeNode* aParent) : mFrame(aFrame), mParent(aParent), mDisplay(0), mIndent(0)
  1.8972 +  {
  1.8973 +    MOZ_COUNT_CTOR(DR_FrameTreeNode);
  1.8974 +  }
  1.8975 +
  1.8976 +  ~DR_FrameTreeNode()
  1.8977 +  {
  1.8978 +    MOZ_COUNT_DTOR(DR_FrameTreeNode);
  1.8979 +  }
  1.8980 +
  1.8981 +  nsIFrame*         mFrame;
  1.8982 +  DR_FrameTreeNode* mParent;
  1.8983 +  bool              mDisplay;
  1.8984 +  uint32_t          mIndent;
  1.8985 +};
  1.8986 +
  1.8987 +// DR_State implementation
  1.8988 +
  1.8989 +DR_State::DR_State() 
  1.8990 +: mInited(false), mActive(false), mCount(0), mAssert(-1), mIndent(0), 
  1.8991 +  mIndentUndisplayedFrames(false), mDisplayPixelErrors(false)
  1.8992 +{
  1.8993 +  MOZ_COUNT_CTOR(DR_State);
  1.8994 +}
  1.8995 +
  1.8996 +void DR_State::Init() 
  1.8997 +{
  1.8998 +  char* env = PR_GetEnv("GECKO_DISPLAY_REFLOW_ASSERT");
  1.8999 +  int32_t num;
  1.9000 +  if (env) {
  1.9001 +    if (GetNumber(env, num)) 
  1.9002 +      mAssert = num;
  1.9003 +    else 
  1.9004 +      printf("GECKO_DISPLAY_REFLOW_ASSERT - invalid value = %s", env);
  1.9005 +  }
  1.9006 +
  1.9007 +  env = PR_GetEnv("GECKO_DISPLAY_REFLOW_INDENT_START");
  1.9008 +  if (env) {
  1.9009 +    if (GetNumber(env, num)) 
  1.9010 +      mIndent = num;
  1.9011 +    else 
  1.9012 +      printf("GECKO_DISPLAY_REFLOW_INDENT_START - invalid value = %s", env);
  1.9013 +  }
  1.9014 +
  1.9015 +  env = PR_GetEnv("GECKO_DISPLAY_REFLOW_INDENT_UNDISPLAYED_FRAMES");
  1.9016 +  if (env) {
  1.9017 +    if (GetNumber(env, num)) 
  1.9018 +      mIndentUndisplayedFrames = num;
  1.9019 +    else 
  1.9020 +      printf("GECKO_DISPLAY_REFLOW_INDENT_UNDISPLAYED_FRAMES - invalid value = %s", env);
  1.9021 +  }
  1.9022 +
  1.9023 +  env = PR_GetEnv("GECKO_DISPLAY_REFLOW_FLAG_PIXEL_ERRORS");
  1.9024 +  if (env) {
  1.9025 +    if (GetNumber(env, num)) 
  1.9026 +      mDisplayPixelErrors = num;
  1.9027 +    else 
  1.9028 +      printf("GECKO_DISPLAY_REFLOW_FLAG_PIXEL_ERRORS - invalid value = %s", env);
  1.9029 +  }
  1.9030 +
  1.9031 +  InitFrameTypeTable();
  1.9032 +  ParseRulesFile();
  1.9033 +  mInited = true;
  1.9034 +}
  1.9035 +
  1.9036 +DR_State::~DR_State()
  1.9037 +{
  1.9038 +  MOZ_COUNT_DTOR(DR_State);
  1.9039 +  int32_t numElements, i;
  1.9040 +  numElements = mWildRules.Length();
  1.9041 +  for (i = numElements - 1; i >= 0; i--) {
  1.9042 +    delete mWildRules.ElementAt(i);
  1.9043 +  }
  1.9044 +  numElements = mFrameTreeLeaves.Length();
  1.9045 +  for (i = numElements - 1; i >= 0; i--) {
  1.9046 +    delete mFrameTreeLeaves.ElementAt(i);
  1.9047 +  }
  1.9048 +}
  1.9049 +
  1.9050 +bool DR_State::GetNumber(char*     aBuf, 
  1.9051 +                           int32_t&  aNumber)
  1.9052 +{
  1.9053 +  if (sscanf(aBuf, "%d", &aNumber) > 0) 
  1.9054 +    return true;
  1.9055 +  else 
  1.9056 +    return false;
  1.9057 +}
  1.9058 +
  1.9059 +bool DR_State::IsWhiteSpace(int c) {
  1.9060 +  return (c == ' ') || (c == '\t') || (c == '\n') || (c == '\r');
  1.9061 +}
  1.9062 +
  1.9063 +bool DR_State::GetToken(FILE* aFile,
  1.9064 +                          char* aBuf,
  1.9065 +                          size_t aBufSize)
  1.9066 +{
  1.9067 +  bool haveToken = false;
  1.9068 +  aBuf[0] = 0;
  1.9069 +  // get the 1st non whitespace char
  1.9070 +  int c = -1;
  1.9071 +  for (c = getc(aFile); (c > 0) && IsWhiteSpace(c); c = getc(aFile)) {
  1.9072 +  }
  1.9073 +
  1.9074 +  if (c > 0) {
  1.9075 +    haveToken = true;
  1.9076 +    aBuf[0] = c;
  1.9077 +    // get everything up to the next whitespace char
  1.9078 +    size_t cX;
  1.9079 +    for (cX = 1; cX + 1 < aBufSize ; cX++) {
  1.9080 +      c = getc(aFile);
  1.9081 +      if (c < 0) { // EOF
  1.9082 +        ungetc(' ', aFile); 
  1.9083 +        break;
  1.9084 +      }
  1.9085 +      else {
  1.9086 +        if (IsWhiteSpace(c)) {
  1.9087 +          break;
  1.9088 +        }
  1.9089 +        else {
  1.9090 +          aBuf[cX] = c;
  1.9091 +        }
  1.9092 +      }
  1.9093 +    }
  1.9094 +    aBuf[cX] = 0;
  1.9095 +  }
  1.9096 +  return haveToken;
  1.9097 +}
  1.9098 +
  1.9099 +DR_Rule* DR_State::ParseRule(FILE* aFile)
  1.9100 +{
  1.9101 +  char buf[128];
  1.9102 +  int32_t doDisplay;
  1.9103 +  DR_Rule* rule = nullptr;
  1.9104 +  while (GetToken(aFile, buf, sizeof(buf))) {
  1.9105 +    if (GetNumber(buf, doDisplay)) {
  1.9106 +      if (rule) { 
  1.9107 +        rule->mDisplay = !!doDisplay;
  1.9108 +        break;
  1.9109 +      }
  1.9110 +      else {
  1.9111 +        printf("unexpected token - %s \n", buf);
  1.9112 +      }
  1.9113 +    }
  1.9114 +    else {
  1.9115 +      if (!rule) {
  1.9116 +        rule = new DR_Rule;
  1.9117 +      }
  1.9118 +      if (strcmp(buf, "*") == 0) {
  1.9119 +        rule->AddPart(nullptr);
  1.9120 +      }
  1.9121 +      else {
  1.9122 +        DR_FrameTypeInfo* info = GetFrameTypeInfo(buf);
  1.9123 +        if (info) {
  1.9124 +          rule->AddPart(info->mType);
  1.9125 +        }
  1.9126 +        else {
  1.9127 +          printf("invalid frame type - %s \n", buf);
  1.9128 +        }
  1.9129 +      }
  1.9130 +    }
  1.9131 +  }
  1.9132 +  return rule;
  1.9133 +}
  1.9134 +
  1.9135 +void DR_State::AddRule(nsTArray<DR_Rule*>& aRules,
  1.9136 +                       DR_Rule&            aRule)
  1.9137 +{
  1.9138 +  int32_t numRules = aRules.Length();
  1.9139 +  for (int32_t ruleX = 0; ruleX < numRules; ruleX++) {
  1.9140 +    DR_Rule* rule = aRules.ElementAt(ruleX);
  1.9141 +    NS_ASSERTION(rule, "program error");
  1.9142 +    if (aRule.mLength > rule->mLength) {
  1.9143 +      aRules.InsertElementAt(ruleX, &aRule);
  1.9144 +      return;
  1.9145 +    }
  1.9146 +  }
  1.9147 +  aRules.AppendElement(&aRule);
  1.9148 +}
  1.9149 +
  1.9150 +void DR_State::ParseRulesFile()
  1.9151 +{
  1.9152 +  char* path = PR_GetEnv("GECKO_DISPLAY_REFLOW_RULES_FILE");
  1.9153 +  if (path) {
  1.9154 +    FILE* inFile = fopen(path, "r");
  1.9155 +    if (inFile) {
  1.9156 +      for (DR_Rule* rule = ParseRule(inFile); rule; rule = ParseRule(inFile)) {
  1.9157 +        if (rule->mTarget) {
  1.9158 +          nsIAtom* fType = rule->mTarget->mFrameType;
  1.9159 +          if (fType) {
  1.9160 +            DR_FrameTypeInfo* info = GetFrameTypeInfo(fType);
  1.9161 +            if (info) {
  1.9162 +              AddRule(info->mRules, *rule);
  1.9163 +            }
  1.9164 +          }
  1.9165 +          else {
  1.9166 +            AddRule(mWildRules, *rule);
  1.9167 +          }
  1.9168 +          mActive = true;
  1.9169 +        }
  1.9170 +      }
  1.9171 +    }
  1.9172 +  }
  1.9173 +}
  1.9174 +
  1.9175 +
  1.9176 +void DR_State::AddFrameTypeInfo(nsIAtom* aFrameType,
  1.9177 +                                const char* aFrameNameAbbrev,
  1.9178 +                                const char* aFrameName)
  1.9179 +{
  1.9180 +  mFrameTypeTable.AppendElement(DR_FrameTypeInfo(aFrameType, aFrameNameAbbrev, aFrameName));
  1.9181 +}
  1.9182 +
  1.9183 +DR_FrameTypeInfo* DR_State::GetFrameTypeInfo(nsIAtom* aFrameType)
  1.9184 +{
  1.9185 +  int32_t numEntries = mFrameTypeTable.Length();
  1.9186 +  NS_ASSERTION(numEntries != 0, "empty FrameTypeTable");
  1.9187 +  for (int32_t i = 0; i < numEntries; i++) {
  1.9188 +    DR_FrameTypeInfo& info = mFrameTypeTable.ElementAt(i);
  1.9189 +    if (info.mType == aFrameType) {
  1.9190 +      return &info;
  1.9191 +    }
  1.9192 +  }
  1.9193 +  return &mFrameTypeTable.ElementAt(numEntries - 1); // return unknown frame type
  1.9194 +}
  1.9195 +
  1.9196 +DR_FrameTypeInfo* DR_State::GetFrameTypeInfo(char* aFrameName)
  1.9197 +{
  1.9198 +  int32_t numEntries = mFrameTypeTable.Length();
  1.9199 +  NS_ASSERTION(numEntries != 0, "empty FrameTypeTable");
  1.9200 +  for (int32_t i = 0; i < numEntries; i++) {
  1.9201 +    DR_FrameTypeInfo& info = mFrameTypeTable.ElementAt(i);
  1.9202 +    if ((strcmp(aFrameName, info.mName) == 0) || (strcmp(aFrameName, info.mNameAbbrev) == 0)) {
  1.9203 +      return &info;
  1.9204 +    }
  1.9205 +  }
  1.9206 +  return &mFrameTypeTable.ElementAt(numEntries - 1); // return unknown frame type
  1.9207 +}
  1.9208 +
  1.9209 +void DR_State::InitFrameTypeTable()
  1.9210 +{  
  1.9211 +  AddFrameTypeInfo(nsGkAtoms::blockFrame,            "block",     "block");
  1.9212 +  AddFrameTypeInfo(nsGkAtoms::brFrame,               "br",        "br");
  1.9213 +  AddFrameTypeInfo(nsGkAtoms::bulletFrame,           "bullet",    "bullet");
  1.9214 +  AddFrameTypeInfo(nsGkAtoms::colorControlFrame,     "color",     "colorControl");
  1.9215 +  AddFrameTypeInfo(nsGkAtoms::gfxButtonControlFrame, "button",    "gfxButtonControl");
  1.9216 +  AddFrameTypeInfo(nsGkAtoms::HTMLButtonControlFrame, "HTMLbutton",    "HTMLButtonControl");
  1.9217 +  AddFrameTypeInfo(nsGkAtoms::HTMLCanvasFrame,       "HTMLCanvas","HTMLCanvas");
  1.9218 +  AddFrameTypeInfo(nsGkAtoms::subDocumentFrame,      "subdoc",    "subDocument");
  1.9219 +  AddFrameTypeInfo(nsGkAtoms::imageFrame,            "img",       "image");
  1.9220 +  AddFrameTypeInfo(nsGkAtoms::inlineFrame,           "inline",    "inline");
  1.9221 +  AddFrameTypeInfo(nsGkAtoms::letterFrame,           "letter",    "letter");
  1.9222 +  AddFrameTypeInfo(nsGkAtoms::lineFrame,             "line",      "line");
  1.9223 +  AddFrameTypeInfo(nsGkAtoms::listControlFrame,      "select",    "select");
  1.9224 +  AddFrameTypeInfo(nsGkAtoms::objectFrame,           "obj",       "object");
  1.9225 +  AddFrameTypeInfo(nsGkAtoms::pageFrame,             "page",      "page");
  1.9226 +  AddFrameTypeInfo(nsGkAtoms::placeholderFrame,      "place",     "placeholder");
  1.9227 +  AddFrameTypeInfo(nsGkAtoms::canvasFrame,           "canvas",    "canvas");
  1.9228 +  AddFrameTypeInfo(nsGkAtoms::rootFrame,             "root",      "root");
  1.9229 +  AddFrameTypeInfo(nsGkAtoms::scrollFrame,           "scroll",    "scroll");
  1.9230 +  AddFrameTypeInfo(nsGkAtoms::tableCaptionFrame,     "caption",   "tableCaption");
  1.9231 +  AddFrameTypeInfo(nsGkAtoms::tableCellFrame,        "cell",      "tableCell");
  1.9232 +  AddFrameTypeInfo(nsGkAtoms::bcTableCellFrame,      "bcCell",    "bcTableCell");
  1.9233 +  AddFrameTypeInfo(nsGkAtoms::tableColFrame,         "col",       "tableCol");
  1.9234 +  AddFrameTypeInfo(nsGkAtoms::tableColGroupFrame,    "colG",      "tableColGroup");
  1.9235 +  AddFrameTypeInfo(nsGkAtoms::tableFrame,            "tbl",       "table");
  1.9236 +  AddFrameTypeInfo(nsGkAtoms::tableOuterFrame,       "tblO",      "tableOuter");
  1.9237 +  AddFrameTypeInfo(nsGkAtoms::tableRowGroupFrame,    "rowG",      "tableRowGroup");
  1.9238 +  AddFrameTypeInfo(nsGkAtoms::tableRowFrame,         "row",       "tableRow");
  1.9239 +  AddFrameTypeInfo(nsGkAtoms::textInputFrame,        "textCtl",   "textInput");
  1.9240 +  AddFrameTypeInfo(nsGkAtoms::textFrame,             "text",      "text");
  1.9241 +  AddFrameTypeInfo(nsGkAtoms::viewportFrame,         "VP",        "viewport");
  1.9242 +#ifdef MOZ_XUL
  1.9243 +  AddFrameTypeInfo(nsGkAtoms::XULLabelFrame,         "XULLabel",  "XULLabel");
  1.9244 +  AddFrameTypeInfo(nsGkAtoms::boxFrame,              "Box",       "Box");
  1.9245 +  AddFrameTypeInfo(nsGkAtoms::sliderFrame,           "Slider",    "Slider");
  1.9246 +  AddFrameTypeInfo(nsGkAtoms::popupSetFrame,         "PopupSet",  "PopupSet");
  1.9247 +#endif
  1.9248 +  AddFrameTypeInfo(nullptr,                               "unknown",   "unknown");
  1.9249 +}
  1.9250 +
  1.9251 +
  1.9252 +void DR_State::DisplayFrameTypeInfo(nsIFrame* aFrame,
  1.9253 +                                    int32_t   aIndent)
  1.9254 +{ 
  1.9255 +  DR_FrameTypeInfo* frameTypeInfo = GetFrameTypeInfo(aFrame->GetType());
  1.9256 +  if (frameTypeInfo) {
  1.9257 +    for (int32_t i = 0; i < aIndent; i++) {
  1.9258 +      printf(" ");
  1.9259 +    }
  1.9260 +    if(!strcmp(frameTypeInfo->mNameAbbrev, "unknown")) {
  1.9261 +      if (aFrame) {
  1.9262 +       nsAutoString  name;
  1.9263 +       aFrame->GetFrameName(name);
  1.9264 +       printf("%s %p ", NS_LossyConvertUTF16toASCII(name).get(), (void*)aFrame);
  1.9265 +      }
  1.9266 +      else {
  1.9267 +        printf("%s %p ", frameTypeInfo->mNameAbbrev, (void*)aFrame);
  1.9268 +      }
  1.9269 +    }
  1.9270 +    else {
  1.9271 +      printf("%s %p ", frameTypeInfo->mNameAbbrev, (void*)aFrame);
  1.9272 +    }
  1.9273 +  }
  1.9274 +}
  1.9275 +
  1.9276 +bool DR_State::RuleMatches(DR_Rule&          aRule,
  1.9277 +                             DR_FrameTreeNode& aNode)
  1.9278 +{
  1.9279 +  NS_ASSERTION(aRule.mTarget, "program error");
  1.9280 +
  1.9281 +  DR_RulePart* rulePart;
  1.9282 +  DR_FrameTreeNode* parentNode;
  1.9283 +  for (rulePart = aRule.mTarget->mNext, parentNode = aNode.mParent;
  1.9284 +       rulePart && parentNode;
  1.9285 +       rulePart = rulePart->mNext, parentNode = parentNode->mParent) {
  1.9286 +    if (rulePart->mFrameType) {
  1.9287 +      if (parentNode->mFrame) {
  1.9288 +        if (rulePart->mFrameType != parentNode->mFrame->GetType()) {
  1.9289 +          return false;
  1.9290 +        }
  1.9291 +      }
  1.9292 +      else NS_ASSERTION(false, "program error");
  1.9293 +    }
  1.9294 +    // else wild card match
  1.9295 +  }
  1.9296 +  return true;
  1.9297 +}
  1.9298 +
  1.9299 +void DR_State::FindMatchingRule(DR_FrameTreeNode& aNode)
  1.9300 +{
  1.9301 +  if (!aNode.mFrame) {
  1.9302 +    NS_ASSERTION(false, "invalid DR_FrameTreeNode \n");
  1.9303 +    return;
  1.9304 +  }
  1.9305 +
  1.9306 +  bool matchingRule = false;
  1.9307 +
  1.9308 +  DR_FrameTypeInfo* info = GetFrameTypeInfo(aNode.mFrame->GetType());
  1.9309 +  NS_ASSERTION(info, "program error");
  1.9310 +  int32_t numRules = info->mRules.Length();
  1.9311 +  for (int32_t ruleX = 0; ruleX < numRules; ruleX++) {
  1.9312 +    DR_Rule* rule = info->mRules.ElementAt(ruleX);
  1.9313 +    if (rule && RuleMatches(*rule, aNode)) {
  1.9314 +      aNode.mDisplay = rule->mDisplay;
  1.9315 +      matchingRule = true;
  1.9316 +      break;
  1.9317 +    }
  1.9318 +  }
  1.9319 +  if (!matchingRule) {
  1.9320 +    int32_t numWildRules = mWildRules.Length();
  1.9321 +    for (int32_t ruleX = 0; ruleX < numWildRules; ruleX++) {
  1.9322 +      DR_Rule* rule = mWildRules.ElementAt(ruleX);
  1.9323 +      if (rule && RuleMatches(*rule, aNode)) {
  1.9324 +        aNode.mDisplay = rule->mDisplay;
  1.9325 +        break;
  1.9326 +      }
  1.9327 +    }
  1.9328 +  }
  1.9329 +}
  1.9330 +    
  1.9331 +DR_FrameTreeNode* DR_State::CreateTreeNode(nsIFrame*                aFrame,
  1.9332 +                                           const nsHTMLReflowState* aReflowState)
  1.9333 +{
  1.9334 +  // find the frame of the parent reflow state (usually just the parent of aFrame)
  1.9335 +  nsIFrame* parentFrame;
  1.9336 +  if (aReflowState) {
  1.9337 +    const nsHTMLReflowState* parentRS = aReflowState->parentReflowState;
  1.9338 +    parentFrame = (parentRS) ? parentRS->frame : nullptr;
  1.9339 +  } else {
  1.9340 +    parentFrame = aFrame->GetParent();
  1.9341 +  }
  1.9342 +
  1.9343 +  // find the parent tree node leaf
  1.9344 +  DR_FrameTreeNode* parentNode = nullptr;
  1.9345 +  
  1.9346 +  DR_FrameTreeNode* lastLeaf = nullptr;
  1.9347 +  if(mFrameTreeLeaves.Length())
  1.9348 +    lastLeaf = mFrameTreeLeaves.ElementAt(mFrameTreeLeaves.Length() - 1);
  1.9349 +  if (lastLeaf) {
  1.9350 +    for (parentNode = lastLeaf; parentNode && (parentNode->mFrame != parentFrame); parentNode = parentNode->mParent) {
  1.9351 +    }
  1.9352 +  }
  1.9353 +  DR_FrameTreeNode* newNode = new DR_FrameTreeNode(aFrame, parentNode);
  1.9354 +  FindMatchingRule(*newNode);
  1.9355 +
  1.9356 +  newNode->mIndent = mIndent;
  1.9357 +  if (newNode->mDisplay || mIndentUndisplayedFrames) {
  1.9358 +    ++mIndent;
  1.9359 +  }
  1.9360 +
  1.9361 +  if (lastLeaf && (lastLeaf == parentNode)) {
  1.9362 +    mFrameTreeLeaves.RemoveElementAt(mFrameTreeLeaves.Length() - 1);
  1.9363 +  }
  1.9364 +  mFrameTreeLeaves.AppendElement(newNode);
  1.9365 +  mCount++;
  1.9366 +
  1.9367 +  return newNode;
  1.9368 +}
  1.9369 +
  1.9370 +void DR_State::PrettyUC(nscoord aSize,
  1.9371 +                        char*   aBuf)
  1.9372 +{
  1.9373 +  if (NS_UNCONSTRAINEDSIZE == aSize) {
  1.9374 +    strcpy(aBuf, "UC");
  1.9375 +  }
  1.9376 +  else {
  1.9377 +    if ((nscoord)0xdeadbeefU == aSize)
  1.9378 +    {
  1.9379 +      strcpy(aBuf, "deadbeef");
  1.9380 +    }
  1.9381 +    else {
  1.9382 +      sprintf(aBuf, "%d", aSize);
  1.9383 +    }
  1.9384 +  }
  1.9385 +}
  1.9386 +
  1.9387 +void DR_State::PrintMargin(const char *tag, const nsMargin* aMargin)
  1.9388 +{
  1.9389 +  if (aMargin) {
  1.9390 +    char t[16], r[16], b[16], l[16];
  1.9391 +    PrettyUC(aMargin->top, t);
  1.9392 +    PrettyUC(aMargin->right, r);
  1.9393 +    PrettyUC(aMargin->bottom, b);
  1.9394 +    PrettyUC(aMargin->left, l);
  1.9395 +    printf(" %s=%s,%s,%s,%s", tag, t, r, b, l);
  1.9396 +  } else {
  1.9397 +    // use %p here for consistency with other null-pointer printouts
  1.9398 +    printf(" %s=%p", tag, (void*)aMargin);
  1.9399 +  }
  1.9400 +}
  1.9401 +
  1.9402 +void DR_State::DeleteTreeNode(DR_FrameTreeNode& aNode)
  1.9403 +{
  1.9404 +  mFrameTreeLeaves.RemoveElement(&aNode);
  1.9405 +  int32_t numLeaves = mFrameTreeLeaves.Length();
  1.9406 +  if ((0 == numLeaves) || (aNode.mParent != mFrameTreeLeaves.ElementAt(numLeaves - 1))) {
  1.9407 +    mFrameTreeLeaves.AppendElement(aNode.mParent);
  1.9408 +  }
  1.9409 +
  1.9410 +  if (aNode.mDisplay || mIndentUndisplayedFrames) {
  1.9411 +    --mIndent;
  1.9412 +  }
  1.9413 +  // delete the tree node 
  1.9414 +  delete &aNode;
  1.9415 +}
  1.9416 +
  1.9417 +static void
  1.9418 +CheckPixelError(nscoord aSize,
  1.9419 +                int32_t aPixelToTwips)
  1.9420 +{
  1.9421 +  if (NS_UNCONSTRAINEDSIZE != aSize) {
  1.9422 +    if ((aSize % aPixelToTwips) > 0) {
  1.9423 +      printf("VALUE %d is not a whole pixel \n", aSize);
  1.9424 +    }
  1.9425 +  }
  1.9426 +}
  1.9427 +
  1.9428 +static void DisplayReflowEnterPrint(nsPresContext*          aPresContext,
  1.9429 +                                    nsIFrame*                aFrame,
  1.9430 +                                    const nsHTMLReflowState& aReflowState,
  1.9431 +                                    DR_FrameTreeNode&        aTreeNode,
  1.9432 +                                    bool                     aChanged)
  1.9433 +{
  1.9434 +  if (aTreeNode.mDisplay) {
  1.9435 +    DR_state->DisplayFrameTypeInfo(aFrame, aTreeNode.mIndent);
  1.9436 +
  1.9437 +    char width[16];
  1.9438 +    char height[16];
  1.9439 +
  1.9440 +    DR_state->PrettyUC(aReflowState.AvailableWidth(), width);
  1.9441 +    DR_state->PrettyUC(aReflowState.AvailableHeight(), height);
  1.9442 +    printf("Reflow a=%s,%s ", width, height);
  1.9443 +
  1.9444 +    DR_state->PrettyUC(aReflowState.ComputedWidth(), width);
  1.9445 +    DR_state->PrettyUC(aReflowState.ComputedHeight(), height);
  1.9446 +    printf("c=%s,%s ", width, height);
  1.9447 +
  1.9448 +    if (aFrame->GetStateBits() & NS_FRAME_IS_DIRTY)
  1.9449 +      printf("dirty ");
  1.9450 +
  1.9451 +    if (aFrame->GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN)
  1.9452 +      printf("dirty-children ");
  1.9453 +
  1.9454 +    if (aReflowState.mFlags.mSpecialHeightReflow)
  1.9455 +      printf("special-height ");
  1.9456 +
  1.9457 +    if (aReflowState.mFlags.mHResize)
  1.9458 +      printf("h-resize ");
  1.9459 +
  1.9460 +    if (aReflowState.mFlags.mVResize)
  1.9461 +      printf("v-resize ");
  1.9462 +
  1.9463 +    nsIFrame* inFlow = aFrame->GetPrevInFlow();
  1.9464 +    if (inFlow) {
  1.9465 +      printf("pif=%p ", (void*)inFlow);
  1.9466 +    }
  1.9467 +    inFlow = aFrame->GetNextInFlow();
  1.9468 +    if (inFlow) {
  1.9469 +      printf("nif=%p ", (void*)inFlow);
  1.9470 +    }
  1.9471 +    if (aChanged) 
  1.9472 +      printf("CHANGED \n");
  1.9473 +    else 
  1.9474 +      printf("cnt=%d \n", DR_state->mCount);
  1.9475 +    if (DR_state->mDisplayPixelErrors) {
  1.9476 +      int32_t p2t = aPresContext->AppUnitsPerDevPixel();
  1.9477 +      CheckPixelError(aReflowState.AvailableWidth(), p2t);
  1.9478 +      CheckPixelError(aReflowState.AvailableHeight(), p2t);
  1.9479 +      CheckPixelError(aReflowState.ComputedWidth(), p2t);
  1.9480 +      CheckPixelError(aReflowState.ComputedHeight(), p2t);
  1.9481 +    }
  1.9482 +  }
  1.9483 +}
  1.9484 +
  1.9485 +void* nsFrame::DisplayReflowEnter(nsPresContext*          aPresContext,
  1.9486 +                                  nsIFrame*                aFrame,
  1.9487 +                                  const nsHTMLReflowState& aReflowState)
  1.9488 +{
  1.9489 +  if (!DR_state->mInited) DR_state->Init();
  1.9490 +  if (!DR_state->mActive) return nullptr;
  1.9491 +
  1.9492 +  NS_ASSERTION(aFrame, "invalid call");
  1.9493 +
  1.9494 +  DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, &aReflowState);
  1.9495 +  if (treeNode) {
  1.9496 +    DisplayReflowEnterPrint(aPresContext, aFrame, aReflowState, *treeNode, false);
  1.9497 +  }
  1.9498 +  return treeNode;
  1.9499 +}
  1.9500 +
  1.9501 +void* nsFrame::DisplayLayoutEnter(nsIFrame* aFrame)
  1.9502 +{
  1.9503 +  if (!DR_state->mInited) DR_state->Init();
  1.9504 +  if (!DR_state->mActive) return nullptr;
  1.9505 +
  1.9506 +  NS_ASSERTION(aFrame, "invalid call");
  1.9507 +
  1.9508 +  DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nullptr);
  1.9509 +  if (treeNode && treeNode->mDisplay) {
  1.9510 +    DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
  1.9511 +    printf("Layout\n");
  1.9512 +  }
  1.9513 +  return treeNode;
  1.9514 +}
  1.9515 +
  1.9516 +void* nsFrame::DisplayIntrinsicWidthEnter(nsIFrame* aFrame,
  1.9517 +                                          const char* aType)
  1.9518 +{
  1.9519 +  if (!DR_state->mInited) DR_state->Init();
  1.9520 +  if (!DR_state->mActive) return nullptr;
  1.9521 +
  1.9522 +  NS_ASSERTION(aFrame, "invalid call");
  1.9523 +
  1.9524 +  DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nullptr);
  1.9525 +  if (treeNode && treeNode->mDisplay) {
  1.9526 +    DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
  1.9527 +    printf("Get%sWidth\n", aType);
  1.9528 +  }
  1.9529 +  return treeNode;
  1.9530 +}
  1.9531 +
  1.9532 +void* nsFrame::DisplayIntrinsicSizeEnter(nsIFrame* aFrame,
  1.9533 +                                         const char* aType)
  1.9534 +{
  1.9535 +  if (!DR_state->mInited) DR_state->Init();
  1.9536 +  if (!DR_state->mActive) return nullptr;
  1.9537 +
  1.9538 +  NS_ASSERTION(aFrame, "invalid call");
  1.9539 +
  1.9540 +  DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nullptr);
  1.9541 +  if (treeNode && treeNode->mDisplay) {
  1.9542 +    DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
  1.9543 +    printf("Get%sSize\n", aType);
  1.9544 +  }
  1.9545 +  return treeNode;
  1.9546 +}
  1.9547 +
  1.9548 +void nsFrame::DisplayReflowExit(nsPresContext*      aPresContext,
  1.9549 +                                nsIFrame*            aFrame,
  1.9550 +                                nsHTMLReflowMetrics& aMetrics,
  1.9551 +                                nsReflowStatus       aStatus,
  1.9552 +                                void*                aFrameTreeNode)
  1.9553 +{
  1.9554 +  if (!DR_state->mActive) return;
  1.9555 +
  1.9556 +  NS_ASSERTION(aFrame, "DisplayReflowExit - invalid call");
  1.9557 +  if (!aFrameTreeNode) return;
  1.9558 +
  1.9559 +  DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode;
  1.9560 +  if (treeNode->mDisplay) {
  1.9561 +    DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
  1.9562 +
  1.9563 +    char width[16];
  1.9564 +    char height[16];
  1.9565 +    char x[16];
  1.9566 +    char y[16];
  1.9567 +    DR_state->PrettyUC(aMetrics.Width(), width);
  1.9568 +    DR_state->PrettyUC(aMetrics.Height(), height);
  1.9569 +    printf("Reflow d=%s,%s", width, height);
  1.9570 +
  1.9571 +    if (!NS_FRAME_IS_FULLY_COMPLETE(aStatus)) {
  1.9572 +      printf(" status=0x%x", aStatus);
  1.9573 +    }
  1.9574 +    if (aFrame->HasOverflowAreas()) {
  1.9575 +      DR_state->PrettyUC(aMetrics.VisualOverflow().x, x);
  1.9576 +      DR_state->PrettyUC(aMetrics.VisualOverflow().y, y);
  1.9577 +      DR_state->PrettyUC(aMetrics.VisualOverflow().width, width);
  1.9578 +      DR_state->PrettyUC(aMetrics.VisualOverflow().height, height);
  1.9579 +      printf(" vis-o=(%s,%s) %s x %s", x, y, width, height);
  1.9580 +
  1.9581 +      nsRect storedOverflow = aFrame->GetVisualOverflowRect();
  1.9582 +      DR_state->PrettyUC(storedOverflow.x, x);
  1.9583 +      DR_state->PrettyUC(storedOverflow.y, y);
  1.9584 +      DR_state->PrettyUC(storedOverflow.width, width);
  1.9585 +      DR_state->PrettyUC(storedOverflow.height, height);
  1.9586 +      printf(" vis-sto=(%s,%s) %s x %s", x, y, width, height);
  1.9587 +
  1.9588 +      DR_state->PrettyUC(aMetrics.ScrollableOverflow().x, x);
  1.9589 +      DR_state->PrettyUC(aMetrics.ScrollableOverflow().y, y);
  1.9590 +      DR_state->PrettyUC(aMetrics.ScrollableOverflow().width, width);
  1.9591 +      DR_state->PrettyUC(aMetrics.ScrollableOverflow().height, height);
  1.9592 +      printf(" scr-o=(%s,%s) %s x %s", x, y, width, height);
  1.9593 +
  1.9594 +      storedOverflow = aFrame->GetScrollableOverflowRect();
  1.9595 +      DR_state->PrettyUC(storedOverflow.x, x);
  1.9596 +      DR_state->PrettyUC(storedOverflow.y, y);
  1.9597 +      DR_state->PrettyUC(storedOverflow.width, width);
  1.9598 +      DR_state->PrettyUC(storedOverflow.height, height);
  1.9599 +      printf(" scr-sto=(%s,%s) %s x %s", x, y, width, height);
  1.9600 +    }
  1.9601 +    printf("\n");
  1.9602 +    if (DR_state->mDisplayPixelErrors) {
  1.9603 +      int32_t p2t = aPresContext->AppUnitsPerDevPixel();
  1.9604 +      CheckPixelError(aMetrics.Width(), p2t);
  1.9605 +      CheckPixelError(aMetrics.Height(), p2t);
  1.9606 +    }
  1.9607 +  }
  1.9608 +  DR_state->DeleteTreeNode(*treeNode);
  1.9609 +}
  1.9610 +
  1.9611 +void nsFrame::DisplayLayoutExit(nsIFrame*            aFrame,
  1.9612 +                                void*                aFrameTreeNode)
  1.9613 +{
  1.9614 +  if (!DR_state->mActive) return;
  1.9615 +
  1.9616 +  NS_ASSERTION(aFrame, "non-null frame required");
  1.9617 +  if (!aFrameTreeNode) return;
  1.9618 +
  1.9619 +  DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode;
  1.9620 +  if (treeNode->mDisplay) {
  1.9621 +    DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
  1.9622 +    nsRect rect = aFrame->GetRect();
  1.9623 +    printf("Layout=%d,%d,%d,%d\n", rect.x, rect.y, rect.width, rect.height);
  1.9624 +  }
  1.9625 +  DR_state->DeleteTreeNode(*treeNode);
  1.9626 +}
  1.9627 +
  1.9628 +void nsFrame::DisplayIntrinsicWidthExit(nsIFrame*            aFrame,
  1.9629 +                                        const char*          aType,
  1.9630 +                                        nscoord              aResult,
  1.9631 +                                        void*                aFrameTreeNode)
  1.9632 +{
  1.9633 +  if (!DR_state->mActive) return;
  1.9634 +
  1.9635 +  NS_ASSERTION(aFrame, "non-null frame required");
  1.9636 +  if (!aFrameTreeNode) return;
  1.9637 +
  1.9638 +  DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode;
  1.9639 +  if (treeNode->mDisplay) {
  1.9640 +    DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
  1.9641 +    char width[16];
  1.9642 +    DR_state->PrettyUC(aResult, width);
  1.9643 +    printf("Get%sWidth=%s\n", aType, width);
  1.9644 +  }
  1.9645 +  DR_state->DeleteTreeNode(*treeNode);
  1.9646 +}
  1.9647 +
  1.9648 +void nsFrame::DisplayIntrinsicSizeExit(nsIFrame*            aFrame,
  1.9649 +                                       const char*          aType,
  1.9650 +                                       nsSize               aResult,
  1.9651 +                                       void*                aFrameTreeNode)
  1.9652 +{
  1.9653 +  if (!DR_state->mActive) return;
  1.9654 +
  1.9655 +  NS_ASSERTION(aFrame, "non-null frame required");
  1.9656 +  if (!aFrameTreeNode) return;
  1.9657 +
  1.9658 +  DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode;
  1.9659 +  if (treeNode->mDisplay) {
  1.9660 +    DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
  1.9661 +
  1.9662 +    char width[16];
  1.9663 +    char height[16];
  1.9664 +    DR_state->PrettyUC(aResult.width, width);
  1.9665 +    DR_state->PrettyUC(aResult.height, height);
  1.9666 +    printf("Get%sSize=%s,%s\n", aType, width, height);
  1.9667 +  }
  1.9668 +  DR_state->DeleteTreeNode(*treeNode);
  1.9669 +}
  1.9670 +
  1.9671 +/* static */ void
  1.9672 +nsFrame::DisplayReflowStartup()
  1.9673 +{
  1.9674 +  DR_state = new DR_State();
  1.9675 +}
  1.9676 +
  1.9677 +/* static */ void
  1.9678 +nsFrame::DisplayReflowShutdown()
  1.9679 +{
  1.9680 +  delete DR_state;
  1.9681 +  DR_state = nullptr;
  1.9682 +}
  1.9683 +
  1.9684 +void DR_cookie::Change() const
  1.9685 +{
  1.9686 +  DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)mValue;
  1.9687 +  if (treeNode && treeNode->mDisplay) {
  1.9688 +    DisplayReflowEnterPrint(mPresContext, mFrame, mReflowState, *treeNode, true);
  1.9689 +  }
  1.9690 +}
  1.9691 +
  1.9692 +/* static */ void*
  1.9693 +nsHTMLReflowState::DisplayInitConstraintsEnter(nsIFrame* aFrame,
  1.9694 +                                               nsHTMLReflowState* aState,
  1.9695 +                                               nscoord aContainingBlockWidth,
  1.9696 +                                               nscoord aContainingBlockHeight,
  1.9697 +                                               const nsMargin* aBorder,
  1.9698 +                                               const nsMargin* aPadding)
  1.9699 +{
  1.9700 +  NS_PRECONDITION(aFrame, "non-null frame required");
  1.9701 +  NS_PRECONDITION(aState, "non-null state required");
  1.9702 +
  1.9703 +  if (!DR_state->mInited) DR_state->Init();
  1.9704 +  if (!DR_state->mActive) return nullptr;
  1.9705 +
  1.9706 +  DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, aState);
  1.9707 +  if (treeNode && treeNode->mDisplay) {
  1.9708 +    DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
  1.9709 +
  1.9710 +    printf("InitConstraints parent=%p",
  1.9711 +           (void*)aState->parentReflowState);
  1.9712 +
  1.9713 +    char width[16];
  1.9714 +    char height[16];
  1.9715 +
  1.9716 +    DR_state->PrettyUC(aContainingBlockWidth, width);
  1.9717 +    DR_state->PrettyUC(aContainingBlockHeight, height);
  1.9718 +    printf(" cb=%s,%s", width, height);
  1.9719 +
  1.9720 +    DR_state->PrettyUC(aState->AvailableWidth(), width);
  1.9721 +    DR_state->PrettyUC(aState->AvailableHeight(), height);
  1.9722 +    printf(" as=%s,%s", width, height);
  1.9723 +
  1.9724 +    DR_state->PrintMargin("b", aBorder);
  1.9725 +    DR_state->PrintMargin("p", aPadding);
  1.9726 +    putchar('\n');
  1.9727 +  }
  1.9728 +  return treeNode;
  1.9729 +}
  1.9730 +
  1.9731 +/* static */ void
  1.9732 +nsHTMLReflowState::DisplayInitConstraintsExit(nsIFrame* aFrame,
  1.9733 +                                              nsHTMLReflowState* aState,
  1.9734 +                                              void* aValue)
  1.9735 +{
  1.9736 +  NS_PRECONDITION(aFrame, "non-null frame required");
  1.9737 +  NS_PRECONDITION(aState, "non-null state required");
  1.9738 +
  1.9739 +  if (!DR_state->mActive) return;
  1.9740 +  if (!aValue) return;
  1.9741 +
  1.9742 +  DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aValue;
  1.9743 +  if (treeNode->mDisplay) {
  1.9744 +    DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
  1.9745 +    char cmiw[16], cw[16], cmxw[16], cmih[16], ch[16], cmxh[16];
  1.9746 +    DR_state->PrettyUC(aState->ComputedMinWidth(), cmiw);
  1.9747 +    DR_state->PrettyUC(aState->ComputedWidth(), cw);
  1.9748 +    DR_state->PrettyUC(aState->ComputedMaxWidth(), cmxw);
  1.9749 +    DR_state->PrettyUC(aState->ComputedMinHeight(), cmih);
  1.9750 +    DR_state->PrettyUC(aState->ComputedHeight(), ch);
  1.9751 +    DR_state->PrettyUC(aState->ComputedMaxHeight(), cmxh);
  1.9752 +    printf("InitConstraints= cw=(%s <= %s <= %s) ch=(%s <= %s <= %s)",
  1.9753 +           cmiw, cw, cmxw, cmih, ch, cmxh);
  1.9754 +    DR_state->PrintMargin("co", &aState->ComputedPhysicalOffsets());
  1.9755 +    putchar('\n');
  1.9756 +  }
  1.9757 +  DR_state->DeleteTreeNode(*treeNode);
  1.9758 +}
  1.9759 +
  1.9760 +
  1.9761 +/* static */ void*
  1.9762 +nsCSSOffsetState::DisplayInitOffsetsEnter(nsIFrame* aFrame,
  1.9763 +                                          nsCSSOffsetState* aState,
  1.9764 +                                          nscoord aHorizontalPercentBasis,
  1.9765 +                                          nscoord aVerticalPercentBasis,
  1.9766 +                                          const nsMargin* aBorder,
  1.9767 +                                          const nsMargin* aPadding)
  1.9768 +{
  1.9769 +  NS_PRECONDITION(aFrame, "non-null frame required");
  1.9770 +  NS_PRECONDITION(aState, "non-null state required");
  1.9771 +
  1.9772 +  if (!DR_state->mInited) DR_state->Init();
  1.9773 +  if (!DR_state->mActive) return nullptr;
  1.9774 +
  1.9775 +  // aState is not necessarily a nsHTMLReflowState
  1.9776 +  DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nullptr);
  1.9777 +  if (treeNode && treeNode->mDisplay) {
  1.9778 +    DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
  1.9779 +
  1.9780 +    char horizPctBasisStr[16];
  1.9781 +    char vertPctBasisStr[16];
  1.9782 +    DR_state->PrettyUC(aHorizontalPercentBasis, horizPctBasisStr);
  1.9783 +    DR_state->PrettyUC(aVerticalPercentBasis,   vertPctBasisStr);
  1.9784 +    printf("InitOffsets pct_basis=%s,%s", horizPctBasisStr, vertPctBasisStr);
  1.9785 +
  1.9786 +    DR_state->PrintMargin("b", aBorder);
  1.9787 +    DR_state->PrintMargin("p", aPadding);
  1.9788 +    putchar('\n');
  1.9789 +  }
  1.9790 +  return treeNode;
  1.9791 +}
  1.9792 +
  1.9793 +/* static */ void
  1.9794 +nsCSSOffsetState::DisplayInitOffsetsExit(nsIFrame* aFrame,
  1.9795 +                                         nsCSSOffsetState* aState,
  1.9796 +                                         void* aValue)
  1.9797 +{
  1.9798 +  NS_PRECONDITION(aFrame, "non-null frame required");
  1.9799 +  NS_PRECONDITION(aState, "non-null state required");
  1.9800 +
  1.9801 +  if (!DR_state->mActive) return;
  1.9802 +  if (!aValue) return;
  1.9803 +
  1.9804 +  DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aValue;
  1.9805 +  if (treeNode->mDisplay) {
  1.9806 +    DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
  1.9807 +    printf("InitOffsets=");
  1.9808 +    DR_state->PrintMargin("m", &aState->ComputedPhysicalMargin());
  1.9809 +    DR_state->PrintMargin("p", &aState->ComputedPhysicalPadding());
  1.9810 +    DR_state->PrintMargin("p+b", &aState->ComputedPhysicalBorderPadding());
  1.9811 +    putchar('\n');
  1.9812 +  }
  1.9813 +  DR_state->DeleteTreeNode(*treeNode);
  1.9814 +}
  1.9815 +
  1.9816 +/* static */ void*
  1.9817 +nsHTMLReflowState::DisplayInitFrameTypeEnter(nsIFrame* aFrame,
  1.9818 +                                             nsHTMLReflowState* aState)
  1.9819 +{
  1.9820 +  NS_PRECONDITION(aFrame, "non-null frame required");
  1.9821 +  NS_PRECONDITION(aState, "non-null state required");
  1.9822 +
  1.9823 +  if (!DR_state->mInited) DR_state->Init();
  1.9824 +  if (!DR_state->mActive) return nullptr;
  1.9825 +
  1.9826 +  // we don't print anything here
  1.9827 +  return DR_state->CreateTreeNode(aFrame, aState);
  1.9828 +}
  1.9829 +
  1.9830 +/* static */ void
  1.9831 +nsHTMLReflowState::DisplayInitFrameTypeExit(nsIFrame* aFrame,
  1.9832 +                                            nsHTMLReflowState* aState,
  1.9833 +                                            void* aValue)
  1.9834 +{
  1.9835 +  NS_PRECONDITION(aFrame, "non-null frame required");
  1.9836 +  NS_PRECONDITION(aState, "non-null state required");
  1.9837 +
  1.9838 +  if (!DR_state->mActive) return;
  1.9839 +  if (!aValue) return;
  1.9840 +
  1.9841 +  DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aValue;
  1.9842 +  if (treeNode->mDisplay) {
  1.9843 +    DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
  1.9844 +    printf("InitFrameType");
  1.9845 +
  1.9846 +    const nsStyleDisplay *disp = aState->mStyleDisplay;
  1.9847 +
  1.9848 +    if (aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
  1.9849 +      printf(" out-of-flow");
  1.9850 +    if (aFrame->GetPrevInFlow())
  1.9851 +      printf(" prev-in-flow");
  1.9852 +    if (aFrame->IsAbsolutelyPositioned())
  1.9853 +      printf(" abspos");
  1.9854 +    if (aFrame->IsFloating())
  1.9855 +      printf(" float");
  1.9856 +
  1.9857 +    // This array must exactly match the NS_STYLE_DISPLAY constants.
  1.9858 +    const char *const displayTypes[] = {
  1.9859 +      "none", "block", "inline", "inline-block", "list-item", "marker",
  1.9860 +      "run-in", "compact", "table", "inline-table", "table-row-group",
  1.9861 +      "table-column", "table-column-group", "table-header-group",
  1.9862 +      "table-footer-group", "table-row", "table-cell", "table-caption",
  1.9863 +      "box", "inline-box",
  1.9864 +#ifdef MOZ_XUL
  1.9865 +      "grid", "inline-grid", "grid-group", "grid-line", "stack",
  1.9866 +      "inline-stack", "deck", "popup", "groupbox",
  1.9867 +#endif
  1.9868 +    };
  1.9869 +    if (disp->mDisplay >= ArrayLength(displayTypes))
  1.9870 +      printf(" display=%u", disp->mDisplay);
  1.9871 +    else
  1.9872 +      printf(" display=%s", displayTypes[disp->mDisplay]);
  1.9873 +
  1.9874 +    // This array must exactly match the NS_CSS_FRAME_TYPE constants.
  1.9875 +    const char *const cssFrameTypes[] = {
  1.9876 +      "unknown", "inline", "block", "floating", "absolute", "internal-table"
  1.9877 +    };
  1.9878 +    nsCSSFrameType bareType = NS_FRAME_GET_TYPE(aState->mFrameType);
  1.9879 +    bool repNoBlock = NS_FRAME_IS_REPLACED_NOBLOCK(aState->mFrameType);
  1.9880 +    bool repBlock = NS_FRAME_IS_REPLACED_CONTAINS_BLOCK(aState->mFrameType);
  1.9881 +
  1.9882 +    if (bareType >= ArrayLength(cssFrameTypes)) {
  1.9883 +      printf(" result=type %u", bareType);
  1.9884 +    } else {
  1.9885 +      printf(" result=%s", cssFrameTypes[bareType]);
  1.9886 +    }
  1.9887 +    printf("%s%s\n", repNoBlock ? " +rep" : "", repBlock ? " +repBlk" : "");
  1.9888 +  }
  1.9889 +  DR_state->DeleteTreeNode(*treeNode);
  1.9890 +}
  1.9891 +
  1.9892 +#endif
  1.9893 +// End Display Reflow
  1.9894 +
  1.9895 +#endif

mercurial