зеркало из https://github.com/mozilla/gecko-dev.git
210 строки
5.2 KiB
C++
210 строки
5.2 KiB
C++
/* -*- 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/. */
|
|
|
|
//
|
|
// Eric Vaughan
|
|
// Netscape Communications
|
|
//
|
|
// See documentation in associated header file
|
|
//
|
|
|
|
#include "nsStackLayout.h"
|
|
#include "nsCOMPtr.h"
|
|
#include "nsBoxLayoutState.h"
|
|
#include "nsBoxFrame.h"
|
|
#include "nsGkAtoms.h"
|
|
#include "nsIContent.h"
|
|
#include "nsNameSpaceManager.h"
|
|
|
|
using namespace mozilla;
|
|
|
|
nsBoxLayout* nsStackLayout::gInstance = nullptr;
|
|
|
|
nsresult NS_NewStackLayout(nsCOMPtr<nsBoxLayout>& aNewLayout) {
|
|
if (!nsStackLayout::gInstance) {
|
|
nsStackLayout::gInstance = new nsStackLayout();
|
|
NS_IF_ADDREF(nsStackLayout::gInstance);
|
|
}
|
|
// we have not instance variables so just return our static one.
|
|
aNewLayout = nsStackLayout::gInstance;
|
|
return NS_OK;
|
|
}
|
|
|
|
/*static*/
|
|
void nsStackLayout::Shutdown() { NS_IF_RELEASE(gInstance); }
|
|
|
|
nsStackLayout::nsStackLayout() = default;
|
|
|
|
/*
|
|
* Sizing: we are as wide as the widest child
|
|
* we are tall as the tallest child.
|
|
*/
|
|
|
|
nsSize nsStackLayout::GetXULPrefSize(nsIFrame* aBox, nsBoxLayoutState& aState) {
|
|
nsSize prefSize(0, 0);
|
|
|
|
nsIFrame* child = nsIFrame::GetChildXULBox(aBox);
|
|
while (child) {
|
|
nsSize pref = child->GetXULPrefSize(aState);
|
|
|
|
AddXULMargin(child, pref);
|
|
|
|
if (pref.width > prefSize.width) {
|
|
prefSize.width = pref.width;
|
|
}
|
|
if (pref.height > prefSize.height) {
|
|
prefSize.height = pref.height;
|
|
}
|
|
|
|
child = nsIFrame::GetNextXULBox(child);
|
|
}
|
|
|
|
AddXULBorderAndPadding(aBox, prefSize);
|
|
|
|
return prefSize;
|
|
}
|
|
|
|
nsSize nsStackLayout::GetXULMinSize(nsIFrame* aBox, nsBoxLayoutState& aState) {
|
|
nsSize minSize(0, 0);
|
|
|
|
nsIFrame* child = nsIFrame::GetChildXULBox(aBox);
|
|
while (child) {
|
|
nsSize min = child->GetXULMinSize(aState);
|
|
|
|
AddXULMargin(child, min);
|
|
|
|
if (min.width > minSize.width) {
|
|
minSize.width = min.width;
|
|
}
|
|
if (min.height > minSize.height) {
|
|
minSize.height = min.height;
|
|
}
|
|
|
|
child = nsIFrame::GetNextXULBox(child);
|
|
}
|
|
|
|
AddXULBorderAndPadding(aBox, minSize);
|
|
|
|
return minSize;
|
|
}
|
|
|
|
nsSize nsStackLayout::GetXULMaxSize(nsIFrame* aBox, nsBoxLayoutState& aState) {
|
|
nsSize maxSize(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
|
|
|
|
nsIFrame* child = nsIFrame::GetChildXULBox(aBox);
|
|
while (child) {
|
|
nsSize min = child->GetXULMinSize(aState);
|
|
nsSize max = child->GetXULMaxSize(aState);
|
|
|
|
max = nsIFrame::XULBoundsCheckMinMax(min, max);
|
|
|
|
AddXULMargin(child, max);
|
|
|
|
if (max.width < maxSize.width) {
|
|
maxSize.width = max.width;
|
|
}
|
|
if (max.height < maxSize.height) {
|
|
maxSize.height = max.height;
|
|
}
|
|
|
|
child = nsIFrame::GetNextXULBox(child);
|
|
}
|
|
|
|
AddXULBorderAndPadding(aBox, maxSize);
|
|
|
|
return maxSize;
|
|
}
|
|
|
|
nscoord nsStackLayout::GetAscent(nsIFrame* aBox, nsBoxLayoutState& aState) {
|
|
nscoord vAscent = 0;
|
|
|
|
nsIFrame* child = nsIFrame::GetChildXULBox(aBox);
|
|
while (child) {
|
|
nscoord ascent = child->GetXULBoxAscent(aState);
|
|
nsMargin margin;
|
|
child->GetXULMargin(margin);
|
|
ascent += margin.top;
|
|
if (ascent > vAscent) vAscent = ascent;
|
|
|
|
child = nsIFrame::GetNextXULBox(child);
|
|
}
|
|
|
|
return vAscent;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsStackLayout::XULLayout(nsIFrame* aBox, nsBoxLayoutState& aState) {
|
|
nsRect clientRect;
|
|
aBox->GetXULClientRect(clientRect);
|
|
|
|
bool grow;
|
|
|
|
do {
|
|
nsIFrame* child = nsIFrame::GetChildXULBox(aBox);
|
|
grow = false;
|
|
|
|
while (child) {
|
|
nsMargin margin;
|
|
child->GetXULMargin(margin);
|
|
nsRect childRect(clientRect);
|
|
childRect.Deflate(margin);
|
|
|
|
if (childRect.width < 0) childRect.width = 0;
|
|
|
|
if (childRect.height < 0) childRect.height = 0;
|
|
|
|
nsRect oldRect(child->GetRect());
|
|
bool sizeChanged = !oldRect.IsEqualEdges(childRect);
|
|
|
|
// only lay out dirty children or children whose sizes have changed
|
|
if (sizeChanged || child->IsSubtreeDirty()) {
|
|
// add in the child's margin
|
|
nsMargin margin;
|
|
child->GetXULMargin(margin);
|
|
|
|
// Now place the child.
|
|
child->SetXULBounds(aState, childRect);
|
|
|
|
// Flow the child.
|
|
child->XULLayout(aState);
|
|
|
|
// Get the child's new rect.
|
|
childRect = child->GetRect();
|
|
childRect.Inflate(margin);
|
|
|
|
// Did the child push back on us and get bigger?
|
|
if (childRect.width > clientRect.width) {
|
|
clientRect.width = childRect.width;
|
|
grow = true;
|
|
}
|
|
|
|
if (childRect.height > clientRect.height) {
|
|
clientRect.height = childRect.height;
|
|
grow = true;
|
|
}
|
|
}
|
|
|
|
child = nsIFrame::GetNextXULBox(child);
|
|
}
|
|
} while (grow);
|
|
|
|
// if some HTML inside us got bigger we need to force ourselves to
|
|
// get bigger
|
|
nsRect bounds(aBox->GetRect());
|
|
nsMargin bp;
|
|
aBox->GetXULBorderAndPadding(bp);
|
|
clientRect.Inflate(bp);
|
|
|
|
if (clientRect.width > bounds.width || clientRect.height > bounds.height) {
|
|
if (clientRect.width > bounds.width) bounds.width = clientRect.width;
|
|
if (clientRect.height > bounds.height) bounds.height = clientRect.height;
|
|
|
|
aBox->SetXULBounds(aState, bounds);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|