forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			717 lines
		
	
	
	
		
			27 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			717 lines
		
	
	
	
		
			27 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | 
						|
/* ***** BEGIN LICENSE BLOCK *****
 | 
						|
 * Version: NPL 1.1/GPL 2.0/LGPL 2.1
 | 
						|
 *
 | 
						|
 * The contents of this file are subject to the Netscape Public License
 | 
						|
 * Version 1.1 (the "License"); you may not use this file except in
 | 
						|
 * compliance with the License. You may obtain a copy of the License at
 | 
						|
 * http://www.mozilla.org/NPL/
 | 
						|
 *
 | 
						|
 * Software distributed under the License is distributed on an "AS IS" basis,
 | 
						|
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 | 
						|
 * for the specific language governing rights and limitations under the
 | 
						|
 * License.
 | 
						|
 *
 | 
						|
 * The Original Code is mozilla.org code.
 | 
						|
 *
 | 
						|
 * The Initial Developer of the Original Code is 
 | 
						|
 * Netscape Communications Corporation.
 | 
						|
 * Portions created by the Initial Developer are Copyright (C) 1998
 | 
						|
 * the Initial Developer. All Rights Reserved.
 | 
						|
 *
 | 
						|
 * Contributor(s):
 | 
						|
 *
 | 
						|
 * Alternatively, the contents of this file may be used under the terms of
 | 
						|
 * either the GNU General Public License Version 2 or later (the "GPL"), or 
 | 
						|
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 | 
						|
 * in which case the provisions of the GPL or the LGPL are applicable instead
 | 
						|
 * of those above. If you wish to allow use of your version of this file only
 | 
						|
 * under the terms of either the GPL or the LGPL, and not to allow others to
 | 
						|
 * use your version of this file under the terms of the NPL, indicate your
 | 
						|
 * decision by deleting the provisions above and replace them with the notice
 | 
						|
 * and other provisions required by the GPL or the LGPL. If you do not delete
 | 
						|
 * the provisions above, a recipient may use your version of this file under
 | 
						|
 * the terms of any one of the NPL, the GPL or the LGPL.
 | 
						|
 *
 | 
						|
 * ***** END LICENSE BLOCK ***** */
 | 
						|
 | 
						|
// YY need to pass isMultiple before create called
 | 
						|
 | 
						|
//#include "nsFormControlFrame.h"
 | 
						|
#include "nsHTMLContainerFrame.h"
 | 
						|
#include "nsLegendFrame.h"
 | 
						|
#include "nsIDOMNode.h"
 | 
						|
#include "nsIDOMHTMLFieldSetElement.h"
 | 
						|
#include "nsIDOMHTMLLegendElement.h"
 | 
						|
#include "nsCSSRendering.h"
 | 
						|
//#include "nsIDOMHTMLCollection.h"
 | 
						|
#include "nsIContent.h"
 | 
						|
#include "nsIFrame.h"
 | 
						|
#include "nsISupports.h"
 | 
						|
#include "nsIAtom.h"
 | 
						|
#include "nsIPresContext.h"
 | 
						|
#include "nsIHTMLContent.h"
 | 
						|
#include "nsHTMLParts.h"
 | 
						|
#include "nsHTMLAtoms.h"
 | 
						|
#include "nsLayoutAtoms.h"
 | 
						|
#include "nsStyleConsts.h"
 | 
						|
#include "nsFont.h"
 | 
						|
#include "nsCOMPtr.h"
 | 
						|
#ifdef ACCESSIBILITY
 | 
						|
#include "nsIAccessibilityService.h"
 | 
						|
#endif
 | 
						|
#include "nsIServiceManager.h"
 | 
						|
#include "nsSpaceManager.h"
 | 
						|
 | 
						|
class nsLegendFrame;
 | 
						|
 | 
						|
class nsFieldSetFrame : public nsHTMLContainerFrame {
 | 
						|
public:
 | 
						|
 | 
						|
  nsFieldSetFrame();
 | 
						|
 | 
						|
  NS_IMETHOD SetInitialChildList(nsIPresContext* aPresContext,
 | 
						|
                                 nsIAtom*        aListName,
 | 
						|
                                 nsIFrame*       aChildList);
 | 
						|
 | 
						|
  NS_IMETHOD Reflow(nsIPresContext* aPresContext,
 | 
						|
                    nsHTMLReflowMetrics& aDesiredSize,
 | 
						|
                    const nsHTMLReflowState& aReflowState,
 | 
						|
                    nsReflowStatus& aStatus);
 | 
						|
                               
