123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981 |
- /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- #include "nsBoxLayoutState.h"
- #include "nsBox.h"
- #include "nsBoxFrame.h"
- #include "nsPresContext.h"
- #include "nsCOMPtr.h"
- #include "nsIContent.h"
- #include "nsContainerFrame.h"
- #include "nsNameSpaceManager.h"
- #include "nsGkAtoms.h"
- #include "nsIDOMNode.h"
- #include "nsIDOMMozNamedAttrMap.h"
- #include "nsIDOMAttr.h"
- #include "nsITheme.h"
- #include "nsIServiceManager.h"
- #include "nsBoxLayout.h"
- #include "FrameLayerBuilder.h"
- #include <algorithm>
- using namespace mozilla;
- #ifdef DEBUG_LAYOUT
- int32_t gIndent = 0;
- #endif
- #ifdef DEBUG_LAYOUT
- void
- nsBoxAddIndents()
- {
- for(int32_t i=0; i < gIndent; i++)
- {
- printf(" ");
- }
- }
- #endif
- #ifdef DEBUG_LAYOUT
- void
- nsBox::AppendAttribute(const nsAutoString& aAttribute, const nsAutoString& aValue, nsAutoString& aResult)
- {
- aResult.Append(aAttribute);
- aResult.AppendLiteral("='");
- aResult.Append(aValue);
- aResult.AppendLiteral("' ");
- }
- void
- nsBox::ListBox(nsAutoString& aResult)
- {
- nsAutoString name;
- GetBoxName(name);
- char addr[100];
- sprintf(addr, "[@%p] ", static_cast<void*>(this));
- aResult.AppendASCII(addr);
- aResult.Append(name);
- aResult.Append(' ');
- nsIContent* content = GetContent();
- // add on all the set attributes
- if (content) {
- nsCOMPtr<nsIDOMNode> node(do_QueryInterface(content));
- nsCOMPtr<nsIDOMMozNamedAttrMap> namedMap;
- node->GetAttributes(getter_AddRefs(namedMap));
- uint32_t length;
- namedMap->GetLength(&length);
- nsCOMPtr<nsIDOMAttr> attribute;
- for (uint32_t i = 0; i < length; ++i)
- {
- namedMap->Item(i, getter_AddRefs(attribute));
- attribute->GetName(name);
- nsAutoString value;
- attribute->GetValue(value);
- AppendAttribute(name, value, aResult);
- }
- }
- }
- nsresult
- nsBox::XULDumpBox(FILE* aFile)
- {
- nsAutoString s;
- ListBox(s);
- fprintf(aFile, "%s", NS_LossyConvertUTF16toASCII(s).get());
- return NS_OK;
- }
- void
- nsBox::PropagateDebug(nsBoxLayoutState& aState)
- {
- // propagate debug information
- if (mState & NS_STATE_DEBUG_WAS_SET) {
- if (mState & NS_STATE_SET_TO_DEBUG)
- SetXULDebug(aState, true);
- else
- SetXULDebug(aState, false);
- } else if (mState & NS_STATE_IS_ROOT) {
- SetXULDebug(aState, gDebug);
- }
- }
- #endif
- #ifdef DEBUG_LAYOUT
- void
- nsBox::GetBoxName(nsAutoString& aName)
- {
- aName.AssignLiteral("Box");
- }
- #endif
- nsresult
- nsBox::BeginXULLayout(nsBoxLayoutState& aState)
- {
- #ifdef DEBUG_LAYOUT
- nsBoxAddIndents();
- printf("XULLayout: ");
- XULDumpBox(stdout);
- printf("\n");
- gIndent++;
- #endif
- // mark ourselves as dirty so no child under us
- // can post an incremental layout.
- // XXXldb Is this still needed?
- mState |= NS_FRAME_HAS_DIRTY_CHILDREN;
- if (GetStateBits() & NS_FRAME_IS_DIRTY)
- {
- // If the parent is dirty, all the children are dirty (ReflowInput
- // does this too).
- nsIFrame* box;
- for (box = GetChildXULBox(this); box; box = GetNextXULBox(box))
- box->AddStateBits(NS_FRAME_IS_DIRTY);
- }
- // Another copy-over from ReflowInput.
- // Since we are in reflow, we don't need to store these properties anymore.
- DeleteProperty(UsedBorderProperty());
- DeleteProperty(UsedPaddingProperty());
- DeleteProperty(UsedMarginProperty());
- #ifdef DEBUG_LAYOUT
- PropagateDebug(aState);
- #endif
- return NS_OK;
- }
- NS_IMETHODIMP
- nsBox::DoXULLayout(nsBoxLayoutState& aState)
- {
- return NS_OK;
- }
- nsresult
- nsBox::EndXULLayout(nsBoxLayoutState& aState)
- {
- #ifdef DEBUG_LAYOUT
- --gIndent;
- #endif
- return SyncLayout(aState);
- }
- bool nsBox::gGotTheme = false;
- nsITheme* nsBox::gTheme = nullptr;
- nsBox::nsBox()
- {
- MOZ_COUNT_CTOR(nsBox);
- //mX = 0;
- //mY = 0;
- if (!gGotTheme) {
- gGotTheme = true;
- CallGetService("@mozilla.org/chrome/chrome-native-theme;1", &gTheme);
- }
- }
- nsBox::~nsBox()
- {
- // NOTE: This currently doesn't get called for |nsBoxToBlockAdaptor|
- // objects, so don't rely on putting anything here.
- MOZ_COUNT_DTOR(nsBox);
- }
- /* static */ void
- nsBox::Shutdown()
- {
- gGotTheme = false;
- NS_IF_RELEASE(gTheme);
- }
- nsresult
- nsBox::XULRelayoutChildAtOrdinal(nsIFrame* aChild)
- {
- return NS_OK;
- }
- nsresult
- nsIFrame::GetXULClientRect(nsRect& aClientRect)
- {
- aClientRect = mRect;
- aClientRect.MoveTo(0,0);
- nsMargin borderPadding;
- GetXULBorderAndPadding(borderPadding);
- aClientRect.Deflate(borderPadding);
- if (aClientRect.width < 0)
- aClientRect.width = 0;
- if (aClientRect.height < 0)
- aClientRect.height = 0;
- // NS_ASSERTION(aClientRect.width >=0 && aClientRect.height >= 0, "Content Size < 0");
- return NS_OK;
- }
- void
- nsBox::SetXULBounds(nsBoxLayoutState& aState, const nsRect& aRect, bool aRemoveOverflowAreas)
- {
- NS_BOX_ASSERTION(this, aRect.width >=0 && aRect.height >= 0, "SetXULBounds Size < 0");
- nsRect rect(mRect);
- uint32_t flags = GetXULLayoutFlags();
- uint32_t stateFlags = aState.LayoutFlags();
- flags |= stateFlags;
- if ((flags & NS_FRAME_NO_MOVE_FRAME) == NS_FRAME_NO_MOVE_FRAME)
- SetSize(aRect.Size());
- else
- SetRect(aRect);
- // Nuke the overflow area. The caller is responsible for restoring
- // it if necessary.
- if (aRemoveOverflowAreas) {
- // remove the previously stored overflow area
- ClearOverflowRects();
- }
- if (!(flags & NS_FRAME_NO_MOVE_VIEW))
- {
- nsContainerFrame::PositionFrameView(this);
- if ((rect.x != aRect.x) || (rect.y != aRect.y))
- nsContainerFrame::PositionChildViews(this);
- }
-
- /*
- // only if the origin changed
- if ((rect.x != aRect.x) || (rect.y != aRect.y)) {
- if (frame->HasView()) {
- nsContainerFrame::PositionFrameView(presContext, frame,
- frame->GetView());
- } else {
- nsContainerFrame::PositionChildViews(presContext, frame);
- }
- }
- */
- }
- nsresult
- nsIFrame::GetXULBorderAndPadding(nsMargin& aBorderAndPadding)
- {
- aBorderAndPadding.SizeTo(0, 0, 0, 0);
- nsresult rv = GetXULBorder(aBorderAndPadding);
- if (NS_FAILED(rv))
- return rv;
- nsMargin padding;
- rv = GetXULPadding(padding);
- if (NS_FAILED(rv))
- return rv;
- aBorderAndPadding += padding;
- return rv;
- }
- nsresult
- nsBox::GetXULBorder(nsMargin& aMargin)
- {
- aMargin.SizeTo(0,0,0,0);
-
- const nsStyleDisplay* disp = StyleDisplay();
- if (disp->mAppearance && gTheme) {
- // Go to the theme for the border.
- nsPresContext *context = PresContext();
- if (gTheme->ThemeSupportsWidget(context, this, disp->mAppearance)) {
- nsIntMargin margin(0, 0, 0, 0);
- gTheme->GetWidgetBorder(context->DeviceContext(), this,
- disp->mAppearance, &margin);
- aMargin.top = context->DevPixelsToAppUnits(margin.top);
- aMargin.right = context->DevPixelsToAppUnits(margin.right);
- aMargin.bottom = context->DevPixelsToAppUnits(margin.bottom);
- aMargin.left = context->DevPixelsToAppUnits(margin.left);
- return NS_OK;
- }
- }
- aMargin = StyleBorder()->GetComputedBorder();
- return NS_OK;
- }
- nsresult
- nsBox::GetXULPadding(nsMargin& aMargin)
- {
- const nsStyleDisplay *disp = StyleDisplay();
- if (disp->mAppearance && gTheme) {
- // Go to the theme for the padding.
- nsPresContext *context = PresContext();
- if (gTheme->ThemeSupportsWidget(context, this, disp->mAppearance)) {
- nsIntMargin margin(0, 0, 0, 0);
- bool useThemePadding;
- useThemePadding = gTheme->GetWidgetPadding(context->DeviceContext(),
- this, disp->mAppearance,
- &margin);
- if (useThemePadding) {
- aMargin.top = context->DevPixelsToAppUnits(margin.top);
- aMargin.right = context->DevPixelsToAppUnits(margin.right);
- aMargin.bottom = context->DevPixelsToAppUnits(margin.bottom);
- aMargin.left = context->DevPixelsToAppUnits(margin.left);
- return NS_OK;
- }
- }
- }
- aMargin.SizeTo(0,0,0,0);
- StylePadding()->GetPadding(aMargin);
- return NS_OK;
- }
- nsresult
- nsBox::GetXULMargin(nsMargin& aMargin)
- {
- aMargin.SizeTo(0,0,0,0);
- StyleMargin()->GetMargin(aMargin);
- return NS_OK;
- }
- void
- nsBox::SizeNeedsRecalc(nsSize& aSize)
- {
- aSize.width = -1;
- aSize.height = -1;
- }
- void
- nsBox::CoordNeedsRecalc(nscoord& aFlex)
- {
- aFlex = -1;
- }
- bool
- nsBox::DoesNeedRecalc(const nsSize& aSize)
- {
- return (aSize.width == -1 || aSize.height == -1);
- }
- bool
- nsBox::DoesNeedRecalc(nscoord aCoord)
- {
- return (aCoord == -1);
- }
- nsSize
- nsBox::GetXULPrefSize(nsBoxLayoutState& aState)
- {
- NS_ASSERTION(aState.GetRenderingContext(), "must have rendering context");
- nsSize pref(0,0);
- DISPLAY_PREF_SIZE(this, pref);
- if (IsXULCollapsed())
- return pref;
- AddBorderAndPadding(pref);
- bool widthSet, heightSet;
- nsIFrame::AddXULPrefSize(this, pref, widthSet, heightSet);
- nsSize minSize = GetXULMinSize(aState);
- nsSize maxSize = GetXULMaxSize(aState);
- return BoundsCheck(minSize, pref, maxSize);
- }
- nsSize
- nsBox::GetXULMinSize(nsBoxLayoutState& aState)
- {
- NS_ASSERTION(aState.GetRenderingContext(), "must have rendering context");
- nsSize min(0,0);
- DISPLAY_MIN_SIZE(this, min);
- if (IsXULCollapsed())
- return min;
- AddBorderAndPadding(min);
- bool widthSet, heightSet;
- nsIFrame::AddXULMinSize(aState, this, min, widthSet, heightSet);
- return min;
- }
- nsSize
- nsBox::GetXULMinSizeForScrollArea(nsBoxLayoutState& aBoxLayoutState)
- {
- return nsSize(0, 0);
- }
- nsSize
- nsBox::GetXULMaxSize(nsBoxLayoutState& aState)
- {
- NS_ASSERTION(aState.GetRenderingContext(), "must have rendering context");
- nsSize maxSize(NS_INTRINSICSIZE, NS_INTRINSICSIZE);
- DISPLAY_MAX_SIZE(this, maxSize);
- if (IsXULCollapsed())
- return maxSize;
- AddBorderAndPadding(maxSize);
- bool widthSet, heightSet;
- nsIFrame::AddXULMaxSize(this, maxSize, widthSet, heightSet);
- return maxSize;
- }
- nscoord
- nsBox::GetXULFlex()
- {
- nscoord flex = 0;
- nsIFrame::AddXULFlex(this, flex);
- return flex;
- }
- uint32_t
- nsIFrame::GetXULOrdinal()
- {
- uint32_t ordinal = StyleXUL()->mBoxOrdinal;
- // When present, attribute value overrides CSS.
- nsIContent* content = GetContent();
- if (content && content->IsXULElement()) {
- nsresult error;
- nsAutoString value;
- content->GetAttr(kNameSpaceID_None, nsGkAtoms::ordinal, value);
- if (!value.IsEmpty()) {
- ordinal = value.ToInteger(&error);
- }
- }
- return ordinal;
- }
- nscoord
- nsBox::GetXULBoxAscent(nsBoxLayoutState& aState)
- {
- if (IsXULCollapsed())
- return 0;
- return GetXULPrefSize(aState).height;
- }
- bool
- nsBox::IsXULCollapsed()
- {
- return StyleVisibility()->mVisible == NS_STYLE_VISIBILITY_COLLAPSE;
- }
- nsresult
- nsIFrame::XULLayout(nsBoxLayoutState& aState)
- {
- NS_ASSERTION(aState.GetRenderingContext(), "must have rendering context");
- nsBox *box = static_cast<nsBox*>(this);
- DISPLAY_LAYOUT(box);
- box->BeginXULLayout(aState);
- box->DoXULLayout(aState);
- box->EndXULLayout(aState);
- return NS_OK;
- }
- bool
- nsBox::DoesClipChildren()
- {
- const nsStyleDisplay* display = StyleDisplay();
- NS_ASSERTION((display->mOverflowY == NS_STYLE_OVERFLOW_CLIP) ==
- (display->mOverflowX == NS_STYLE_OVERFLOW_CLIP),
- "If one overflow is clip, the other should be too");
- return display->mOverflowX == NS_STYLE_OVERFLOW_CLIP;
- }
- nsresult
- nsBox::SyncLayout(nsBoxLayoutState& aState)
- {
- /*
- if (IsXULCollapsed()) {
- CollapseChild(aState, this, true);
- return NS_OK;
- }
- */
-
- if (GetStateBits() & NS_FRAME_IS_DIRTY)
- XULRedraw(aState);
- RemoveStateBits(NS_FRAME_HAS_DIRTY_CHILDREN | NS_FRAME_IS_DIRTY
- | NS_FRAME_FIRST_REFLOW | NS_FRAME_IN_REFLOW);
- nsPresContext* presContext = aState.PresContext();
- uint32_t flags = GetXULLayoutFlags();
- uint32_t stateFlags = aState.LayoutFlags();
- flags |= stateFlags;
- nsRect visualOverflow;
- if (ComputesOwnOverflowArea()) {
- visualOverflow = GetVisualOverflowRect();
- }
- else {
- nsRect rect(nsPoint(0, 0), GetSize());
- nsOverflowAreas overflowAreas(rect, rect);
- if (!DoesClipChildren() && !IsXULCollapsed()) {
- // See if our child frames caused us to overflow after being laid
- // out. If so, store the overflow area. This normally can't happen
- // in XUL, but it can happen with the CSS 'outline' property and
- // possibly with other exotic stuff (e.g. relatively positioned
- // frames in HTML inside XUL).
- nsLayoutUtils::UnionChildOverflow(this, overflowAreas);
- }
- FinishAndStoreOverflow(overflowAreas, GetSize());
- visualOverflow = overflowAreas.VisualOverflow();
- }
- nsView* view = GetView();
- if (view) {
- // Make sure the frame's view is properly sized and positioned and has
- // things like opacity correct
- nsContainerFrame::SyncFrameViewAfterReflow(presContext, this, view,
- visualOverflow, flags);
- }
- return NS_OK;
- }
- nsresult
- nsIFrame::XULRedraw(nsBoxLayoutState& aState)
- {
- if (aState.PaintingDisabled())
- return NS_OK;
- // nsStackLayout, at least, expects us to repaint descendants even
- // if a damage rect is provided
- InvalidateFrameSubtree();
- return NS_OK;
- }
- bool
- nsIFrame::AddXULPrefSize(nsIFrame* aBox, nsSize& aSize, bool &aWidthSet, bool &aHeightSet)
- {
- aWidthSet = false;
- aHeightSet = false;
- // add in the css min, max, pref
- const nsStylePosition* position = aBox->StylePosition();
- // see if the width or height was specifically set
- // XXX Handle eStyleUnit_Enumerated?
- // (Handling the eStyleUnit_Enumerated types requires
- // GetXULPrefSize/GetXULMinSize methods that don't consider
- // (min-/max-/)(width/height) properties.)
- const nsStyleCoord &width = position->mWidth;
- if (width.GetUnit() == eStyleUnit_Coord) {
- aSize.width = width.GetCoordValue();
- aWidthSet = true;
- } else if (width.IsCalcUnit()) {
- if (!width.CalcHasPercent()) {
- // pass 0 for percentage basis since we know there are no %s
- aSize.width = nsRuleNode::ComputeComputedCalc(width, 0);
- if (aSize.width < 0)
- aSize.width = 0;
- aWidthSet = true;
- }
- }
- const nsStyleCoord &height = position->mHeight;
- if (height.GetUnit() == eStyleUnit_Coord) {
- aSize.height = height.GetCoordValue();
- aHeightSet = true;
- } else if (height.IsCalcUnit()) {
- if (!height.CalcHasPercent()) {
- // pass 0 for percentage basis since we know there are no %s
- aSize.height = nsRuleNode::ComputeComputedCalc(height, 0);
- if (aSize.height < 0)
- aSize.height = 0;
- aHeightSet = true;
- }
- }
- nsIContent* content = aBox->GetContent();
- // ignore 'height' and 'width' attributes if the actual element is not XUL
- // For example, we might be magic XUL frames whose primary content is an HTML
- // <select>
- if (content && content->IsXULElement()) {
- nsAutoString value;
- nsresult error;
- content->GetAttr(kNameSpaceID_None, nsGkAtoms::width, value);
- if (!value.IsEmpty()) {
- value.Trim("%");
- aSize.width =
- nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
- aWidthSet = true;
- }
- content->GetAttr(kNameSpaceID_None, nsGkAtoms::height, value);
- if (!value.IsEmpty()) {
- value.Trim("%");
- aSize.height =
- nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
- aHeightSet = true;
- }
- }
- return (aWidthSet && aHeightSet);
- }
- bool
- nsIFrame::AddXULMinSize(nsBoxLayoutState& aState, nsIFrame* aBox, nsSize& aSize,
- bool &aWidthSet, bool &aHeightSet)
- {
- aWidthSet = false;
- aHeightSet = false;
- bool canOverride = true;
- // See if a native theme wants to supply a minimum size.
- const nsStyleDisplay* display = aBox->StyleDisplay();
- if (display->mAppearance) {
- nsITheme *theme = aState.PresContext()->GetTheme();
- if (theme && theme->ThemeSupportsWidget(aState.PresContext(), aBox, display->mAppearance)) {
- LayoutDeviceIntSize size;
- theme->GetMinimumWidgetSize(aState.PresContext(), aBox,
- display->mAppearance, &size, &canOverride);
- if (size.width) {
- aSize.width = aState.PresContext()->DevPixelsToAppUnits(size.width);
- aWidthSet = true;
- }
- if (size.height) {
- aSize.height = aState.PresContext()->DevPixelsToAppUnits(size.height);
- aHeightSet = true;
- }
- }
- }
- // add in the css min, max, pref
- const nsStylePosition* position = aBox->StylePosition();
- // same for min size. Unfortunately min size is always set to 0. So for now
- // we will assume 0 (as a coord) means not set.
- const nsStyleCoord &minWidth = position->mMinWidth;
- if ((minWidth.GetUnit() == eStyleUnit_Coord &&
- minWidth.GetCoordValue() != 0) ||
- (minWidth.IsCalcUnit() && !minWidth.CalcHasPercent())) {
- nscoord min = nsRuleNode::ComputeCoordPercentCalc(minWidth, 0);
- if (!aWidthSet || (min > aSize.width && canOverride)) {
- aSize.width = min;
- aWidthSet = true;
- }
- } else if (minWidth.GetUnit() == eStyleUnit_Percent) {
- NS_ASSERTION(minWidth.GetPercentValue() == 0.0f,
- "Non-zero percentage values not currently supported");
- aSize.width = 0;
- aWidthSet = true; // FIXME: should we really do this for
- // nonzero values?
- }
- // XXX Handle eStyleUnit_Enumerated?
- // (Handling the eStyleUnit_Enumerated types requires
- // GetXULPrefSize/GetXULMinSize methods that don't consider
- // (min-/max-/)(width/height) properties.
- // calc() with percentage is treated like '0' (unset)
- const nsStyleCoord &minHeight = position->mMinHeight;
- if ((minHeight.GetUnit() == eStyleUnit_Coord &&
- minHeight.GetCoordValue() != 0) ||
- (minHeight.IsCalcUnit() && !minHeight.CalcHasPercent())) {
- nscoord min = nsRuleNode::ComputeCoordPercentCalc(minHeight, 0);
- if (!aHeightSet || (min > aSize.height && canOverride)) {
- aSize.height = min;
- aHeightSet = true;
- }
- } else if (minHeight.GetUnit() == eStyleUnit_Percent) {
- NS_ASSERTION(position->mMinHeight.GetPercentValue() == 0.0f,
- "Non-zero percentage values not currently supported");
- aSize.height = 0;
- aHeightSet = true; // FIXME: should we really do this for
- // nonzero values?
- }
- // calc() with percentage is treated like '0' (unset)
- nsIContent* content = aBox->GetContent();
- if (content && content->IsXULElement()) {
- nsAutoString value;
- nsresult error;
- content->GetAttr(kNameSpaceID_None, nsGkAtoms::minwidth, value);
- if (!value.IsEmpty())
- {
- value.Trim("%");
- nscoord val =
- nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
- if (val > aSize.width)
- aSize.width = val;
- aWidthSet = true;
- }
- content->GetAttr(kNameSpaceID_None, nsGkAtoms::minheight, value);
- if (!value.IsEmpty())
- {
- value.Trim("%");
- nscoord val =
- nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
- if (val > aSize.height)
- aSize.height = val;
- aHeightSet = true;
- }
- }
- return (aWidthSet && aHeightSet);
- }
- bool
- nsIFrame::AddXULMaxSize(nsIFrame* aBox, nsSize& aSize, bool &aWidthSet, bool &aHeightSet)
- {
- aWidthSet = false;
- aHeightSet = false;
- // add in the css min, max, pref
- const nsStylePosition* position = aBox->StylePosition();
- // and max
- // see if the width or height was specifically set
- // XXX Handle eStyleUnit_Enumerated?
- // (Handling the eStyleUnit_Enumerated types requires
- // GetXULPrefSize/GetXULMinSize methods that don't consider
- // (min-/max-/)(width/height) properties.)
- const nsStyleCoord maxWidth = position->mMaxWidth;
- if (maxWidth.ConvertsToLength()) {
- aSize.width = nsRuleNode::ComputeCoordPercentCalc(maxWidth, 0);
- aWidthSet = true;
- }
- // percentages and calc() with percentages are treated like 'none'
- const nsStyleCoord &maxHeight = position->mMaxHeight;
- if (maxHeight.ConvertsToLength()) {
- aSize.height = nsRuleNode::ComputeCoordPercentCalc(maxHeight, 0);
- aHeightSet = true;
- }
- // percentages and calc() with percentages are treated like 'none'
- nsIContent* content = aBox->GetContent();
- if (content && content->IsXULElement()) {
- nsAutoString value;
- nsresult error;
- content->GetAttr(kNameSpaceID_None, nsGkAtoms::maxwidth, value);
- if (!value.IsEmpty()) {
- value.Trim("%");
- nscoord val =
- nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
- aSize.width = val;
- aWidthSet = true;
- }
- content->GetAttr(kNameSpaceID_None, nsGkAtoms::maxheight, value);
- if (!value.IsEmpty()) {
- value.Trim("%");
- nscoord val =
- nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
- aSize.height = val;
- aHeightSet = true;
- }
- }
- return (aWidthSet || aHeightSet);
- }
- bool
- nsIFrame::AddXULFlex(nsIFrame* aBox, nscoord& aFlex)
- {
- bool flexSet = false;
- // get the flexibility
- aFlex = aBox->StyleXUL()->mBoxFlex;
- // attribute value overrides CSS
- nsIContent* content = aBox->GetContent();
- if (content && content->IsXULElement()) {
- nsresult error;
- nsAutoString value;
- content->GetAttr(kNameSpaceID_None, nsGkAtoms::flex, value);
- if (!value.IsEmpty()) {
- value.Trim("%");
- aFlex = value.ToInteger(&error);
- flexSet = true;
- }
- }
- if (aFlex < 0)
- aFlex = 0;
- if (aFlex >= nscoord_MAX)
- aFlex = nscoord_MAX - 1;
- return flexSet || aFlex > 0;
- }
- void
- nsBox::AddBorderAndPadding(nsSize& aSize)
- {
- AddBorderAndPadding(this, aSize);
- }
- void
- nsBox::AddBorderAndPadding(nsIFrame* aBox, nsSize& aSize)
- {
- nsMargin borderPadding(0,0,0,0);
- aBox->GetXULBorderAndPadding(borderPadding);
- AddMargin(aSize, borderPadding);
- }
- void
- nsBox::AddMargin(nsIFrame* aChild, nsSize& aSize)
- {
- nsMargin margin(0,0,0,0);
- aChild->GetXULMargin(margin);
- AddMargin(aSize, margin);
- }
- void
- nsBox::AddMargin(nsSize& aSize, const nsMargin& aMargin)
- {
- if (aSize.width != NS_INTRINSICSIZE)
- aSize.width += aMargin.left + aMargin.right;
- if (aSize.height != NS_INTRINSICSIZE)
- aSize.height += aMargin.top + aMargin.bottom;
- }
- nscoord
- nsBox::BoundsCheck(nscoord aMin, nscoord aPref, nscoord aMax)
- {
- if (aPref > aMax)
- aPref = aMax;
- if (aPref < aMin)
- aPref = aMin;
- return aPref;
- }
- nsSize
- nsBox::BoundsCheckMinMax(const nsSize& aMinSize, const nsSize& aMaxSize)
- {
- return nsSize(std::max(aMaxSize.width, aMinSize.width),
- std::max(aMaxSize.height, aMinSize.height));
- }
- nsSize
- nsBox::BoundsCheck(const nsSize& aMinSize, const nsSize& aPrefSize, const nsSize& aMaxSize)
- {
- return nsSize(BoundsCheck(aMinSize.width, aPrefSize.width, aMaxSize.width),
- BoundsCheck(aMinSize.height, aPrefSize.height, aMaxSize.height));
- }
- /*static*/ nsIFrame*
- nsBox::GetChildXULBox(const nsIFrame* aFrame)
- {
- // box layout ends at box-wrapped frames, so don't allow these frames
- // to report child boxes.
- return aFrame->IsXULBoxFrame() ? aFrame->PrincipalChildList().FirstChild() : nullptr;
- }
- /*static*/ nsIFrame*
- nsBox::GetNextXULBox(const nsIFrame* aFrame)
- {
- return aFrame->GetParent() &&
- aFrame->GetParent()->IsXULBoxFrame() ? aFrame->GetNextSibling() : nullptr;
- }
- /*static*/ nsIFrame*
- nsBox::GetParentXULBox(const nsIFrame* aFrame)
- {
- return aFrame->GetParent() &&
- aFrame->GetParent()->IsXULBoxFrame() ? aFrame->GetParent() : nullptr;
- }
- #ifdef DEBUG_LAYOUT
- nsresult
- nsBox::SetXULDebug(nsBoxLayoutState& aState, bool aDebug)
- {
- return NS_OK;
- }
- NS_IMETHODIMP
- nsBox::GetDebugBoxAt( const nsPoint& aPoint,
- nsIFrame** aBox)
- {
- nsRect thisRect(nsPoint(0,0), GetSize());
- if (!thisRect.Contains(aPoint))
- return NS_ERROR_FAILURE;
- nsIFrame* child = nsBox::GetChildXULBox(this);
- nsIFrame* hit = nullptr;
- *aBox = nullptr;
- while (nullptr != child) {
- nsresult rv = child->GetDebugBoxAt(aPoint - child->GetOffsetTo(this), &hit);
- if (NS_SUCCEEDED(rv) && hit) {
- *aBox = hit;
- }
- child = GetNextXULBox(child);
- }
- // found a child
- if (*aBox) {
- return NS_OK;
- }
- return NS_ERROR_FAILURE;
- }
- nsresult
- nsBox::GetXULDebug(bool& aDebug)
- {
- aDebug = false;
- return NS_OK;
- }
- #endif
|