layout/xul/nsBox.cpp

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "nsBoxLayoutState.h"
     7 #include "nsBox.h"
     8 #include "nsBoxFrame.h"
     9 #include "nsPresContext.h"
    10 #include "nsCOMPtr.h"
    11 #include "nsIContent.h"
    12 #include "nsContainerFrame.h"
    13 #include "nsNameSpaceManager.h"
    14 #include "nsGkAtoms.h"
    15 #include "nsFrameManager.h"
    16 #include "nsIDOMNode.h"
    17 #include "nsIDOMMozNamedAttrMap.h"
    18 #include "nsIDOMAttr.h"
    19 #include "nsITheme.h"
    20 #include "nsIServiceManager.h"
    21 #include "nsBoxLayout.h"
    22 #include "FrameLayerBuilder.h"
    23 #include <algorithm>
    25 using namespace mozilla;
    27 #ifdef DEBUG_LAYOUT
    28 int32_t gIndent = 0;
    29 #endif
    31 #ifdef DEBUG_LAYOUT
    32 void
    33 nsBoxAddIndents()
    34 {
    35     for(int32_t i=0; i < gIndent; i++)
    36     {
    37         printf(" ");
    38     }
    39 }
    40 #endif
    42 #ifdef DEBUG_LAYOUT
    43 void
    44 nsBox::AppendAttribute(const nsAutoString& aAttribute, const nsAutoString& aValue, nsAutoString& aResult)
    45 {
    46    aResult.Append(aAttribute);
    47    aResult.AppendLiteral("='");
    48    aResult.Append(aValue);
    49    aResult.AppendLiteral("' ");
    50 }
    52 void
    53 nsBox::ListBox(nsAutoString& aResult)
    54 {
    55     nsAutoString name;
    56     GetBoxName(name);
    58     char addr[100];
    59     sprintf(addr, "[@%p] ", static_cast<void*>(this));
    61     aResult.AppendASCII(addr);
    62     aResult.Append(name);
    63     aResult.AppendLiteral(" ");
    65     nsIContent* content = GetContent();
    67     // add on all the set attributes
    68     if (content) {
    69       nsCOMPtr<nsIDOMNode> node(do_QueryInterface(content));
    70       nsCOMPtr<nsIDOMMozNamedAttrMap> namedMap;
    72       node->GetAttributes(getter_AddRefs(namedMap));
    73       uint32_t length;
    74       namedMap->GetLength(&length);
    76       nsCOMPtr<nsIDOMAttr> attribute;
    77       for (uint32_t i = 0; i < length; ++i)
    78       {
    79         namedMap->Item(i, getter_AddRefs(attribute));
    80         attribute->GetName(name);
    81         nsAutoString value;
    82         attribute->GetValue(value);
    83         AppendAttribute(name, value, aResult);
    84       }
    85     }
    86 }
    88 nsresult
    89 nsBox::DumpBox(FILE* aFile)
    90 {
    91   nsAutoString s;
    92   ListBox(s);
    93   fprintf(aFile, "%s", NS_LossyConvertUTF16toASCII(s).get());
    94   return NS_OK;
    95 }
    97 void
    98 nsBox::PropagateDebug(nsBoxLayoutState& aState)
    99 {
   100   // propagate debug information
   101   if (mState & NS_STATE_DEBUG_WAS_SET) {
   102     if (mState & NS_STATE_SET_TO_DEBUG)
   103       SetDebug(aState, true);
   104     else
   105       SetDebug(aState, false);
   106   } else if (mState & NS_STATE_IS_ROOT) {
   107     SetDebug(aState, gDebug);
   108   }
   109 }
   110 #endif
   112 #ifdef DEBUG_LAYOUT
   113 void
   114 nsBox::GetBoxName(nsAutoString& aName)
   115 {
   116   aName.AssignLiteral("Box");
   117 }
   118 #endif
   120 nsresult
   121 nsBox::BeginLayout(nsBoxLayoutState& aState)
   122 {
   123 #ifdef DEBUG_LAYOUT 
   125   nsBoxAddIndents();
   126   printf("Layout: ");
   127   DumpBox(stdout);
   128   printf("\n");
   129   gIndent++;
   130 #endif
   132   // mark ourselves as dirty so no child under us
   133   // can post an incremental layout.
   134   // XXXldb Is this still needed?
   135   mState |= NS_FRAME_HAS_DIRTY_CHILDREN;
   137   if (GetStateBits() & NS_FRAME_IS_DIRTY)
   138   {
   139     // If the parent is dirty, all the children are dirty (nsHTMLReflowState
   140     // does this too).
   141     nsIFrame* box;
   142     for (box = GetChildBox(); box; box = box->GetNextBox())
   143       box->AddStateBits(NS_FRAME_IS_DIRTY);
   144   }
   146   // Another copy-over from nsHTMLReflowState.
   147   // Since we are in reflow, we don't need to store these properties anymore.
   148   FrameProperties props = Properties();
   149   props.Delete(UsedBorderProperty());
   150   props.Delete(UsedPaddingProperty());
   151   props.Delete(UsedMarginProperty());
   153 #ifdef DEBUG_LAYOUT
   154   PropagateDebug(aState);
   155 #endif
   157   return NS_OK;
   158 }
   160 NS_IMETHODIMP
   161 nsBox::DoLayout(nsBoxLayoutState& aState)
   162 {
   163   return NS_OK;
   164 }
   166 nsresult
   167 nsBox::EndLayout(nsBoxLayoutState& aState)
   168 {
   170   #ifdef DEBUG_LAYOUT
   171       --gIndent;
   172   #endif
   174   return SyncLayout(aState);
   175 }
   177 bool nsBox::gGotTheme = false;
   178 nsITheme* nsBox::gTheme = nullptr;
   180 nsBox::nsBox()
   181 {
   182   MOZ_COUNT_CTOR(nsBox);
   183   //mX = 0;
   184   //mY = 0;
   185   if (!gGotTheme) {
   186     gGotTheme = true;
   187     CallGetService("@mozilla.org/chrome/chrome-native-theme;1", &gTheme);
   188   }
   189 }
   191 nsBox::~nsBox()
   192 {
   193   // NOTE:  This currently doesn't get called for |nsBoxToBlockAdaptor|
   194   // objects, so don't rely on putting anything here.
   195   MOZ_COUNT_DTOR(nsBox);
   196 }
   198 /* static */ void
   199 nsBox::Shutdown()
   200 {
   201   gGotTheme = false;
   202   NS_IF_RELEASE(gTheme);
   203 }
   205 nsresult
   206 nsBox::RelayoutChildAtOrdinal(nsBoxLayoutState& aState, nsIFrame* aChild)
   207 {
   208   return NS_OK;
   209 }
   211 nsresult
   212 nsIFrame::GetClientRect(nsRect& aClientRect)
   213 {
   214   aClientRect = mRect;
   215   aClientRect.MoveTo(0,0);
   217   nsMargin borderPadding;
   218   GetBorderAndPadding(borderPadding);
   220   aClientRect.Deflate(borderPadding);
   222   if (aClientRect.width < 0)
   223      aClientRect.width = 0;
   225   if (aClientRect.height < 0)
   226      aClientRect.height = 0;
   228  // NS_ASSERTION(aClientRect.width >=0 && aClientRect.height >= 0, "Content Size < 0");
   230   return NS_OK;
   231 }
   233 void
   234 nsBox::SetBounds(nsBoxLayoutState& aState, const nsRect& aRect, bool aRemoveOverflowAreas)
   235 {
   236     NS_BOX_ASSERTION(this, aRect.width >=0 && aRect.height >= 0, "SetBounds Size < 0");
   238     nsRect rect(mRect);
   240     uint32_t flags = 0;
   241     GetLayoutFlags(flags);
   243     uint32_t stateFlags = aState.LayoutFlags();
   245     flags |= stateFlags;
   247     if ((flags & NS_FRAME_NO_MOVE_FRAME) == NS_FRAME_NO_MOVE_FRAME)
   248       SetSize(aRect.Size());
   249     else
   250       SetRect(aRect);
   252     // Nuke the overflow area. The caller is responsible for restoring
   253     // it if necessary.
   254     if (aRemoveOverflowAreas) {
   255       // remove the previously stored overflow area
   256       ClearOverflowRects();
   257     }
   259     if (!(flags & NS_FRAME_NO_MOVE_VIEW))
   260     {
   261       nsContainerFrame::PositionFrameView(this);
   262       if ((rect.x != aRect.x) || (rect.y != aRect.y))
   263         nsContainerFrame::PositionChildViews(this);
   264     }
   267    /*  
   268     // only if the origin changed
   269     if ((rect.x != aRect.x) || (rect.y != aRect.y))  {
   270       if (frame->HasView()) {
   271         nsContainerFrame::PositionFrameView(presContext, frame,
   272                                             frame->GetView());
   273       } else {
   274         nsContainerFrame::PositionChildViews(presContext, frame);
   275       }
   276     }
   277     */
   278 }
   280 void
   281 nsBox::GetLayoutFlags(uint32_t& aFlags)
   282 {
   283   aFlags = 0;
   284 }
   287 nsresult
   288 nsIFrame::GetBorderAndPadding(nsMargin& aBorderAndPadding)
   289 {
   290   aBorderAndPadding.SizeTo(0, 0, 0, 0);
   291   nsresult rv = GetBorder(aBorderAndPadding);
   292   if (NS_FAILED(rv))
   293     return rv;
   295   nsMargin padding;
   296   rv = GetPadding(padding);
   297   if (NS_FAILED(rv))
   298     return rv;
   300   aBorderAndPadding += padding;
   302   return rv;
   303 }
   305 nsresult
   306 nsBox::GetBorder(nsMargin& aMargin)
   307 {
   308   aMargin.SizeTo(0,0,0,0);
   310   const nsStyleDisplay* disp = StyleDisplay();
   311   if (disp->mAppearance && gTheme) {
   312     // Go to the theme for the border.
   313     nsPresContext *context = PresContext();
   314     if (gTheme->ThemeSupportsWidget(context, this, disp->mAppearance)) {
   315       nsIntMargin margin(0, 0, 0, 0);
   316       gTheme->GetWidgetBorder(context->DeviceContext(), this,
   317                               disp->mAppearance, &margin);
   318       aMargin.top = context->DevPixelsToAppUnits(margin.top);
   319       aMargin.right = context->DevPixelsToAppUnits(margin.right);
   320       aMargin.bottom = context->DevPixelsToAppUnits(margin.bottom);
   321       aMargin.left = context->DevPixelsToAppUnits(margin.left);
   322       return NS_OK;
   323     }
   324   }
   326   aMargin = StyleBorder()->GetComputedBorder();
   328   return NS_OK;
   329 }
   331 nsresult
   332 nsBox::GetPadding(nsMargin& aMargin)
   333 {
   334   const nsStyleDisplay *disp = StyleDisplay();
   335   if (disp->mAppearance && gTheme) {
   336     // Go to the theme for the padding.
   337     nsPresContext *context = PresContext();
   338     if (gTheme->ThemeSupportsWidget(context, this, disp->mAppearance)) {
   339       nsIntMargin margin(0, 0, 0, 0);
   340       bool useThemePadding;
   342       useThemePadding = gTheme->GetWidgetPadding(context->DeviceContext(),
   343                                                  this, disp->mAppearance,
   344                                                  &margin);
   345       if (useThemePadding) {
   346         aMargin.top = context->DevPixelsToAppUnits(margin.top);
   347         aMargin.right = context->DevPixelsToAppUnits(margin.right);
   348         aMargin.bottom = context->DevPixelsToAppUnits(margin.bottom);
   349         aMargin.left = context->DevPixelsToAppUnits(margin.left);
   350         return NS_OK;
   351       }
   352     }
   353   }
   355   aMargin.SizeTo(0,0,0,0);
   356   StylePadding()->GetPadding(aMargin);
   358   return NS_OK;
   359 }
   361 nsresult
   362 nsBox::GetMargin(nsMargin& aMargin)
   363 {
   364   aMargin.SizeTo(0,0,0,0);
   365   StyleMargin()->GetMargin(aMargin);
   367   return NS_OK;
   368 }
   370 void
   371 nsBox::SizeNeedsRecalc(nsSize& aSize)
   372 {
   373   aSize.width  = -1;
   374   aSize.height = -1;
   375 }
   377 void
   378 nsBox::CoordNeedsRecalc(nscoord& aFlex)
   379 {
   380   aFlex = -1;
   381 }
   383 bool
   384 nsBox::DoesNeedRecalc(const nsSize& aSize)
   385 {
   386   return (aSize.width == -1 || aSize.height == -1);
   387 }
   389 bool
   390 nsBox::DoesNeedRecalc(nscoord aCoord)
   391 {
   392   return (aCoord == -1);
   393 }
   395 nsSize
   396 nsBox::GetPrefSize(nsBoxLayoutState& aState)
   397 {
   398   NS_ASSERTION(aState.GetRenderingContext(), "must have rendering context");
   400   nsSize pref(0,0);
   401   DISPLAY_PREF_SIZE(this, pref);
   403   if (IsCollapsed())
   404     return pref;
   406   AddBorderAndPadding(pref);
   407   bool widthSet, heightSet;
   408   nsIFrame::AddCSSPrefSize(this, pref, widthSet, heightSet);
   410   nsSize minSize = GetMinSize(aState);
   411   nsSize maxSize = GetMaxSize(aState);
   412   return BoundsCheck(minSize, pref, maxSize);
   413 }
   415 nsSize
   416 nsBox::GetMinSize(nsBoxLayoutState& aState)
   417 {
   418   NS_ASSERTION(aState.GetRenderingContext(), "must have rendering context");
   420   nsSize min(0,0);
   421   DISPLAY_MIN_SIZE(this, min);
   423   if (IsCollapsed())
   424     return min;
   426   AddBorderAndPadding(min);
   427   bool widthSet, heightSet;
   428   nsIFrame::AddCSSMinSize(aState, this, min, widthSet, heightSet);
   429   return min;
   430 }
   432 nsSize
   433 nsBox::GetMinSizeForScrollArea(nsBoxLayoutState& aBoxLayoutState)
   434 {
   435   return nsSize(0, 0);
   436 }
   438 nsSize
   439 nsBox::GetMaxSize(nsBoxLayoutState& aState)
   440 {
   441   NS_ASSERTION(aState.GetRenderingContext(), "must have rendering context");
   443   nsSize maxSize(NS_INTRINSICSIZE, NS_INTRINSICSIZE);
   444   DISPLAY_MAX_SIZE(this, maxSize);
   446   if (IsCollapsed())
   447     return maxSize;
   449   AddBorderAndPadding(maxSize);
   450   bool widthSet, heightSet;
   451   nsIFrame::AddCSSMaxSize(this, maxSize, widthSet, heightSet);
   452   return maxSize;
   453 }
   455 nscoord
   456 nsBox::GetFlex(nsBoxLayoutState& aState)
   457 {
   458   nscoord flex = 0;
   460   nsIFrame::AddCSSFlex(aState, this, flex);
   462   return flex;
   463 }
   465 uint32_t
   466 nsIFrame::GetOrdinal()
   467 {
   468   uint32_t ordinal = StyleXUL()->mBoxOrdinal;
   470   // When present, attribute value overrides CSS.
   471   nsIContent* content = GetContent();
   472   if (content && content->IsXUL()) {
   473     nsresult error;
   474     nsAutoString value;
   476     content->GetAttr(kNameSpaceID_None, nsGkAtoms::ordinal, value);
   477     if (!value.IsEmpty()) {
   478       ordinal = value.ToInteger(&error);
   479     }
   480   }
   482   return ordinal;
   483 }
   485 nscoord
   486 nsBox::GetBoxAscent(nsBoxLayoutState& aState)
   487 {
   488   if (IsCollapsed())
   489     return 0;
   491   return GetPrefSize(aState).height;
   492 }
   494 bool
   495 nsBox::IsCollapsed()
   496 {
   497   return StyleVisibility()->mVisible == NS_STYLE_VISIBILITY_COLLAPSE;
   498 }
   500 nsresult
   501 nsIFrame::Layout(nsBoxLayoutState& aState)
   502 {
   503   NS_ASSERTION(aState.GetRenderingContext(), "must have rendering context");
   505   nsBox *box = static_cast<nsBox*>(this);
   506   DISPLAY_LAYOUT(box);
   508   box->BeginLayout(aState);
   510   box->DoLayout(aState);
   512   box->EndLayout(aState);
   514   return NS_OK;
   515 }
   517 bool
   518 nsBox::DoesClipChildren()
   519 {
   520   const nsStyleDisplay* display = StyleDisplay();
   521   NS_ASSERTION((display->mOverflowY == NS_STYLE_OVERFLOW_CLIP) ==
   522                (display->mOverflowX == NS_STYLE_OVERFLOW_CLIP),
   523                "If one overflow is clip, the other should be too");
   524   return display->mOverflowX == NS_STYLE_OVERFLOW_CLIP;
   525 }
   527 nsresult
   528 nsBox::SyncLayout(nsBoxLayoutState& aState)
   529 {
   530   /*
   531   if (IsCollapsed()) {
   532     CollapseChild(aState, this, true);
   533     return NS_OK;
   534   }
   535   */
   538   if (GetStateBits() & NS_FRAME_IS_DIRTY)
   539      Redraw(aState);
   541   RemoveStateBits(NS_FRAME_HAS_DIRTY_CHILDREN | NS_FRAME_IS_DIRTY
   542                   | NS_FRAME_FIRST_REFLOW | NS_FRAME_IN_REFLOW);
   544   nsPresContext* presContext = aState.PresContext();
   546   uint32_t flags = 0;
   547   GetLayoutFlags(flags);
   549   uint32_t stateFlags = aState.LayoutFlags();
   551   flags |= stateFlags;
   553   nsRect visualOverflow;
   555   if (ComputesOwnOverflowArea()) {
   556     visualOverflow = GetVisualOverflowRect();
   557   }
   558   else {
   559     nsRect rect(nsPoint(0, 0), GetSize());
   560     nsOverflowAreas overflowAreas(rect, rect);
   561     if (!DoesClipChildren() && !IsCollapsed()) {
   562       // See if our child frames caused us to overflow after being laid
   563       // out. If so, store the overflow area.  This normally can't happen
   564       // in XUL, but it can happen with the CSS 'outline' property and
   565       // possibly with other exotic stuff (e.g. relatively positioned
   566       // frames in HTML inside XUL).
   567       nsLayoutUtils::UnionChildOverflow(this, overflowAreas);
   568     }
   570     FinishAndStoreOverflow(overflowAreas, GetSize());
   571     visualOverflow = overflowAreas.VisualOverflow();
   572   }
   574   nsView* view = GetView();
   575   if (view) {
   576     // Make sure the frame's view is properly sized and positioned and has
   577     // things like opacity correct
   578     nsContainerFrame::SyncFrameViewAfterReflow(presContext, this, view,
   579                                                visualOverflow, flags);
   580   } 
   582   return NS_OK;
   583 }
   585 nsresult
   586 nsIFrame::Redraw(nsBoxLayoutState& aState)
   587 {
   588   if (aState.PaintingDisabled())
   589     return NS_OK;
   591   // nsStackLayout, at least, expects us to repaint descendants even
   592   // if a damage rect is provided
   593   InvalidateFrameSubtree();
   595   return NS_OK;
   596 }
   598 bool
   599 nsIFrame::AddCSSPrefSize(nsIFrame* aBox, nsSize& aSize, bool &aWidthSet, bool &aHeightSet)
   600 {
   601     aWidthSet = false;
   602     aHeightSet = false;
   604     // add in the css min, max, pref
   605     const nsStylePosition* position = aBox->StylePosition();
   607     // see if the width or height was specifically set
   608     // XXX Handle eStyleUnit_Enumerated?
   609     // (Handling the eStyleUnit_Enumerated types requires
   610     // GetPrefSize/GetMinSize methods that don't consider
   611     // (min-/max-/)(width/height) properties.)
   612     const nsStyleCoord &width = position->mWidth;
   613     if (width.GetUnit() == eStyleUnit_Coord) {
   614         aSize.width = width.GetCoordValue();
   615         aWidthSet = true;
   616     } else if (width.IsCalcUnit()) {
   617         if (!width.CalcHasPercent()) {
   618             // pass 0 for percentage basis since we know there are no %s
   619             aSize.width = nsRuleNode::ComputeComputedCalc(width, 0);
   620             if (aSize.width < 0)
   621                 aSize.width = 0;
   622             aWidthSet = true;
   623         }
   624     }
   626     const nsStyleCoord &height = position->mHeight;
   627     if (height.GetUnit() == eStyleUnit_Coord) {
   628         aSize.height = height.GetCoordValue();
   629         aHeightSet = true;
   630     } else if (height.IsCalcUnit()) {
   631         if (!height.CalcHasPercent()) {
   632             // pass 0 for percentage basis since we know there are no %s
   633             aSize.height = nsRuleNode::ComputeComputedCalc(height, 0);
   634             if (aSize.height < 0)
   635                 aSize.height = 0;
   636             aHeightSet = true;
   637         }
   638     }
   640     nsIContent* content = aBox->GetContent();
   641     // ignore 'height' and 'width' attributes if the actual element is not XUL
   642     // For example, we might be magic XUL frames whose primary content is an HTML
   643     // <select>
   644     if (content && content->IsXUL()) {
   645         nsAutoString value;
   646         nsresult error;
   648         content->GetAttr(kNameSpaceID_None, nsGkAtoms::width, value);
   649         if (!value.IsEmpty()) {
   650             value.Trim("%");
   652             aSize.width =
   653               nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
   654             aWidthSet = true;
   655         }
   657         content->GetAttr(kNameSpaceID_None, nsGkAtoms::height, value);
   658         if (!value.IsEmpty()) {
   659             value.Trim("%");
   661             aSize.height =
   662               nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
   663             aHeightSet = true;
   664         }
   665     }
   667     return (aWidthSet && aHeightSet);
   668 }
   671 bool
   672 nsIFrame::AddCSSMinSize(nsBoxLayoutState& aState, nsIFrame* aBox, nsSize& aSize,
   673                       bool &aWidthSet, bool &aHeightSet)
   674 {
   675     aWidthSet = false;
   676     aHeightSet = false;
   678     bool canOverride = true;
   680     // See if a native theme wants to supply a minimum size.
   681     const nsStyleDisplay* display = aBox->StyleDisplay();
   682     if (display->mAppearance) {
   683       nsITheme *theme = aState.PresContext()->GetTheme();
   684       if (theme && theme->ThemeSupportsWidget(aState.PresContext(), aBox, display->mAppearance)) {
   685         nsIntSize size;
   686         nsRenderingContext* rendContext = aState.GetRenderingContext();
   687         if (rendContext) {
   688           theme->GetMinimumWidgetSize(rendContext, aBox,
   689                                       display->mAppearance, &size, &canOverride);
   690           if (size.width) {
   691             aSize.width = aState.PresContext()->DevPixelsToAppUnits(size.width);
   692             aWidthSet = true;
   693           }
   694           if (size.height) {
   695             aSize.height = aState.PresContext()->DevPixelsToAppUnits(size.height);
   696             aHeightSet = true;
   697           }
   698         }
   699       }
   700     }
   702     // add in the css min, max, pref
   703     const nsStylePosition* position = aBox->StylePosition();
   705     // same for min size. Unfortunately min size is always set to 0. So for now
   706     // we will assume 0 (as a coord) means not set.
   707     const nsStyleCoord &minWidth = position->mMinWidth;
   708     if ((minWidth.GetUnit() == eStyleUnit_Coord &&
   709          minWidth.GetCoordValue() != 0) ||
   710         (minWidth.IsCalcUnit() && !minWidth.CalcHasPercent())) {
   711         nscoord min = nsRuleNode::ComputeCoordPercentCalc(minWidth, 0);
   712         if (!aWidthSet || (min > aSize.width && canOverride)) {
   713            aSize.width = min;
   714            aWidthSet = true;
   715         }
   716     } else if (minWidth.GetUnit() == eStyleUnit_Percent) {
   717         NS_ASSERTION(minWidth.GetPercentValue() == 0.0f,
   718           "Non-zero percentage values not currently supported");
   719         aSize.width = 0;
   720         aWidthSet = true; // FIXME: should we really do this for
   721                              // nonzero values?
   722     }
   723     // XXX Handle eStyleUnit_Enumerated?
   724     // (Handling the eStyleUnit_Enumerated types requires
   725     // GetPrefSize/GetMinSize methods that don't consider
   726     // (min-/max-/)(width/height) properties.
   727     // calc() with percentage is treated like '0' (unset)
   729     const nsStyleCoord &minHeight = position->mMinHeight;
   730     if ((minHeight.GetUnit() == eStyleUnit_Coord &&
   731          minHeight.GetCoordValue() != 0) ||
   732         (minHeight.IsCalcUnit() && !minHeight.CalcHasPercent())) {
   733         nscoord min = nsRuleNode::ComputeCoordPercentCalc(minHeight, 0);
   734         if (!aHeightSet || (min > aSize.height && canOverride)) {
   735            aSize.height = min;
   736            aHeightSet = true;
   737         }
   738     } else if (minHeight.GetUnit() == eStyleUnit_Percent) {
   739         NS_ASSERTION(position->mMinHeight.GetPercentValue() == 0.0f,
   740           "Non-zero percentage values not currently supported");
   741         aSize.height = 0;
   742         aHeightSet = true; // FIXME: should we really do this for
   743                               // nonzero values?
   744     }
   745     // calc() with percentage is treated like '0' (unset)
   747     nsIContent* content = aBox->GetContent();
   748     if (content && content->IsXUL()) {
   749         nsAutoString value;
   750         nsresult error;
   752         content->GetAttr(kNameSpaceID_None, nsGkAtoms::minwidth, value);
   753         if (!value.IsEmpty())
   754         {
   755             value.Trim("%");
   757             nscoord val =
   758               nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
   759             if (val > aSize.width)
   760               aSize.width = val;
   761             aWidthSet = true;
   762         }
   764         content->GetAttr(kNameSpaceID_None, nsGkAtoms::minheight, value);
   765         if (!value.IsEmpty())
   766         {
   767             value.Trim("%");
   769             nscoord val =
   770               nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
   771             if (val > aSize.height)
   772               aSize.height = val;
   774             aHeightSet = true;
   775         }
   776     }
   778     return (aWidthSet && aHeightSet);
   779 }
   781 bool
   782 nsIFrame::AddCSSMaxSize(nsIFrame* aBox, nsSize& aSize, bool &aWidthSet, bool &aHeightSet)
   783 {
   784     aWidthSet = false;
   785     aHeightSet = false;
   787     // add in the css min, max, pref
   788     const nsStylePosition* position = aBox->StylePosition();
   790     // and max
   791     // see if the width or height was specifically set
   792     // XXX Handle eStyleUnit_Enumerated?
   793     // (Handling the eStyleUnit_Enumerated types requires
   794     // GetPrefSize/GetMinSize methods that don't consider
   795     // (min-/max-/)(width/height) properties.)
   796     const nsStyleCoord maxWidth = position->mMaxWidth;
   797     if (maxWidth.ConvertsToLength()) {
   798         aSize.width = nsRuleNode::ComputeCoordPercentCalc(maxWidth, 0);
   799         aWidthSet = true;
   800     }
   801     // percentages and calc() with percentages are treated like 'none'
   803     const nsStyleCoord &maxHeight = position->mMaxHeight;
   804     if (maxHeight.ConvertsToLength()) {
   805         aSize.height = nsRuleNode::ComputeCoordPercentCalc(maxHeight, 0);
   806         aHeightSet = true;
   807     }
   808     // percentages and calc() with percentages are treated like 'none'
   810     nsIContent* content = aBox->GetContent();
   811     if (content && content->IsXUL()) {
   812         nsAutoString value;
   813         nsresult error;
   815         content->GetAttr(kNameSpaceID_None, nsGkAtoms::maxwidth, value);
   816         if (!value.IsEmpty()) {
   817             value.Trim("%");
   819             nscoord val =
   820               nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
   821             aSize.width = val;
   822             aWidthSet = true;
   823         }
   825         content->GetAttr(kNameSpaceID_None, nsGkAtoms::maxheight, value);
   826         if (!value.IsEmpty()) {
   827             value.Trim("%");
   829             nscoord val =
   830               nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
   831             aSize.height = val;
   833             aHeightSet = true;
   834         }
   835     }
   837     return (aWidthSet || aHeightSet);
   838 }
   840 bool
   841 nsIFrame::AddCSSFlex(nsBoxLayoutState& aState, nsIFrame* aBox, nscoord& aFlex)
   842 {
   843     bool flexSet = false;
   845     // get the flexibility
   846     aFlex = aBox->StyleXUL()->mBoxFlex;
   848     // attribute value overrides CSS
   849     nsIContent* content = aBox->GetContent();
   850     if (content && content->IsXUL()) {
   851         nsresult error;
   852         nsAutoString value;
   854         content->GetAttr(kNameSpaceID_None, nsGkAtoms::flex, value);
   855         if (!value.IsEmpty()) {
   856             value.Trim("%");
   857             aFlex = value.ToInteger(&error);
   858             flexSet = true;
   859         }
   860     }
   862     if (aFlex < 0)
   863       aFlex = 0;
   864     if (aFlex >= nscoord_MAX)
   865       aFlex = nscoord_MAX - 1;
   867     return flexSet || aFlex > 0;
   868 }
   870 void
   871 nsBox::AddBorderAndPadding(nsSize& aSize)
   872 {
   873   AddBorderAndPadding(this, aSize);
   874 }
   876 void
   877 nsBox::AddBorderAndPadding(nsIFrame* aBox, nsSize& aSize)
   878 {
   879   nsMargin borderPadding(0,0,0,0);
   880   aBox->GetBorderAndPadding(borderPadding);
   881   AddMargin(aSize, borderPadding);
   882 }
   884 void
   885 nsBox::AddMargin(nsIFrame* aChild, nsSize& aSize)
   886 {
   887   nsMargin margin(0,0,0,0);
   888   aChild->GetMargin(margin);
   889   AddMargin(aSize, margin);
   890 }
   892 void
   893 nsBox::AddMargin(nsSize& aSize, const nsMargin& aMargin)
   894 {
   895   if (aSize.width != NS_INTRINSICSIZE)
   896     aSize.width += aMargin.left + aMargin.right;
   898   if (aSize.height != NS_INTRINSICSIZE)
   899      aSize.height += aMargin.top + aMargin.bottom;
   900 }
   902 nscoord
   903 nsBox::BoundsCheck(nscoord aMin, nscoord aPref, nscoord aMax)
   904 {
   905    if (aPref > aMax)
   906        aPref = aMax;
   908    if (aPref < aMin)
   909        aPref = aMin;
   911    return aPref;
   912 }
   914 nsSize
   915 nsBox::BoundsCheckMinMax(const nsSize& aMinSize, const nsSize& aMaxSize)
   916 {
   917   return nsSize(std::max(aMaxSize.width, aMinSize.width),
   918                 std::max(aMaxSize.height, aMinSize.height));
   919 }
   921 nsSize
   922 nsBox::BoundsCheck(const nsSize& aMinSize, const nsSize& aPrefSize, const nsSize& aMaxSize)
   923 {
   924   return nsSize(BoundsCheck(aMinSize.width, aPrefSize.width, aMaxSize.width),
   925                 BoundsCheck(aMinSize.height, aPrefSize.height, aMaxSize.height));
   926 }
   928 #ifdef DEBUG_LAYOUT
   929 nsresult
   930 nsBox::SetDebug(nsBoxLayoutState& aState, bool aDebug)
   931 {
   932     return NS_OK;
   933 }
   935 NS_IMETHODIMP
   936 nsBox::GetDebugBoxAt( const nsPoint& aPoint,
   937                       nsIFrame**     aBox)
   938 {
   939   nsRect thisRect(nsPoint(0,0), GetSize());
   940   if (!thisRect.Contains(aPoint))
   941     return NS_ERROR_FAILURE;
   943   nsIFrame* child = GetChildBox();
   944   nsIFrame* hit = nullptr;
   946   *aBox = nullptr;
   947   while (nullptr != child) {
   948     nsresult rv = child->GetDebugBoxAt(aPoint - child->GetOffsetTo(this), &hit);
   950     if (NS_SUCCEEDED(rv) && hit) {
   951       *aBox = hit;
   952     }
   953     child = child->GetNextBox();
   954   }
   956   // found a child
   957   if (*aBox) {
   958     return NS_OK;
   959   }
   961   return NS_ERROR_FAILURE;
   962 }
   965 nsresult
   966 nsBox::GetDebug(bool& aDebug)
   967 {
   968   aDebug = false;
   969   return NS_OK;
   970 }
   972 #endif

mercurial