 | 
						|
  NS_METHOD Paint(nsIPresContext*      aPresContext,
 | 
						|
                  nsIRenderingContext& aRenderingContext,
 | 
						|
                  const nsRect&        aDirtyRect,
 | 
						|
                  nsFramePaintLayer    aWhichLayer,
 | 
						|
                  PRUint32             aFlags);
 | 
						|
 | 
						|
  NS_IMETHOD  AppendFrames(nsIPresContext* aPresContext,
 | 
						|
                           nsIPresShell&   aPresShell,
 | 
						|
                           nsIAtom*        aListName,
 | 
						|
                           nsIFrame*       aFrameList);
 | 
						|
  NS_IMETHOD  InsertFrames(nsIPresContext* aPresContext,
 | 
						|
                           nsIPresShell&   aPresShell,
 | 
						|
                           nsIAtom*        aListName,
 | 
						|
                           nsIFrame*       aPrevFrame,
 | 
						|
                           nsIFrame*       aFrameList);
 | 
						|
  NS_IMETHOD  RemoveFrame(nsIPresContext* aPresContext,
 | 
						|
                          nsIPresShell&   aPresShell,
 | 
						|
                          nsIAtom*        aListName,
 | 
						|
                          nsIFrame*       aOldFrame);
 | 
						|
  NS_IMETHOD  ReplaceFrame(nsIPresContext* aPresContext,
 | 
						|
                           nsIPresShell&   aPresShell,
 | 
						|
                           nsIAtom*        aListName,
 | 
						|
                           nsIFrame*       aOldFrame,
 | 
						|
                           nsIFrame*       aNewFrame);
 | 
						|
  NS_IMETHOD  GetFrameForPoint(nsIPresContext*   aPresContext,
 | 
						|
                               const nsPoint&    aPoint, 
 | 
						|
                               nsFramePaintLayer aWhichLayer,
 | 
						|
                               nsIFrame**        aFrame);
 | 
						|
  NS_IMETHOD GetFrameType(nsIAtom** aType) const;
 | 
						|
 | 
						|
#ifdef ACCESSIBILITY  
 | 
						|
  NS_IMETHOD  GetAccessible(nsIAccessible** aAccessible);
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef DEBUG
 | 
						|
  NS_IMETHOD GetFrameName(nsAString& aResult) const {
 | 
						|
    return MakeFrameName(NS_LITERAL_STRING("FieldSet"), aResult);
 | 
						|
  }
 | 
						|
#endif
 | 
						|
 | 
						|
protected:
 | 
						|
 | 
						|
  virtual PRIntn GetSkipSides() const;
 | 
						|
 | 
						|
  nsIFrame* mLegendFrame;
 | 
						|
  nsIFrame* mContentFrame;
 | 
						|
  nsRect    mLegendRect;
 | 
						|
  nscoord   mLegendSpace;
 | 
						|
};
 | 
						|
 | 
						|
nsresult
 | 
						|
