layout/xul/nsBoxFrame.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/layout/xul/nsBoxFrame.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,2109 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set ts=2 sw=2 et tw=80: */
     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 +//
    1.11 +// Eric Vaughan
    1.12 +// Netscape Communications
    1.13 +//
    1.14 +// See documentation in associated header file
    1.15 +//
    1.16 +
    1.17 +// How boxes layout
    1.18 +// ----------------
    1.19 +// Boxes layout a bit differently than html. html does a bottom up layout. Where boxes do a top down.
    1.20 +// 1) First thing a box does it goes out and askes each child for its min, max, and preferred sizes.
    1.21 +// 2) It then adds them up to determine its size.
    1.22 +// 3) If the box was asked to layout it self intrinically it will layout its children at their preferred size
    1.23 +//    otherwise it will layout the child at the size it was told to. It will squeeze or stretch its children if 
    1.24 +//    Necessary.
    1.25 +//
    1.26 +// However there is a catch. Some html components like block frames can not determine their preferred size. 
    1.27 +// this is their size if they were laid out intrinsically. So the box will flow the child to determine this can
    1.28 +// cache the value.
    1.29 +
    1.30 +// Boxes and Incremental Reflow
    1.31 +// ----------------------------
    1.32 +// Boxes layout out top down by adding up their children's min, max, and preferred sizes. Only problem is if a incremental
    1.33 +// reflow occurs. The preferred size of a child deep in the hierarchy could change. And this could change
    1.34 +// any number of syblings around the box. Basically any children in the reflow chain must have their caches cleared
    1.35 +// so when asked for there current size they can relayout themselves. 
    1.36 +
    1.37 +#include "nsBoxLayoutState.h"
    1.38 +#include "nsBoxFrame.h"
    1.39 +#include "mozilla/dom/Touch.h"
    1.40 +#include "nsStyleContext.h"
    1.41 +#include "nsPlaceholderFrame.h"
    1.42 +#include "nsPresContext.h"
    1.43 +#include "nsCOMPtr.h"
    1.44 +#include "nsNameSpaceManager.h"
    1.45 +#include "nsGkAtoms.h"
    1.46 +#include "nsIContent.h"
    1.47 +#include "nsHTMLParts.h"
    1.48 +#include "nsViewManager.h"
    1.49 +#include "nsView.h"
    1.50 +#include "nsIPresShell.h"
    1.51 +#include "nsCSSRendering.h"
    1.52 +#include "nsIServiceManager.h"
    1.53 +#include "nsBoxLayout.h"
    1.54 +#include "nsSprocketLayout.h"
    1.55 +#include "nsIScrollableFrame.h"
    1.56 +#include "nsWidgetsCID.h"
    1.57 +#include "nsCSSAnonBoxes.h"
    1.58 +#include "nsContainerFrame.h"
    1.59 +#include "nsIDOMElement.h"
    1.60 +#include "nsITheme.h"
    1.61 +#include "nsTransform2D.h"
    1.62 +#include "mozilla/EventStateManager.h"
    1.63 +#include "nsIDOMEvent.h"
    1.64 +#include "nsDisplayList.h"
    1.65 +#include "mozilla/Preferences.h"
    1.66 +#include "nsThemeConstants.h"
    1.67 +#include "nsLayoutUtils.h"
    1.68 +#include <algorithm>
    1.69 +
    1.70 +// Needed for Print Preview
    1.71 +#include "nsIURI.h"
    1.72 +
    1.73 +#include "mozilla/TouchEvents.h"
    1.74 +
    1.75 +using namespace mozilla;
    1.76 +using namespace mozilla::dom;
    1.77 +
    1.78 +//define DEBUG_REDRAW
    1.79 +
    1.80 +#define DEBUG_SPRING_SIZE 8
    1.81 +#define DEBUG_BORDER_SIZE 2
    1.82 +#define COIL_SIZE 8
    1.83 +
    1.84 +//#define TEST_SANITY
    1.85 +
    1.86 +#ifdef DEBUG_rods
    1.87 +//#define DO_NOISY_REFLOW
    1.88 +#endif
    1.89 +
    1.90 +#ifdef DEBUG_LAYOUT
    1.91 +bool nsBoxFrame::gDebug = false;
    1.92 +nsIFrame* nsBoxFrame::mDebugChild = nullptr;
    1.93 +#endif
    1.94 +
    1.95 +nsIFrame*
    1.96 +NS_NewBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, bool aIsRoot, nsBoxLayout* aLayoutManager)
    1.97 +{
    1.98 +  return new (aPresShell) nsBoxFrame(aPresShell, aContext, aIsRoot, aLayoutManager);
    1.99 +}
   1.100 +
   1.101 +nsIFrame*
   1.102 +NS_NewBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
   1.103 +{
   1.104 +  return new (aPresShell) nsBoxFrame(aPresShell, aContext);
   1.105 +}
   1.106 +
   1.107 +NS_IMPL_FRAMEARENA_HELPERS(nsBoxFrame)
   1.108 +
   1.109 +#ifdef DEBUG
   1.110 +NS_QUERYFRAME_HEAD(nsBoxFrame)
   1.111 +  NS_QUERYFRAME_ENTRY(nsBoxFrame)
   1.112 +NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
   1.113 +#endif
   1.114 +
   1.115 +nsBoxFrame::nsBoxFrame(nsIPresShell* aPresShell,
   1.116 +                       nsStyleContext* aContext,
   1.117 +                       bool aIsRoot,
   1.118 +                       nsBoxLayout* aLayoutManager) :
   1.119 +  nsContainerFrame(aContext)
   1.120 +{
   1.121 +  mState |= NS_STATE_IS_HORIZONTAL;
   1.122 +  mState |= NS_STATE_AUTO_STRETCH;
   1.123 +
   1.124 +  if (aIsRoot) 
   1.125 +     mState |= NS_STATE_IS_ROOT;
   1.126 +
   1.127 +  mValign = vAlign_Top;
   1.128 +  mHalign = hAlign_Left;
   1.129 +  
   1.130 +  // if no layout manager specified us the static sprocket layout
   1.131 +  nsCOMPtr<nsBoxLayout> layout = aLayoutManager;
   1.132 +
   1.133 +  if (layout == nullptr) {
   1.134 +    NS_NewSprocketLayout(aPresShell, layout);
   1.135 +  }
   1.136 +
   1.137 +  SetLayoutManager(layout);
   1.138 +}
   1.139 +
   1.140 +nsBoxFrame::~nsBoxFrame()
   1.141 +{
   1.142 +}
   1.143 +
   1.144 +nsresult
   1.145 +nsBoxFrame::SetInitialChildList(ChildListID     aListID,
   1.146 +                                nsFrameList&    aChildList)
   1.147 +{
   1.148 +  nsresult r = nsContainerFrame::SetInitialChildList(aListID, aChildList);
   1.149 +  if (r == NS_OK) {
   1.150 +    // initialize our list of infos.
   1.151 +    nsBoxLayoutState state(PresContext());
   1.152 +    CheckBoxOrder();
   1.153 +    if (mLayoutManager)
   1.154 +      mLayoutManager->ChildrenSet(this, state, mFrames.FirstChild());
   1.155 +  } else {
   1.156 +    NS_WARNING("Warning add child failed!!\n");
   1.157 +  }
   1.158 +
   1.159 +  return r;
   1.160 +}
   1.161 +
   1.162 +/* virtual */ void
   1.163 +nsBoxFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
   1.164 +{
   1.165 +  nsContainerFrame::DidSetStyleContext(aOldStyleContext);
   1.166 +
   1.167 +  // The values that CacheAttributes() computes depend on our style,
   1.168 +  // so we need to recompute them here...
   1.169 +  CacheAttributes();
   1.170 +}
   1.171 +
   1.172 +/**
   1.173 + * Initialize us. This is a good time to get the alignment of the box
   1.174 + */
   1.175 +void
   1.176 +nsBoxFrame::Init(nsIContent*      aContent,
   1.177 +                 nsIFrame*        aParent,
   1.178 +                 nsIFrame*        aPrevInFlow)
   1.179 +{
   1.180 +  nsContainerFrame::Init(aContent, aParent, aPrevInFlow);
   1.181 +
   1.182 +  if (GetStateBits() & NS_FRAME_FONT_INFLATION_CONTAINER) {
   1.183 +    AddStateBits(NS_FRAME_FONT_INFLATION_FLOW_ROOT);
   1.184 +  }
   1.185 +
   1.186 +  MarkIntrinsicWidthsDirty();
   1.187 +
   1.188 +  CacheAttributes();
   1.189 +
   1.190 +#ifdef DEBUG_LAYOUT
   1.191 +    // if we are root and this
   1.192 +  if (mState & NS_STATE_IS_ROOT) 
   1.193 +      GetDebugPref(GetPresContext());
   1.194 +#endif
   1.195 +
   1.196 +  UpdateMouseThrough();
   1.197 +
   1.198 +  // register access key
   1.199 +  RegUnregAccessKey(true);
   1.200 +}
   1.201 +
   1.202 +void nsBoxFrame::UpdateMouseThrough()
   1.203 +{
   1.204 +  if (mContent) {
   1.205 +    static nsIContent::AttrValuesArray strings[] =
   1.206 +      {&nsGkAtoms::never, &nsGkAtoms::always, nullptr};
   1.207 +    switch (mContent->FindAttrValueIn(kNameSpaceID_None,
   1.208 +              nsGkAtoms::mousethrough, strings, eCaseMatters)) {
   1.209 +      case 0: AddStateBits(NS_FRAME_MOUSE_THROUGH_NEVER); break;
   1.210 +      case 1: AddStateBits(NS_FRAME_MOUSE_THROUGH_ALWAYS); break;
   1.211 +      case 2: {
   1.212 +        RemoveStateBits(NS_FRAME_MOUSE_THROUGH_ALWAYS);
   1.213 +        RemoveStateBits(NS_FRAME_MOUSE_THROUGH_NEVER);
   1.214 +        break;
   1.215 +      }
   1.216 +    }
   1.217 +  }
   1.218 +}
   1.219 +
   1.220 +void
   1.221 +nsBoxFrame::CacheAttributes()
   1.222 +{
   1.223 +  /*
   1.224 +  printf("Caching: ");
   1.225 +  DumpBox(stdout);
   1.226 +  printf("\n");
   1.227 +   */
   1.228 +
   1.229 +  mValign = vAlign_Top;
   1.230 +  mHalign = hAlign_Left;
   1.231 +
   1.232 +  bool orient = false;
   1.233 +  GetInitialOrientation(orient); 
   1.234 +  if (orient)
   1.235 +    mState |= NS_STATE_IS_HORIZONTAL;
   1.236 +  else
   1.237 +    mState &= ~NS_STATE_IS_HORIZONTAL;
   1.238 +
   1.239 +  bool normal = true;
   1.240 +  GetInitialDirection(normal); 
   1.241 +  if (normal)
   1.242 +    mState |= NS_STATE_IS_DIRECTION_NORMAL;
   1.243 +  else
   1.244 +    mState &= ~NS_STATE_IS_DIRECTION_NORMAL;
   1.245 +
   1.246 +  GetInitialVAlignment(mValign);
   1.247 +  GetInitialHAlignment(mHalign);
   1.248 +  
   1.249 +  bool equalSize = false;
   1.250 +  GetInitialEqualSize(equalSize); 
   1.251 +  if (equalSize)
   1.252 +        mState |= NS_STATE_EQUAL_SIZE;
   1.253 +    else
   1.254 +        mState &= ~NS_STATE_EQUAL_SIZE;
   1.255 +
   1.256 +  bool autostretch = !!(mState & NS_STATE_AUTO_STRETCH);
   1.257 +  GetInitialAutoStretch(autostretch);
   1.258 +  if (autostretch)
   1.259 +        mState |= NS_STATE_AUTO_STRETCH;
   1.260 +     else
   1.261 +        mState &= ~NS_STATE_AUTO_STRETCH;
   1.262 +
   1.263 +
   1.264 +#ifdef DEBUG_LAYOUT
   1.265 +  bool debug = mState & NS_STATE_SET_TO_DEBUG;
   1.266 +  bool debugSet = GetInitialDebug(debug); 
   1.267 +  if (debugSet) {
   1.268 +        mState |= NS_STATE_DEBUG_WAS_SET;
   1.269 +        if (debug)
   1.270 +            mState |= NS_STATE_SET_TO_DEBUG;
   1.271 +        else
   1.272 +            mState &= ~NS_STATE_SET_TO_DEBUG;
   1.273 +  } else {
   1.274 +        mState &= ~NS_STATE_DEBUG_WAS_SET;
   1.275 +  }
   1.276 +#endif
   1.277 +}
   1.278 +
   1.279 +#ifdef DEBUG_LAYOUT
   1.280 +bool
   1.281 +nsBoxFrame::GetInitialDebug(bool& aDebug)
   1.282 +{
   1.283 +  if (!GetContent())
   1.284 +    return false;
   1.285 +
   1.286 +  static nsIContent::AttrValuesArray strings[] =
   1.287 +    {&nsGkAtoms::_false, &nsGkAtoms::_true, nullptr};
   1.288 +  int32_t index = GetContent()->FindAttrValueIn(kNameSpaceID_None,
   1.289 +      nsGkAtoms::debug, strings, eCaseMatters);
   1.290 +  if (index >= 0) {
   1.291 +    aDebug = index == 1;
   1.292 +    return true;
   1.293 +  }
   1.294 +
   1.295 +  return false;
   1.296 +}
   1.297 +#endif
   1.298 +
   1.299 +bool
   1.300 +nsBoxFrame::GetInitialHAlignment(nsBoxFrame::Halignment& aHalign)
   1.301 +{
   1.302 +  if (!GetContent())
   1.303 +    return false;
   1.304 +
   1.305 +  // XXXdwh Everything inside this if statement is deprecated code.
   1.306 +  static nsIContent::AttrValuesArray alignStrings[] =
   1.307 +    {&nsGkAtoms::left, &nsGkAtoms::right, nullptr};
   1.308 +  static const Halignment alignValues[] = {hAlign_Left, hAlign_Right};
   1.309 +  int32_t index = GetContent()->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::align,
   1.310 +      alignStrings, eCaseMatters);
   1.311 +  if (index >= 0) {
   1.312 +    aHalign = alignValues[index];
   1.313 +    return true;
   1.314 +  }
   1.315 +      
   1.316 +  // Now that the deprecated stuff is out of the way, we move on to check the appropriate 
   1.317 +  // attribute.  For horizontal boxes, we are checking the PACK attribute.  For vertical boxes
   1.318 +  // we are checking the ALIGN attribute.
   1.319 +  nsIAtom* attrName = IsHorizontal() ? nsGkAtoms::pack : nsGkAtoms::align;
   1.320 +  static nsIContent::AttrValuesArray strings[] =
   1.321 +    {&nsGkAtoms::_empty, &nsGkAtoms::start, &nsGkAtoms::center, &nsGkAtoms::end, nullptr};
   1.322 +  static const Halignment values[] =
   1.323 +    {hAlign_Left/*not used*/, hAlign_Left, hAlign_Center, hAlign_Right};
   1.324 +  index = GetContent()->FindAttrValueIn(kNameSpaceID_None, attrName,
   1.325 +      strings, eCaseMatters);
   1.326 +
   1.327 +  if (index == nsIContent::ATTR_VALUE_NO_MATCH) {
   1.328 +    // The attr was present but had a nonsensical value. Revert to the default.
   1.329 +    return false;
   1.330 +  }
   1.331 +  if (index > 0) {    
   1.332 +    aHalign = values[index];
   1.333 +    return true;
   1.334 +  }
   1.335 +
   1.336 +  // Now that we've checked for the attribute it's time to check CSS.  For 
   1.337 +  // horizontal boxes we're checking PACK.  For vertical boxes we are checking
   1.338 +  // ALIGN.
   1.339 +  const nsStyleXUL* boxInfo = StyleXUL();
   1.340 +  if (IsHorizontal()) {
   1.341 +    switch (boxInfo->mBoxPack) {
   1.342 +      case NS_STYLE_BOX_PACK_START:
   1.343 +        aHalign = nsBoxFrame::hAlign_Left;
   1.344 +        return true;
   1.345 +      case NS_STYLE_BOX_PACK_CENTER:
   1.346 +        aHalign = nsBoxFrame::hAlign_Center;
   1.347 +        return true;
   1.348 +      case NS_STYLE_BOX_PACK_END:
   1.349 +        aHalign = nsBoxFrame::hAlign_Right;
   1.350 +        return true;
   1.351 +      default: // Nonsensical value. Just bail.
   1.352 +        return false;
   1.353 +    }
   1.354 +  }
   1.355 +  else {
   1.356 +    switch (boxInfo->mBoxAlign) {
   1.357 +      case NS_STYLE_BOX_ALIGN_START:
   1.358 +        aHalign = nsBoxFrame::hAlign_Left;
   1.359 +        return true;
   1.360 +      case NS_STYLE_BOX_ALIGN_CENTER:
   1.361 +        aHalign = nsBoxFrame::hAlign_Center;
   1.362 +        return true;
   1.363 +      case NS_STYLE_BOX_ALIGN_END:
   1.364 +        aHalign = nsBoxFrame::hAlign_Right;
   1.365 +        return true;
   1.366 +      default: // Nonsensical value. Just bail.
   1.367 +        return false;
   1.368 +    }
   1.369 +  }
   1.370 +
   1.371 +  return false;
   1.372 +}
   1.373 +
   1.374 +bool
   1.375 +nsBoxFrame::GetInitialVAlignment(nsBoxFrame::Valignment& aValign)
   1.376 +{
   1.377 +  if (!GetContent())
   1.378 +    return false;
   1.379 +
   1.380 +  static nsIContent::AttrValuesArray valignStrings[] =
   1.381 +    {&nsGkAtoms::top, &nsGkAtoms::baseline, &nsGkAtoms::middle, &nsGkAtoms::bottom, nullptr};
   1.382 +  static const Valignment valignValues[] =
   1.383 +    {vAlign_Top, vAlign_BaseLine, vAlign_Middle, vAlign_Bottom};
   1.384 +  int32_t index = GetContent()->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::valign,
   1.385 +      valignStrings, eCaseMatters);
   1.386 +  if (index >= 0) {
   1.387 +    aValign = valignValues[index];
   1.388 +    return true;
   1.389 +  }
   1.390 +
   1.391 +  // Now that the deprecated stuff is out of the way, we move on to check the appropriate 
   1.392 +  // attribute.  For horizontal boxes, we are checking the ALIGN attribute.  For vertical boxes
   1.393 +  // we are checking the PACK attribute.
   1.394 +  nsIAtom* attrName = IsHorizontal() ? nsGkAtoms::align : nsGkAtoms::pack;
   1.395 +  static nsIContent::AttrValuesArray strings[] =
   1.396 +    {&nsGkAtoms::_empty, &nsGkAtoms::start, &nsGkAtoms::center,
   1.397 +     &nsGkAtoms::baseline, &nsGkAtoms::end, nullptr};
   1.398 +  static const Valignment values[] =
   1.399 +    {vAlign_Top/*not used*/, vAlign_Top, vAlign_Middle, vAlign_BaseLine, vAlign_Bottom};
   1.400 +  index = GetContent()->FindAttrValueIn(kNameSpaceID_None, attrName,
   1.401 +      strings, eCaseMatters);
   1.402 +  if (index == nsIContent::ATTR_VALUE_NO_MATCH) {
   1.403 +    // The attr was present but had a nonsensical value. Revert to the default.
   1.404 +    return false;
   1.405 +  }
   1.406 +  if (index > 0) {
   1.407 +    aValign = values[index];
   1.408 +    return true;
   1.409 +  }
   1.410 +
   1.411 +  // Now that we've checked for the attribute it's time to check CSS.  For 
   1.412 +  // horizontal boxes we're checking ALIGN.  For vertical boxes we are checking
   1.413 +  // PACK.
   1.414 +  const nsStyleXUL* boxInfo = StyleXUL();
   1.415 +  if (IsHorizontal()) {
   1.416 +    switch (boxInfo->mBoxAlign) {
   1.417 +      case NS_STYLE_BOX_ALIGN_START:
   1.418 +        aValign = nsBoxFrame::vAlign_Top;
   1.419 +        return true;
   1.420 +      case NS_STYLE_BOX_ALIGN_CENTER:
   1.421 +        aValign = nsBoxFrame::vAlign_Middle;
   1.422 +        return true;
   1.423 +      case NS_STYLE_BOX_ALIGN_BASELINE:
   1.424 +        aValign = nsBoxFrame::vAlign_BaseLine;
   1.425 +        return true;
   1.426 +      case NS_STYLE_BOX_ALIGN_END:
   1.427 +        aValign = nsBoxFrame::vAlign_Bottom;
   1.428 +        return true;
   1.429 +      default: // Nonsensical value. Just bail.
   1.430 +        return false;
   1.431 +    }
   1.432 +  }
   1.433 +  else {
   1.434 +    switch (boxInfo->mBoxPack) {
   1.435 +      case NS_STYLE_BOX_PACK_START:
   1.436 +        aValign = nsBoxFrame::vAlign_Top;
   1.437 +        return true;
   1.438 +      case NS_STYLE_BOX_PACK_CENTER:
   1.439 +        aValign = nsBoxFrame::vAlign_Middle;
   1.440 +        return true;
   1.441 +      case NS_STYLE_BOX_PACK_END:
   1.442 +        aValign = nsBoxFrame::vAlign_Bottom;
   1.443 +        return true;
   1.444 +      default: // Nonsensical value. Just bail.
   1.445 +        return false;
   1.446 +    }
   1.447 +  }
   1.448 +
   1.449 +  return false;
   1.450 +}
   1.451 +
   1.452 +void
   1.453 +nsBoxFrame::GetInitialOrientation(bool& aIsHorizontal)
   1.454 +{
   1.455 + // see if we are a vertical or horizontal box.
   1.456 +  if (!GetContent())
   1.457 +    return;
   1.458 +
   1.459 +  // Check the style system first.
   1.460 +  const nsStyleXUL* boxInfo = StyleXUL();
   1.461 +  if (boxInfo->mBoxOrient == NS_STYLE_BOX_ORIENT_HORIZONTAL)
   1.462 +    aIsHorizontal = true;
   1.463 +  else 
   1.464 +    aIsHorizontal = false;
   1.465 +
   1.466 +  // Now see if we have an attribute.  The attribute overrides
   1.467 +  // the style system value.
   1.468 +  static nsIContent::AttrValuesArray strings[] =
   1.469 +    {&nsGkAtoms::vertical, &nsGkAtoms::horizontal, nullptr};
   1.470 +  int32_t index = GetContent()->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::orient,
   1.471 +      strings, eCaseMatters);
   1.472 +  if (index >= 0) {
   1.473 +    aIsHorizontal = index == 1;
   1.474 +  }
   1.475 +}
   1.476 +
   1.477 +void
   1.478 +nsBoxFrame::GetInitialDirection(bool& aIsNormal)
   1.479 +{
   1.480 +  if (!GetContent())
   1.481 +    return;
   1.482 +
   1.483 +  if (IsHorizontal()) {
   1.484 +    // For horizontal boxes only, we initialize our value based off the CSS 'direction' property.
   1.485 +    // This means that BiDI users will end up with horizontally inverted chrome.
   1.486 +    aIsNormal = (StyleVisibility()->mDirection == NS_STYLE_DIRECTION_LTR); // If text runs RTL then so do we.
   1.487 +  }
   1.488 +  else
   1.489 +    aIsNormal = true; // Assume a normal direction in the vertical case.
   1.490 +
   1.491 +  // Now check the style system to see if we should invert aIsNormal.
   1.492 +  const nsStyleXUL* boxInfo = StyleXUL();
   1.493 +  if (boxInfo->mBoxDirection == NS_STYLE_BOX_DIRECTION_REVERSE)
   1.494 +    aIsNormal = !aIsNormal; // Invert our direction.
   1.495 +  
   1.496 +  // Now see if we have an attribute.  The attribute overrides
   1.497 +  // the style system value.
   1.498 +  if (IsHorizontal()) {
   1.499 +    static nsIContent::AttrValuesArray strings[] =
   1.500 +      {&nsGkAtoms::reverse, &nsGkAtoms::ltr, &nsGkAtoms::rtl, nullptr};
   1.501 +    int32_t index = GetContent()->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::dir,
   1.502 +        strings, eCaseMatters);
   1.503 +    if (index >= 0) {
   1.504 +      bool values[] = {!aIsNormal, true, false};
   1.505 +      aIsNormal = values[index];
   1.506 +    }
   1.507 +  } else if (GetContent()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::dir,
   1.508 +                                       nsGkAtoms::reverse, eCaseMatters)) {
   1.509 +    aIsNormal = !aIsNormal;
   1.510 +  }
   1.511 +}
   1.512 +
   1.513 +/* Returns true if it was set.
   1.514 + */
   1.515 +bool
   1.516 +nsBoxFrame::GetInitialEqualSize(bool& aEqualSize)
   1.517 +{
   1.518 + // see if we are a vertical or horizontal box.
   1.519 +  if (!GetContent())
   1.520 +     return false;
   1.521 +
   1.522 +  if (GetContent()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::equalsize,
   1.523 +                           nsGkAtoms::always, eCaseMatters)) {
   1.524 +    aEqualSize = true;
   1.525 +    return true;
   1.526 +  }
   1.527 +
   1.528 +  return false;
   1.529 +}
   1.530 +
   1.531 +/* Returns true if it was set.
   1.532 + */
   1.533 +bool
   1.534 +nsBoxFrame::GetInitialAutoStretch(bool& aStretch)
   1.535 +{
   1.536 +  if (!GetContent())
   1.537 +     return false;
   1.538 +  
   1.539 +  // Check the align attribute.
   1.540 +  static nsIContent::AttrValuesArray strings[] =
   1.541 +    {&nsGkAtoms::_empty, &nsGkAtoms::stretch, nullptr};
   1.542 +  int32_t index = GetContent()->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::align,
   1.543 +      strings, eCaseMatters);
   1.544 +  if (index != nsIContent::ATTR_MISSING && index != 0) {
   1.545 +    aStretch = index == 1;
   1.546 +    return true;
   1.547 +  }
   1.548 +
   1.549 +  // Check the CSS box-align property.
   1.550 +  const nsStyleXUL* boxInfo = StyleXUL();
   1.551 +  aStretch = (boxInfo->mBoxAlign == NS_STYLE_BOX_ALIGN_STRETCH);
   1.552 +
   1.553 +  return true;
   1.554 +}
   1.555 +
   1.556 +nsresult
   1.557 +nsBoxFrame::DidReflow(nsPresContext*           aPresContext,
   1.558 +                      const nsHTMLReflowState*  aReflowState,
   1.559 +                      nsDidReflowStatus         aStatus)
   1.560 +{
   1.561 +  nsFrameState preserveBits =
   1.562 +    mState & (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN);
   1.563 +  nsresult rv = nsFrame::DidReflow(aPresContext, aReflowState, aStatus);
   1.564 +  mState |= preserveBits;
   1.565 +  return rv;
   1.566 +}
   1.567 +
   1.568 +bool
   1.569 +nsBoxFrame::HonorPrintBackgroundSettings()
   1.570 +{
   1.571 +  return (!mContent || !mContent->IsInNativeAnonymousSubtree()) &&
   1.572 +    nsContainerFrame::HonorPrintBackgroundSettings();
   1.573 +}
   1.574 +
   1.575 +#ifdef DO_NOISY_REFLOW
   1.576 +static int myCounter = 0;
   1.577 +static void printSize(char * aDesc, nscoord aSize) 
   1.578 +{
   1.579 +  printf(" %s: ", aDesc);
   1.580 +  if (aSize == NS_UNCONSTRAINEDSIZE) {
   1.581 +    printf("UC");
   1.582 +  } else {
   1.583 +    printf("%d", aSize);
   1.584 +  }
   1.585 +}
   1.586 +#endif
   1.587 +
   1.588 +/* virtual */ nscoord
   1.589 +nsBoxFrame::GetMinWidth(nsRenderingContext *aRenderingContext)
   1.590 +{
   1.591 +  nscoord result;
   1.592 +  DISPLAY_MIN_WIDTH(this, result);
   1.593 +
   1.594 +  nsBoxLayoutState state(PresContext(), aRenderingContext);
   1.595 +  nsSize minSize = GetMinSize(state);
   1.596 +
   1.597 +  // GetMinSize returns border-box width, and we want to return content
   1.598 +  // width.  Since Reflow uses the reflow state's border and padding, we
   1.599 +  // actually just want to subtract what GetMinSize added, which is the
   1.600 +  // result of GetBorderAndPadding.
   1.601 +  nsMargin bp;
   1.602 +  GetBorderAndPadding(bp);
   1.603 +
   1.604 +  result = minSize.width - bp.LeftRight();
   1.605 +  result = std::max(result, 0);
   1.606 +
   1.607 +  return result;
   1.608 +}
   1.609 +
   1.610 +/* virtual */ nscoord
   1.611 +nsBoxFrame::GetPrefWidth(nsRenderingContext *aRenderingContext)
   1.612 +{
   1.613 +  nscoord result;
   1.614 +  DISPLAY_PREF_WIDTH(this, result);
   1.615 +
   1.616 +  nsBoxLayoutState state(PresContext(), aRenderingContext);
   1.617 +  nsSize prefSize = GetPrefSize(state);
   1.618 +
   1.619 +  // GetPrefSize returns border-box width, and we want to return content
   1.620 +  // width.  Since Reflow uses the reflow state's border and padding, we
   1.621 +  // actually just want to subtract what GetPrefSize added, which is the
   1.622 +  // result of GetBorderAndPadding.
   1.623 +  nsMargin bp;
   1.624 +  GetBorderAndPadding(bp);
   1.625 +
   1.626 +  result = prefSize.width - bp.LeftRight();
   1.627 +  result = std::max(result, 0);
   1.628 +
   1.629 +  return result;
   1.630 +}
   1.631 +
   1.632 +nsresult
   1.633 +nsBoxFrame::Reflow(nsPresContext*          aPresContext,
   1.634 +                   nsHTMLReflowMetrics&     aDesiredSize,
   1.635 +                   const nsHTMLReflowState& aReflowState,
   1.636 +                   nsReflowStatus&          aStatus)
   1.637 +{
   1.638 +  // If you make changes to this method, please keep nsLeafBoxFrame::Reflow
   1.639 +  // in sync, if the changes are applicable there.
   1.640 +
   1.641 +  DO_GLOBAL_REFLOW_COUNT("nsBoxFrame");
   1.642 +  DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
   1.643 +
   1.644 +  NS_ASSERTION(aReflowState.ComputedWidth() >=0 &&
   1.645 +               aReflowState.ComputedHeight() >= 0, "Computed Size < 0");
   1.646 +
   1.647 +#ifdef DO_NOISY_REFLOW
   1.648 +  printf("\n-------------Starting BoxFrame Reflow ----------------------------\n");
   1.649 +  printf("%p ** nsBF::Reflow %d ", this, myCounter++);
   1.650 +  
   1.651 +  printSize("AW", aReflowState.AvailableWidth());
   1.652 +  printSize("AH", aReflowState.AvailableHeight());
   1.653 +  printSize("CW", aReflowState.ComputedWidth());
   1.654 +  printSize("CH", aReflowState.ComputedHeight());
   1.655 +
   1.656 +  printf(" *\n");
   1.657 +
   1.658 +#endif
   1.659 +
   1.660 +  aStatus = NS_FRAME_COMPLETE;
   1.661 +
   1.662 +  // create the layout state
   1.663 +  nsBoxLayoutState state(aPresContext, aReflowState.rendContext,
   1.664 +                         &aReflowState, aReflowState.mReflowDepth);
   1.665 +
   1.666 +  nsSize computedSize(aReflowState.ComputedWidth(),aReflowState.ComputedHeight());
   1.667 +
   1.668 +  nsMargin m;
   1.669 +  m = aReflowState.ComputedPhysicalBorderPadding();
   1.670 +  // GetBorderAndPadding(m);
   1.671 +
   1.672 +  nsSize prefSize(0,0);
   1.673 +
   1.674 +  // if we are told to layout intrinsic then get our preferred size.
   1.675 +  NS_ASSERTION(computedSize.width != NS_INTRINSICSIZE,
   1.676 +               "computed width should always be computed");
   1.677 +  if (computedSize.height == NS_INTRINSICSIZE) {
   1.678 +    prefSize = GetPrefSize(state);
   1.679 +    nsSize minSize = GetMinSize(state);
   1.680 +    nsSize maxSize = GetMaxSize(state);
   1.681 +    // XXXbz isn't GetPrefSize supposed to bounds-check for us?
   1.682 +    prefSize = BoundsCheck(minSize, prefSize, maxSize);
   1.683 +  }
   1.684 +
   1.685 +  // get our desiredSize
   1.686 +  computedSize.width += m.left + m.right;
   1.687 +
   1.688 +  if (aReflowState.ComputedHeight() == NS_INTRINSICSIZE) {
   1.689 +    computedSize.height = prefSize.height;
   1.690 +    // prefSize is border-box but min/max constraints are content-box.
   1.691 +    nscoord verticalBorderPadding =
   1.692 +      aReflowState.ComputedPhysicalBorderPadding().TopBottom();
   1.693 +    nscoord contentHeight = computedSize.height - verticalBorderPadding;
   1.694 +    // Note: contentHeight might be negative, but that's OK because min-height
   1.695 +    // is never negative.
   1.696 +    computedSize.height = aReflowState.ApplyMinMaxHeight(contentHeight) +
   1.697 +                          verticalBorderPadding;
   1.698 +  } else {
   1.699 +    computedSize.height += m.top + m.bottom;
   1.700 +  }
   1.701 +
   1.702 +  nsRect r(mRect.x, mRect.y, computedSize.width, computedSize.height);
   1.703 +
   1.704 +  SetBounds(state, r);
   1.705 + 
   1.706 +  // layout our children
   1.707 +  Layout(state);
   1.708 +  
   1.709 +  // ok our child could have gotten bigger. So lets get its bounds
   1.710 +  
   1.711 +  // get the ascent
   1.712 +  nscoord ascent = mRect.height;
   1.713 +
   1.714 +  // getting the ascent could be a lot of work. Don't get it if
   1.715 +  // we are the root. The viewport doesn't care about it.
   1.716 +  if (!(mState & NS_STATE_IS_ROOT)) {
   1.717 +    ascent = GetBoxAscent(state);
   1.718 +  }
   1.719 +
   1.720 +  aDesiredSize.Width() = mRect.width;
   1.721 +  aDesiredSize.Height() = mRect.height;
   1.722 +  aDesiredSize.SetTopAscent(ascent);
   1.723 +
   1.724 +  aDesiredSize.mOverflowAreas = GetOverflowAreas();
   1.725 +
   1.726 +#ifdef DO_NOISY_REFLOW
   1.727 +  {
   1.728 +    printf("%p ** nsBF(done) W:%d H:%d  ", this, aDesiredSize.Width(), aDesiredSize.Height());
   1.729 +
   1.730 +    if (maxElementSize) {
   1.731 +      printf("MW:%d\n", *maxElementWidth); 
   1.732 +    } else {
   1.733 +      printf("MW:?\n"); 
   1.734 +    }
   1.735 +
   1.736 +  }
   1.737 +#endif
   1.738 +
   1.739 +  ReflowAbsoluteFrames(aPresContext, aDesiredSize, aReflowState, aStatus);
   1.740 +
   1.741 +  NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
   1.742 +  return NS_OK;
   1.743 +}
   1.744 +
   1.745 +nsSize
   1.746 +nsBoxFrame::GetPrefSize(nsBoxLayoutState& aBoxLayoutState)
   1.747 +{
   1.748 +  NS_ASSERTION(aBoxLayoutState.GetRenderingContext(),
   1.749 +               "must have rendering context");
   1.750 +
   1.751 +  nsSize size(0,0);
   1.752 +  DISPLAY_PREF_SIZE(this, size);
   1.753 +  if (!DoesNeedRecalc(mPrefSize)) {
   1.754 +     return mPrefSize;
   1.755 +  }
   1.756 +
   1.757 +#ifdef DEBUG_LAYOUT
   1.758 +  PropagateDebug(aBoxLayoutState);
   1.759 +#endif
   1.760 +
   1.761 +  if (IsCollapsed())
   1.762 +    return size;
   1.763 +
   1.764 +  // if the size was not completely redefined in CSS then ask our children
   1.765 +  bool widthSet, heightSet;
   1.766 +  if (!nsIFrame::AddCSSPrefSize(this, size, widthSet, heightSet))
   1.767 +  {
   1.768 +    if (mLayoutManager) {
   1.769 +      nsSize layoutSize = mLayoutManager->GetPrefSize(this, aBoxLayoutState);
   1.770 +      if (!widthSet)
   1.771 +        size.width = layoutSize.width;
   1.772 +      if (!heightSet)
   1.773 +        size.height = layoutSize.height;
   1.774 +    }
   1.775 +    else {
   1.776 +      size = nsBox::GetPrefSize(aBoxLayoutState);
   1.777 +    }
   1.778 +  }
   1.779 +
   1.780 +  nsSize minSize = GetMinSize(aBoxLayoutState);
   1.781 +  nsSize maxSize = GetMaxSize(aBoxLayoutState);
   1.782 +  mPrefSize = BoundsCheck(minSize, size, maxSize);
   1.783 + 
   1.784 +  return mPrefSize;
   1.785 +}
   1.786 +
   1.787 +nscoord
   1.788 +nsBoxFrame::GetBoxAscent(nsBoxLayoutState& aBoxLayoutState)
   1.789 +{
   1.790 +  if (!DoesNeedRecalc(mAscent))
   1.791 +     return mAscent;
   1.792 +
   1.793 +#ifdef DEBUG_LAYOUT
   1.794 +  PropagateDebug(aBoxLayoutState);
   1.795 +#endif
   1.796 +
   1.797 +  if (IsCollapsed())
   1.798 +    return 0;
   1.799 +
   1.800 +  if (mLayoutManager)
   1.801 +    mAscent = mLayoutManager->GetAscent(this, aBoxLayoutState);
   1.802 +  else
   1.803 +    mAscent = nsBox::GetBoxAscent(aBoxLayoutState);
   1.804 +
   1.805 +  return mAscent;
   1.806 +}
   1.807 +
   1.808 +nsSize
   1.809 +nsBoxFrame::GetMinSize(nsBoxLayoutState& aBoxLayoutState)
   1.810 +{
   1.811 +  NS_ASSERTION(aBoxLayoutState.GetRenderingContext(),
   1.812 +               "must have rendering context");
   1.813 +
   1.814 +  nsSize size(0,0);
   1.815 +  DISPLAY_MIN_SIZE(this, size);
   1.816 +  if (!DoesNeedRecalc(mMinSize)) {
   1.817 +    return mMinSize;
   1.818 +  }
   1.819 +
   1.820 +#ifdef DEBUG_LAYOUT
   1.821 +  PropagateDebug(aBoxLayoutState);
   1.822 +#endif
   1.823 +
   1.824 +  if (IsCollapsed())
   1.825 +    return size;
   1.826 +
   1.827 +  // if the size was not completely redefined in CSS then ask our children
   1.828 +  bool widthSet, heightSet;
   1.829 +  if (!nsIFrame::AddCSSMinSize(aBoxLayoutState, this, size, widthSet, heightSet))
   1.830 +  {
   1.831 +    if (mLayoutManager) {
   1.832 +      nsSize layoutSize = mLayoutManager->GetMinSize(this, aBoxLayoutState);
   1.833 +      if (!widthSet)
   1.834 +        size.width = layoutSize.width;
   1.835 +      if (!heightSet)
   1.836 +        size.height = layoutSize.height;
   1.837 +    }
   1.838 +    else {
   1.839 +      size = nsBox::GetMinSize(aBoxLayoutState);
   1.840 +    }
   1.841 +  }
   1.842 +  
   1.843 +  mMinSize = size;
   1.844 +
   1.845 +  return size;
   1.846 +}
   1.847 +
   1.848 +nsSize
   1.849 +nsBoxFrame::GetMaxSize(nsBoxLayoutState& aBoxLayoutState)
   1.850 +{
   1.851 +  NS_ASSERTION(aBoxLayoutState.GetRenderingContext(),
   1.852 +               "must have rendering context");
   1.853 +
   1.854 +  nsSize size(NS_INTRINSICSIZE, NS_INTRINSICSIZE);
   1.855 +  DISPLAY_MAX_SIZE(this, size);
   1.856 +  if (!DoesNeedRecalc(mMaxSize)) {
   1.857 +    return mMaxSize;
   1.858 +  }
   1.859 +
   1.860 +#ifdef DEBUG_LAYOUT
   1.861 +  PropagateDebug(aBoxLayoutState);
   1.862 +#endif
   1.863 +
   1.864 +  if (IsCollapsed())
   1.865 +    return size;
   1.866 +
   1.867 +  // if the size was not completely redefined in CSS then ask our children
   1.868 +  bool widthSet, heightSet;
   1.869 +  if (!nsIFrame::AddCSSMaxSize(this, size, widthSet, heightSet))
   1.870 +  {
   1.871 +    if (mLayoutManager) {
   1.872 +      nsSize layoutSize = mLayoutManager->GetMaxSize(this, aBoxLayoutState);
   1.873 +      if (!widthSet)
   1.874 +        size.width = layoutSize.width;
   1.875 +      if (!heightSet)
   1.876 +        size.height = layoutSize.height;
   1.877 +    }
   1.878 +    else {
   1.879 +      size = nsBox::GetMaxSize(aBoxLayoutState);
   1.880 +    }
   1.881 +  }
   1.882 +
   1.883 +  mMaxSize = size;
   1.884 +
   1.885 +  return size;
   1.886 +}
   1.887 +
   1.888 +nscoord
   1.889 +nsBoxFrame::GetFlex(nsBoxLayoutState& aBoxLayoutState)
   1.890 +{
   1.891 +  if (!DoesNeedRecalc(mFlex))
   1.892 +     return mFlex;
   1.893 +
   1.894 +  mFlex = nsBox::GetFlex(aBoxLayoutState);
   1.895 +
   1.896 +  return mFlex;
   1.897 +}
   1.898 +
   1.899 +/**
   1.900 + * If subclassing please subclass this method not layout. 
   1.901 + * layout will call this method.
   1.902 + */
   1.903 +NS_IMETHODIMP
   1.904 +nsBoxFrame::DoLayout(nsBoxLayoutState& aState)
   1.905 +{
   1.906 +  uint32_t oldFlags = aState.LayoutFlags();
   1.907 +  aState.SetLayoutFlags(0);
   1.908 +
   1.909 +  nsresult rv = NS_OK;
   1.910 +  if (mLayoutManager) {
   1.911 +    CoordNeedsRecalc(mAscent);
   1.912 +    rv = mLayoutManager->Layout(this, aState);
   1.913 +  }
   1.914 +
   1.915 +  aState.SetLayoutFlags(oldFlags);
   1.916 +
   1.917 +  if (HasAbsolutelyPositionedChildren()) {
   1.918 +    // Set up a |reflowState| to pass into ReflowAbsoluteFrames
   1.919 +    nsHTMLReflowState reflowState(aState.PresContext(), this,
   1.920 +                                  aState.GetRenderingContext(),
   1.921 +                                  nsSize(mRect.width, NS_UNCONSTRAINEDSIZE));
   1.922 +
   1.923 +    // Set up a |desiredSize| to pass into ReflowAbsoluteFrames
   1.924 +    nsHTMLReflowMetrics desiredSize(reflowState);
   1.925 +    desiredSize.Width() = mRect.width;
   1.926 +    desiredSize.Height() = mRect.height;
   1.927 +
   1.928 +    // get the ascent (cribbed from ::Reflow)
   1.929 +    nscoord ascent = mRect.height;
   1.930 +
   1.931 +    // getting the ascent could be a lot of work. Don't get it if
   1.932 +    // we are the root. The viewport doesn't care about it.
   1.933 +    if (!(mState & NS_STATE_IS_ROOT)) {
   1.934 +      ascent = GetBoxAscent(aState);
   1.935 +    }
   1.936 +    desiredSize.SetTopAscent(ascent);
   1.937 +    desiredSize.mOverflowAreas = GetOverflowAreas();
   1.938 +
   1.939 +    AddStateBits(NS_FRAME_IN_REFLOW);
   1.940 +    // Set up a |reflowStatus| to pass into ReflowAbsoluteFrames
   1.941 +    // (just a dummy value; hopefully that's OK)
   1.942 +    nsReflowStatus reflowStatus = NS_FRAME_COMPLETE;
   1.943 +    ReflowAbsoluteFrames(aState.PresContext(), desiredSize,
   1.944 +                         reflowState, reflowStatus);
   1.945 +    RemoveStateBits(NS_FRAME_IN_REFLOW);
   1.946 +  }
   1.947 +
   1.948 +  return rv;
   1.949 +}
   1.950 +
   1.951 +void
   1.952 +nsBoxFrame::DestroyFrom(nsIFrame* aDestructRoot)
   1.953 +{
   1.954 +  // unregister access key
   1.955 +  RegUnregAccessKey(false);
   1.956 +
   1.957 +  // clean up the container box's layout manager and child boxes
   1.958 +  SetLayoutManager(nullptr);
   1.959 +
   1.960 +  nsContainerFrame::DestroyFrom(aDestructRoot);
   1.961 +} 
   1.962 +
   1.963 +#ifdef DEBUG_LAYOUT
   1.964 +nsresult
   1.965 +nsBoxFrame::SetDebug(nsBoxLayoutState& aState, bool aDebug)
   1.966 +{
   1.967 +  // see if our state matches the given debug state
   1.968 +  bool debugSet = mState & NS_STATE_CURRENTLY_IN_DEBUG;
   1.969 +  bool debugChanged = (!aDebug && debugSet) || (aDebug && !debugSet);
   1.970 +
   1.971 +  // if it doesn't then tell each child below us the new debug state
   1.972 +  if (debugChanged)
   1.973 +  {
   1.974 +     if (aDebug) {
   1.975 +         mState |= NS_STATE_CURRENTLY_IN_DEBUG;
   1.976 +     } else {
   1.977 +         mState &= ~NS_STATE_CURRENTLY_IN_DEBUG;
   1.978 +     }
   1.979 + 
   1.980 +     SetDebugOnChildList(aState, mFirstChild, aDebug);
   1.981 +
   1.982 +    MarkIntrinsicWidthsDirty();
   1.983 +  }
   1.984 +
   1.985 +  return NS_OK;
   1.986 +}
   1.987 +#endif
   1.988 +
   1.989 +/* virtual */ void
   1.990 +nsBoxFrame::MarkIntrinsicWidthsDirty()
   1.991 +{
   1.992 +  SizeNeedsRecalc(mPrefSize);
   1.993 +  SizeNeedsRecalc(mMinSize);
   1.994 +  SizeNeedsRecalc(mMaxSize);
   1.995 +  CoordNeedsRecalc(mFlex);
   1.996 +  CoordNeedsRecalc(mAscent);
   1.997 +
   1.998 +  if (mLayoutManager) {
   1.999 +    nsBoxLayoutState state(PresContext());
  1.1000 +    mLayoutManager->IntrinsicWidthsDirty(this, state);
  1.1001 +  }
  1.1002 +
  1.1003 +  // Don't call base class method, since everything it does is within an
  1.1004 +  // IsBoxWrapped check.
  1.1005 +}
  1.1006 +
  1.1007 +nsresult
  1.1008 +nsBoxFrame::RemoveFrame(ChildListID     aListID,
  1.1009 +                        nsIFrame*       aOldFrame)
  1.1010 +{
  1.1011 +  NS_PRECONDITION(aListID == kPrincipalList, "We don't support out-of-flow kids");
  1.1012 +  nsPresContext* presContext = PresContext();
  1.1013 +  nsBoxLayoutState state(presContext);
  1.1014 +
  1.1015 +  // remove the child frame
  1.1016 +  mFrames.RemoveFrame(aOldFrame);
  1.1017 +
  1.1018 +  // notify the layout manager
  1.1019 +  if (mLayoutManager)
  1.1020 +    mLayoutManager->ChildrenRemoved(this, state, aOldFrame);
  1.1021 +
  1.1022 +  // destroy the child frame
  1.1023 +  aOldFrame->Destroy();
  1.1024 +
  1.1025 +  // mark us dirty and generate a reflow command
  1.1026 +  PresContext()->PresShell()->
  1.1027 +    FrameNeedsReflow(this, nsIPresShell::eTreeChange,
  1.1028 +                     NS_FRAME_HAS_DIRTY_CHILDREN);
  1.1029 +  return NS_OK;
  1.1030 +}
  1.1031 +
  1.1032 +nsresult
  1.1033 +nsBoxFrame::InsertFrames(ChildListID     aListID,
  1.1034 +                         nsIFrame*       aPrevFrame,
  1.1035 +                         nsFrameList&    aFrameList)
  1.1036 +{
  1.1037 +   NS_ASSERTION(!aPrevFrame || aPrevFrame->GetParent() == this,
  1.1038 +                "inserting after sibling frame with different parent");
  1.1039 +   NS_ASSERTION(!aPrevFrame || mFrames.ContainsFrame(aPrevFrame),
  1.1040 +                "inserting after sibling frame not in our child list");
  1.1041 +   NS_PRECONDITION(aListID == kPrincipalList, "We don't support out-of-flow kids");
  1.1042 +   nsBoxLayoutState state(PresContext());
  1.1043 +
  1.1044 +   // insert the child frames
  1.1045 +   const nsFrameList::Slice& newFrames =
  1.1046 +     mFrames.InsertFrames(this, aPrevFrame, aFrameList);
  1.1047 +
  1.1048 +   // notify the layout manager
  1.1049 +   if (mLayoutManager)
  1.1050 +     mLayoutManager->ChildrenInserted(this, state, aPrevFrame, newFrames);
  1.1051 +
  1.1052 +   // Make sure to check box order _after_ notifying the layout
  1.1053 +   // manager; otherwise the slice we give the layout manager will
  1.1054 +   // just be bogus.  If the layout manager cares about the order, we
  1.1055 +   // just lose.
  1.1056 +   CheckBoxOrder();
  1.1057 +
  1.1058 +#ifdef DEBUG_LAYOUT
  1.1059 +   // if we are in debug make sure our children are in debug as well.
  1.1060 +   if (mState & NS_STATE_CURRENTLY_IN_DEBUG)
  1.1061 +       SetDebugOnChildList(state, mFrames.FirstChild(), true);
  1.1062 +#endif
  1.1063 +
  1.1064 +   PresContext()->PresShell()->
  1.1065 +     FrameNeedsReflow(this, nsIPresShell::eTreeChange,
  1.1066 +                      NS_FRAME_HAS_DIRTY_CHILDREN);
  1.1067 +   return NS_OK;
  1.1068 +}
  1.1069 +
  1.1070 +
  1.1071 +nsresult
  1.1072 +nsBoxFrame::AppendFrames(ChildListID     aListID,
  1.1073 +                         nsFrameList&    aFrameList)
  1.1074 +{
  1.1075 +   NS_PRECONDITION(aListID == kPrincipalList, "We don't support out-of-flow kids");
  1.1076 +   nsBoxLayoutState state(PresContext());
  1.1077 +
  1.1078 +   // append the new frames
  1.1079 +   const nsFrameList::Slice& newFrames = mFrames.AppendFrames(this, aFrameList);
  1.1080 +
  1.1081 +   // notify the layout manager
  1.1082 +   if (mLayoutManager)
  1.1083 +     mLayoutManager->ChildrenAppended(this, state, newFrames);
  1.1084 +
  1.1085 +   // Make sure to check box order _after_ notifying the layout
  1.1086 +   // manager; otherwise the slice we give the layout manager will
  1.1087 +   // just be bogus.  If the layout manager cares about the order, we
  1.1088 +   // just lose.
  1.1089 +   CheckBoxOrder();
  1.1090 +
  1.1091 +#ifdef DEBUG_LAYOUT
  1.1092 +   // if we are in debug make sure our children are in debug as well.
  1.1093 +   if (mState & NS_STATE_CURRENTLY_IN_DEBUG)
  1.1094 +       SetDebugOnChildList(state, mFrames.FirstChild(), true);
  1.1095 +#endif
  1.1096 +
  1.1097 +   // XXXbz why is this NS_FRAME_FIRST_REFLOW check here?
  1.1098 +   if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
  1.1099 +     PresContext()->PresShell()->
  1.1100 +       FrameNeedsReflow(this, nsIPresShell::eTreeChange,
  1.1101 +                        NS_FRAME_HAS_DIRTY_CHILDREN);
  1.1102 +   }
  1.1103 +   return NS_OK;
  1.1104 +}
  1.1105 +
  1.1106 +/* virtual */ nsIFrame*
  1.1107 +nsBoxFrame::GetContentInsertionFrame()
  1.1108 +{
  1.1109 +  if (GetStateBits() & NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK)
  1.1110 +    return GetFirstPrincipalChild()->GetContentInsertionFrame();
  1.1111 +  return nsContainerFrame::GetContentInsertionFrame();
  1.1112 +}
  1.1113 +
  1.1114 +nsresult
  1.1115 +nsBoxFrame::AttributeChanged(int32_t aNameSpaceID,
  1.1116 +                             nsIAtom* aAttribute,
  1.1117 +                             int32_t aModType)
  1.1118 +{
  1.1119 +  nsresult rv = nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute,
  1.1120 +                                                   aModType);
  1.1121 +
  1.1122 +  // Ignore 'width', 'height', 'screenX', 'screenY' and 'sizemode' on a
  1.1123 +  // <window>.
  1.1124 +  nsIAtom *tag = mContent->Tag();
  1.1125 +  if ((tag == nsGkAtoms::window ||
  1.1126 +       tag == nsGkAtoms::page ||
  1.1127 +       tag == nsGkAtoms::dialog ||
  1.1128 +       tag == nsGkAtoms::wizard) &&
  1.1129 +      (nsGkAtoms::width == aAttribute ||
  1.1130 +       nsGkAtoms::height == aAttribute ||
  1.1131 +       nsGkAtoms::screenX == aAttribute ||
  1.1132 +       nsGkAtoms::screenY == aAttribute ||
  1.1133 +       nsGkAtoms::sizemode == aAttribute)) {
  1.1134 +    return rv;
  1.1135 +  }
  1.1136 +
  1.1137 +  if (aAttribute == nsGkAtoms::width       ||
  1.1138 +      aAttribute == nsGkAtoms::height      ||
  1.1139 +      aAttribute == nsGkAtoms::align       ||
  1.1140 +      aAttribute == nsGkAtoms::valign      ||
  1.1141 +      aAttribute == nsGkAtoms::left        ||
  1.1142 +      aAttribute == nsGkAtoms::top         ||
  1.1143 +      aAttribute == nsGkAtoms::right        ||
  1.1144 +      aAttribute == nsGkAtoms::bottom       ||
  1.1145 +      aAttribute == nsGkAtoms::start        ||
  1.1146 +      aAttribute == nsGkAtoms::end          ||
  1.1147 +      aAttribute == nsGkAtoms::minwidth     ||
  1.1148 +      aAttribute == nsGkAtoms::maxwidth     ||
  1.1149 +      aAttribute == nsGkAtoms::minheight    ||
  1.1150 +      aAttribute == nsGkAtoms::maxheight    ||
  1.1151 +      aAttribute == nsGkAtoms::flex         ||
  1.1152 +      aAttribute == nsGkAtoms::orient       ||
  1.1153 +      aAttribute == nsGkAtoms::pack         ||
  1.1154 +      aAttribute == nsGkAtoms::dir          ||
  1.1155 +      aAttribute == nsGkAtoms::mousethrough ||
  1.1156 +      aAttribute == nsGkAtoms::equalsize) {
  1.1157 +
  1.1158 +    if (aAttribute == nsGkAtoms::align  ||
  1.1159 +        aAttribute == nsGkAtoms::valign ||
  1.1160 +        aAttribute == nsGkAtoms::orient  ||
  1.1161 +        aAttribute == nsGkAtoms::pack    ||
  1.1162 +#ifdef DEBUG_LAYOUT
  1.1163 +        aAttribute == nsGkAtoms::debug   ||
  1.1164 +#endif
  1.1165 +        aAttribute == nsGkAtoms::dir) {
  1.1166 +
  1.1167 +      mValign = nsBoxFrame::vAlign_Top;
  1.1168 +      mHalign = nsBoxFrame::hAlign_Left;
  1.1169 +
  1.1170 +      bool orient = true;
  1.1171 +      GetInitialOrientation(orient); 
  1.1172 +      if (orient)
  1.1173 +        mState |= NS_STATE_IS_HORIZONTAL;
  1.1174 +      else
  1.1175 +        mState &= ~NS_STATE_IS_HORIZONTAL;
  1.1176 +
  1.1177 +      bool normal = true;
  1.1178 +      GetInitialDirection(normal);
  1.1179 +      if (normal)
  1.1180 +        mState |= NS_STATE_IS_DIRECTION_NORMAL;
  1.1181 +      else
  1.1182 +        mState &= ~NS_STATE_IS_DIRECTION_NORMAL;
  1.1183 +
  1.1184 +      GetInitialVAlignment(mValign);
  1.1185 +      GetInitialHAlignment(mHalign);
  1.1186 +
  1.1187 +      bool equalSize = false;
  1.1188 +      GetInitialEqualSize(equalSize); 
  1.1189 +      if (equalSize)
  1.1190 +        mState |= NS_STATE_EQUAL_SIZE;
  1.1191 +      else
  1.1192 +        mState &= ~NS_STATE_EQUAL_SIZE;
  1.1193 +
  1.1194 +#ifdef DEBUG_LAYOUT
  1.1195 +      bool debug = mState & NS_STATE_SET_TO_DEBUG;
  1.1196 +      bool debugSet = GetInitialDebug(debug);
  1.1197 +      if (debugSet) {
  1.1198 +        mState |= NS_STATE_DEBUG_WAS_SET;
  1.1199 +
  1.1200 +        if (debug)
  1.1201 +          mState |= NS_STATE_SET_TO_DEBUG;
  1.1202 +        else
  1.1203 +          mState &= ~NS_STATE_SET_TO_DEBUG;
  1.1204 +      } else {
  1.1205 +        mState &= ~NS_STATE_DEBUG_WAS_SET;
  1.1206 +      }
  1.1207 +#endif
  1.1208 +
  1.1209 +      bool autostretch = !!(mState & NS_STATE_AUTO_STRETCH);
  1.1210 +      GetInitialAutoStretch(autostretch);
  1.1211 +      if (autostretch)
  1.1212 +        mState |= NS_STATE_AUTO_STRETCH;
  1.1213 +      else
  1.1214 +        mState &= ~NS_STATE_AUTO_STRETCH;
  1.1215 +    }
  1.1216 +    else if (aAttribute == nsGkAtoms::left ||
  1.1217 +             aAttribute == nsGkAtoms::top ||
  1.1218 +             aAttribute == nsGkAtoms::right ||
  1.1219 +             aAttribute == nsGkAtoms::bottom ||
  1.1220 +             aAttribute == nsGkAtoms::start ||
  1.1221 +             aAttribute == nsGkAtoms::end) {
  1.1222 +      mState &= ~NS_STATE_STACK_NOT_POSITIONED;
  1.1223 +    }
  1.1224 +    else if (aAttribute == nsGkAtoms::mousethrough) {
  1.1225 +      UpdateMouseThrough();
  1.1226 +    }
  1.1227 +
  1.1228 +    PresContext()->PresShell()->
  1.1229 +      FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
  1.1230 +  }
  1.1231 +  else if (aAttribute == nsGkAtoms::ordinal) {
  1.1232 +    nsBoxLayoutState state(PresContext());
  1.1233 +    nsIFrame* parent = GetParentBox();
  1.1234 +    // If our parent is not a box, there's not much we can do... but in that
  1.1235 +    // case our ordinal doesn't matter anyway, so that's ok.
  1.1236 +    // Also don't bother with popup frames since they are kept on the 
  1.1237 +    // kPopupList and RelayoutChildAtOrdinal() only handles
  1.1238 +    // principal children.
  1.1239 +    if (parent && !(GetStateBits() & NS_FRAME_OUT_OF_FLOW) &&
  1.1240 +        StyleDisplay()->mDisplay != NS_STYLE_DISPLAY_POPUP) {
  1.1241 +      parent->RelayoutChildAtOrdinal(state, this);
  1.1242 +      // XXXldb Should this instead be a tree change on the child or parent?
  1.1243 +      PresContext()->PresShell()->
  1.1244 +        FrameNeedsReflow(parent, nsIPresShell::eStyleChange,
  1.1245 +                         NS_FRAME_IS_DIRTY);
  1.1246 +    }
  1.1247 +  }
  1.1248 +  // If the accesskey changed, register for the new value
  1.1249 +  // The old value has been unregistered in nsXULElement::SetAttr
  1.1250 +  else if (aAttribute == nsGkAtoms::accesskey) {
  1.1251 +    RegUnregAccessKey(true);
  1.1252 +  }
  1.1253 +  else if (aAttribute == nsGkAtoms::rows &&
  1.1254 +           tag == nsGkAtoms::tree) {
  1.1255 +    // Reflow ourselves and all our children if "rows" changes, since
  1.1256 +    // nsTreeBodyFrame's layout reads this from its parent (this frame).
  1.1257 +    PresContext()->PresShell()->
  1.1258 +      FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
  1.1259 +  }
  1.1260 +
  1.1261 +  return rv;
  1.1262 +}
  1.1263 +
  1.1264 +#ifdef DEBUG_LAYOUT
  1.1265 +void
  1.1266 +nsBoxFrame::GetDebugPref(nsPresContext* aPresContext)
  1.1267 +{
  1.1268 +    gDebug = Preferences::GetBool("xul.debug.box");
  1.1269 +}
  1.1270 +
  1.1271 +class nsDisplayXULDebug : public nsDisplayItem {
  1.1272 +public:
  1.1273 +  nsDisplayXULDebug(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) :
  1.1274 +    nsDisplayItem(aBuilder, aFrame) {
  1.1275 +    MOZ_COUNT_CTOR(nsDisplayXULDebug);
  1.1276 +  }
  1.1277 +#ifdef NS_BUILD_REFCNT_LOGGING
  1.1278 +  virtual ~nsDisplayXULDebug() {
  1.1279 +    MOZ_COUNT_DTOR(nsDisplayXULDebug);
  1.1280 +  }
  1.1281 +#endif
  1.1282 +
  1.1283 +  virtual void HitTest(nsDisplayListBuilder* aBuilder, nsRect aRect,
  1.1284 +                       HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) {
  1.1285 +    nsPoint rectCenter(aRect.x + aRect.width / 2, aRect.y + aRect.height / 2);
  1.1286 +    static_cast<nsBoxFrame*>(mFrame)->
  1.1287 +      DisplayDebugInfoFor(this, rectCenter - ToReferenceFrame());
  1.1288 +    aOutFrames->AppendElement(this);
  1.1289 +  }
  1.1290 +  virtual void Paint(nsDisplayListBuilder* aBuilder
  1.1291 +                     nsRenderingContext* aCtx);
  1.1292 +  NS_DISPLAY_DECL_NAME("XULDebug", TYPE_XUL_DEBUG)
  1.1293 +};
  1.1294 +
  1.1295 +void
  1.1296 +nsDisplayXULDebug::Paint(nsDisplayListBuilder* aBuilder,
  1.1297 +                         nsRenderingContext* aCtx)
  1.1298 +{
  1.1299 +  static_cast<nsBoxFrame*>(mFrame)->
  1.1300 +    PaintXULDebugOverlay(*aCtx, ToReferenceFrame());
  1.1301 +}
  1.1302 +
  1.1303 +static void
  1.1304 +PaintXULDebugBackground(nsIFrame* aFrame, nsRenderingContext* aCtx,
  1.1305 +                        const nsRect& aDirtyRect, nsPoint aPt)
  1.1306 +{
  1.1307 +  static_cast<nsBoxFrame*>(aFrame)->PaintXULDebugBackground(*aCtx, aPt);
  1.1308 +}
  1.1309 +#endif
  1.1310 +
  1.1311 +void
  1.1312 +nsBoxFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
  1.1313 +                             const nsRect&           aDirtyRect,
  1.1314 +                             const nsDisplayListSet& aLists)
  1.1315 +{
  1.1316 +  // forcelayer is only supported on XUL elements with box layout
  1.1317 +  bool forceLayer =
  1.1318 +    GetContent()->HasAttr(kNameSpaceID_None, nsGkAtoms::layer) &&
  1.1319 +    GetContent()->IsXUL();
  1.1320 +
  1.1321 +  // Check for frames that are marked as a part of the region used
  1.1322 +  // in calculating glass margins on Windows.
  1.1323 +  if (GetContent()->IsXUL()) {
  1.1324 +      const nsStyleDisplay* styles = StyleDisplay();
  1.1325 +      if (styles && styles->mAppearance == NS_THEME_WIN_EXCLUDE_GLASS) {
  1.1326 +        nsRect rect = nsRect(aBuilder->ToReferenceFrame(this), GetSize());
  1.1327 +        aBuilder->AddExcludedGlassRegion(rect);
  1.1328 +      }
  1.1329 +  }
  1.1330 +
  1.1331 +  nsDisplayListCollection tempLists;
  1.1332 +  const nsDisplayListSet& destination = forceLayer ? tempLists : aLists;
  1.1333 +
  1.1334 +  DisplayBorderBackgroundOutline(aBuilder, destination);
  1.1335 +
  1.1336 +#ifdef DEBUG_LAYOUT
  1.1337 +  if (mState & NS_STATE_CURRENTLY_IN_DEBUG) {
  1.1338 +    destination.BorderBackground()->AppendNewToTop(new (aBuilder)
  1.1339 +      nsDisplayGeneric(aBuilder, this, PaintXULDebugBackground,
  1.1340 +                       "XULDebugBackground"));
  1.1341 +    destination.Outlines()->AppendNewToTop(new (aBuilder)
  1.1342 +      nsDisplayXULDebug(aBuilder, this));
  1.1343 +  }
  1.1344 +#endif
  1.1345 +
  1.1346 +  BuildDisplayListForChildren(aBuilder, aDirtyRect, destination);
  1.1347 +
  1.1348 +  // see if we have to draw a selection frame around this container
  1.1349 +  DisplaySelectionOverlay(aBuilder, destination.Content());
  1.1350 +
  1.1351 +  if (forceLayer) {
  1.1352 +    // This is a bit of a hack. Collect up all descendant display items
  1.1353 +    // and merge them into a single Content() list. This can cause us
  1.1354 +    // to violate CSS stacking order, but forceLayer is a magic
  1.1355 +    // XUL-only extension anyway.
  1.1356 +    nsDisplayList masterList;
  1.1357 +    masterList.AppendToTop(tempLists.BorderBackground());
  1.1358 +    masterList.AppendToTop(tempLists.BlockBorderBackgrounds());
  1.1359 +    masterList.AppendToTop(tempLists.Floats());
  1.1360 +    masterList.AppendToTop(tempLists.Content());
  1.1361 +    masterList.AppendToTop(tempLists.PositionedDescendants());
  1.1362 +    masterList.AppendToTop(tempLists.Outlines());
  1.1363 +    // Wrap the list to make it its own layer
  1.1364 +    aLists.Content()->AppendNewToTop(new (aBuilder)
  1.1365 +      nsDisplayOwnLayer(aBuilder, this, &masterList));
  1.1366 +  }
  1.1367 +}
  1.1368 +
  1.1369 +void
  1.1370 +nsBoxFrame::BuildDisplayListForChildren(nsDisplayListBuilder*   aBuilder,
  1.1371 +                                        const nsRect&           aDirtyRect,
  1.1372 +                                        const nsDisplayListSet& aLists)
  1.1373 +{
  1.1374 +  nsIFrame* kid = mFrames.FirstChild();
  1.1375 +  // Put each child's background onto the BlockBorderBackgrounds list
  1.1376 +  // to emulate the existing two-layer XUL painting scheme.
  1.1377 +  nsDisplayListSet set(aLists, aLists.BlockBorderBackgrounds());
  1.1378 +  // The children should be in the right order
  1.1379 +  while (kid) {
  1.1380 +    BuildDisplayListForChild(aBuilder, kid, aDirtyRect, set);
  1.1381 +    kid = kid->GetNextSibling();
  1.1382 +  }
  1.1383 +}
  1.1384 +
  1.1385 +// REVIEW: PaintChildren did a few things none of which are a big deal
  1.1386 +// anymore:
  1.1387 +// * Paint some debugging rects for this frame.
  1.1388 +// This is done by nsDisplayXULDebugBackground, which goes in the
  1.1389 +// BorderBackground() layer so it isn't clipped by OVERFLOW_CLIP.
  1.1390 +// * Apply OVERFLOW_CLIP to the children.
  1.1391 +// This is now in nsFrame::BuildDisplayListForStackingContext/Child.
  1.1392 +// * Actually paint the children.
  1.1393 +// Moved to BuildDisplayList.
  1.1394 +// * Paint per-kid debug information.
  1.1395 +// This is done by nsDisplayXULDebug, which is in the Outlines()
  1.1396 +// layer so it goes on top. This means it is not clipped by OVERFLOW_CLIP,
  1.1397 +// whereas it did used to respect OVERFLOW_CLIP, but too bad.
  1.1398 +#ifdef DEBUG_LAYOUT
  1.1399 +void
  1.1400 +nsBoxFrame::PaintXULDebugBackground(nsRenderingContext& aRenderingContext,
  1.1401 +                                    nsPoint aPt)
  1.1402 +{
  1.1403 +  nsMargin border;
  1.1404 +  GetBorder(border);
  1.1405 +
  1.1406 +  nsMargin debugBorder;
  1.1407 +  nsMargin debugMargin;
  1.1408 +  nsMargin debugPadding;
  1.1409 +
  1.1410 +  bool isHorizontal = IsHorizontal();
  1.1411 +
  1.1412 +  GetDebugBorder(debugBorder);
  1.1413 +  PixelMarginToTwips(GetPresContext(), debugBorder);
  1.1414 +
  1.1415 +  GetDebugMargin(debugMargin);
  1.1416 +  PixelMarginToTwips(GetPresContext(), debugMargin);
  1.1417 +
  1.1418 +  GetDebugPadding(debugPadding);
  1.1419 +  PixelMarginToTwips(GetPresContext(), debugPadding);
  1.1420 +
  1.1421 +  nsRect inner(mRect);
  1.1422 +  inner.MoveTo(aPt);
  1.1423 +  inner.Deflate(debugMargin);
  1.1424 +  inner.Deflate(border);
  1.1425 +  //nsRect borderRect(inner);
  1.1426 +
  1.1427 +  nscolor color;
  1.1428 +  if (isHorizontal) {
  1.1429 +    color = NS_RGB(0,0,255);
  1.1430 +  } else {
  1.1431 +    color = NS_RGB(255,0,0);
  1.1432 +  }
  1.1433 +
  1.1434 +  aRenderingContext.SetColor(color);
  1.1435 +
  1.1436 +  //left
  1.1437 +  nsRect r(inner);
  1.1438 +  r.width = debugBorder.left;
  1.1439 +  aRenderingContext.FillRect(r);
  1.1440 +
  1.1441 +  // top
  1.1442 +  r = inner;
  1.1443 +  r.height = debugBorder.top;
  1.1444 +  aRenderingContext.FillRect(r);
  1.1445 +
  1.1446 +  //right
  1.1447 +  r = inner;
  1.1448 +  r.x = r.x + r.width - debugBorder.right;
  1.1449 +  r.width = debugBorder.right;
  1.1450 +  aRenderingContext.FillRect(r);
  1.1451 +
  1.1452 +  //bottom
  1.1453 +  r = inner;
  1.1454 +  r.y = r.y + r.height - debugBorder.bottom;
  1.1455 +  r.height = debugBorder.bottom;
  1.1456 +  aRenderingContext.FillRect(r);
  1.1457 +
  1.1458 +  
  1.1459 +  // if we have dirty children or we are dirty 
  1.1460 +  // place a green border around us.
  1.1461 +  if (NS_SUBTREE_DIRTY(this)) {
  1.1462 +     nsRect dirtyr(inner);
  1.1463 +     aRenderingContext.SetColor(NS_RGB(0,255,0));
  1.1464 +     aRenderingContext.DrawRect(dirtyr);
  1.1465 +     aRenderingContext.SetColor(color);
  1.1466 +  }
  1.1467 +}
  1.1468 +
  1.1469 +void
  1.1470 +nsBoxFrame::PaintXULDebugOverlay(nsRenderingContext& aRenderingContext,
  1.1471 +                                 nsPoint aPt)
  1.1472 +  nsMargin border;
  1.1473 +  GetBorder(border);
  1.1474 +
  1.1475 +  nsMargin debugMargin;
  1.1476 +  GetDebugMargin(debugMargin);
  1.1477 +  PixelMarginToTwips(GetPresContext(), debugMargin);
  1.1478 +
  1.1479 +  nsRect inner(mRect);
  1.1480 +  inner.MoveTo(aPt);
  1.1481 +  inner.Deflate(debugMargin);
  1.1482 +  inner.Deflate(border);
  1.1483 +
  1.1484 +  nscoord onePixel = GetPresContext()->IntScaledPixelsToTwips(1);
  1.1485 +
  1.1486 +  kid = GetChildBox();
  1.1487 +  while (nullptr != kid) {
  1.1488 +    bool isHorizontal = IsHorizontal();
  1.1489 +
  1.1490 +    nscoord x, y, borderSize, spacerSize;
  1.1491 +    
  1.1492 +    nsRect cr(kid->mRect);
  1.1493 +    nsMargin margin;
  1.1494 +    kid->GetMargin(margin);
  1.1495 +    cr.Inflate(margin);
  1.1496 +    
  1.1497 +    if (isHorizontal) 
  1.1498 +    {
  1.1499 +        cr.y = inner.y;
  1.1500 +        x = cr.x;
  1.1501 +        y = cr.y + onePixel;
  1.1502 +        spacerSize = debugBorder.top - onePixel*4;
  1.1503 +    } else {
  1.1504 +        cr.x = inner.x;
  1.1505 +        x = cr.y;
  1.1506 +        y = cr.x + onePixel;
  1.1507 +        spacerSize = debugBorder.left - onePixel*4;
  1.1508 +    }
  1.1509 +
  1.1510 +    nsBoxLayoutState state(GetPresContext());
  1.1511 +    nscoord flex = kid->GetFlex(state);
  1.1512 +
  1.1513 +    if (!kid->IsCollapsed()) {
  1.1514 +      aRenderingContext.SetColor(NS_RGB(255,255,255));
  1.1515 +
  1.1516 +      if (isHorizontal) 
  1.1517 +          borderSize = cr.width;
  1.1518 +      else 
  1.1519 +          borderSize = cr.height;
  1.1520 +    
  1.1521 +      DrawSpacer(GetPresContext(), aRenderingContext, isHorizontal, flex, x, y, borderSize, spacerSize);
  1.1522 +    }
  1.1523 +
  1.1524 +    kid = kid->GetNextBox();
  1.1525 +  }
  1.1526 +}
  1.1527 +#endif
  1.1528 +
  1.1529 +#ifdef DEBUG_LAYOUT
  1.1530 +void
  1.1531 +nsBoxFrame::GetBoxName(nsAutoString& aName)
  1.1532 +{
  1.1533 +   GetFrameName(aName);
  1.1534 +}
  1.1535 +#endif
  1.1536 +
  1.1537 +#ifdef DEBUG_FRAME_DUMP
  1.1538 +nsresult
  1.1539 +nsBoxFrame::GetFrameName(nsAString& aResult) const
  1.1540 +{
  1.1541 +  return MakeFrameName(NS_LITERAL_STRING("Box"), aResult);
  1.1542 +}
  1.1543 +#endif
  1.1544 +
  1.1545 +nsIAtom*
  1.1546 +nsBoxFrame::GetType() const
  1.1547 +{
  1.1548 +  return nsGkAtoms::boxFrame;
  1.1549 +}
  1.1550 +
  1.1551 +#ifdef DEBUG_LAYOUT
  1.1552 +nsresult
  1.1553 +nsBoxFrame::GetDebug(bool& aDebug)
  1.1554 +{
  1.1555 +  aDebug = (mState & NS_STATE_CURRENTLY_IN_DEBUG);
  1.1556 +  return NS_OK;
  1.1557 +}
  1.1558 +#endif
  1.1559 +
  1.1560 +// REVIEW: nsBoxFrame::GetFrameForPoint is a problem because of 'mousethrough'
  1.1561 +// attribute support. Here's how it works:
  1.1562 +// * For each child frame F, we determine the target frame T(F) by recursively
  1.1563 +// invoking GetFrameForPoint on the child
  1.1564 +// * Let F' be the last child frame such that T(F') doesn't have mousethrough.
  1.1565 +// If F' exists, return T(F')
  1.1566 +// * Otherwise let F'' be the first child frame such that T(F'') is non-null.
  1.1567 +// If F'' exists, return T(F'')
  1.1568 +// * Otherwise return this frame, if this frame contains the point
  1.1569 +// * Otherwise return null
  1.1570 +// It's not clear how this should work for more complex z-ordering situations.
  1.1571 +// The basic principle seems to be that if a frame F has a descendant
  1.1572 +// 'mousethrough' frame that includes the target position, then F
  1.1573 +// will not receive events (unless it overrides GetFrameForPoint).
  1.1574 +// A 'mousethrough' frame will only receive an event if, after applying that rule,
  1.1575 +// all eligible frames are 'mousethrough'; the bottom-most inner-most 'mousethrough'
  1.1576 +// frame is then chosen (the first eligible frame reached in a
  1.1577 +// traversal of the frame tree --- pre/post is irrelevant since ancestors
  1.1578 +// of the mousethrough frames can't be eligible).
  1.1579 +// IMHO this is very bogus and adds a great deal of complexity for something
  1.1580 +// that is very rarely used. So I'm redefining 'mousethrough' to the following:
  1.1581 +// a frame with mousethrough is transparent to mouse events. This is compatible
  1.1582 +// with the way 'mousethrough' is used in Seamonkey's navigator.xul and
  1.1583 +// Firefox's browser.xul. The only other place it's used is in the 'expander'
  1.1584 +// XBL binding, which in our tree is only used by Thunderbird SMIME Advanced
  1.1585 +// Preferences, and I can't figure out what that does, so I'll have to test it.
  1.1586 +// If it's broken I'll probably just change the binding to use it more sensibly.
  1.1587 +// This new behaviour is implemented in nsDisplayList::HitTest. 
  1.1588 +// REVIEW: This debug-box stuff is annoying. I'm just going to put debug boxes
  1.1589 +// in the outline layer and avoid GetDebugBoxAt.
  1.1590 +
  1.1591 +// REVIEW: GetCursor had debug-only event dumping code. I have replaced it
  1.1592 +// with instrumentation in nsDisplayXULDebug.
  1.1593 +
  1.1594 +#ifdef DEBUG_LAYOUT
  1.1595 +void
  1.1596 +nsBoxFrame::DrawLine(nsRenderingContext& aRenderingContext, bool aHorizontal, nscoord x1, nscoord y1, nscoord x2, nscoord y2)
  1.1597 +{
  1.1598 +    if (aHorizontal)
  1.1599 +       aRenderingContext.DrawLine(x1,y1,x2,y2);
  1.1600 +    else
  1.1601 +       aRenderingContext.DrawLine(y1,x1,y2,x2);
  1.1602 +}
  1.1603 +
  1.1604 +void
  1.1605 +nsBoxFrame::FillRect(nsRenderingContext& aRenderingContext, bool aHorizontal, nscoord x, nscoord y, nscoord width, nscoord height)
  1.1606 +{
  1.1607 +    if (aHorizontal)
  1.1608 +       aRenderingContext.FillRect(x,y,width,height);
  1.1609 +    else
  1.1610 +       aRenderingContext.FillRect(y,x,height,width);
  1.1611 +}
  1.1612 +
  1.1613 +void 
  1.1614 +nsBoxFrame::DrawSpacer(nsPresContext* aPresContext, nsRenderingContext& aRenderingContext, bool aHorizontal, int32_t flex, nscoord x, nscoord y, nscoord size, nscoord spacerSize)
  1.1615 +{    
  1.1616 +         nscoord onePixel = aPresContext->IntScaledPixelsToTwips(1);
  1.1617 +
  1.1618 +     // if we do draw the coils
  1.1619 +        int distance = 0;
  1.1620 +        int center = 0;
  1.1621 +        int offset = 0;
  1.1622 +        int coilSize = COIL_SIZE*onePixel;
  1.1623 +        int halfSpacer = spacerSize/2;
  1.1624 +
  1.1625 +        distance = size;
  1.1626 +        center = y + halfSpacer;
  1.1627 +        offset = x;
  1.1628 +
  1.1629 +        int coils = distance/coilSize;
  1.1630 +
  1.1631 +        int halfCoilSize = coilSize/2;
  1.1632 +
  1.1633 +        if (flex == 0) {
  1.1634 +            DrawLine(aRenderingContext, aHorizontal, x,y + spacerSize/2, x + size, y + spacerSize/2);
  1.1635 +        } else {
  1.1636 +            for (int i=0; i < coils; i++)
  1.1637 +            {
  1.1638 +                   DrawLine(aRenderingContext, aHorizontal, offset, center+halfSpacer, offset+halfCoilSize, center-halfSpacer);
  1.1639 +                   DrawLine(aRenderingContext, aHorizontal, offset+halfCoilSize, center-halfSpacer, offset+coilSize, center+halfSpacer);
  1.1640 +
  1.1641 +                   offset += coilSize;
  1.1642 +            }
  1.1643 +        }
  1.1644 +
  1.1645 +        FillRect(aRenderingContext, aHorizontal, x + size - spacerSize/2, y, spacerSize/2, spacerSize);
  1.1646 +        FillRect(aRenderingContext, aHorizontal, x, y, spacerSize/2, spacerSize);
  1.1647 +
  1.1648 +        //DrawKnob(aPresContext, aRenderingContext, x + size - spacerSize, y, spacerSize);
  1.1649 +}
  1.1650 +
  1.1651 +void
  1.1652 +nsBoxFrame::GetDebugBorder(nsMargin& aInset)
  1.1653 +{
  1.1654 +    aInset.SizeTo(2,2,2,2);
  1.1655 +
  1.1656 +    if (IsHorizontal()) 
  1.1657 +       aInset.top = 10;
  1.1658 +    else 
  1.1659 +       aInset.left = 10;
  1.1660 +}
  1.1661 +
  1.1662 +void
  1.1663 +nsBoxFrame::GetDebugMargin(nsMargin& aInset)
  1.1664 +{
  1.1665 +    aInset.SizeTo(2,2,2,2);
  1.1666 +}
  1.1667 +
  1.1668 +void
  1.1669 +nsBoxFrame::GetDebugPadding(nsMargin& aPadding)
  1.1670 +{
  1.1671 +    aPadding.SizeTo(2,2,2,2);
  1.1672 +}
  1.1673 +
  1.1674 +void 
  1.1675 +nsBoxFrame::PixelMarginToTwips(nsPresContext* aPresContext, nsMargin& aMarginPixels)
  1.1676 +{
  1.1677 +  nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
  1.1678 +  aMarginPixels.left   *= onePixel;
  1.1679 +  aMarginPixels.right  *= onePixel;
  1.1680 +  aMarginPixels.top    *= onePixel;
  1.1681 +  aMarginPixels.bottom *= onePixel;
  1.1682 +}
  1.1683 +
  1.1684 +void
  1.1685 +nsBoxFrame::GetValue(nsPresContext* aPresContext, const nsSize& a, const nsSize& b, char* ch) 
  1.1686 +{
  1.1687 +    float p2t = aPresContext->ScaledPixelsToTwips();
  1.1688 +
  1.1689 +    char width[100];
  1.1690 +    char height[100];
  1.1691 +    
  1.1692 +    if (a.width == NS_INTRINSICSIZE)
  1.1693 +        sprintf(width,"%s","INF");
  1.1694 +    else
  1.1695 +        sprintf(width,"%d", nscoord(a.width/*/p2t*/));
  1.1696 +    
  1.1697 +    if (a.height == NS_INTRINSICSIZE)
  1.1698 +        sprintf(height,"%s","INF");
  1.1699 +    else 
  1.1700 +        sprintf(height,"%d", nscoord(a.height/*/p2t*/));
  1.1701 +    
  1.1702 +
  1.1703 +    sprintf(ch, "(%s%s, %s%s)", width, (b.width != NS_INTRINSICSIZE ? "[SET]" : ""),
  1.1704 +                    height, (b.height != NS_INTRINSICSIZE ? "[SET]" : ""));
  1.1705 +
  1.1706 +}
  1.1707 +
  1.1708 +void
  1.1709 +nsBoxFrame::GetValue(nsPresContext* aPresContext, int32_t a, int32_t b, char* ch) 
  1.1710 +{
  1.1711 +    if (a == NS_INTRINSICSIZE)
  1.1712 +      sprintf(ch, "%d[SET]", b);             
  1.1713 +    else
  1.1714 +      sprintf(ch, "%d", a);             
  1.1715 +}
  1.1716 +
  1.1717 +nsresult
  1.1718 +nsBoxFrame::DisplayDebugInfoFor(nsIFrame*  aBox,
  1.1719 +                                nsPoint& aPoint)
  1.1720 +{
  1.1721 +    nsBoxLayoutState state(GetPresContext());
  1.1722 +
  1.1723 +    nscoord x = aPoint.x;
  1.1724 +    nscoord y = aPoint.y;
  1.1725 +
  1.1726 +    // get the area inside our border but not our debug margins.
  1.1727 +    nsRect insideBorder(aBox->mRect);
  1.1728 +    insideBorder.MoveTo(0,0):
  1.1729 +    nsMargin border(0,0,0,0);
  1.1730 +    aBox->GetBorderAndPadding(border);
  1.1731 +    insideBorder.Deflate(border);
  1.1732 +
  1.1733 +    bool isHorizontal = IsHorizontal();
  1.1734 +
  1.1735 +    if (!insideBorder.Contains(nsPoint(x,y)))
  1.1736 +        return NS_ERROR_FAILURE;
  1.1737 +
  1.1738 +    //printf("%%%%%% inside box %%%%%%%\n");
  1.1739 +
  1.1740 +    int count = 0;
  1.1741 +    nsIFrame* child = aBox->GetChildBox();
  1.1742 +
  1.1743 +    nsMargin m;
  1.1744 +    nsMargin m2;
  1.1745 +    GetDebugBorder(m);
  1.1746 +    PixelMarginToTwips(aPresContext, m);
  1.1747 +
  1.1748 +    GetDebugMargin(m2);
  1.1749 +    PixelMarginToTwips(aPresContext, m2);
  1.1750 +
  1.1751 +    m += m2;
  1.1752 +
  1.1753 +    if ((isHorizontal && y < insideBorder.y + m.top) ||
  1.1754 +        (!isHorizontal && x < insideBorder.x + m.left)) {
  1.1755 +        //printf("**** inside debug border *******\n");
  1.1756 +        while (child) 
  1.1757 +        {
  1.1758 +            const nsRect& r = child->mRect;
  1.1759 +
  1.1760 +            // if we are not in the child. But in the spacer above the child.
  1.1761 +            if ((isHorizontal && x >= r.x && x < r.x + r.width) ||
  1.1762 +                (!isHorizontal && y >= r.y && y < r.y + r.height)) {
  1.1763 +                aCursor = NS_STYLE_CURSOR_POINTER;
  1.1764 +                   // found it but we already showed it.
  1.1765 +                    if (mDebugChild == child)
  1.1766 +                        return NS_OK;
  1.1767 +
  1.1768 +                    if (aBox->GetContent()) {
  1.1769 +                      printf("---------------\n");
  1.1770 +                      DumpBox(stdout);
  1.1771 +                      printf("\n");
  1.1772 +                    }
  1.1773 +
  1.1774 +                    if (child->GetContent()) {
  1.1775 +                        printf("child #%d: ", count);
  1.1776 +                        child->DumpBox(stdout);
  1.1777 +                        printf("\n");
  1.1778 +                    }
  1.1779 +
  1.1780 +                    mDebugChild = child;
  1.1781 +
  1.1782 +                    nsSize prefSizeCSS(NS_INTRINSICSIZE, NS_INTRINSICSIZE);
  1.1783 +                    nsSize minSizeCSS (NS_INTRINSICSIZE, NS_INTRINSICSIZE);
  1.1784 +                    nsSize maxSizeCSS (NS_INTRINSICSIZE, NS_INTRINSICSIZE);
  1.1785 +                    nscoord flexCSS = NS_INTRINSICSIZE;
  1.1786 +
  1.1787 +                    bool widthSet, heightSet;
  1.1788 +                    nsIFrame::AddCSSPrefSize(child, prefSizeCSS, widthSet, heightSet);
  1.1789 +                    nsIFrame::AddCSSMinSize (state, child, minSizeCSS, widthSet, heightSet);
  1.1790 +                    nsIFrame::AddCSSMaxSize (child, maxSizeCSS, widthSet, heightSet);
  1.1791 +                    nsIFrame::AddCSSFlex    (state, child, flexCSS);
  1.1792 +
  1.1793 +                    nsSize prefSize = child->GetPrefSize(state);
  1.1794 +                    nsSize minSize = child->GetMinSize(state);
  1.1795 +                    nsSize maxSize = child->GetMaxSize(state);
  1.1796 +                    nscoord flexSize = child->GetFlex(state);
  1.1797 +                    nscoord ascentSize = child->GetBoxAscent(state);
  1.1798 +
  1.1799 +                    char min[100];
  1.1800 +                    char pref[100];
  1.1801 +                    char max[100];
  1.1802 +                    char calc[100];
  1.1803 +                    char flex[100];
  1.1804 +                    char ascent[100];
  1.1805 +                  
  1.1806 +                    nsSize actualSize;
  1.1807 +                    GetFrameSizeWithMargin(child, actualSize);
  1.1808 +                    nsSize actualSizeCSS (NS_INTRINSICSIZE, NS_INTRINSICSIZE);
  1.1809 +
  1.1810 +                    GetValue(aPresContext, minSize,  minSizeCSS, min);
  1.1811 +                    GetValue(aPresContext, prefSize, prefSizeCSS, pref);
  1.1812 +                    GetValue(aPresContext, maxSize,  maxSizeCSS, max);
  1.1813 +                    GetValue(aPresContext, actualSize, actualSizeCSS, calc);
  1.1814 +                    GetValue(aPresContext, flexSize,  flexCSS, flex);
  1.1815 +                    GetValue(aPresContext, ascentSize,  NS_INTRINSICSIZE, ascent);
  1.1816 +
  1.1817 +
  1.1818 +                    printf("min%s, pref%s, max%s, actual%s, flex=%s, ascent=%s\n\n", 
  1.1819 +                        min,
  1.1820 +                        pref,
  1.1821 +                        max,
  1.1822 +                        calc,
  1.1823 +                        flex,
  1.1824 +                        ascent
  1.1825 +                    );
  1.1826 +
  1.1827 +                    return NS_OK;   
  1.1828 +            }
  1.1829 +
  1.1830 +          child = child->GetNextBox();
  1.1831 +          count++;
  1.1832 +        }
  1.1833 +    } else {
  1.1834 +    }
  1.1835 +
  1.1836 +    mDebugChild = nullptr;
  1.1837 +
  1.1838 +    return NS_OK;
  1.1839 +}
  1.1840 +
  1.1841 +void
  1.1842 +nsBoxFrame::SetDebugOnChildList(nsBoxLayoutState& aState, nsIFrame* aChild, bool aDebug)
  1.1843 +{
  1.1844 +    nsIFrame* child = GetChildBox();
  1.1845 +     while (child)
  1.1846 +     {
  1.1847 +        child->SetDebug(aState, aDebug);
  1.1848 +        child = child->GetNextBox();
  1.1849 +     }
  1.1850 +}
  1.1851 +
  1.1852 +nsresult
  1.1853 +nsBoxFrame::GetFrameSizeWithMargin(nsIFrame* aBox, nsSize& aSize)
  1.1854 +{
  1.1855 +  nsRect rect(aBox->GetRect());
  1.1856 +  nsMargin margin(0,0,0,0);
  1.1857 +  aBox->GetMargin(margin);
  1.1858 +  rect.Inflate(margin);
  1.1859 +  aSize.width = rect.width;
  1.1860 +  aSize.height = rect.height;
  1.1861 +  return NS_OK;
  1.1862 +}
  1.1863 +#endif
  1.1864 +
  1.1865 +// If you make changes to this function, check its counterparts
  1.1866 +// in nsTextBoxFrame and nsXULLabelFrame
  1.1867 +void
  1.1868 +nsBoxFrame::RegUnregAccessKey(bool aDoReg)
  1.1869 +{
  1.1870 +  MOZ_ASSERT(mContent);
  1.1871 +
  1.1872 +  // find out what type of element this is
  1.1873 +  nsIAtom *atom = mContent->Tag();
  1.1874 +
  1.1875 +  // only support accesskeys for the following elements
  1.1876 +  if (atom != nsGkAtoms::button &&
  1.1877 +      atom != nsGkAtoms::toolbarbutton &&
  1.1878 +      atom != nsGkAtoms::checkbox &&
  1.1879 +      atom != nsGkAtoms::textbox &&
  1.1880 +      atom != nsGkAtoms::tab &&
  1.1881 +      atom != nsGkAtoms::radio) {
  1.1882 +    return;
  1.1883 +  }
  1.1884 +
  1.1885 +  nsAutoString accessKey;
  1.1886 +  mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::accesskey, accessKey);
  1.1887 +
  1.1888 +  if (accessKey.IsEmpty())
  1.1889 +    return;
  1.1890 +
  1.1891 +  // With a valid PresContext we can get the ESM 
  1.1892 +  // and register the access key
  1.1893 +  EventStateManager* esm = PresContext()->EventStateManager();
  1.1894 +
  1.1895 +  uint32_t key = accessKey.First();
  1.1896 +  if (aDoReg)
  1.1897 +    esm->RegisterAccessKey(mContent, key);
  1.1898 +  else
  1.1899 +    esm->UnregisterAccessKey(mContent, key);
  1.1900 +}
  1.1901 +
  1.1902 +bool
  1.1903 +nsBoxFrame::SupportsOrdinalsInChildren()
  1.1904 +{
  1.1905 +  return true;
  1.1906 +}
  1.1907 +
  1.1908 +// Helper less-than-or-equal function, used in CheckBoxOrder() as a
  1.1909 +// template-parameter for the sorting functions.
  1.1910 +bool
  1.1911 +IsBoxOrdinalLEQ(nsIFrame* aFrame1,
  1.1912 +                nsIFrame* aFrame2)
  1.1913 +{
  1.1914 +  // If we've got a placeholder frame, use its out-of-flow frame's ordinal val.
  1.1915 +  nsIFrame* aRealFrame1 = nsPlaceholderFrame::GetRealFrameFor(aFrame1);
  1.1916 +  nsIFrame* aRealFrame2 = nsPlaceholderFrame::GetRealFrameFor(aFrame2);
  1.1917 +  return aRealFrame1->GetOrdinal() <= aRealFrame2->GetOrdinal();
  1.1918 +}
  1.1919 +
  1.1920 +void 
  1.1921 +nsBoxFrame::CheckBoxOrder()
  1.1922 +{
  1.1923 +  if (SupportsOrdinalsInChildren() &&
  1.1924 +      !nsIFrame::IsFrameListSorted<IsBoxOrdinalLEQ>(mFrames)) {
  1.1925 +    nsIFrame::SortFrameList<IsBoxOrdinalLEQ>(mFrames);
  1.1926 +  }
  1.1927 +}
  1.1928 +
  1.1929 +nsresult
  1.1930 +nsBoxFrame::LayoutChildAt(nsBoxLayoutState& aState, nsIFrame* aBox, const nsRect& aRect)
  1.1931 +{
  1.1932 +  // get the current rect
  1.1933 +  nsRect oldRect(aBox->GetRect());
  1.1934 +  aBox->SetBounds(aState, aRect);
  1.1935 +
  1.1936 +  bool layout = NS_SUBTREE_DIRTY(aBox);
  1.1937 +  
  1.1938 +  if (layout || (oldRect.width != aRect.width || oldRect.height != aRect.height))  {
  1.1939 +    return aBox->Layout(aState);
  1.1940 +  }
  1.1941 +
  1.1942 +  return NS_OK;
  1.1943 +}
  1.1944 +
  1.1945 +nsresult
  1.1946 +nsBoxFrame::RelayoutChildAtOrdinal(nsBoxLayoutState& aState, nsIFrame* aChild)
  1.1947 +{
  1.1948 +  if (!SupportsOrdinalsInChildren())
  1.1949 +    return NS_OK;
  1.1950 +
  1.1951 +  uint32_t ord = aChild->GetOrdinal();
  1.1952 +  
  1.1953 +  nsIFrame* child = mFrames.FirstChild();
  1.1954 +  nsIFrame* newPrevSib = nullptr;
  1.1955 +
  1.1956 +  while (child) {
  1.1957 +    if (ord < child->GetOrdinal()) {
  1.1958 +      break;
  1.1959 +    }
  1.1960 +
  1.1961 +    if (child != aChild) {
  1.1962 +      newPrevSib = child;
  1.1963 +    }
  1.1964 +
  1.1965 +    child = child->GetNextBox();
  1.1966 +  }
  1.1967 +
  1.1968 +  if (aChild->GetPrevSibling() == newPrevSib) {
  1.1969 +    // This box is not moving.
  1.1970 +    return NS_OK;
  1.1971 +  }
  1.1972 +
  1.1973 +  // Take |aChild| out of its old position in the child list.
  1.1974 +  mFrames.RemoveFrame(aChild);
  1.1975 +
  1.1976 +  // Insert it after |newPrevSib| or at the start if it's null.
  1.1977 +  mFrames.InsertFrame(nullptr, newPrevSib, aChild);
  1.1978 +
  1.1979 +  return NS_OK;
  1.1980 +}
  1.1981 +
  1.1982 +/**
  1.1983 + * This wrapper class lets us redirect mouse hits from descendant frames
  1.1984 + * of a menu to the menu itself, if they didn't specify 'allowevents'.
  1.1985 + * 
  1.1986 + * The wrapper simply turns a hit on a descendant element
  1.1987 + * into a hit on the menu itself, unless there is an element between the target
  1.1988 + * and the menu with the "allowevents" attribute.
  1.1989 + * 
  1.1990 + * This is used by nsMenuFrame and nsTreeColFrame.
  1.1991 + * 
  1.1992 + * Note that turning a hit on a descendant element into nullptr, so events
  1.1993 + * could fall through to the menu background, might be an appealing simplification
  1.1994 + * but it would mean slightly strange behaviour in some cases, because grabber
  1.1995 + * wrappers can be created for many individual lists and items, so the exact
  1.1996 + * fallthrough behaviour would be complex. E.g. an element with "allowevents"
  1.1997 + * on top of the Content() list could receive the event even if it was covered
  1.1998 + * by a PositionedDescenants() element without "allowevents". It is best to
  1.1999 + * never convert a non-null hit into null.
  1.2000 + */
  1.2001 +// REVIEW: This is roughly of what nsMenuFrame::GetFrameForPoint used to do.
  1.2002 +// I've made 'allowevents' affect child elements because that seems the only
  1.2003 +// reasonable thing to do.
  1.2004 +class nsDisplayXULEventRedirector : public nsDisplayWrapList {
  1.2005 +public:
  1.2006 +  nsDisplayXULEventRedirector(nsDisplayListBuilder* aBuilder,
  1.2007 +                              nsIFrame* aFrame, nsDisplayItem* aItem,
  1.2008 +                              nsIFrame* aTargetFrame)
  1.2009 +    : nsDisplayWrapList(aBuilder, aFrame, aItem), mTargetFrame(aTargetFrame) {}
  1.2010 +  nsDisplayXULEventRedirector(nsDisplayListBuilder* aBuilder,
  1.2011 +                              nsIFrame* aFrame, nsDisplayList* aList,
  1.2012 +                              nsIFrame* aTargetFrame)
  1.2013 +    : nsDisplayWrapList(aBuilder, aFrame, aList), mTargetFrame(aTargetFrame) {}
  1.2014 +  virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
  1.2015 +                       HitTestState* aState,
  1.2016 +                       nsTArray<nsIFrame*> *aOutFrames) MOZ_OVERRIDE;
  1.2017 +  NS_DISPLAY_DECL_NAME("XULEventRedirector", TYPE_XUL_EVENT_REDIRECTOR)
  1.2018 +private:
  1.2019 +  nsIFrame* mTargetFrame;
  1.2020 +};
  1.2021 +
  1.2022 +void nsDisplayXULEventRedirector::HitTest(nsDisplayListBuilder* aBuilder,
  1.2023 +    const nsRect& aRect, HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames)
  1.2024 +{
  1.2025 +  nsTArray<nsIFrame*> outFrames;
  1.2026 +  mList.HitTest(aBuilder, aRect, aState, &outFrames);
  1.2027 +
  1.2028 +  bool topMostAdded = false;
  1.2029 +  uint32_t localLength = outFrames.Length();
  1.2030 +
  1.2031 +  for (uint32_t i = 0; i < localLength; i++) {
  1.2032 +
  1.2033 +    for (nsIContent* content = outFrames.ElementAt(i)->GetContent();
  1.2034 +         content && content != mTargetFrame->GetContent();
  1.2035 +         content = content->GetParent()) {
  1.2036 +      if (content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::allowevents,
  1.2037 +                               nsGkAtoms::_true, eCaseMatters)) {
  1.2038 +        // Events are allowed on 'frame', so let it go.
  1.2039 +        aOutFrames->AppendElement(outFrames.ElementAt(i));
  1.2040 +        topMostAdded = true;
  1.2041 +      }
  1.2042 +    }
  1.2043 +
  1.2044 +    // If there was no hit on the topmost frame or its ancestors,
  1.2045 +    // add the target frame itself as the first candidate (see bug 562554).
  1.2046 +    if (!topMostAdded) {
  1.2047 +      topMostAdded = true;
  1.2048 +      aOutFrames->AppendElement(mTargetFrame);
  1.2049 +    }
  1.2050 +  }
  1.2051 +}
  1.2052 +
  1.2053 +class nsXULEventRedirectorWrapper : public nsDisplayWrapper
  1.2054 +{
  1.2055 +public:
  1.2056 +  nsXULEventRedirectorWrapper(nsIFrame* aTargetFrame)
  1.2057 +      : mTargetFrame(aTargetFrame) {}
  1.2058 +  virtual nsDisplayItem* WrapList(nsDisplayListBuilder* aBuilder,
  1.2059 +                                  nsIFrame* aFrame,
  1.2060 +                                  nsDisplayList* aList) MOZ_OVERRIDE {
  1.2061 +    return new (aBuilder)
  1.2062 +        nsDisplayXULEventRedirector(aBuilder, aFrame, aList, mTargetFrame);
  1.2063 +  }
  1.2064 +  virtual nsDisplayItem* WrapItem(nsDisplayListBuilder* aBuilder,
  1.2065 +                                  nsDisplayItem* aItem) MOZ_OVERRIDE {
  1.2066 +    return new (aBuilder)
  1.2067 +        nsDisplayXULEventRedirector(aBuilder, aItem->Frame(), aItem,
  1.2068 +                                    mTargetFrame);
  1.2069 +  }
  1.2070 +private:
  1.2071 +  nsIFrame* mTargetFrame;
  1.2072 +};
  1.2073 +
  1.2074 +void
  1.2075 +nsBoxFrame::WrapListsInRedirector(nsDisplayListBuilder*   aBuilder,
  1.2076 +                                  const nsDisplayListSet& aIn,
  1.2077 +                                  const nsDisplayListSet& aOut)
  1.2078 +{
  1.2079 +  nsXULEventRedirectorWrapper wrapper(this);
  1.2080 +  wrapper.WrapLists(aBuilder, this, aIn, aOut);
  1.2081 +}
  1.2082 +
  1.2083 +bool
  1.2084 +nsBoxFrame::GetEventPoint(WidgetGUIEvent* aEvent, nsPoint &aPoint) {
  1.2085 +  nsIntPoint refPoint;
  1.2086 +  bool res = GetEventPoint(aEvent, refPoint);
  1.2087 +  aPoint = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, refPoint, this);
  1.2088 +  return res;
  1.2089 +}
  1.2090 +
  1.2091 +bool
  1.2092 +nsBoxFrame::GetEventPoint(WidgetGUIEvent* aEvent, nsIntPoint &aPoint) {
  1.2093 +  NS_ENSURE_TRUE(aEvent, false);
  1.2094 +
  1.2095 +  WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
  1.2096 +  if (touchEvent) {
  1.2097 +    // return false if there is more than one touch on the page, or if
  1.2098 +    // we can't find a touch point
  1.2099 +    if (touchEvent->touches.Length() != 1) {
  1.2100 +      return false;
  1.2101 +    }
  1.2102 +
  1.2103 +    dom::Touch* touch = touchEvent->touches.SafeElementAt(0);
  1.2104 +    if (!touch) {
  1.2105 +      return false;
  1.2106 +    }
  1.2107 +    aPoint = touch->mRefPoint;
  1.2108 +  } else {
  1.2109 +    aPoint = LayoutDeviceIntPoint::ToUntyped(aEvent->refPoint);
  1.2110 +  }
  1.2111 +  return true;
  1.2112 +}

mercurial