layout/xul/nsBoxFrame.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set ts=2 sw=2 et tw=80: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 //
     8 // Eric Vaughan
     9 // Netscape Communications
    10 //
    11 // See documentation in associated header file
    12 //
    14 // How boxes layout
    15 // ----------------
    16 // Boxes layout a bit differently than html. html does a bottom up layout. Where boxes do a top down.
    17 // 1) First thing a box does it goes out and askes each child for its min, max, and preferred sizes.
    18 // 2) It then adds them up to determine its size.
    19 // 3) If the box was asked to layout it self intrinically it will layout its children at their preferred size
    20 //    otherwise it will layout the child at the size it was told to. It will squeeze or stretch its children if 
    21 //    Necessary.
    22 //
    23 // However there is a catch. Some html components like block frames can not determine their preferred size. 
    24 // this is their size if they were laid out intrinsically. So the box will flow the child to determine this can
    25 // cache the value.
    27 // Boxes and Incremental Reflow
    28 // ----------------------------
    29 // Boxes layout out top down by adding up their children's min, max, and preferred sizes. Only problem is if a incremental
    30 // reflow occurs. The preferred size of a child deep in the hierarchy could change. And this could change
    31 // any number of syblings around the box. Basically any children in the reflow chain must have their caches cleared
    32 // so when asked for there current size they can relayout themselves. 
    34 #include "nsBoxLayoutState.h"
    35 #include "nsBoxFrame.h"
    36 #include "mozilla/dom/Touch.h"
    37 #include "nsStyleContext.h"
    38 #include "nsPlaceholderFrame.h"
    39 #include "nsPresContext.h"
    40 #include "nsCOMPtr.h"
    41 #include "nsNameSpaceManager.h"
    42 #include "nsGkAtoms.h"
    43 #include "nsIContent.h"
    44 #include "nsHTMLParts.h"
    45 #include "nsViewManager.h"
    46 #include "nsView.h"
    47 #include "nsIPresShell.h"
    48 #include "nsCSSRendering.h"
    49 #include "nsIServiceManager.h"
    50 #include "nsBoxLayout.h"
    51 #include "nsSprocketLayout.h"
    52 #include "nsIScrollableFrame.h"
    53 #include "nsWidgetsCID.h"
    54 #include "nsCSSAnonBoxes.h"
    55 #include "nsContainerFrame.h"
    56 #include "nsIDOMElement.h"
    57 #include "nsITheme.h"
    58 #include "nsTransform2D.h"
    59 #include "mozilla/EventStateManager.h"
    60 #include "nsIDOMEvent.h"
    61 #include "nsDisplayList.h"
    62 #include "mozilla/Preferences.h"
    63 #include "nsThemeConstants.h"
    64 #include "nsLayoutUtils.h"
    65 #include <algorithm>
    67 // Needed for Print Preview
    68 #include "nsIURI.h"
    70 #include "mozilla/TouchEvents.h"
    72 using namespace mozilla;
    73 using namespace mozilla::dom;
    75 //define DEBUG_REDRAW
    77 #define DEBUG_SPRING_SIZE 8
    78 #define DEBUG_BORDER_SIZE 2
    79 #define COIL_SIZE 8
    81 //#define TEST_SANITY
    83 #ifdef DEBUG_rods
    84 //#define DO_NOISY_REFLOW
    85 #endif
    87 #ifdef DEBUG_LAYOUT
    88 bool nsBoxFrame::gDebug = false;
    89 nsIFrame* nsBoxFrame::mDebugChild = nullptr;
    90 #endif
    92 nsIFrame*
    93 NS_NewBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, bool aIsRoot, nsBoxLayout* aLayoutManager)
    94 {
    95   return new (aPresShell) nsBoxFrame(aPresShell, aContext, aIsRoot, aLayoutManager);
    96 }
    98 nsIFrame*
    99 NS_NewBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
   100 {
   101   return new (aPresShell) nsBoxFrame(aPresShell, aContext);
   102 }
   104 NS_IMPL_FRAMEARENA_HELPERS(nsBoxFrame)
   106 #ifdef DEBUG
   107 NS_QUERYFRAME_HEAD(nsBoxFrame)
   108   NS_QUERYFRAME_ENTRY(nsBoxFrame)
   109 NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
   110 #endif
   112 nsBoxFrame::nsBoxFrame(nsIPresShell* aPresShell,
   113                        nsStyleContext* aContext,
   114                        bool aIsRoot,
   115                        nsBoxLayout* aLayoutManager) :
   116   nsContainerFrame(aContext)
   117 {
   118   mState |= NS_STATE_IS_HORIZONTAL;
   119   mState |= NS_STATE_AUTO_STRETCH;
   121   if (aIsRoot) 
   122      mState |= NS_STATE_IS_ROOT;
   124   mValign = vAlign_Top;
   125   mHalign = hAlign_Left;
   127   // if no layout manager specified us the static sprocket layout
   128   nsCOMPtr<nsBoxLayout> layout = aLayoutManager;
   130   if (layout == nullptr) {
   131     NS_NewSprocketLayout(aPresShell, layout);
   132   }
   134   SetLayoutManager(layout);
   135 }
   137 nsBoxFrame::~nsBoxFrame()
   138 {
   139 }
   141 nsresult
   142 nsBoxFrame::SetInitialChildList(ChildListID     aListID,
   143                                 nsFrameList&    aChildList)
   144 {
   145   nsresult r = nsContainerFrame::SetInitialChildList(aListID, aChildList);
   146   if (r == NS_OK) {
   147     // initialize our list of infos.
   148     nsBoxLayoutState state(PresContext());
   149     CheckBoxOrder();
   150     if (mLayoutManager)
   151       mLayoutManager->ChildrenSet(this, state, mFrames.FirstChild());
   152   } else {
   153     NS_WARNING("Warning add child failed!!\n");
   154   }
   156   return r;
   157 }
   159 /* virtual */ void
   160 nsBoxFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
   161 {
   162   nsContainerFrame::DidSetStyleContext(aOldStyleContext);
   164   // The values that CacheAttributes() computes depend on our style,
   165   // so we need to recompute them here...
   166   CacheAttributes();
   167 }
   169 /**
   170  * Initialize us. This is a good time to get the alignment of the box
   171  */
   172 void
   173 nsBoxFrame::Init(nsIContent*      aContent,
   174                  nsIFrame*        aParent,
   175                  nsIFrame*        aPrevInFlow)
   176 {
   177   nsContainerFrame::Init(aContent, aParent, aPrevInFlow);
   179   if (GetStateBits() & NS_FRAME_FONT_INFLATION_CONTAINER) {
   180     AddStateBits(NS_FRAME_FONT_INFLATION_FLOW_ROOT);
   181   }
   183   MarkIntrinsicWidthsDirty();
   185   CacheAttributes();
   187 #ifdef DEBUG_LAYOUT
   188     // if we are root and this
   189   if (mState & NS_STATE_IS_ROOT) 
   190       GetDebugPref(GetPresContext());
   191 #endif
   193   UpdateMouseThrough();
   195   // register access key
   196   RegUnregAccessKey(true);
   197 }
   199 void nsBoxFrame::UpdateMouseThrough()
   200 {
   201   if (mContent) {
   202     static nsIContent::AttrValuesArray strings[] =
   203       {&nsGkAtoms::never, &nsGkAtoms::always, nullptr};
   204     switch (mContent->FindAttrValueIn(kNameSpaceID_None,
   205               nsGkAtoms::mousethrough, strings, eCaseMatters)) {
   206       case 0: AddStateBits(NS_FRAME_MOUSE_THROUGH_NEVER); break;
   207       case 1: AddStateBits(NS_FRAME_MOUSE_THROUGH_ALWAYS); break;
   208       case 2: {
   209         RemoveStateBits(NS_FRAME_MOUSE_THROUGH_ALWAYS);
   210         RemoveStateBits(NS_FRAME_MOUSE_THROUGH_NEVER);
   211         break;
   212       }
   213     }
   214   }
   215 }
   217 void
   218 nsBoxFrame::CacheAttributes()
   219 {
   220   /*
   221   printf("Caching: ");
   222   DumpBox(stdout);
   223   printf("\n");
   224    */
   226   mValign = vAlign_Top;
   227   mHalign = hAlign_Left;
   229   bool orient = false;
   230   GetInitialOrientation(orient); 
   231   if (orient)
   232     mState |= NS_STATE_IS_HORIZONTAL;
   233   else
   234     mState &= ~NS_STATE_IS_HORIZONTAL;
   236   bool normal = true;
   237   GetInitialDirection(normal); 
   238   if (normal)
   239     mState |= NS_STATE_IS_DIRECTION_NORMAL;
   240   else
   241     mState &= ~NS_STATE_IS_DIRECTION_NORMAL;
   243   GetInitialVAlignment(mValign);
   244   GetInitialHAlignment(mHalign);
   246   bool equalSize = false;
   247   GetInitialEqualSize(equalSize); 
   248   if (equalSize)
   249         mState |= NS_STATE_EQUAL_SIZE;
   250     else
   251         mState &= ~NS_STATE_EQUAL_SIZE;
   253   bool autostretch = !!(mState & NS_STATE_AUTO_STRETCH);
   254   GetInitialAutoStretch(autostretch);
   255   if (autostretch)
   256         mState |= NS_STATE_AUTO_STRETCH;
   257      else
   258         mState &= ~NS_STATE_AUTO_STRETCH;
   261 #ifdef DEBUG_LAYOUT
   262   bool debug = mState & NS_STATE_SET_TO_DEBUG;
   263   bool debugSet = GetInitialDebug(debug); 
   264   if (debugSet) {
   265         mState |= NS_STATE_DEBUG_WAS_SET;
   266         if (debug)
   267             mState |= NS_STATE_SET_TO_DEBUG;
   268         else
   269             mState &= ~NS_STATE_SET_TO_DEBUG;
   270   } else {
   271         mState &= ~NS_STATE_DEBUG_WAS_SET;
   272   }
   273 #endif
   274 }
   276 #ifdef DEBUG_LAYOUT
   277 bool
   278 nsBoxFrame::GetInitialDebug(bool& aDebug)
   279 {
   280   if (!GetContent())
   281     return false;
   283   static nsIContent::AttrValuesArray strings[] =
   284     {&nsGkAtoms::_false, &nsGkAtoms::_true, nullptr};
   285   int32_t index = GetContent()->FindAttrValueIn(kNameSpaceID_None,
   286       nsGkAtoms::debug, strings, eCaseMatters);
   287   if (index >= 0) {
   288     aDebug = index == 1;
   289     return true;
   290   }
   292   return false;
   293 }
   294 #endif
   296 bool
   297 nsBoxFrame::GetInitialHAlignment(nsBoxFrame::Halignment& aHalign)
   298 {
   299   if (!GetContent())
   300     return false;
   302   // XXXdwh Everything inside this if statement is deprecated code.
   303   static nsIContent::AttrValuesArray alignStrings[] =
   304     {&nsGkAtoms::left, &nsGkAtoms::right, nullptr};
   305   static const Halignment alignValues[] = {hAlign_Left, hAlign_Right};
   306   int32_t index = GetContent()->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::align,
   307       alignStrings, eCaseMatters);
   308   if (index >= 0) {
   309     aHalign = alignValues[index];
   310     return true;
   311   }
   313   // Now that the deprecated stuff is out of the way, we move on to check the appropriate 
   314   // attribute.  For horizontal boxes, we are checking the PACK attribute.  For vertical boxes
   315   // we are checking the ALIGN attribute.
   316   nsIAtom* attrName = IsHorizontal() ? nsGkAtoms::pack : nsGkAtoms::align;
   317   static nsIContent::AttrValuesArray strings[] =
   318     {&nsGkAtoms::_empty, &nsGkAtoms::start, &nsGkAtoms::center, &nsGkAtoms::end, nullptr};
   319   static const Halignment values[] =
   320     {hAlign_Left/*not used*/, hAlign_Left, hAlign_Center, hAlign_Right};
   321   index = GetContent()->FindAttrValueIn(kNameSpaceID_None, attrName,
   322       strings, eCaseMatters);
   324   if (index == nsIContent::ATTR_VALUE_NO_MATCH) {
   325     // The attr was present but had a nonsensical value. Revert to the default.
   326     return false;
   327   }
   328   if (index > 0) {    
   329     aHalign = values[index];
   330     return true;
   331   }
   333   // Now that we've checked for the attribute it's time to check CSS.  For 
   334   // horizontal boxes we're checking PACK.  For vertical boxes we are checking
   335   // ALIGN.
   336   const nsStyleXUL* boxInfo = StyleXUL();
   337   if (IsHorizontal()) {
   338     switch (boxInfo->mBoxPack) {
   339       case NS_STYLE_BOX_PACK_START:
   340         aHalign = nsBoxFrame::hAlign_Left;
   341         return true;
   342       case NS_STYLE_BOX_PACK_CENTER:
   343         aHalign = nsBoxFrame::hAlign_Center;
   344         return true;
   345       case NS_STYLE_BOX_PACK_END:
   346         aHalign = nsBoxFrame::hAlign_Right;
   347         return true;
   348       default: // Nonsensical value. Just bail.
   349         return false;
   350     }
   351   }
   352   else {
   353     switch (boxInfo->mBoxAlign) {
   354       case NS_STYLE_BOX_ALIGN_START:
   355         aHalign = nsBoxFrame::hAlign_Left;
   356         return true;
   357       case NS_STYLE_BOX_ALIGN_CENTER:
   358         aHalign = nsBoxFrame::hAlign_Center;
   359         return true;
   360       case NS_STYLE_BOX_ALIGN_END:
   361         aHalign = nsBoxFrame::hAlign_Right;
   362         return true;
   363       default: // Nonsensical value. Just bail.
   364         return false;
   365     }
   366   }
   368   return false;
   369 }
   371 bool
   372 nsBoxFrame::GetInitialVAlignment(nsBoxFrame::Valignment& aValign)
   373 {
   374   if (!GetContent())
   375     return false;
   377   static nsIContent::AttrValuesArray valignStrings[] =
   378     {&nsGkAtoms::top, &nsGkAtoms::baseline, &nsGkAtoms::middle, &nsGkAtoms::bottom, nullptr};
   379   static const Valignment valignValues[] =
   380     {vAlign_Top, vAlign_BaseLine, vAlign_Middle, vAlign_Bottom};
   381   int32_t index = GetContent()->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::valign,
   382       valignStrings, eCaseMatters);
   383   if (index >= 0) {
   384     aValign = valignValues[index];
   385     return true;
   386   }
   388   // Now that the deprecated stuff is out of the way, we move on to check the appropriate 
   389   // attribute.  For horizontal boxes, we are checking the ALIGN attribute.  For vertical boxes
   390   // we are checking the PACK attribute.
   391   nsIAtom* attrName = IsHorizontal() ? nsGkAtoms::align : nsGkAtoms::pack;
   392   static nsIContent::AttrValuesArray strings[] =
   393     {&nsGkAtoms::_empty, &nsGkAtoms::start, &nsGkAtoms::center,
   394      &nsGkAtoms::baseline, &nsGkAtoms::end, nullptr};
   395   static const Valignment values[] =
   396     {vAlign_Top/*not used*/, vAlign_Top, vAlign_Middle, vAlign_BaseLine, vAlign_Bottom};
   397   index = GetContent()->FindAttrValueIn(kNameSpaceID_None, attrName,
   398       strings, eCaseMatters);
   399   if (index == nsIContent::ATTR_VALUE_NO_MATCH) {
   400     // The attr was present but had a nonsensical value. Revert to the default.
   401     return false;
   402   }
   403   if (index > 0) {
   404     aValign = values[index];
   405     return true;
   406   }
   408   // Now that we've checked for the attribute it's time to check CSS.  For 
   409   // horizontal boxes we're checking ALIGN.  For vertical boxes we are checking
   410   // PACK.
   411   const nsStyleXUL* boxInfo = StyleXUL();
   412   if (IsHorizontal()) {
   413     switch (boxInfo->mBoxAlign) {
   414       case NS_STYLE_BOX_ALIGN_START:
   415         aValign = nsBoxFrame::vAlign_Top;
   416         return true;
   417       case NS_STYLE_BOX_ALIGN_CENTER:
   418         aValign = nsBoxFrame::vAlign_Middle;
   419         return true;
   420       case NS_STYLE_BOX_ALIGN_BASELINE:
   421         aValign = nsBoxFrame::vAlign_BaseLine;
   422         return true;
   423       case NS_STYLE_BOX_ALIGN_END:
   424         aValign = nsBoxFrame::vAlign_Bottom;
   425         return true;
   426       default: // Nonsensical value. Just bail.
   427         return false;
   428     }
   429   }
   430   else {
   431     switch (boxInfo->mBoxPack) {
   432       case NS_STYLE_BOX_PACK_START:
   433         aValign = nsBoxFrame::vAlign_Top;
   434         return true;
   435       case NS_STYLE_BOX_PACK_CENTER:
   436         aValign = nsBoxFrame::vAlign_Middle;
   437         return true;
   438       case NS_STYLE_BOX_PACK_END:
   439         aValign = nsBoxFrame::vAlign_Bottom;
   440         return true;
   441       default: // Nonsensical value. Just bail.
   442         return false;
   443     }
   444   }
   446   return false;
   447 }
   449 void
   450 nsBoxFrame::GetInitialOrientation(bool& aIsHorizontal)
   451 {
   452  // see if we are a vertical or horizontal box.
   453   if (!GetContent())
   454     return;
   456   // Check the style system first.
   457   const nsStyleXUL* boxInfo = StyleXUL();
   458   if (boxInfo->mBoxOrient == NS_STYLE_BOX_ORIENT_HORIZONTAL)
   459     aIsHorizontal = true;
   460   else 
   461     aIsHorizontal = false;
   463   // Now see if we have an attribute.  The attribute overrides
   464   // the style system value.
   465   static nsIContent::AttrValuesArray strings[] =
   466     {&nsGkAtoms::vertical, &nsGkAtoms::horizontal, nullptr};
   467   int32_t index = GetContent()->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::orient,
   468       strings, eCaseMatters);
   469   if (index >= 0) {
   470     aIsHorizontal = index == 1;
   471   }
   472 }
   474 void
   475 nsBoxFrame::GetInitialDirection(bool& aIsNormal)
   476 {
   477   if (!GetContent())
   478     return;
   480   if (IsHorizontal()) {
   481     // For horizontal boxes only, we initialize our value based off the CSS 'direction' property.
   482     // This means that BiDI users will end up with horizontally inverted chrome.
   483     aIsNormal = (StyleVisibility()->mDirection == NS_STYLE_DIRECTION_LTR); // If text runs RTL then so do we.
   484   }
   485   else
   486     aIsNormal = true; // Assume a normal direction in the vertical case.
   488   // Now check the style system to see if we should invert aIsNormal.
   489   const nsStyleXUL* boxInfo = StyleXUL();
   490   if (boxInfo->mBoxDirection == NS_STYLE_BOX_DIRECTION_REVERSE)
   491     aIsNormal = !aIsNormal; // Invert our direction.
   493   // Now see if we have an attribute.  The attribute overrides
   494   // the style system value.
   495   if (IsHorizontal()) {
   496     static nsIContent::AttrValuesArray strings[] =
   497       {&nsGkAtoms::reverse, &nsGkAtoms::ltr, &nsGkAtoms::rtl, nullptr};
   498     int32_t index = GetContent()->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::dir,
   499         strings, eCaseMatters);
   500     if (index >= 0) {
   501       bool values[] = {!aIsNormal, true, false};
   502       aIsNormal = values[index];
   503     }
   504   } else if (GetContent()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::dir,
   505                                        nsGkAtoms::reverse, eCaseMatters)) {
   506     aIsNormal = !aIsNormal;
   507   }
   508 }
   510 /* Returns true if it was set.
   511  */
   512 bool
   513 nsBoxFrame::GetInitialEqualSize(bool& aEqualSize)
   514 {
   515  // see if we are a vertical or horizontal box.
   516   if (!GetContent())
   517      return false;
   519   if (GetContent()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::equalsize,
   520                            nsGkAtoms::always, eCaseMatters)) {
   521     aEqualSize = true;
   522     return true;
   523   }
   525   return false;
   526 }
   528 /* Returns true if it was set.
   529  */
   530 bool
   531 nsBoxFrame::GetInitialAutoStretch(bool& aStretch)
   532 {
   533   if (!GetContent())
   534      return false;
   536   // Check the align attribute.
   537   static nsIContent::AttrValuesArray strings[] =
   538     {&nsGkAtoms::_empty, &nsGkAtoms::stretch, nullptr};
   539   int32_t index = GetContent()->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::align,
   540       strings, eCaseMatters);
   541   if (index != nsIContent::ATTR_MISSING && index != 0) {
   542     aStretch = index == 1;
   543     return true;
   544   }
   546   // Check the CSS box-align property.
   547   const nsStyleXUL* boxInfo = StyleXUL();
   548   aStretch = (boxInfo->mBoxAlign == NS_STYLE_BOX_ALIGN_STRETCH);
   550   return true;
   551 }
   553 nsresult
   554 nsBoxFrame::DidReflow(nsPresContext*           aPresContext,
   555                       const nsHTMLReflowState*  aReflowState,
   556                       nsDidReflowStatus         aStatus)
   557 {
   558   nsFrameState preserveBits =
   559     mState & (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN);
   560   nsresult rv = nsFrame::DidReflow(aPresContext, aReflowState, aStatus);
   561   mState |= preserveBits;
   562   return rv;
   563 }
   565 bool
   566 nsBoxFrame::HonorPrintBackgroundSettings()
   567 {
   568   return (!mContent || !mContent->IsInNativeAnonymousSubtree()) &&
   569     nsContainerFrame::HonorPrintBackgroundSettings();
   570 }
   572 #ifdef DO_NOISY_REFLOW
   573 static int myCounter = 0;
   574 static void printSize(char * aDesc, nscoord aSize) 
   575 {
   576   printf(" %s: ", aDesc);
   577   if (aSize == NS_UNCONSTRAINEDSIZE) {
   578     printf("UC");
   579   } else {
   580     printf("%d", aSize);
   581   }
   582 }
   583 #endif
   585 /* virtual */ nscoord
   586 nsBoxFrame::GetMinWidth(nsRenderingContext *aRenderingContext)
   587 {
   588   nscoord result;
   589   DISPLAY_MIN_WIDTH(this, result);
   591   nsBoxLayoutState state(PresContext(), aRenderingContext);
   592   nsSize minSize = GetMinSize(state);
   594   // GetMinSize returns border-box width, and we want to return content
   595   // width.  Since Reflow uses the reflow state's border and padding, we
   596   // actually just want to subtract what GetMinSize added, which is the
   597   // result of GetBorderAndPadding.
   598   nsMargin bp;
   599   GetBorderAndPadding(bp);
   601   result = minSize.width - bp.LeftRight();
   602   result = std::max(result, 0);
   604   return result;
   605 }
   607 /* virtual */ nscoord
   608 nsBoxFrame::GetPrefWidth(nsRenderingContext *aRenderingContext)
   609 {
   610   nscoord result;
   611   DISPLAY_PREF_WIDTH(this, result);
   613   nsBoxLayoutState state(PresContext(), aRenderingContext);
   614   nsSize prefSize = GetPrefSize(state);
   616   // GetPrefSize returns border-box width, and we want to return content
   617   // width.  Since Reflow uses the reflow state's border and padding, we
   618   // actually just want to subtract what GetPrefSize added, which is the
   619   // result of GetBorderAndPadding.
   620   nsMargin bp;
   621   GetBorderAndPadding(bp);
   623   result = prefSize.width - bp.LeftRight();
   624   result = std::max(result, 0);
   626   return result;
   627 }
   629 nsresult
   630 nsBoxFrame::Reflow(nsPresContext*          aPresContext,
   631                    nsHTMLReflowMetrics&     aDesiredSize,
   632                    const nsHTMLReflowState& aReflowState,
   633                    nsReflowStatus&          aStatus)
   634 {
   635   // If you make changes to this method, please keep nsLeafBoxFrame::Reflow
   636   // in sync, if the changes are applicable there.
   638   DO_GLOBAL_REFLOW_COUNT("nsBoxFrame");
   639   DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
   641   NS_ASSERTION(aReflowState.ComputedWidth() >=0 &&
   642                aReflowState.ComputedHeight() >= 0, "Computed Size < 0");
   644 #ifdef DO_NOISY_REFLOW
   645   printf("\n-------------Starting BoxFrame Reflow ----------------------------\n");
   646   printf("%p ** nsBF::Reflow %d ", this, myCounter++);
   648   printSize("AW", aReflowState.AvailableWidth());
   649   printSize("AH", aReflowState.AvailableHeight());
   650   printSize("CW", aReflowState.ComputedWidth());
   651   printSize("CH", aReflowState.ComputedHeight());
   653   printf(" *\n");
   655 #endif
   657   aStatus = NS_FRAME_COMPLETE;
   659   // create the layout state
   660   nsBoxLayoutState state(aPresContext, aReflowState.rendContext,
   661                          &aReflowState, aReflowState.mReflowDepth);
   663   nsSize computedSize(aReflowState.ComputedWidth(),aReflowState.ComputedHeight());
   665   nsMargin m;
   666   m = aReflowState.ComputedPhysicalBorderPadding();
   667   // GetBorderAndPadding(m);
   669   nsSize prefSize(0,0);
   671   // if we are told to layout intrinsic then get our preferred size.
   672   NS_ASSERTION(computedSize.width != NS_INTRINSICSIZE,
   673                "computed width should always be computed");
   674   if (computedSize.height == NS_INTRINSICSIZE) {
   675     prefSize = GetPrefSize(state);
   676     nsSize minSize = GetMinSize(state);
   677     nsSize maxSize = GetMaxSize(state);
   678     // XXXbz isn't GetPrefSize supposed to bounds-check for us?
   679     prefSize = BoundsCheck(minSize, prefSize, maxSize);
   680   }
   682   // get our desiredSize
   683   computedSize.width += m.left + m.right;
   685   if (aReflowState.ComputedHeight() == NS_INTRINSICSIZE) {
   686     computedSize.height = prefSize.height;
   687     // prefSize is border-box but min/max constraints are content-box.
   688     nscoord verticalBorderPadding =
   689       aReflowState.ComputedPhysicalBorderPadding().TopBottom();
   690     nscoord contentHeight = computedSize.height - verticalBorderPadding;
   691     // Note: contentHeight might be negative, but that's OK because min-height
   692     // is never negative.
   693     computedSize.height = aReflowState.ApplyMinMaxHeight(contentHeight) +
   694                           verticalBorderPadding;
   695   } else {
   696     computedSize.height += m.top + m.bottom;
   697   }
   699   nsRect r(mRect.x, mRect.y, computedSize.width, computedSize.height);
   701   SetBounds(state, r);
   703   // layout our children
   704   Layout(state);
   706   // ok our child could have gotten bigger. So lets get its bounds
   708   // get the ascent
   709   nscoord ascent = mRect.height;
   711   // getting the ascent could be a lot of work. Don't get it if
   712   // we are the root. The viewport doesn't care about it.
   713   if (!(mState & NS_STATE_IS_ROOT)) {
   714     ascent = GetBoxAscent(state);
   715   }
   717   aDesiredSize.Width() = mRect.width;
   718   aDesiredSize.Height() = mRect.height;
   719   aDesiredSize.SetTopAscent(ascent);
   721   aDesiredSize.mOverflowAreas = GetOverflowAreas();
   723 #ifdef DO_NOISY_REFLOW
   724   {
   725     printf("%p ** nsBF(done) W:%d H:%d  ", this, aDesiredSize.Width(), aDesiredSize.Height());
   727     if (maxElementSize) {
   728       printf("MW:%d\n", *maxElementWidth); 
   729     } else {
   730       printf("MW:?\n"); 
   731     }
   733   }
   734 #endif
   736   ReflowAbsoluteFrames(aPresContext, aDesiredSize, aReflowState, aStatus);
   738   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
   739   return NS_OK;
   740 }
   742 nsSize
   743 nsBoxFrame::GetPrefSize(nsBoxLayoutState& aBoxLayoutState)
   744 {
   745   NS_ASSERTION(aBoxLayoutState.GetRenderingContext(),
   746                "must have rendering context");
   748   nsSize size(0,0);
   749   DISPLAY_PREF_SIZE(this, size);
   750   if (!DoesNeedRecalc(mPrefSize)) {
   751      return mPrefSize;
   752   }
   754 #ifdef DEBUG_LAYOUT
   755   PropagateDebug(aBoxLayoutState);
   756 #endif
   758   if (IsCollapsed())
   759     return size;
   761   // if the size was not completely redefined in CSS then ask our children
   762   bool widthSet, heightSet;
   763   if (!nsIFrame::AddCSSPrefSize(this, size, widthSet, heightSet))
   764   {
   765     if (mLayoutManager) {
   766       nsSize layoutSize = mLayoutManager->GetPrefSize(this, aBoxLayoutState);
   767       if (!widthSet)
   768         size.width = layoutSize.width;
   769       if (!heightSet)
   770         size.height = layoutSize.height;
   771     }
   772     else {
   773       size = nsBox::GetPrefSize(aBoxLayoutState);
   774     }
   775   }
   777   nsSize minSize = GetMinSize(aBoxLayoutState);
   778   nsSize maxSize = GetMaxSize(aBoxLayoutState);
   779   mPrefSize = BoundsCheck(minSize, size, maxSize);
   781   return mPrefSize;
   782 }
   784 nscoord
   785 nsBoxFrame::GetBoxAscent(nsBoxLayoutState& aBoxLayoutState)
   786 {
   787   if (!DoesNeedRecalc(mAscent))
   788      return mAscent;
   790 #ifdef DEBUG_LAYOUT
   791   PropagateDebug(aBoxLayoutState);
   792 #endif
   794   if (IsCollapsed())
   795     return 0;
   797   if (mLayoutManager)
   798     mAscent = mLayoutManager->GetAscent(this, aBoxLayoutState);
   799   else
   800     mAscent = nsBox::GetBoxAscent(aBoxLayoutState);
   802   return mAscent;
   803 }
   805 nsSize
   806 nsBoxFrame::GetMinSize(nsBoxLayoutState& aBoxLayoutState)
   807 {
   808   NS_ASSERTION(aBoxLayoutState.GetRenderingContext(),
   809                "must have rendering context");
   811   nsSize size(0,0);
   812   DISPLAY_MIN_SIZE(this, size);
   813   if (!DoesNeedRecalc(mMinSize)) {
   814     return mMinSize;
   815   }
   817 #ifdef DEBUG_LAYOUT
   818   PropagateDebug(aBoxLayoutState);
   819 #endif
   821   if (IsCollapsed())
   822     return size;
   824   // if the size was not completely redefined in CSS then ask our children
   825   bool widthSet, heightSet;
   826   if (!nsIFrame::AddCSSMinSize(aBoxLayoutState, this, size, widthSet, heightSet))
   827   {
   828     if (mLayoutManager) {
   829       nsSize layoutSize = mLayoutManager->GetMinSize(this, aBoxLayoutState);
   830       if (!widthSet)
   831         size.width = layoutSize.width;
   832       if (!heightSet)
   833         size.height = layoutSize.height;
   834     }
   835     else {
   836       size = nsBox::GetMinSize(aBoxLayoutState);
   837     }
   838   }
   840   mMinSize = size;
   842   return size;
   843 }
   845 nsSize
   846 nsBoxFrame::GetMaxSize(nsBoxLayoutState& aBoxLayoutState)
   847 {
   848   NS_ASSERTION(aBoxLayoutState.GetRenderingContext(),
   849                "must have rendering context");
   851   nsSize size(NS_INTRINSICSIZE, NS_INTRINSICSIZE);
   852   DISPLAY_MAX_SIZE(this, size);
   853   if (!DoesNeedRecalc(mMaxSize)) {
   854     return mMaxSize;
   855   }
   857 #ifdef DEBUG_LAYOUT
   858   PropagateDebug(aBoxLayoutState);
   859 #endif
   861   if (IsCollapsed())
   862     return size;
   864   // if the size was not completely redefined in CSS then ask our children
   865   bool widthSet, heightSet;
   866   if (!nsIFrame::AddCSSMaxSize(this, size, widthSet, heightSet))
   867   {
   868     if (mLayoutManager) {
   869       nsSize layoutSize = mLayoutManager->GetMaxSize(this, aBoxLayoutState);
   870       if (!widthSet)
   871         size.width = layoutSize.width;
   872       if (!heightSet)
   873         size.height = layoutSize.height;
   874     }
   875     else {
   876       size = nsBox::GetMaxSize(aBoxLayoutState);
   877     }
   878   }
   880   mMaxSize = size;
   882   return size;
   883 }
   885 nscoord
   886 nsBoxFrame::GetFlex(nsBoxLayoutState& aBoxLayoutState)
   887 {
   888   if (!DoesNeedRecalc(mFlex))
   889      return mFlex;
   891   mFlex = nsBox::GetFlex(aBoxLayoutState);
   893   return mFlex;
   894 }
   896 /**
   897  * If subclassing please subclass this method not layout. 
   898  * layout will call this method.
   899  */
   900 NS_IMETHODIMP
   901 nsBoxFrame::DoLayout(nsBoxLayoutState& aState)
   902 {
   903   uint32_t oldFlags = aState.LayoutFlags();
   904   aState.SetLayoutFlags(0);
   906   nsresult rv = NS_OK;
   907   if (mLayoutManager) {
   908     CoordNeedsRecalc(mAscent);
   909     rv = mLayoutManager->Layout(this, aState);
   910   }
   912   aState.SetLayoutFlags(oldFlags);
   914   if (HasAbsolutelyPositionedChildren()) {
   915     // Set up a |reflowState| to pass into ReflowAbsoluteFrames
   916     nsHTMLReflowState reflowState(aState.PresContext(), this,
   917                                   aState.GetRenderingContext(),
   918                                   nsSize(mRect.width, NS_UNCONSTRAINEDSIZE));
   920     // Set up a |desiredSize| to pass into ReflowAbsoluteFrames
   921     nsHTMLReflowMetrics desiredSize(reflowState);
   922     desiredSize.Width() = mRect.width;
   923     desiredSize.Height() = mRect.height;
   925     // get the ascent (cribbed from ::Reflow)
   926     nscoord ascent = mRect.height;
   928     // getting the ascent could be a lot of work. Don't get it if
   929     // we are the root. The viewport doesn't care about it.
   930     if (!(mState & NS_STATE_IS_ROOT)) {
   931       ascent = GetBoxAscent(aState);
   932     }
   933     desiredSize.SetTopAscent(ascent);
   934     desiredSize.mOverflowAreas = GetOverflowAreas();
   936     AddStateBits(NS_FRAME_IN_REFLOW);
   937     // Set up a |reflowStatus| to pass into ReflowAbsoluteFrames
   938     // (just a dummy value; hopefully that's OK)
   939     nsReflowStatus reflowStatus = NS_FRAME_COMPLETE;
   940     ReflowAbsoluteFrames(aState.PresContext(), desiredSize,
   941                          reflowState, reflowStatus);
   942     RemoveStateBits(NS_FRAME_IN_REFLOW);
   943   }
   945   return rv;
   946 }
   948 void
   949 nsBoxFrame::DestroyFrom(nsIFrame* aDestructRoot)
   950 {
   951   // unregister access key
   952   RegUnregAccessKey(false);
   954   // clean up the container box's layout manager and child boxes
   955   SetLayoutManager(nullptr);
   957   nsContainerFrame::DestroyFrom(aDestructRoot);
   958 } 
   960 #ifdef DEBUG_LAYOUT
   961 nsresult
   962 nsBoxFrame::SetDebug(nsBoxLayoutState& aState, bool aDebug)
   963 {
   964   // see if our state matches the given debug state
   965   bool debugSet = mState & NS_STATE_CURRENTLY_IN_DEBUG;
   966   bool debugChanged = (!aDebug && debugSet) || (aDebug && !debugSet);
   968   // if it doesn't then tell each child below us the new debug state
   969   if (debugChanged)
   970   {
   971      if (aDebug) {
   972          mState |= NS_STATE_CURRENTLY_IN_DEBUG;
   973      } else {
   974          mState &= ~NS_STATE_CURRENTLY_IN_DEBUG;
   975      }
   977      SetDebugOnChildList(aState, mFirstChild, aDebug);
   979     MarkIntrinsicWidthsDirty();
   980   }
   982   return NS_OK;
   983 }
   984 #endif
   986 /* virtual */ void
   987 nsBoxFrame::MarkIntrinsicWidthsDirty()
   988 {
   989   SizeNeedsRecalc(mPrefSize);
   990   SizeNeedsRecalc(mMinSize);
   991   SizeNeedsRecalc(mMaxSize);
   992   CoordNeedsRecalc(mFlex);
   993   CoordNeedsRecalc(mAscent);
   995   if (mLayoutManager) {
   996     nsBoxLayoutState state(PresContext());
   997     mLayoutManager->IntrinsicWidthsDirty(this, state);
   998   }
  1000   // Don't call base class method, since everything it does is within an
  1001   // IsBoxWrapped check.
  1004 nsresult
  1005 nsBoxFrame::RemoveFrame(ChildListID     aListID,
  1006                         nsIFrame*       aOldFrame)
  1008   NS_PRECONDITION(aListID == kPrincipalList, "We don't support out-of-flow kids");
  1009   nsPresContext* presContext = PresContext();
  1010   nsBoxLayoutState state(presContext);
  1012   // remove the child frame
  1013   mFrames.RemoveFrame(aOldFrame);
  1015   // notify the layout manager
  1016   if (mLayoutManager)
  1017     mLayoutManager->ChildrenRemoved(this, state, aOldFrame);
  1019   // destroy the child frame
  1020   aOldFrame->Destroy();
  1022   // mark us dirty and generate a reflow command
  1023   PresContext()->PresShell()->
  1024     FrameNeedsReflow(this, nsIPresShell::eTreeChange,
  1025                      NS_FRAME_HAS_DIRTY_CHILDREN);
  1026   return NS_OK;
  1029 nsresult
  1030 nsBoxFrame::InsertFrames(ChildListID     aListID,
  1031                          nsIFrame*       aPrevFrame,
  1032                          nsFrameList&    aFrameList)
  1034    NS_ASSERTION(!aPrevFrame || aPrevFrame->GetParent() == this,
  1035                 "inserting after sibling frame with different parent");
  1036    NS_ASSERTION(!aPrevFrame || mFrames.ContainsFrame(aPrevFrame),
  1037                 "inserting after sibling frame not in our child list");
  1038    NS_PRECONDITION(aListID == kPrincipalList, "We don't support out-of-flow kids");
  1039    nsBoxLayoutState state(PresContext());
  1041    // insert the child frames
  1042    const nsFrameList::Slice& newFrames =
  1043      mFrames.InsertFrames(this, aPrevFrame, aFrameList);
  1045    // notify the layout manager
  1046    if (mLayoutManager)
  1047      mLayoutManager->ChildrenInserted(this, state, aPrevFrame, newFrames);
  1049    // Make sure to check box order _after_ notifying the layout
  1050    // manager; otherwise the slice we give the layout manager will
  1051    // just be bogus.  If the layout manager cares about the order, we
  1052    // just lose.
  1053    CheckBoxOrder();
  1055 #ifdef DEBUG_LAYOUT
  1056    // if we are in debug make sure our children are in debug as well.
  1057    if (mState & NS_STATE_CURRENTLY_IN_DEBUG)
  1058        SetDebugOnChildList(state, mFrames.FirstChild(), true);
  1059 #endif
  1061    PresContext()->PresShell()->
  1062      FrameNeedsReflow(this, nsIPresShell::eTreeChange,
  1063                       NS_FRAME_HAS_DIRTY_CHILDREN);
  1064    return NS_OK;
  1068 nsresult
  1069 nsBoxFrame::AppendFrames(ChildListID     aListID,
  1070                          nsFrameList&    aFrameList)
  1072    NS_PRECONDITION(aListID == kPrincipalList, "We don't support out-of-flow kids");
  1073    nsBoxLayoutState state(PresContext());
  1075    // append the new frames
  1076    const nsFrameList::Slice& newFrames = mFrames.AppendFrames(this, aFrameList);
  1078    // notify the layout manager
  1079    if (mLayoutManager)
  1080      mLayoutManager->ChildrenAppended(this, state, newFrames);
  1082    // Make sure to check box order _after_ notifying the layout
  1083    // manager; otherwise the slice we give the layout manager will
  1084    // just be bogus.  If the layout manager cares about the order, we
  1085    // just lose.
  1086    CheckBoxOrder();
  1088 #ifdef DEBUG_LAYOUT
  1089    // if we are in debug make sure our children are in debug as well.
  1090    if (mState & NS_STATE_CURRENTLY_IN_DEBUG)
  1091        SetDebugOnChildList(state, mFrames.FirstChild(), true);
  1092 #endif
  1094    // XXXbz why is this NS_FRAME_FIRST_REFLOW check here?
  1095    if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
  1096      PresContext()->PresShell()->
  1097        FrameNeedsReflow(this, nsIPresShell::eTreeChange,
  1098                         NS_FRAME_HAS_DIRTY_CHILDREN);
  1100    return NS_OK;
  1103 /* virtual */ nsIFrame*
  1104 nsBoxFrame::GetContentInsertionFrame()
  1106   if (GetStateBits() & NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK)
  1107     return GetFirstPrincipalChild()->GetContentInsertionFrame();
  1108   return nsContainerFrame::GetContentInsertionFrame();
  1111 nsresult
  1112 nsBoxFrame::AttributeChanged(int32_t aNameSpaceID,
  1113                              nsIAtom* aAttribute,
  1114                              int32_t aModType)
  1116   nsresult rv = nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute,
  1117                                                    aModType);
  1119   // Ignore 'width', 'height', 'screenX', 'screenY' and 'sizemode' on a
  1120   // <window>.
  1121   nsIAtom *tag = mContent->Tag();
  1122   if ((tag == nsGkAtoms::window ||
  1123        tag == nsGkAtoms::page ||
  1124        tag == nsGkAtoms::dialog ||
  1125        tag == nsGkAtoms::wizard) &&
  1126       (nsGkAtoms::width == aAttribute ||
  1127        nsGkAtoms::height == aAttribute ||
  1128        nsGkAtoms::screenX == aAttribute ||
  1129        nsGkAtoms::screenY == aAttribute ||
  1130        nsGkAtoms::sizemode == aAttribute)) {
  1131     return rv;
  1134   if (aAttribute == nsGkAtoms::width       ||
  1135       aAttribute == nsGkAtoms::height      ||
  1136       aAttribute == nsGkAtoms::align       ||
  1137       aAttribute == nsGkAtoms::valign      ||
  1138       aAttribute == nsGkAtoms::left        ||
  1139       aAttribute == nsGkAtoms::top         ||
  1140       aAttribute == nsGkAtoms::right        ||
  1141       aAttribute == nsGkAtoms::bottom       ||
  1142       aAttribute == nsGkAtoms::start        ||
  1143       aAttribute == nsGkAtoms::end          ||
  1144       aAttribute == nsGkAtoms::minwidth     ||
  1145       aAttribute == nsGkAtoms::maxwidth     ||
  1146       aAttribute == nsGkAtoms::minheight    ||
  1147       aAttribute == nsGkAtoms::maxheight    ||
  1148       aAttribute == nsGkAtoms::flex         ||
  1149       aAttribute == nsGkAtoms::orient       ||
  1150       aAttribute == nsGkAtoms::pack         ||
  1151       aAttribute == nsGkAtoms::dir          ||
  1152       aAttribute == nsGkAtoms::mousethrough ||
  1153       aAttribute == nsGkAtoms::equalsize) {
  1155     if (aAttribute == nsGkAtoms::align  ||
  1156         aAttribute == nsGkAtoms::valign ||
  1157         aAttribute == nsGkAtoms::orient  ||
  1158         aAttribute == nsGkAtoms::pack    ||
  1159 #ifdef DEBUG_LAYOUT
  1160         aAttribute == nsGkAtoms::debug   ||
  1161 #endif
  1162         aAttribute == nsGkAtoms::dir) {
  1164       mValign = nsBoxFrame::vAlign_Top;
  1165       mHalign = nsBoxFrame::hAlign_Left;
  1167       bool orient = true;
  1168       GetInitialOrientation(orient); 
  1169       if (orient)
  1170         mState |= NS_STATE_IS_HORIZONTAL;
  1171       else
  1172         mState &= ~NS_STATE_IS_HORIZONTAL;
  1174       bool normal = true;
  1175       GetInitialDirection(normal);
  1176       if (normal)
  1177         mState |= NS_STATE_IS_DIRECTION_NORMAL;
  1178       else
  1179         mState &= ~NS_STATE_IS_DIRECTION_NORMAL;
  1181       GetInitialVAlignment(mValign);
  1182       GetInitialHAlignment(mHalign);
  1184       bool equalSize = false;
  1185       GetInitialEqualSize(equalSize); 
  1186       if (equalSize)
  1187         mState |= NS_STATE_EQUAL_SIZE;
  1188       else
  1189         mState &= ~NS_STATE_EQUAL_SIZE;
  1191 #ifdef DEBUG_LAYOUT
  1192       bool debug = mState & NS_STATE_SET_TO_DEBUG;
  1193       bool debugSet = GetInitialDebug(debug);
  1194       if (debugSet) {
  1195         mState |= NS_STATE_DEBUG_WAS_SET;
  1197         if (debug)
  1198           mState |= NS_STATE_SET_TO_DEBUG;
  1199         else
  1200           mState &= ~NS_STATE_SET_TO_DEBUG;
  1201       } else {
  1202         mState &= ~NS_STATE_DEBUG_WAS_SET;
  1204 #endif
  1206       bool autostretch = !!(mState & NS_STATE_AUTO_STRETCH);
  1207       GetInitialAutoStretch(autostretch);
  1208       if (autostretch)
  1209         mState |= NS_STATE_AUTO_STRETCH;
  1210       else
  1211         mState &= ~NS_STATE_AUTO_STRETCH;
  1213     else if (aAttribute == nsGkAtoms::left ||
  1214              aAttribute == nsGkAtoms::top ||
  1215              aAttribute == nsGkAtoms::right ||
  1216              aAttribute == nsGkAtoms::bottom ||
  1217              aAttribute == nsGkAtoms::start ||
  1218              aAttribute == nsGkAtoms::end) {
  1219       mState &= ~NS_STATE_STACK_NOT_POSITIONED;
  1221     else if (aAttribute == nsGkAtoms::mousethrough) {
  1222       UpdateMouseThrough();
  1225     PresContext()->PresShell()->
  1226       FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
  1228   else if (aAttribute == nsGkAtoms::ordinal) {
  1229     nsBoxLayoutState state(PresContext());
  1230     nsIFrame* parent = GetParentBox();
  1231     // If our parent is not a box, there's not much we can do... but in that
  1232     // case our ordinal doesn't matter anyway, so that's ok.
  1233     // Also don't bother with popup frames since they are kept on the 
  1234     // kPopupList and RelayoutChildAtOrdinal() only handles
  1235     // principal children.
  1236     if (parent && !(GetStateBits() & NS_FRAME_OUT_OF_FLOW) &&
  1237         StyleDisplay()->mDisplay != NS_STYLE_DISPLAY_POPUP) {
  1238       parent->RelayoutChildAtOrdinal(state, this);
  1239       // XXXldb Should this instead be a tree change on the child or parent?
  1240       PresContext()->PresShell()->
  1241         FrameNeedsReflow(parent, nsIPresShell::eStyleChange,
  1242                          NS_FRAME_IS_DIRTY);
  1245   // If the accesskey changed, register for the new value
  1246   // The old value has been unregistered in nsXULElement::SetAttr
  1247   else if (aAttribute == nsGkAtoms::accesskey) {
  1248     RegUnregAccessKey(true);
  1250   else if (aAttribute == nsGkAtoms::rows &&
  1251            tag == nsGkAtoms::tree) {
  1252     // Reflow ourselves and all our children if "rows" changes, since
  1253     // nsTreeBodyFrame's layout reads this from its parent (this frame).
  1254     PresContext()->PresShell()->
  1255       FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
  1258   return rv;
  1261 #ifdef DEBUG_LAYOUT
  1262 void
  1263 nsBoxFrame::GetDebugPref(nsPresContext* aPresContext)
  1265     gDebug = Preferences::GetBool("xul.debug.box");
  1268 class nsDisplayXULDebug : public nsDisplayItem {
  1269 public:
  1270   nsDisplayXULDebug(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) :
  1271     nsDisplayItem(aBuilder, aFrame) {
  1272     MOZ_COUNT_CTOR(nsDisplayXULDebug);
  1274 #ifdef NS_BUILD_REFCNT_LOGGING
  1275   virtual ~nsDisplayXULDebug() {
  1276     MOZ_COUNT_DTOR(nsDisplayXULDebug);
  1278 #endif
  1280   virtual void HitTest(nsDisplayListBuilder* aBuilder, nsRect aRect,
  1281                        HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) {
  1282     nsPoint rectCenter(aRect.x + aRect.width / 2, aRect.y + aRect.height / 2);
  1283     static_cast<nsBoxFrame*>(mFrame)->
  1284       DisplayDebugInfoFor(this, rectCenter - ToReferenceFrame());
  1285     aOutFrames->AppendElement(this);
  1287   virtual void Paint(nsDisplayListBuilder* aBuilder
  1288                      nsRenderingContext* aCtx);
  1289   NS_DISPLAY_DECL_NAME("XULDebug", TYPE_XUL_DEBUG)
  1290 };
  1292 void
  1293 nsDisplayXULDebug::Paint(nsDisplayListBuilder* aBuilder,
  1294                          nsRenderingContext* aCtx)
  1296   static_cast<nsBoxFrame*>(mFrame)->
  1297     PaintXULDebugOverlay(*aCtx, ToReferenceFrame());
  1300 static void
  1301 PaintXULDebugBackground(nsIFrame* aFrame, nsRenderingContext* aCtx,
  1302                         const nsRect& aDirtyRect, nsPoint aPt)
  1304   static_cast<nsBoxFrame*>(aFrame)->PaintXULDebugBackground(*aCtx, aPt);
  1306 #endif
  1308 void
  1309 nsBoxFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
  1310                              const nsRect&           aDirtyRect,
  1311                              const nsDisplayListSet& aLists)
  1313   // forcelayer is only supported on XUL elements with box layout
  1314   bool forceLayer =
  1315     GetContent()->HasAttr(kNameSpaceID_None, nsGkAtoms::layer) &&
  1316     GetContent()->IsXUL();
  1318   // Check for frames that are marked as a part of the region used
  1319   // in calculating glass margins on Windows.
  1320   if (GetContent()->IsXUL()) {
  1321       const nsStyleDisplay* styles = StyleDisplay();
  1322       if (styles && styles->mAppearance == NS_THEME_WIN_EXCLUDE_GLASS) {
  1323         nsRect rect = nsRect(aBuilder->ToReferenceFrame(this), GetSize());
  1324         aBuilder->AddExcludedGlassRegion(rect);
  1328   nsDisplayListCollection tempLists;
  1329   const nsDisplayListSet& destination = forceLayer ? tempLists : aLists;
  1331   DisplayBorderBackgroundOutline(aBuilder, destination);
  1333 #ifdef DEBUG_LAYOUT
  1334   if (mState & NS_STATE_CURRENTLY_IN_DEBUG) {
  1335     destination.BorderBackground()->AppendNewToTop(new (aBuilder)
  1336       nsDisplayGeneric(aBuilder, this, PaintXULDebugBackground,
  1337                        "XULDebugBackground"));
  1338     destination.Outlines()->AppendNewToTop(new (aBuilder)
  1339       nsDisplayXULDebug(aBuilder, this));
  1341 #endif
  1343   BuildDisplayListForChildren(aBuilder, aDirtyRect, destination);
  1345   // see if we have to draw a selection frame around this container
  1346   DisplaySelectionOverlay(aBuilder, destination.Content());
  1348   if (forceLayer) {
  1349     // This is a bit of a hack. Collect up all descendant display items
  1350     // and merge them into a single Content() list. This can cause us
  1351     // to violate CSS stacking order, but forceLayer is a magic
  1352     // XUL-only extension anyway.
  1353     nsDisplayList masterList;
  1354     masterList.AppendToTop(tempLists.BorderBackground());
  1355     masterList.AppendToTop(tempLists.BlockBorderBackgrounds());
  1356     masterList.AppendToTop(tempLists.Floats());
  1357     masterList.AppendToTop(tempLists.Content());
  1358     masterList.AppendToTop(tempLists.PositionedDescendants());
  1359     masterList.AppendToTop(tempLists.Outlines());
  1360     // Wrap the list to make it its own layer
  1361     aLists.Content()->AppendNewToTop(new (aBuilder)
  1362       nsDisplayOwnLayer(aBuilder, this, &masterList));
  1366 void
  1367 nsBoxFrame::BuildDisplayListForChildren(nsDisplayListBuilder*   aBuilder,
  1368                                         const nsRect&           aDirtyRect,
  1369                                         const nsDisplayListSet& aLists)
  1371   nsIFrame* kid = mFrames.FirstChild();
  1372   // Put each child's background onto the BlockBorderBackgrounds list
  1373   // to emulate the existing two-layer XUL painting scheme.
  1374   nsDisplayListSet set(aLists, aLists.BlockBorderBackgrounds());
  1375   // The children should be in the right order
  1376   while (kid) {
  1377     BuildDisplayListForChild(aBuilder, kid, aDirtyRect, set);
  1378     kid = kid->GetNextSibling();
  1382 // REVIEW: PaintChildren did a few things none of which are a big deal
  1383 // anymore:
  1384 // * Paint some debugging rects for this frame.
  1385 // This is done by nsDisplayXULDebugBackground, which goes in the
  1386 // BorderBackground() layer so it isn't clipped by OVERFLOW_CLIP.
  1387 // * Apply OVERFLOW_CLIP to the children.
  1388 // This is now in nsFrame::BuildDisplayListForStackingContext/Child.
  1389 // * Actually paint the children.
  1390 // Moved to BuildDisplayList.
  1391 // * Paint per-kid debug information.
  1392 // This is done by nsDisplayXULDebug, which is in the Outlines()
  1393 // layer so it goes on top. This means it is not clipped by OVERFLOW_CLIP,
  1394 // whereas it did used to respect OVERFLOW_CLIP, but too bad.
  1395 #ifdef DEBUG_LAYOUT
  1396 void
  1397 nsBoxFrame::PaintXULDebugBackground(nsRenderingContext& aRenderingContext,
  1398                                     nsPoint aPt)
  1400   nsMargin border;
  1401   GetBorder(border);
  1403   nsMargin debugBorder;
  1404   nsMargin debugMargin;
  1405   nsMargin debugPadding;
  1407   bool isHorizontal = IsHorizontal();
  1409   GetDebugBorder(debugBorder);
  1410   PixelMarginToTwips(GetPresContext(), debugBorder);
  1412   GetDebugMargin(debugMargin);
  1413   PixelMarginToTwips(GetPresContext(), debugMargin);
  1415   GetDebugPadding(debugPadding);
  1416   PixelMarginToTwips(GetPresContext(), debugPadding);
  1418   nsRect inner(mRect);
  1419   inner.MoveTo(aPt);
  1420   inner.Deflate(debugMargin);
  1421   inner.Deflate(border);
  1422   //nsRect borderRect(inner);
  1424   nscolor color;
  1425   if (isHorizontal) {
  1426     color = NS_RGB(0,0,255);
  1427   } else {
  1428     color = NS_RGB(255,0,0);
  1431   aRenderingContext.SetColor(color);
  1433   //left
  1434   nsRect r(inner);
  1435   r.width = debugBorder.left;
  1436   aRenderingContext.FillRect(r);
  1438   // top
  1439   r = inner;
  1440   r.height = debugBorder.top;
  1441   aRenderingContext.FillRect(r);
  1443   //right
  1444   r = inner;
  1445   r.x = r.x + r.width - debugBorder.right;
  1446   r.width = debugBorder.right;
  1447   aRenderingContext.FillRect(r);
  1449   //bottom
  1450   r = inner;
  1451   r.y = r.y + r.height - debugBorder.bottom;
  1452   r.height = debugBorder.bottom;
  1453   aRenderingContext.FillRect(r);
  1456   // if we have dirty children or we are dirty 
  1457   // place a green border around us.
  1458   if (NS_SUBTREE_DIRTY(this)) {
  1459      nsRect dirtyr(inner);
  1460      aRenderingContext.SetColor(NS_RGB(0,255,0));
  1461      aRenderingContext.DrawRect(dirtyr);
  1462      aRenderingContext.SetColor(color);
  1466 void
  1467 nsBoxFrame::PaintXULDebugOverlay(nsRenderingContext& aRenderingContext,
  1468                                  nsPoint aPt)
  1469   nsMargin border;
  1470   GetBorder(border);
  1472   nsMargin debugMargin;
  1473   GetDebugMargin(debugMargin);
  1474   PixelMarginToTwips(GetPresContext(), debugMargin);
  1476   nsRect inner(mRect);
  1477   inner.MoveTo(aPt);
  1478   inner.Deflate(debugMargin);
  1479   inner.Deflate(border);
  1481   nscoord onePixel = GetPresContext()->IntScaledPixelsToTwips(1);
  1483   kid = GetChildBox();
  1484   while (nullptr != kid) {
  1485     bool isHorizontal = IsHorizontal();
  1487     nscoord x, y, borderSize, spacerSize;
  1489     nsRect cr(kid->mRect);
  1490     nsMargin margin;
  1491     kid->GetMargin(margin);
  1492     cr.Inflate(margin);
  1494     if (isHorizontal) 
  1496         cr.y = inner.y;
  1497         x = cr.x;
  1498         y = cr.y + onePixel;
  1499         spacerSize = debugBorder.top - onePixel*4;
  1500     } else {
  1501         cr.x = inner.x;
  1502         x = cr.y;
  1503         y = cr.x + onePixel;
  1504         spacerSize = debugBorder.left - onePixel*4;
  1507     nsBoxLayoutState state(GetPresContext());
  1508     nscoord flex = kid->GetFlex(state);
  1510     if (!kid->IsCollapsed()) {
  1511       aRenderingContext.SetColor(NS_RGB(255,255,255));
  1513       if (isHorizontal) 
  1514           borderSize = cr.width;
  1515       else 
  1516           borderSize = cr.height;
  1518       DrawSpacer(GetPresContext(), aRenderingContext, isHorizontal, flex, x, y, borderSize, spacerSize);
  1521     kid = kid->GetNextBox();
  1524 #endif
  1526 #ifdef DEBUG_LAYOUT
  1527 void
  1528 nsBoxFrame::GetBoxName(nsAutoString& aName)
  1530    GetFrameName(aName);
  1532 #endif
  1534 #ifdef DEBUG_FRAME_DUMP
  1535 nsresult
  1536 nsBoxFrame::GetFrameName(nsAString& aResult) const
  1538   return MakeFrameName(NS_LITERAL_STRING("Box"), aResult);
  1540 #endif
  1542 nsIAtom*
  1543 nsBoxFrame::GetType() const
  1545   return nsGkAtoms::boxFrame;
  1548 #ifdef DEBUG_LAYOUT
  1549 nsresult
  1550 nsBoxFrame::GetDebug(bool& aDebug)
  1552   aDebug = (mState & NS_STATE_CURRENTLY_IN_DEBUG);
  1553   return NS_OK;
  1555 #endif
  1557 // REVIEW: nsBoxFrame::GetFrameForPoint is a problem because of 'mousethrough'
  1558 // attribute support. Here's how it works:
  1559 // * For each child frame F, we determine the target frame T(F) by recursively
  1560 // invoking GetFrameForPoint on the child
  1561 // * Let F' be the last child frame such that T(F') doesn't have mousethrough.
  1562 // If F' exists, return T(F')
  1563 // * Otherwise let F'' be the first child frame such that T(F'') is non-null.
  1564 // If F'' exists, return T(F'')
  1565 // * Otherwise return this frame, if this frame contains the point
  1566 // * Otherwise return null
  1567 // It's not clear how this should work for more complex z-ordering situations.
  1568 // The basic principle seems to be that if a frame F has a descendant
  1569 // 'mousethrough' frame that includes the target position, then F
  1570 // will not receive events (unless it overrides GetFrameForPoint).
  1571 // A 'mousethrough' frame will only receive an event if, after applying that rule,
  1572 // all eligible frames are 'mousethrough'; the bottom-most inner-most 'mousethrough'
  1573 // frame is then chosen (the first eligible frame reached in a
  1574 // traversal of the frame tree --- pre/post is irrelevant since ancestors
  1575 // of the mousethrough frames can't be eligible).
  1576 // IMHO this is very bogus and adds a great deal of complexity for something
  1577 // that is very rarely used. So I'm redefining 'mousethrough' to the following:
  1578 // a frame with mousethrough is transparent to mouse events. This is compatible
  1579 // with the way 'mousethrough' is used in Seamonkey's navigator.xul and
  1580 // Firefox's browser.xul. The only other place it's used is in the 'expander'
  1581 // XBL binding, which in our tree is only used by Thunderbird SMIME Advanced
  1582 // Preferences, and I can't figure out what that does, so I'll have to test it.
  1583 // If it's broken I'll probably just change the binding to use it more sensibly.
  1584 // This new behaviour is implemented in nsDisplayList::HitTest. 
  1585 // REVIEW: This debug-box stuff is annoying. I'm just going to put debug boxes
  1586 // in the outline layer and avoid GetDebugBoxAt.
  1588 // REVIEW: GetCursor had debug-only event dumping code. I have replaced it
  1589 // with instrumentation in nsDisplayXULDebug.
  1591 #ifdef DEBUG_LAYOUT
  1592 void
  1593 nsBoxFrame::DrawLine(nsRenderingContext& aRenderingContext, bool aHorizontal, nscoord x1, nscoord y1, nscoord x2, nscoord y2)
  1595     if (aHorizontal)
  1596        aRenderingContext.DrawLine(x1,y1,x2,y2);
  1597     else
  1598        aRenderingContext.DrawLine(y1,x1,y2,x2);
  1601 void
  1602 nsBoxFrame::FillRect(nsRenderingContext& aRenderingContext, bool aHorizontal, nscoord x, nscoord y, nscoord width, nscoord height)
  1604     if (aHorizontal)
  1605        aRenderingContext.FillRect(x,y,width,height);
  1606     else
  1607        aRenderingContext.FillRect(y,x,height,width);
  1610 void 
  1611 nsBoxFrame::DrawSpacer(nsPresContext* aPresContext, nsRenderingContext& aRenderingContext, bool aHorizontal, int32_t flex, nscoord x, nscoord y, nscoord size, nscoord spacerSize)
  1613          nscoord onePixel = aPresContext->IntScaledPixelsToTwips(1);
  1615      // if we do draw the coils
  1616         int distance = 0;
  1617         int center = 0;
  1618         int offset = 0;
  1619         int coilSize = COIL_SIZE*onePixel;
  1620         int halfSpacer = spacerSize/2;
  1622         distance = size;
  1623         center = y + halfSpacer;
  1624         offset = x;
  1626         int coils = distance/coilSize;
  1628         int halfCoilSize = coilSize/2;
  1630         if (flex == 0) {
  1631             DrawLine(aRenderingContext, aHorizontal, x,y + spacerSize/2, x + size, y + spacerSize/2);
  1632         } else {
  1633             for (int i=0; i < coils; i++)
  1635                    DrawLine(aRenderingContext, aHorizontal, offset, center+halfSpacer, offset+halfCoilSize, center-halfSpacer);
  1636                    DrawLine(aRenderingContext, aHorizontal, offset+halfCoilSize, center-halfSpacer, offset+coilSize, center+halfSpacer);
  1638                    offset += coilSize;
  1642         FillRect(aRenderingContext, aHorizontal, x + size - spacerSize/2, y, spacerSize/2, spacerSize);
  1643         FillRect(aRenderingContext, aHorizontal, x, y, spacerSize/2, spacerSize);
  1645         //DrawKnob(aPresContext, aRenderingContext, x + size - spacerSize, y, spacerSize);
  1648 void
  1649 nsBoxFrame::GetDebugBorder(nsMargin& aInset)
  1651     aInset.SizeTo(2,2,2,2);
  1653     if (IsHorizontal()) 
  1654        aInset.top = 10;
  1655     else 
  1656        aInset.left = 10;
  1659 void
  1660 nsBoxFrame::GetDebugMargin(nsMargin& aInset)
  1662     aInset.SizeTo(2,2,2,2);
  1665 void
  1666 nsBoxFrame::GetDebugPadding(nsMargin& aPadding)
  1668     aPadding.SizeTo(2,2,2,2);
  1671 void 
  1672 nsBoxFrame::PixelMarginToTwips(nsPresContext* aPresContext, nsMargin& aMarginPixels)
  1674   nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
  1675   aMarginPixels.left   *= onePixel;
  1676   aMarginPixels.right  *= onePixel;
  1677   aMarginPixels.top    *= onePixel;
  1678   aMarginPixels.bottom *= onePixel;
  1681 void
  1682 nsBoxFrame::GetValue(nsPresContext* aPresContext, const nsSize& a, const nsSize& b, char* ch) 
  1684     float p2t = aPresContext->ScaledPixelsToTwips();
  1686     char width[100];
  1687     char height[100];
  1689     if (a.width == NS_INTRINSICSIZE)
  1690         sprintf(width,"%s","INF");
  1691     else
  1692         sprintf(width,"%d", nscoord(a.width/*/p2t*/));
  1694     if (a.height == NS_INTRINSICSIZE)
  1695         sprintf(height,"%s","INF");
  1696     else 
  1697         sprintf(height,"%d", nscoord(a.height/*/p2t*/));
  1700     sprintf(ch, "(%s%s, %s%s)", width, (b.width != NS_INTRINSICSIZE ? "[SET]" : ""),
  1701                     height, (b.height != NS_INTRINSICSIZE ? "[SET]" : ""));
  1705 void
  1706 nsBoxFrame::GetValue(nsPresContext* aPresContext, int32_t a, int32_t b, char* ch) 
  1708     if (a == NS_INTRINSICSIZE)
  1709       sprintf(ch, "%d[SET]", b);             
  1710     else
  1711       sprintf(ch, "%d", a);             
  1714 nsresult
  1715 nsBoxFrame::DisplayDebugInfoFor(nsIFrame*  aBox,
  1716                                 nsPoint& aPoint)
  1718     nsBoxLayoutState state(GetPresContext());
  1720     nscoord x = aPoint.x;
  1721     nscoord y = aPoint.y;
  1723     // get the area inside our border but not our debug margins.
  1724     nsRect insideBorder(aBox->mRect);
  1725     insideBorder.MoveTo(0,0):
  1726     nsMargin border(0,0,0,0);
  1727     aBox->GetBorderAndPadding(border);
  1728     insideBorder.Deflate(border);
  1730     bool isHorizontal = IsHorizontal();
  1732     if (!insideBorder.Contains(nsPoint(x,y)))
  1733         return NS_ERROR_FAILURE;
  1735     //printf("%%%%%% inside box %%%%%%%\n");
  1737     int count = 0;
  1738     nsIFrame* child = aBox->GetChildBox();
  1740     nsMargin m;
  1741     nsMargin m2;
  1742     GetDebugBorder(m);
  1743     PixelMarginToTwips(aPresContext, m);
  1745     GetDebugMargin(m2);
  1746     PixelMarginToTwips(aPresContext, m2);
  1748     m += m2;
  1750     if ((isHorizontal && y < insideBorder.y + m.top) ||
  1751         (!isHorizontal && x < insideBorder.x + m.left)) {
  1752         //printf("**** inside debug border *******\n");
  1753         while (child) 
  1755             const nsRect& r = child->mRect;
  1757             // if we are not in the child. But in the spacer above the child.
  1758             if ((isHorizontal && x >= r.x && x < r.x + r.width) ||
  1759                 (!isHorizontal && y >= r.y && y < r.y + r.height)) {
  1760                 aCursor = NS_STYLE_CURSOR_POINTER;
  1761                    // found it but we already showed it.
  1762                     if (mDebugChild == child)
  1763                         return NS_OK;
  1765                     if (aBox->GetContent()) {
  1766                       printf("---------------\n");
  1767                       DumpBox(stdout);
  1768                       printf("\n");
  1771                     if (child->GetContent()) {
  1772                         printf("child #%d: ", count);
  1773                         child->DumpBox(stdout);
  1774                         printf("\n");
  1777                     mDebugChild = child;
  1779                     nsSize prefSizeCSS(NS_INTRINSICSIZE, NS_INTRINSICSIZE);
  1780                     nsSize minSizeCSS (NS_INTRINSICSIZE, NS_INTRINSICSIZE);
  1781                     nsSize maxSizeCSS (NS_INTRINSICSIZE, NS_INTRINSICSIZE);
  1782                     nscoord flexCSS = NS_INTRINSICSIZE;
  1784                     bool widthSet, heightSet;
  1785                     nsIFrame::AddCSSPrefSize(child, prefSizeCSS, widthSet, heightSet);
  1786                     nsIFrame::AddCSSMinSize (state, child, minSizeCSS, widthSet, heightSet);
  1787                     nsIFrame::AddCSSMaxSize (child, maxSizeCSS, widthSet, heightSet);
  1788                     nsIFrame::AddCSSFlex    (state, child, flexCSS);
  1790                     nsSize prefSize = child->GetPrefSize(state);
  1791                     nsSize minSize = child->GetMinSize(state);
  1792                     nsSize maxSize = child->GetMaxSize(state);
  1793                     nscoord flexSize = child->GetFlex(state);
  1794                     nscoord ascentSize = child->GetBoxAscent(state);
  1796                     char min[100];
  1797                     char pref[100];
  1798                     char max[100];
  1799                     char calc[100];
  1800                     char flex[100];
  1801                     char ascent[100];
  1803                     nsSize actualSize;
  1804                     GetFrameSizeWithMargin(child, actualSize);
  1805                     nsSize actualSizeCSS (NS_INTRINSICSIZE, NS_INTRINSICSIZE);
  1807                     GetValue(aPresContext, minSize,  minSizeCSS, min);
  1808                     GetValue(aPresContext, prefSize, prefSizeCSS, pref);
  1809                     GetValue(aPresContext, maxSize,  maxSizeCSS, max);
  1810                     GetValue(aPresContext, actualSize, actualSizeCSS, calc);
  1811                     GetValue(aPresContext, flexSize,  flexCSS, flex);
  1812                     GetValue(aPresContext, ascentSize,  NS_INTRINSICSIZE, ascent);
  1815                     printf("min%s, pref%s, max%s, actual%s, flex=%s, ascent=%s\n\n", 
  1816                         min,
  1817                         pref,
  1818                         max,
  1819                         calc,
  1820                         flex,
  1821                         ascent
  1822                     );
  1824                     return NS_OK;   
  1827           child = child->GetNextBox();
  1828           count++;
  1830     } else {
  1833     mDebugChild = nullptr;
  1835     return NS_OK;
  1838 void
  1839 nsBoxFrame::SetDebugOnChildList(nsBoxLayoutState& aState, nsIFrame* aChild, bool aDebug)
  1841     nsIFrame* child = GetChildBox();
  1842      while (child)
  1844         child->SetDebug(aState, aDebug);
  1845         child = child->GetNextBox();
  1849 nsresult
  1850 nsBoxFrame::GetFrameSizeWithMargin(nsIFrame* aBox, nsSize& aSize)
  1852   nsRect rect(aBox->GetRect());
  1853   nsMargin margin(0,0,0,0);
  1854   aBox->GetMargin(margin);
  1855   rect.Inflate(margin);
  1856   aSize.width = rect.width;
  1857   aSize.height = rect.height;
  1858   return NS_OK;
  1860 #endif
  1862 // If you make changes to this function, check its counterparts
  1863 // in nsTextBoxFrame and nsXULLabelFrame
  1864 void
  1865 nsBoxFrame::RegUnregAccessKey(bool aDoReg)
  1867   MOZ_ASSERT(mContent);
  1869   // find out what type of element this is
  1870   nsIAtom *atom = mContent->Tag();
  1872   // only support accesskeys for the following elements
  1873   if (atom != nsGkAtoms::button &&
  1874       atom != nsGkAtoms::toolbarbutton &&
  1875       atom != nsGkAtoms::checkbox &&
  1876       atom != nsGkAtoms::textbox &&
  1877       atom != nsGkAtoms::tab &&
  1878       atom != nsGkAtoms::radio) {
  1879     return;
  1882   nsAutoString accessKey;
  1883   mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::accesskey, accessKey);
  1885   if (accessKey.IsEmpty())
  1886     return;
  1888   // With a valid PresContext we can get the ESM 
  1889   // and register the access key
  1890   EventStateManager* esm = PresContext()->EventStateManager();
  1892   uint32_t key = accessKey.First();
  1893   if (aDoReg)
  1894     esm->RegisterAccessKey(mContent, key);
  1895   else
  1896     esm->UnregisterAccessKey(mContent, key);
  1899 bool
  1900 nsBoxFrame::SupportsOrdinalsInChildren()
  1902   return true;
  1905 // Helper less-than-or-equal function, used in CheckBoxOrder() as a
  1906 // template-parameter for the sorting functions.
  1907 bool
  1908 IsBoxOrdinalLEQ(nsIFrame* aFrame1,
  1909                 nsIFrame* aFrame2)
  1911   // If we've got a placeholder frame, use its out-of-flow frame's ordinal val.
  1912   nsIFrame* aRealFrame1 = nsPlaceholderFrame::GetRealFrameFor(aFrame1);
  1913   nsIFrame* aRealFrame2 = nsPlaceholderFrame::GetRealFrameFor(aFrame2);
  1914   return aRealFrame1->GetOrdinal() <= aRealFrame2->GetOrdinal();
  1917 void 
  1918 nsBoxFrame::CheckBoxOrder()
  1920   if (SupportsOrdinalsInChildren() &&
  1921       !nsIFrame::IsFrameListSorted<IsBoxOrdinalLEQ>(mFrames)) {
  1922     nsIFrame::SortFrameList<IsBoxOrdinalLEQ>(mFrames);
  1926 nsresult
  1927 nsBoxFrame::LayoutChildAt(nsBoxLayoutState& aState, nsIFrame* aBox, const nsRect& aRect)
  1929   // get the current rect
  1930   nsRect oldRect(aBox->GetRect());
  1931   aBox->SetBounds(aState, aRect);
  1933   bool layout = NS_SUBTREE_DIRTY(aBox);
  1935   if (layout || (oldRect.width != aRect.width || oldRect.height != aRect.height))  {
  1936     return aBox->Layout(aState);
  1939   return NS_OK;
  1942 nsresult
  1943 nsBoxFrame::RelayoutChildAtOrdinal(nsBoxLayoutState& aState, nsIFrame* aChild)
  1945   if (!SupportsOrdinalsInChildren())
  1946     return NS_OK;
  1948   uint32_t ord = aChild->GetOrdinal();
  1950   nsIFrame* child = mFrames.FirstChild();
  1951   nsIFrame* newPrevSib = nullptr;
  1953   while (child) {
  1954     if (ord < child->GetOrdinal()) {
  1955       break;
  1958     if (child != aChild) {
  1959       newPrevSib = child;
  1962     child = child->GetNextBox();
  1965   if (aChild->GetPrevSibling() == newPrevSib) {
  1966     // This box is not moving.
  1967     return NS_OK;
  1970   // Take |aChild| out of its old position in the child list.
  1971   mFrames.RemoveFrame(aChild);
  1973   // Insert it after |newPrevSib| or at the start if it's null.
  1974   mFrames.InsertFrame(nullptr, newPrevSib, aChild);
  1976   return NS_OK;
  1979 /**
  1980  * This wrapper class lets us redirect mouse hits from descendant frames
  1981  * of a menu to the menu itself, if they didn't specify 'allowevents'.
  1983  * The wrapper simply turns a hit on a descendant element
  1984  * into a hit on the menu itself, unless there is an element between the target
  1985  * and the menu with the "allowevents" attribute.
  1987  * This is used by nsMenuFrame and nsTreeColFrame.
  1989  * Note that turning a hit on a descendant element into nullptr, so events
  1990  * could fall through to the menu background, might be an appealing simplification
  1991  * but it would mean slightly strange behaviour in some cases, because grabber
  1992  * wrappers can be created for many individual lists and items, so the exact
  1993  * fallthrough behaviour would be complex. E.g. an element with "allowevents"
  1994  * on top of the Content() list could receive the event even if it was covered
  1995  * by a PositionedDescenants() element without "allowevents". It is best to
  1996  * never convert a non-null hit into null.
  1997  */
  1998 // REVIEW: This is roughly of what nsMenuFrame::GetFrameForPoint used to do.
  1999 // I've made 'allowevents' affect child elements because that seems the only
  2000 // reasonable thing to do.
  2001 class nsDisplayXULEventRedirector : public nsDisplayWrapList {
  2002 public:
  2003   nsDisplayXULEventRedirector(nsDisplayListBuilder* aBuilder,
  2004                               nsIFrame* aFrame, nsDisplayItem* aItem,
  2005                               nsIFrame* aTargetFrame)
  2006     : nsDisplayWrapList(aBuilder, aFrame, aItem), mTargetFrame(aTargetFrame) {}
  2007   nsDisplayXULEventRedirector(nsDisplayListBuilder* aBuilder,
  2008                               nsIFrame* aFrame, nsDisplayList* aList,
  2009                               nsIFrame* aTargetFrame)
  2010     : nsDisplayWrapList(aBuilder, aFrame, aList), mTargetFrame(aTargetFrame) {}
  2011   virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
  2012                        HitTestState* aState,
  2013                        nsTArray<nsIFrame*> *aOutFrames) MOZ_OVERRIDE;
  2014   NS_DISPLAY_DECL_NAME("XULEventRedirector", TYPE_XUL_EVENT_REDIRECTOR)
  2015 private:
  2016   nsIFrame* mTargetFrame;
  2017 };
  2019 void nsDisplayXULEventRedirector::HitTest(nsDisplayListBuilder* aBuilder,
  2020     const nsRect& aRect, HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames)
  2022   nsTArray<nsIFrame*> outFrames;
  2023   mList.HitTest(aBuilder, aRect, aState, &outFrames);
  2025   bool topMostAdded = false;
  2026   uint32_t localLength = outFrames.Length();
  2028   for (uint32_t i = 0; i < localLength; i++) {
  2030     for (nsIContent* content = outFrames.ElementAt(i)->GetContent();
  2031          content && content != mTargetFrame->GetContent();
  2032          content = content->GetParent()) {
  2033       if (content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::allowevents,
  2034                                nsGkAtoms::_true, eCaseMatters)) {
  2035         // Events are allowed on 'frame', so let it go.
  2036         aOutFrames->AppendElement(outFrames.ElementAt(i));
  2037         topMostAdded = true;
  2041     // If there was no hit on the topmost frame or its ancestors,
  2042     // add the target frame itself as the first candidate (see bug 562554).
  2043     if (!topMostAdded) {
  2044       topMostAdded = true;
  2045       aOutFrames->AppendElement(mTargetFrame);
  2050 class nsXULEventRedirectorWrapper : public nsDisplayWrapper
  2052 public:
  2053   nsXULEventRedirectorWrapper(nsIFrame* aTargetFrame)
  2054       : mTargetFrame(aTargetFrame) {}
  2055   virtual nsDisplayItem* WrapList(nsDisplayListBuilder* aBuilder,
  2056                                   nsIFrame* aFrame,
  2057                                   nsDisplayList* aList) MOZ_OVERRIDE {
  2058     return new (aBuilder)
  2059         nsDisplayXULEventRedirector(aBuilder, aFrame, aList, mTargetFrame);
  2061   virtual nsDisplayItem* WrapItem(nsDisplayListBuilder* aBuilder,
  2062                                   nsDisplayItem* aItem) MOZ_OVERRIDE {
  2063     return new (aBuilder)
  2064         nsDisplayXULEventRedirector(aBuilder, aItem->Frame(), aItem,
  2065                                     mTargetFrame);
  2067 private:
  2068   nsIFrame* mTargetFrame;
  2069 };
  2071 void
  2072 nsBoxFrame::WrapListsInRedirector(nsDisplayListBuilder*   aBuilder,
  2073                                   const nsDisplayListSet& aIn,
  2074                                   const nsDisplayListSet& aOut)
  2076   nsXULEventRedirectorWrapper wrapper(this);
  2077   wrapper.WrapLists(aBuilder, this, aIn, aOut);
  2080 bool
  2081 nsBoxFrame::GetEventPoint(WidgetGUIEvent* aEvent, nsPoint &aPoint) {
  2082   nsIntPoint refPoint;
  2083   bool res = GetEventPoint(aEvent, refPoint);
  2084   aPoint = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, refPoint, this);
  2085   return res;
  2088 bool
  2089 nsBoxFrame::GetEventPoint(WidgetGUIEvent* aEvent, nsIntPoint &aPoint) {
  2090   NS_ENSURE_TRUE(aEvent, false);
  2092   WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
  2093   if (touchEvent) {
  2094     // return false if there is more than one touch on the page, or if
  2095     // we can't find a touch point
  2096     if (touchEvent->touches.Length() != 1) {
  2097       return false;
  2100     dom::Touch* touch = touchEvent->touches.SafeElementAt(0);
  2101     if (!touch) {
  2102       return false;
  2104     aPoint = touch->mRefPoint;
  2105   } else {
  2106     aPoint = LayoutDeviceIntPoint::ToUntyped(aEvent->refPoint);
  2108   return true;

mercurial