NS_NewFieldSetFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame, PRUint32 aStateFlags )
 | 
						|
{
 | 
						|
  NS_PRECONDITION(aNewFrame, "null OUT ptr");
 | 
						|
  if (nsnull == aNewFrame) {
 | 
						|
    return NS_ERROR_NULL_POINTER;
 | 
						|
  }
 | 
						|
  nsFieldSetFrame* it = new (aPresShell) nsFieldSetFrame;
 | 
						|
  if (!it) {
 | 
						|
    return NS_ERROR_OUT_OF_MEMORY;
 | 
						|
  }
 | 
						|
 | 
						|
  // set the state flags (if any are provided)
 | 
						|
  it->AddStateBits(aStateFlags);
 | 
						|
  
 | 
						|
  *aNewFrame = it;
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
nsFieldSetFrame::nsFieldSetFrame()
 | 
						|
  : nsHTMLContainerFrame()
 | 
						|
{
 | 
						|
  mContentFrame    = nsnull;
 | 
						|
  mLegendFrame     = nsnull;
 | 
						|
  mLegendSpace   = 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
NS_IMETHODIMP
 | 
						|
nsFieldSetFrame::GetFrameType(nsIAtom** aType) const
 | 
						|
{
 | 
						|
  NS_PRECONDITION(aType, "null OUT parameter pointer");
 | 
						|
  *aType = nsLayoutAtoms::fieldSetFrame; 
 | 
						|
  NS_ADDREF(*aType);
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
NS_IMETHODIMP
 | 
						|
nsFieldSetFrame::SetInitialChildList(nsIPresContext* aPresContext,
 | 
						|
                                     nsIAtom*        aListName,
 | 
						|
                                     nsIFrame*       aChildList)
 | 
						|
{
 | 
						|
 
 | 
						|
  // get the content and legend frames.
 | 
						|
  mContentFrame = aChildList;
 | 
						|
  mLegendFrame = mContentFrame->GetNextSibling();
 | 
						|
 | 
						|
  // Queue up the frames for the content frame
 | 
						|
  return nsHTMLContainerFrame::SetInitialChildList(aPresContext, nsnull, aChildList);
 | 
						|
}
 | 
						|
 | 
						|
// this is identical to nsHTMLContainerFrame::Paint except for the background and border. 
 | 
						|
NS_IMETHODIMP
 | 
						|
nsFieldSetFrame::Paint(nsIPresContext*      aPresContext,
 | 
						|
                       nsIRenderingContext& aRenderingContext,
 | 
						|
                       const nsRect&        aDirtyRect,
 | 
						|
                       nsFramePaintLayer    aWhichLayer,
 | 
						|
                       PRUint32             aFlags)
 | 
						|
{
 | 
						|
  if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
 | 
						|
    // Paint our background and border
 | 
						|
    PRBool isVisible;
 | 
						|
    if (NS_SUCCEEDED(IsVisibleForPainting(aPresContext, aRenderingContext, PR_TRUE, &isVisible)) && 
 | 
						|
                     isVisible && mRect.width && mRect.height) {
 | 
						|
      PRIntn skipSides = GetSkipSides();
 | 
						|
      const nsStyleBorder* borderStyle = GetStyleBorder();
 | 
						|
      const nsStylePadding* paddingStyle = GetStylePadding();
 | 
						|
       
 | 
						|
        nsMargin border;
 | 
						|
        if (!borderStyle->GetBorder(border)) {
 | 
						|
          NS_NOTYETIMPLEMENTED("percentage border");
 | 
						|
        }
 | 
						|
 | 
						|
        nscoord yoff = 0;
 | 
						|
        
 | 
						|
        // if the border is smaller than the legend. Move the border down
 | 
						|
        // to be centered on the legend. 
 | 
						|
        if (border.top < mLegendRect.height)
 | 
						|
            yoff = (mLegendRect.height - border.top)/2;
 | 
						|
       
 | 
						|
        nsRect rect(0, yoff, mRect.width, mRect.height - yoff);
 | 
						|
 | 
						|
        nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, this,
 | 
						|
                                        aDirtyRect, rect, *borderStyle,
 | 
						|
                                        *paddingStyle, PR_TRUE);
 | 
						|
 | 
						|
        if (mLegendFrame) {
 | 
						|
 | 
						|
          // we should probably use PaintBorderEdges to do this but for now just use clipping
 | 
						|
          // to achieve the same effect.
 | 
						|
          PRBool clipState;
 | 
						|
 | 
						|
          // draw left side
 | 
						|
          nsRect clipRect(rect);
 | 
						|
          clipRect.width = mLegendRect.x - rect.x;
 | 
						|
          clipRect.height = border.top;
 | 
						|
 | 
						|
          aRenderingContext.PushState();
 | 
						|
          aRenderingContext.SetClipRect(clipRect, nsClipCombine_kIntersect, clipState);
 | 
						|
          nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this,
 | 
						|
                                      aDirtyRect, rect, *borderStyle, mStyleContext, skipSides);
 | 
						|
  
 | 
						|
          aRenderingContext.PopState(clipState);
 | 
						|
 | 
						|
 | 
						|
          // draw right side
 | 
						|
          clipRect = rect;
 | 
						|
          clipRect.x = mLegendRect.x + mLegendRect.width;
 | 
						|
          clipRect.width -= (mLegendRect.x + mLegendRect.width);
 | 
						|
          clipRect.height = border.top;
 | 
						|
 | 
						|
          aRenderingContext.PushState();
 | 
						|
          aRenderingContext.SetClipRect(clipRect, nsClipCombine_kIntersect, clipState);
 | 
						|
          nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this,
 | 
						|
                                      aDirtyRect, rect, *borderStyle, mStyleContext, skipSides);
 | 
						|
  
 | 
						|
          aRenderingContext.PopState(clipState);
 | 
						|
 | 
						|
        
 | 
						|
          // draw bottom
 | 
						|
 | 
						|
          clipRect = rect;
 | 
						|
          clipRect.y += border.top;
 | 
						|
          clipRect.height = mRect.height - (yoff + border.top);
 | 
						|
        
 | 
						|
          aRenderingContext.PushState();
 | 
						|
          aRenderingContext.SetClipRect(clipRect, nsClipCombine_kIntersect, clipState);
 | 
						|
          nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this,
 | 
						|
                                      aDirtyRect, rect, *borderStyle, mStyleContext, skipSides);
 | 
						|
  
 | 
						|
          aRenderingContext.PopState(clipState);
 | 
						|
        } else {
 | 
						|
 | 
						|
          nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this,
 | 
						|
                                      aDirtyRect,
 | 
						|
                                      nsRect(0,0,mRect.width, mRect.height),
 | 
						|
                                      *borderStyle, mStyleContext, skipSides);
 | 
						|
        }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  PaintChildren(aPresContext, aRenderingContext, aDirtyRect, aWhichLayer);
 | 
						|
 | 
						|
#ifdef DEBUG
 | 
						|
  if ((NS_FRAME_PAINT_LAYER_DEBUG == aWhichLayer) && GetShowFrameBorders()) {
 | 
						|
    if (HasView()) {
 | 
						|
      aRenderingContext.SetColor(NS_RGB(0,0,255));
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      aRenderingContext.SetColor(NS_RGB(255,0,0));
 | 
						|
    }
 | 
						|
    aRenderingContext.DrawRect(0, 0, mRect.width, mRect.height);
 | 
						|
  }
 | 
						|
