forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			209 lines
		
	
	
	
		
			5.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			209 lines
		
	
	
	
		
			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;
 | 
						|
}
 |