From 2aa4a82499d4becd2284cdb482213d541b8804dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 28 Apr 2024 16:29:10 +0200 Subject: Adding upstream version 86.0.1. Signed-off-by: Daniel Baumann --- layout/xul/nsBox.cpp | 650 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 650 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..e8710d4358 --- /dev/null +++ b/layout/xul/nsBox.cpp @@ -0,0 +1,650 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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 "mozilla/Attributes.h" +#include "mozilla/StaticPtr.h" +#include "nsIFrame.h" + +#include "nsBoxLayoutState.h" +#include "nsBoxFrame.h" +#include "nsDOMAttributeMap.h" +#include "nsPresContext.h" +#include "nsCOMPtr.h" +#include "nsIContent.h" +#include "nsContainerFrame.h" +#include "nsNameSpaceManager.h" +#include "nsGkAtoms.h" +#include "nsITheme.h" +#include "nsBoxLayout.h" +#include "nsLayoutUtils.h" +#include "FrameLayerBuilder.h" +#include "mozilla/dom/Attr.h" +#include "mozilla/dom/Element.h" +#include + +using namespace mozilla; + +nsresult nsIFrame::BeginXULLayout(nsBoxLayoutState& aState) { + // mark ourselves as dirty so no child under us + // can post an incremental layout. + // XXXldb Is this still needed? + AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN); + + if (HasAnyStateBits(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->MarkSubtreeDirty(); + } + + // Another copy-over from ReflowInput. + // Since we are in reflow, we don't need to store these properties anymore. + RemoveProperty(UsedBorderProperty()); + RemoveProperty(UsedPaddingProperty()); + RemoveProperty(UsedMarginProperty()); + + return NS_OK; +} + +nsresult nsIFrame::EndXULLayout(nsBoxLayoutState& aState) { + return SyncXULLayout(aState); +} + +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; + + return NS_OK; +} + +void nsIFrame::SetXULBounds(nsBoxLayoutState& aState, const nsRect& aRect, + bool aRemoveOverflowAreas) { + nsRect rect(mRect); + + ReflowChildFlags flags = GetXULLayoutFlags() | aState.LayoutFlags(); + + if ((flags & ReflowChildFlags::NoMoveFrame) == + ReflowChildFlags::NoMoveFrame) { + 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 & ReflowChildFlags::NoMoveView)) { + nsContainerFrame::PositionFrameView(this); + if ((rect.x != aRect.x) || (rect.y != aRect.y)) + nsContainerFrame::PositionChildViews(this); + } +} + +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 nsIFrame::GetXULBorder(nsMargin& aBorder) { + aBorder.SizeTo(0, 0, 0, 0); + + StyleAppearance appearance = StyleDisplay()->EffectiveAppearance(); + if (appearance != StyleAppearance::None) { + // Go to the theme for the border. + nsPresContext* pc = PresContext(); + nsITheme* theme = pc->Theme(); + if (theme->ThemeSupportsWidget(pc, this, appearance)) { + LayoutDeviceIntMargin margin = + theme->GetWidgetBorder(pc->DeviceContext(), this, appearance); + aBorder = + LayoutDevicePixel::ToAppUnits(margin, pc->AppUnitsPerDevPixel()); + return NS_OK; + } + } + + aBorder = StyleBorder()->GetComputedBorder(); + + return NS_OK; +} + +nsresult nsIFrame::GetXULPadding(nsMargin& aBorderAndPadding) { + StyleAppearance appearance = StyleDisplay()->EffectiveAppearance(); + if (appearance != StyleAppearance::None) { + // Go to the theme for the padding. + nsPresContext* pc = PresContext(); + nsITheme* theme = pc->Theme(); + if (theme->ThemeSupportsWidget(pc, this, appearance)) { + LayoutDeviceIntMargin padding; + bool useThemePadding = theme->GetWidgetPadding(pc->DeviceContext(), this, + appearance, &padding); + if (useThemePadding) { + aBorderAndPadding = + LayoutDevicePixel::ToAppUnits(padding, pc->AppUnitsPerDevPixel()); + return NS_OK; + } + } + } + + aBorderAndPadding.SizeTo(0, 0, 0, 0); + StylePadding()->GetPadding(aBorderAndPadding); + + return NS_OK; +} + +nsresult nsIFrame::GetXULMargin(nsMargin& aMargin) { + aMargin.SizeTo(0, 0, 0, 0); + StyleMargin()->GetMargin(aMargin); + + return NS_OK; +} + +void nsIFrame::XULSizeNeedsRecalc(nsSize& aSize) { + aSize.width = -1; + aSize.height = -1; +} + +void nsIFrame::XULCoordNeedsRecalc(nscoord& aCoord) { aCoord = -1; } + +bool nsIFrame::XULNeedsRecalc(const nsSize& aSize) { + return (aSize.width == -1 || aSize.height == -1); +} + +bool nsIFrame::XULNeedsRecalc(nscoord aCoord) { return (aCoord == -1); } + +nsSize nsIFrame::GetUncachedXULPrefSize(nsBoxLayoutState& aBoxLayoutState) { + NS_ASSERTION(aBoxLayoutState.GetRenderingContext(), + "must have rendering context"); + + nsSize pref(0, 0); + DISPLAY_PREF_SIZE(this, pref); + + if (IsXULCollapsed()) { + return pref; + } + + AddXULBorderAndPadding(pref); + bool widthSet, heightSet; + nsIFrame::AddXULPrefSize(this, pref, widthSet, heightSet); + + nsSize minSize = GetXULMinSize(aBoxLayoutState); + nsSize maxSize = GetXULMaxSize(aBoxLayoutState); + return XULBoundsCheck(minSize, pref, maxSize); +} + +nsSize nsIFrame::GetUncachedXULMinSize(nsBoxLayoutState& aBoxLayoutState) { + NS_ASSERTION(aBoxLayoutState.GetRenderingContext(), + "must have rendering context"); + + nsSize min(0, 0); + DISPLAY_MIN_SIZE(this, min); + + if (IsXULCollapsed()) { + return min; + } + + AddXULBorderAndPadding(min); + bool widthSet, heightSet; + nsIFrame::AddXULMinSize(this, min, widthSet, heightSet); + return min; +} + +nsSize nsIFrame::GetXULMinSizeForScrollArea(nsBoxLayoutState& aBoxLayoutState) { + return nsSize(0, 0); +} + +nsSize nsIFrame::GetUncachedXULMaxSize(nsBoxLayoutState& aBoxLayoutState) { + NS_ASSERTION(aBoxLayoutState.GetRenderingContext(), + "must have rendering context"); + + nsSize maxSize(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE); + DISPLAY_MAX_SIZE(this, maxSize); + + if (IsXULCollapsed()) { + return maxSize; + } + + AddXULBorderAndPadding(maxSize); + bool widthSet, heightSet; + nsIFrame::AddXULMaxSize(this, maxSize, widthSet, heightSet); + return maxSize; +} + +bool nsIFrame::IsXULCollapsed() { + return StyleVisibility()->mVisible == StyleVisibility::Collapse; +} + +nsresult nsIFrame::XULLayout(nsBoxLayoutState& aState) { + NS_ASSERTION(aState.GetRenderingContext(), "must have rendering context"); + + nsIFrame* box = static_cast(this); + DISPLAY_LAYOUT(box); + + box->BeginXULLayout(aState); + + box->DoXULLayout(aState); + + box->EndXULLayout(aState); + + return NS_OK; +} + +bool nsIFrame::DoesClipChildrenInBothAxes() { + const nsStyleDisplay* display = StyleDisplay(); + return display->mOverflowX == StyleOverflow::Clip && + display->mOverflowY == StyleOverflow::Clip; +} + +nsresult nsIFrame::SyncXULLayout(nsBoxLayoutState& aBoxLayoutState) { + /* + if (IsXULCollapsed()) { + CollapseChild(aBoxLayoutState, this, true); + return NS_OK; + } + */ + + if (HasAnyStateBits(NS_FRAME_IS_DIRTY)) { + XULRedraw(aBoxLayoutState); + } + + RemoveStateBits(NS_FRAME_HAS_DIRTY_CHILDREN | NS_FRAME_IS_DIRTY | + NS_FRAME_FIRST_REFLOW | NS_FRAME_IN_REFLOW); + + nsPresContext* presContext = aBoxLayoutState.PresContext(); + + ReflowChildFlags flags = GetXULLayoutFlags() | aBoxLayoutState.LayoutFlags(); + + nsRect inkOverflow; + + if (XULComputesOwnOverflowArea()) { + inkOverflow = InkOverflowRect(); + } else { + nsRect rect(nsPoint(0, 0), GetSize()); + OverflowAreas overflowAreas(rect, rect); + if (!DoesClipChildrenInBothAxes() && !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()); + inkOverflow = overflowAreas.InkOverflow(); + } + + 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, + inkOverflow, 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 auto& width = position->mWidth; + if (width.ConvertsToLength()) { + aSize.width = std::max(0, width.ToLength()); + aWidthSet = true; + } + + const auto& height = position->mHeight; + if (height.ConvertsToLength()) { + aSize.height = std::max(0, height.ToLength()); + 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 + //