#endif
 | 
						|
  DO_GLOBAL_REFLOW_COUNT_DSP("nsFieldSetFrame", &aRenderingContext);
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
NS_IMETHODIMP 
 | 
						|
nsFieldSetFrame::Reflow(nsIPresContext*          aPresContext,
 | 
						|
                        nsHTMLReflowMetrics&     aDesiredSize,
 | 
						|
                        const nsHTMLReflowState& aReflowState,
 | 
						|
                        nsReflowStatus&          aStatus)
 | 
						|
{
 | 
						|
  DO_GLOBAL_REFLOW_COUNT("nsFieldSetFrame", aReflowState.reason);
 | 
						|
  DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
 | 
						|
 | 
						|
  // Initialize OUT parameter
 | 
						|
  aStatus = NS_FRAME_COMPLETE;
 | 
						|
 | 
						|
  // Should we create a space manager?
 | 
						|
  nsAutoSpaceManager autoSpaceManager(NS_CONST_CAST(nsHTMLReflowState &, aReflowState));
 | 
						|
 | 
						|
  // XXXldb If we start storing the space manager in the frame rather
 | 
						|
  // than keeping it around only during reflow then we should create it
 | 
						|
  // only when there are actually floats to manage.  Otherwise things
 | 
						|
  // like tables will gain significant bloat.
 | 
						|
  if (NS_BLOCK_SPACE_MGR & mState)
 | 
						|
    autoSpaceManager.CreateSpaceManagerFor(aPresContext, this);
 | 
						|
 | 
						|
  if (aDesiredSize.mComputeMEW) {
 | 
						|
    aDesiredSize.mMaxElementWidth = 0;
 | 
						|
  }
 | 
						|
  
 | 
						|
   //------------ Handle Incremental Reflow -----------------
 | 
						|
   PRBool reflowContent = PR_TRUE;
 | 
						|
   PRBool reflowLegend = PR_TRUE;
 | 
						|
   nsReflowReason reason = aReflowState.reason;
 | 
						|
 | 
						|
    if ( aReflowState.reason == eReflowReason_Incremental ) {
 | 
						|
        nsHTMLReflowCommand *command = aReflowState.path->mReflowCommand;
 | 
						|
 | 
						|
        // See if it's targeted at us
 | 
						|
        if (command) {
 | 
						|
            nsReflowType  reflowType;
 | 
						|
            command->GetType(reflowType);
 | 
						|
 | 
						|
            switch (reflowType) {
 | 
						|
 | 
						|
              case eReflowType_StyleChanged: 
 | 
						|
                  {
 | 
						|
                    nsHTMLReflowState newState(aReflowState);
 | 
						|
                    newState.reason = eReflowReason_StyleChange;
 | 
						|
                    return Reflow(aPresContext, aDesiredSize, newState, aStatus);
 | 
						|
                  }
 | 
						|
                  break;
 | 
						|
 | 
						|
                  // if its a dirty type then reflow us with a dirty reflow
 | 
						|
                  case eReflowType_ReflowDirty: 
 | 
						|
                  {
 | 
						|
                    nsHTMLReflowState newState(aReflowState);
 | 
						|
                    newState.reason = eReflowReason_Dirty;
 | 
						|
                    return Reflow(aPresContext, aDesiredSize, newState, aStatus);
 | 
						|
                  }
 | 
						|
                  break;
 | 
						|
 | 
						|
                  default:
 | 
						|
                    NS_ERROR("Unexpected Reflow Type");
 | 
						|
            }
 | 
						|
        } else {
 | 
						|
             reflowContent = PR_FALSE;
 | 
						|
             reflowLegend = PR_FALSE;
 | 
						|
 | 
						|
             nsReflowPath::iterator iter = aReflowState.path->FirstChild();
 | 
						|
             nsReflowPath::iterator end = aReflowState.path->EndChildren();
 | 
						|
 | 
						|
             for ( ; iter != end; ++iter) {
 | 
						|
                 if (*iter == mLegendFrame)
 | 
						|
                     reflowLegend = PR_TRUE;
 | 
						|
                 else if (*iter == mContentFrame)
 | 
						|
                     reflowContent = PR_TRUE;
 | 
						|
             }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    // if dirty then check dirty flags
 | 
						|
    if (reason == eReflowReason_Dirty) 
 | 
						|
    {
 | 
						|
      if (reflowContent) {
 | 
						|
        reflowContent =
 | 
						|
          (mContentFrame->GetStateBits()
 | 
						|
           & (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) != 0;
 | 
						|
      }
 | 
						|
 | 
						|
      if (reflowLegend) {
 | 
						|
        reflowLegend =
 | 
						|
          (mLegendFrame->GetStateBits()
 | 
						|
           & (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) != 0;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    // availSize could have unconstrained values, don't perform any addition on them
 | 
						|
    nsSize availSize(aReflowState.mComputedWidth, aReflowState.availableHeight);
 | 
						|
 | 
						|
    // get our border and padding
 | 
						|
    const nsMargin &borderPadding = aReflowState.mComputedBorderPadding;
 | 
						|
    const nsMargin &padding       = aReflowState.mComputedPadding;
 | 
						|
    nsMargin border = borderPadding - padding;
 | 
						|
 | 
						|
    // Figure out how big the legend is if there is one. 
 | 
						|
    // get the legend's margin
 | 
						|
    nsMargin legendMargin(0,0,0,0);
 | 
						|
    // reflow the legend only if needed
 | 
						|
    if (mLegendFrame) {
 | 
						|
        const nsStyleMargin* marginStyle = mLegendFrame->GetStyleMargin();
 | 
						|
        marginStyle->GetMargin(legendMargin);
 | 
						|
 | 
						|
        if (reflowLegend) {
 | 
						|
          nsHTMLReflowState legendReflowState(aPresContext, aReflowState,
 | 
						|
                                              mLegendFrame, nsSize(NS_INTRINSICSIZE,NS_INTRINSICSIZE),
 | 
						|
                                              reason);
 | 
						|
 | 
						|
          // always give the legend as much size as it needs
 | 
						|
          legendReflowState.mComputedWidth = NS_INTRINSICSIZE;
 | 
						|
          legendReflowState.mComputedHeight = NS_INTRINSICSIZE;
 | 
						|
 | 
						|
          nsHTMLReflowMetrics legendDesiredSize(0,0);
 | 
						|
 | 
						|
          ReflowChild(mLegendFrame, aPresContext, legendDesiredSize, legendReflowState,
 | 
						|
                      0, 0, NS_FRAME_NO_MOVE_FRAME, aStatus);
 | 
						|
#ifdef NOISY_REFLOW
 | 
						|
          printf("  returned (%d, %d)\n", legendDesiredSize.width, legendDesiredSize.height);
 | 
						|
          if (legendDesiredSize.mComputeMEW)
 | 
						|
            printf("  and maxEW %d\n", 
 | 
						|
                   legendDesiredSize.mMaxElementWidth);
 | 
						|
#endif
 | 
						|
          // figure out the legend's rectangle
 | 
						|
          mLegendRect.width  = legendDesiredSize.width + legendMargin.left + legendMargin.right;
 | 
						|
          mLegendRect.height = legendDesiredSize.height + legendMargin.top + legendMargin.bottom;
 | 
						|
          mLegendRect.x = borderPadding.left;
 | 
						|
          mLegendRect.y = 0;
 | 
						|
 | 
						|
          nscoord oldSpace = mLegendSpace;
 | 
						|
          mLegendSpace = 0;
 | 
						|
          if (mLegendRect.height > border.top) {
 | 
						|
              // center the border on the legend
 | 
						|
              mLegendSpace = mLegendRect.height - border.top;
 | 
						|
          } else {
 | 
						|
              mLegendRect.y = (border.top - mLegendRect.height)/2;
 | 
						|
          }
 | 
						|
 | 
						|
          // if the legend space changes then we need to reflow the 
 | 
						|
          // content area as well.
 | 
						|
          if (mLegendSpace != oldSpace) {
 | 
						|
              if (reflowContent == PR_FALSE || reason == eReflowReason_Dirty) {
 | 
						|
                 reflowContent = PR_TRUE;
 | 
						|
                 reason = eReflowReason_Resize;
 | 
						|
              }
 | 
						|
          }
 | 
						|
 | 
						|
          // if we are contrained then remove the legend from our available height.
 | 
						|
          if (NS_INTRINSICSIZE != availSize.height) {
 | 
						|
             if (availSize.height >= mLegendSpace)
 | 
						|
                 availSize.height -= mLegendSpace;
 | 
						|
          }
 | 
						|
  
 | 
						|
          // don't get any smaller than the legend
 | 
						|
          if (NS_INTRINSICSIZE != availSize.width) {
 | 
						|
             if (availSize.width < mLegendRect.width)
 | 
						|
                 availSize.width = mLegendRect.width;
 | 
						|
          }
 | 
						|
 | 
						|
          FinishReflowChild(mLegendFrame, aPresContext, &legendReflowState, 
 | 
						|
                            legendDesiredSize, 0, 0, NS_FRAME_NO_MOVE_FRAME);    
 | 
						|
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    nsRect contentRect;
 | 
						|
 | 
						|
    // reflow the content frame only if needed
 | 
						|
    if (mContentFrame) {
 | 
						|
        if (reflowContent) {
 | 
						|
            availSize.width = aReflowState.mComputedWidth;
 | 
						|
 | 
						|
#if 0
 | 
						|
            if (aReflowState.mComputedHeight != NS_INTRINSICSIZE) {
 | 
						|
              availSize.height = aReflowState.mComputedHeight - mLegendSpace;
 | 
						|
            } else {
 | 
						|
              availSize.height = NS_INTRINSICSIZE;
 | 
						|
            }
 | 
						|
#endif
 | 
						|
            nsHTMLReflowState kidReflowState(aPresContext, aReflowState, mContentFrame,
 | 
						|
                                             availSize, reason);
 | 
						|
 | 
						|
            nsHTMLReflowMetrics kidDesiredSize(aDesiredSize.mComputeMEW, aDesiredSize.mFlags);
 | 
						|
            // Reflow the frame
 | 
						|
            ReflowChild(mContentFrame, aPresContext, kidDesiredSize, kidReflowState,
 | 
						|
                        borderPadding.left + kidReflowState.mComputedMargin.left,
 | 
						|
                        borderPadding.top + mLegendSpace + kidReflowState.mComputedMargin.top,
 | 
						|
                        0, aStatus);
 | 
						|
#ifdef NOISY_REFLOW
 | 
						|
            printf("  returned (%d, %d)\n", kidDesiredSize.width, kidDesiredSize.height);
 | 
						|
            if (kidDesiredSize.mComputeMEW)
 | 
						|
              printf("  and maxES %d\n", 
 | 
						|
                     kidDesiredSize.mMaxElementWidth);
 | 
						|
#endif
 | 
						|
 | 
						|
            /*
 | 
						|
            printf("*** %p computedHgt: %d ", this, aReflowState.mComputedHeight);
 | 
						|
              printf("Reason: ");
 | 
						|
              switch (aReflowState.reason) {
 | 
						|
                case eReflowReason_Initial:printf("Initil");break;
 | 
						|
                case eReflowReason_Incremental:printf("Increm");break;
 | 
						|
                case eReflowReason_Resize: printf("Resize");      break;
 | 
						|
                case eReflowReason_StyleChange:printf("eReflowReason_StyleChange");break;
 | 
						|
              }
 | 
						|
              */
 | 
						|
 | 
						|
            // set the rect. make sure we add the margin back in.
 | 
						|
            contentRect.SetRect(borderPadding.left,borderPadding.top + mLegendSpace,kidDesiredSize.width ,kidDesiredSize.height);
 | 
						|
            if (aReflowState.mComputedHeight != NS_INTRINSICSIZE &&
 | 
						|
                borderPadding.top + mLegendSpace+kidDesiredSize.height > aReflowState.mComputedHeight) {
 | 
						|
              kidDesiredSize.height = aReflowState.mComputedHeight-(borderPadding.top + mLegendSpace);
 | 
						|
            }
 | 
						|
 | 
						|
            FinishReflowChild(mContentFrame, aPresContext, &kidReflowState, 
 | 
						|
                              kidDesiredSize, contentRect.x, contentRect.y, 0);
 | 
						|
            if (aDesiredSize.mComputeMEW) {
 | 
						|
              aDesiredSize.mMaxElementWidth = kidDesiredSize.mMaxElementWidth;
 | 
						|
            }
 | 
						|
 | 
						|
           // printf("width: %d, height: %d\n", desiredSize.mCombinedArea.width, desiredSize.mCombinedArea.height);
 | 
						|
 | 
						|
            /*
 | 
						|
            if (mContentFrame->GetStateBits() & NS_FRAME_OUTSIDE_CHILDREN) {
 | 
						|
                 mState |= NS_FRAME_OUTSIDE_CHILDREN;
 | 
						|
                 aDesiredSize.mOverflowArea.width += borderPadding.left + borderPadding.right;
 | 
						|
                 aDesiredSize.mOverflowArea.height += borderPadding.top + borderPadding.bottom + mLegendSpace;
 | 
						|
            }
 | 
						|
            */
 | 
						|
 | 
						|
            NS_FRAME_TRACE_REFLOW_OUT("FieldSet::Reflow", aStatus);
 | 
						|
 | 
						|
        } else {
 | 
						|
            // if we don't need to reflow just get the old size
 | 
						|
            contentRect = mContentFrame->GetRect();
 | 
						|
            const nsStyleMargin* marginStyle = mContentFrame->GetStyleMargin();
 | 
						|
 | 
						|
            nsMargin m(0,0,0,0);
 | 
						|
            marginStyle->GetMargin(m);
 | 
						|
            contentRect.Inflate(m);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    // use the computed width if the inner content does not fill it
 | 
						|
    if (aReflowState.mComputedWidth != NS_INTRINSICSIZE &&
 | 
						|
        aReflowState.mComputedWidth > contentRect.width) {
 | 
						|
      contentRect.width = aReflowState.mComputedWidth;
 | 
						|
    }
 | 
						|
 | 
						|
    if (mLegendFrame) {
 | 
						|
      // if the content rect is larger then the  legend we can align the legend
 | 
						|
      if (contentRect.width > mLegendRect.width) {
 | 
						|
        PRInt32 align = ((nsLegendFrame*)mLegendFrame)->GetAlign();
 | 
						|
 | 
						|
        switch(align) {
 | 
						|
          case NS_STYLE_TEXT_ALIGN_RIGHT:
 | 
						|
            mLegendRect.x = contentRect.width - mLegendRect.width + borderPadding.left;
 | 
						|
            break;
 | 
						|
          case NS_STYLE_TEXT_ALIGN_CENTER:
 | 
						|
            float p2t;
 | 
						|
            aPresContext->GetPixelsToTwips(&p2t);
 | 
						|
            mLegendRect.x = NSIntPixelsToTwips((nscoord) NSToIntRound((float)(contentRect.width/2 - mLegendRect.width/2 + borderPadding.left) / p2t),p2t);
 | 
						|
        }
 | 
						|
  
 | 
						|
      } else {
 | 
						|
        //otherwise make place for the legend
 | 
						|
        contentRect.width = mLegendRect.width;
 | 
						|
      }
 | 
						|
      // place the legend
 | 
						|
      nsRect actualLegendRect(mLegendRect);
 | 
						|
      actualLegendRect.Deflate(legendMargin);
 | 
						|
 | 
						|
      nsPoint curOrigin = mLegendFrame->GetPosition();
 | 
						|
 | 
						|
      // only if the origin changed
 | 
						|
      if ((curOrigin.x != mLegendRect.x) || (curOrigin.y != mLegendRect.y)) {
 | 
						|
          mLegendFrame->SetPosition(nsPoint(actualLegendRect.x , actualLegendRect.y));
 | 
						|
          nsContainerFrame::PositionFrameView(aPresContext, mLegendFrame);
 | 
						|
 | 
						|
          // We need to recursively process the legend frame's
 | 
						|
          // children since we're moving the frame after Reflow.
 | 
						|
          nsContainerFrame::PositionChildViews(aPresContext, mLegendFrame);
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    // Return our size and our result
 | 
						|
    if (aReflowState.mComputedHeight == NS_INTRINSICSIZE) {
 | 
						|
       aDesiredSize.height = mLegendSpace + 
 | 
						|
                             borderPadding.top +
 | 
						|
                             contentRect.height +
 | 
						|
                             borderPadding.bottom;
 | 
						|
    } else {
 | 
						|
       nscoord min = borderPadding.top + borderPadding.bottom + mLegendRect.height;
 | 
						|
       aDesiredSize.height = aReflowState.mComputedHeight + borderPadding.top + borderPadding.bottom;
 | 
						|
       if (aDesiredSize.height < min)
 | 
						|
           aDesiredSize.height = min;
 | 
						|
    }
 | 
						|
    aDesiredSize.width = contentRect.width + borderPadding.left + borderPadding.right;
 | 
						|
    aDesiredSize.ascent  = aDesiredSize.height;
 | 
						|
    aDesiredSize.descent = 0;
 | 
						|
    aDesiredSize.mMaximumWidth = aDesiredSize.width;
 | 
						|
    if (aDesiredSize.mComputeMEW) {
 | 
						|
        // if the legend is wider use it
 | 
						|
        if (aDesiredSize.mMaxElementWidth < mLegendRect.width)
 | 
						|
            aDesiredSize.mMaxElementWidth = mLegendRect.width;
 | 
						|
 | 
						|
        // add in padding.
 | 
						|
        aDesiredSize.mMaxElementWidth += borderPadding.left + borderPadding.right;
 | 
						|
    }
 | 
						|
    aDesiredSize.mOverflowArea = nsRect(0, 0, aDesiredSize.width, aDesiredSize.height);
 | 
						|
    if (mLegendFrame)
 | 
						|
      ConsiderChildOverflow(aPresContext, aDesiredSize.mOverflowArea, mLegendFrame);
 | 
						|
    if (mContentFrame)
 | 
						|
      ConsiderChildOverflow(aPresContext, aDesiredSize.mOverflowArea, mContentFrame);
 | 
						|
    StoreOverflow(aPresContext, aDesiredSize);
 | 
						|
#ifdef NOISY_REFLOW
 | 
						|
    printf("FIELDSET:  w=%d, maxWidth=%d, MEW=%d\n",
 | 
						|
           aDesiredSize.width, aDesiredSize.mMaximumWidth, 
 | 
						|
           aDesiredSize.mComputeMEW ? aDesiredSize.mMaxElementWidth : -1);
 | 
						|
    if (aDesiredSize.mFlags & NS_REFLOW_CALC_MAX_WIDTH)
 | 
						|
      printf("  and preferred size = %d\n", aDesiredSize.mMaximumWidth);
 | 
						|
 | 
						|
#endif
 | 
						|
  NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
PRIntn
 | 
						|
nsFieldSetFrame::GetSkipSides() const
 | 
						|
{
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
NS_IMETHODIMP
 | 
						|
nsFieldSetFrame::AppendFrames(nsIPresContext* aPresContext,
 | 
						|
                      nsIPresShell&   aPresShell,
 | 
						|
                      nsIAtom*        aListName,
 | 
						|
                      nsIFrame*       aFrameList)
 | 
						|
{
 | 
						|
  return mContentFrame->AppendFrames(aPresContext,
 | 
						|
                                     aPresShell,
 | 
						|
                                     aListName,
 | 
						|
                                     aFrameList);
 | 
						|
}
 | 
						|
 | 
						|
NS_IMETHODIMP
 | 
						|
nsFieldSetFrame::InsertFrames(nsIPresContext* aPresContext,
 | 
						|
                      nsIPresShell&   aPresShell,
 | 
						|
                      nsIAtom*        aListName,
 | 
						|
                      nsIFrame*       aPrevFrame,
 | 
						|
                      nsIFrame*       aFrameList)
 | 
						|
{
 | 
						|
  return mContentFrame->InsertFrames(aPresContext,
 | 
						|
                                     aPresShell,
 | 
						|
                                     aListName,
 | 
						|
                                     aPrevFrame,
 | 
						|
                                     aFrameList);
 | 
						|
}
 | 
						|
 | 
						|
NS_IMETHODIMP
 | 
						|
nsFieldSetFrame::RemoveFrame(nsIPresContext* aPresContext,
 | 
						|
                     nsIPresShell&   aPresShell,
 | 
						|
                     nsIAtom*        aListName,
 | 
						|
                     nsIFrame*       aOldFrame)
 | 
						|
{
 | 
						|
  // XXX XXX
 | 
						|
  // XXX temporary fix for bug 70648
 | 
						|
  if (aOldFrame == mLegendFrame) {   
 | 
						|
    nsIFrame* sibling = mContentFrame->GetNextSibling();
 | 
						|
    NS_ASSERTION(sibling == mLegendFrame, "legendFrame is not next sibling");
 | 
						|
    NS_ASSERTION(mLegendFrame->GetParent() == this, "Legend Parent has wrong parent");
 | 
						|
    nsIFrame* legendSibling = sibling->GetNextSibling();
 | 
						|
    // replace the legend, which is the next sibling, with any siblings of the legend (XXX always null?)
 | 
						|
    mContentFrame->SetNextSibling(legendSibling);
 | 
						|
    // OK, the legend is now removed from the sibling list, but who has ownership of it?
 | 
						|
    mLegendFrame->Destroy(aPresContext);
 | 
						|
    mLegendFrame = nsnull;
 | 
						|
    return NS_OK;
 | 
						|
  } else {
 | 
						|
    return mContentFrame->RemoveFrame (aPresContext,
 | 
						|
                                       aPresShell,
 | 
						|
                                       aListName,
 | 
						|
                                       aOldFrame);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
NS_IMETHODIMP
 | 
						|
nsFieldSetFrame::ReplaceFrame(nsIPresContext* aPresContext,
 | 
						|
                     nsIPresShell&   aPresShell,
 | 
						|
                     nsIAtom*        aListName,
 | 
						|
                     nsIFrame*       aOldFrame,
 | 
						|
                     nsIFrame*       aNewFrame)
 | 
						|
{
 | 
						|
  return mContentFrame->ReplaceFrame (aPresContext,
 | 
						|
                                     aPresShell,
 | 
						|
                                     aListName,
 | 
						|
                                     aOldFrame,
 | 
						|
                                     aNewFrame);
 | 
						|
}
 | 
						|
 | 
						|
NS_IMETHODIMP
 | 
						|
nsFieldSetFrame::GetFrameForPoint(nsIPresContext*   aPresContext,
 | 
						|
                     const nsPoint&    aPoint, 
 | 
						|
                     nsFramePaintLayer aWhichLayer,
 | 
						|
                     nsIFrame**        aFrame)
 | 
						|
{
 | 
						|
  // this should act like a block, so we need to override
 | 
						|
  return GetFrameForPointUsing(aPresContext, aPoint, nsnull, aWhichLayer, (aWhichLayer == NS_FRAME_PAINT_LAYER_BACKGROUND), aFrame);
 | 
						|
}
 | 
						|
 | 
						|
#ifdef ACCESSIBILITY
 | 
						|
NS_IMETHODIMP nsFieldSetFrame::GetAccessible(nsIAccessible** aAccessible)
 | 
						|
{
 | 
						|
  nsCOMPtr<nsIAccessibilityService> accService = do_GetService("@mozilla.org/accessibilityService;1");
 | 
						|
 | 
						|
  if (accService) {
 | 
						|
    return accService->CreateHTMLGroupboxAccessible(NS_STATIC_CAST(nsIFrame*, this), aAccessible);
 | 
						|
  }
 | 
						|
 | 
						|
  return NS_ERROR_FAILURE;
 | 
						|
}
 | 
						|
#endif
 |