From 5f8de423f190bbb79a62f804151bc24824fa32d8 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Fri, 2 Feb 2018 04:16:08 -0500 Subject: Add m-esr52 at 52.6.0 --- layout/xul/nsBox.cpp | 981 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 981 insertions(+) create mode 100644 layout/xul/nsBox.cpp (limited to 'layout/xul/nsBox.cpp') diff --git a/layout/xul/nsBox.cpp b/layout/xul/nsBox.cpp new file mode 100644 index 0000000000..f7ec5fead4 --- /dev/null +++ b/layout/xul/nsBox.cpp @@ -0,0 +1,981 @@ +/* -*- 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 + +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(this)); + + aResult.AppendASCII(addr); + aResult.Append(name); + aResult.Append(' '); + + nsIContent* content = GetContent(); + + // add on all the set attributes + if (content) { + nsCOMPtr node(do_QueryInterface(content)); + nsCOMPtr namedMap; + + node->GetAttributes(getter_AddRefs(namedMap)); + uint32_t length; + namedMap->GetLength(&length); + + nsCOMPtr 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. + FrameProperties props = Properties(); + props.Delete(UsedBorderProperty()); + props.Delete(UsedPaddingProperty()); + props.Delete(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(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 + //