/* -*- 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):
 *    Travis Bogard <travis@netscape.com> 
 *    Håkan Waara <hwaara@chello.se>
 *
 * 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 ***** */
#include "nsCOMPtr.h"
#include "nsLeafFrame.h"
#include "nsHTMLContainerFrame.h"
#include "nsIHTMLContent.h"
#include "nsIWebShell.h"
#include "nsIDocShell.h"
#include "nsIDocShellLoadInfo.h"
#include "nsIDocShellTreeItem.h"
#include "nsIDocShellTreeNode.h"
#include "nsIDocShellTreeOwner.h"
#include "nsIWebNavigation.h"
#include "nsIBaseWindow.h"
#include "nsIContentViewer.h"
#include "nsIMarkupDocumentViewer.h"
#include "nsIPresContext.h"
#include "nsIPresShell.h"
#include "nsHTMLIIDs.h"
#include "nsIComponentManager.h"
#include "nsIStreamListener.h"
#include "nsIURL.h"
#include "nsNetUtil.h"
#include "nsIDocument.h"
#include "nsIView.h"
#include "nsIViewManager.h"
#include "nsWidgetsCID.h"
#include "nsViewsCID.h"
#include "nsHTMLAtoms.h"
#include "nsIScrollableView.h"
#include "nsStyleCoord.h"
#include "nsIStyleContext.h"
#include "nsStyleConsts.h"
#include "nsIDocumentLoader.h"
#include "nsIPref.h"
#include "nsFrameSetFrame.h"
#include "nsIDOMHTMLFrameElement.h"
#include "nsIDOMHTMLIFrameElement.h"
#include "nsLayoutAtoms.h"
#include "nsIChromeEventHandler.h"
#include "nsIScriptSecurityManager.h"
#include "nsICodebasePrincipal.h"
#include "nsXPIDLString.h"
#include "nsIScrollable.h"
#include "nsINameSpaceManager.h"
#include "nsIPrintContext.h"
#include "nsIPrintPreviewContext.h"
#include "nsIWidget.h"
#include "nsIWebProgress.h"
#include "nsIWebProgressListener.h"
#include "nsWeakReference.h"
#include "nsIDOMEventTarget.h"
#include "nsIDOMEventListener.h"
#include "nsIDOMWindow.h"
#include "nsIRenderingContext.h"

// For Accessibility 
#ifdef ACCESSIBILITY
#include "nsIAccessibilityService.h"
#endif
#include "nsIServiceManager.h"

class nsHTMLFrame;

static NS_DEFINE_IID(kIFramesetFrameIID, NS_IFRAMESETFRAME_IID);
static NS_DEFINE_CID(kWebShellCID, NS_WEB_SHELL_CID);
static NS_DEFINE_CID(kCViewCID, NS_VIEW_CID);
static NS_DEFINE_CID(kCChildCID, NS_CHILD_CID);

// Bug 8065: Limit content frame depth to some reasonable level.
//           This does not count chrome frames when determining depth,
//           nor does it prevent chrome recursion.
//           Also see bug 126466.
#define MAX_DEPTH_CONTENT_FRAMES 8

/*******************************************************************************
 * FrameLoadingInfo 
 ******************************************************************************/
class FrameLoadingInfo : public nsISupports
{
public:
  FrameLoadingInfo(const nsSize& aSize);

  // nsISupports interface...
  NS_DECL_ISUPPORTS

protected:
  virtual ~FrameLoadingInfo() {}

public:
  nsSize mFrameSize;
};


/*******************************************************************************
 * nsHTMLFrameOuterFrame
 ******************************************************************************/
#define nsHTMLFrameOuterFrameSuper nsHTMLContainerFrame

class nsHTMLFrameOuterFrame : public nsHTMLFrameOuterFrameSuper {

public:
  nsHTMLFrameOuterFrame();

#ifdef DEBUG
  NS_IMETHOD GetFrameName(nsAString& aResult) const;
#endif

  // nsISupports   
  NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr);

  NS_IMETHOD GetFrameType(nsIAtom** aType) const;

  NS_IMETHOD Paint(nsIPresContext*      aPresContext,
                   nsIRenderingContext& aRenderingContext,
                   const nsRect&        aDirtyRect,
                   nsFramePaintLayer    aWhichLayer,
                   PRUint32             aFlags);

  NS_IMETHOD Init(nsIPresContext*  aPresContext,
                  nsIContent*      aContent,
                  nsIFrame*        aParent,
                  nsIStyleContext* aContext,
                  nsIFrame*        aPrevInFlow);

  NS_IMETHOD Reflow(nsIPresContext*          aPresContext,
                    nsHTMLReflowMetrics&     aDesiredSize,
                    const nsHTMLReflowState& aReflowState,
                    nsReflowStatus&          aStatus);

  NS_IMETHOD AttributeChanged(nsIPresContext* aPresContext,
                              nsIContent* aChild,
                              PRInt32 aNameSpaceID,
                              nsIAtom* aAttribute,
                              PRInt32 aModType, 
                              PRInt32 aHint);

#ifdef ACCESSIBILITY
  NS_IMETHOD GetAccessible(nsIAccessible** aAccessible);
#endif

  NS_IMETHOD  VerifyTree() const;
  PRBool IsInline();

protected:
  virtual ~nsHTMLFrameOuterFrame();
  virtual void GetDesiredSize(nsIPresContext* aPresContext,
                              const nsHTMLReflowState& aReflowState,
                              nsHTMLReflowMetrics& aDesiredSize);
  virtual PRIntn GetSkipSides() const;
  PRBool mIsInline;
  nsCOMPtr<nsIPresContext> mPresContext;
};

/*******************************************************************************
 * nsHTMLFrameInnerFrame
 ******************************************************************************/
class nsHTMLFrameInnerFrame : public nsLeafFrame,
                              public nsIWebProgressListener,
                              public nsSupportsWeakReference
{
public:
  nsHTMLFrameInnerFrame();

  NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr);
  NS_IMETHOD_(nsrefcnt) AddRef(void) { return 2; }
  NS_IMETHOD_(nsrefcnt) Release(void) { return 1; }

  NS_DECL_NSIWEBPROGRESSLISTENER

#ifdef DEBUG
  NS_IMETHOD GetFrameName(nsAString& aResult) const;
#endif

  NS_IMETHOD GetFrameType(nsIAtom** aType) const;
  NS_IMETHOD Destroy(nsIPresContext* aPresContext);

  /**
    * @see nsIFrame::Paint
    */
  NS_IMETHOD Paint(nsIPresContext*      aPresContext,
                   nsIRenderingContext& aRenderingContext,
                   const nsRect&        aDirtyRect,
                   nsFramePaintLayer    aWhichLayer,
                   PRUint32             aFlags);

  /**
    * @see nsIFrame::Reflow
    */
  NS_IMETHOD Reflow(nsIPresContext*          aCX,
                    nsHTMLReflowMetrics&     aDesiredSize,
                    const nsHTMLReflowState& aReflowState,
                    nsReflowStatus&          aStatus);

  NS_IMETHOD DidReflow(nsIPresContext*           aPresContext,
                       const nsHTMLReflowState*  aReflowState,
                       nsDidReflowStatus         aStatus);

  NS_IMETHOD Init(nsIPresContext*  aPresContext,
                  nsIContent*      aContent,
                  nsIFrame*        aParent,
                  nsIStyleContext* aContext,
                  nsIFrame*        aPrevInFlow);

  NS_IMETHOD GetParentContent(nsIContent*& aContent);
  PRBool GetURL(nsIContent* aContent, nsString& aResult);
  PRBool GetName(nsIContent* aContent, nsString& aResult);
  PRInt32 GetScrolling(nsIContent* aContent);
  nsFrameborder GetFrameBorder();
  PRInt32 GetMarginWidth(nsIPresContext* aPresContext, nsIContent* aContent);
  PRInt32 GetMarginHeight(nsIPresContext* aPresContext, nsIContent* aContent);

  nsresult ReloadURL(nsIPresContext* aPresContext);

friend class nsHTMLFrameOuterFrame;

protected:
  nsresult CreateDocShell(nsIPresContext* aPresContext);
  nsresult DoLoadURL(nsIPresContext* aPresContext);
  nsresult CreateViewAndWidget(nsIPresContext* aPresContext,
                               nsIWidget**     aWidget);

  virtual void GetDesiredSize(nsIPresContext* aPresContext,
                              const nsHTMLReflowState& aReflowState,
                              nsHTMLReflowMetrics& aDesiredSize);

  nsCOMPtr<nsIBaseWindow> mSubShell;
  nsWeakPtr mPresShellWeak;   // weak reference to the nsIPresShell
  PRBool mCreatingViewer;
};


/*******************************************************************************
 * nsHTMLFrameOuterFrame
 ******************************************************************************/
nsHTMLFrameOuterFrame::nsHTMLFrameOuterFrame()
  : nsHTMLContainerFrame()
{
  mIsInline = PR_FALSE;
}

nsHTMLFrameOuterFrame::~nsHTMLFrameOuterFrame()
{
  //printf("nsHTMLFrameOuterFrame destructor %X \n", this);
}

#ifdef ACCESSIBILITY
NS_IMETHODIMP nsHTMLFrameOuterFrame::GetAccessible(nsIAccessible** aAccessible)
{
  nsCOMPtr<nsIAccessibilityService> accService = do_GetService("@mozilla.org/accessibilityService;1");

  if (accService) {
    nsCOMPtr<nsIDOMNode> node = do_QueryInterface(mContent);
    return accService->CreateIFrameAccessible(node, aAccessible);
  }

  return NS_ERROR_FAILURE;
}
#endif

//--------------------------------------------------------------
// Frames are not refcounted, no need to AddRef
NS_IMETHODIMP
nsHTMLFrameOuterFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr)
{
  NS_PRECONDITION(0 != aInstancePtr, "null ptr");
  if (NULL == aInstancePtr) {
    return NS_ERROR_NULL_POINTER;
  }

  return nsHTMLFrameOuterFrameSuper::QueryInterface(aIID, aInstancePtr);
}

NS_IMETHODIMP
nsHTMLFrameOuterFrame::Init(nsIPresContext*  aPresContext,
                            nsIContent*      aContent,
                            nsIFrame*        aParent,
                            nsIStyleContext* aContext,
                            nsIFrame*        aPrevInFlow)
{
  mPresContext = aPresContext;
  // determine if we are a <frame> or <iframe>
  if (aContent) {
    nsCOMPtr<nsIDOMHTMLFrameElement> frameElem = do_QueryInterface(aContent);
    mIsInline = frameElem ? PR_FALSE : PR_TRUE;
  }

  nsresult rv =  nsHTMLFrameOuterFrameSuper::Init(aPresContext, aContent, aParent,
                                                  aContext, aPrevInFlow);
  if (NS_FAILED(rv))
    return rv;

  // nsHTMLFrameInnerFrame is going to create a view for its frame
  // right away, in the call to Init().  If we need a view for the
  // OuterFrame but we wait for the normal view creation path in
  // nsCSSFrameConstructor, then we will lose because the InnerFrame's
  // view's parent will already have been set to some outer view
  // (e.g., the canvas) when it really needs to have the OuterFrame's
  // view as its parent. So, create the OuterFrame's view right away
  // if we need it, and the InnerFrame's view will get it as the parent.
  nsIView* view = nsnull;
  GetView(aPresContext, &view);
  if (!view) {
    nsHTMLContainerFrame::CreateViewForFrame(aPresContext,this,mStyleContext,nsnull,PR_TRUE); 
    GetView(aPresContext, &view);
  }

  const nsStyleDisplay* disp;
  aParent->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)disp));
  if (disp->mDisplay == NS_STYLE_DISPLAY_DECK) {
    nsCOMPtr<nsIWidget> widget;
    view->GetWidget(*getter_AddRefs(widget));

    if (!widget)
      view->CreateWidget(kCChildCID);   
  }

  nsCOMPtr<nsIPresShell> shell;
  aPresContext->GetShell(getter_AddRefs(shell));
  nsIFrame* firstChild = new (shell.get()) nsHTMLFrameInnerFrame;
  if (firstChild) {
    mFrames.SetFrames(firstChild);
    // Resolve the style context for the inner frame
    nsresult rv = NS_OK;
    nsIStyleContext *innerStyleContext = nsnull;
    rv = aPresContext->ResolveStyleContextFor(mContent, mStyleContext,
                                              &innerStyleContext);
    if (NS_SUCCEEDED(rv)) {
      rv = firstChild->Init(aPresContext, mContent, this, innerStyleContext, nsnull);
      // have to release the context: Init does its own AddRef...
      NS_RELEASE(innerStyleContext);
    } else {
      NS_WARNING( "Error resolving style for InnerFrame in nsHTMLFrameOuterFrame");
    }
    if (NS_FAILED(rv)){
      NS_WARNING( "Error initializing InnerFrame in nsHTMLFrameOuterFrame");
      return rv;
    }
  } else {
    NS_WARNING("no memory allocating inner frame in nsHTMLFrameOuterFrame");
    return NS_ERROR_OUT_OF_MEMORY;
  }

  return NS_OK;
}

PRIntn
nsHTMLFrameOuterFrame::GetSkipSides() const
{
  return 0;
}

void 
nsHTMLFrameOuterFrame::GetDesiredSize(nsIPresContext* aPresContext,
                                      const nsHTMLReflowState& aReflowState,
                                      nsHTMLReflowMetrics& aDesiredSize)
{
  // <frame> processing does not use this routine, only <iframe>
  float p2t;
  aPresContext->GetScaledPixelsToTwips(&p2t);

  // If no width/height was specified, use 300/150.
  // This is for compatability with IE.
  if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedWidth) {
    aDesiredSize.width = aReflowState.mComputedWidth;
  }
  else {
    aDesiredSize.width = NSIntPixelsToTwips(300, p2t);
  }
  if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedHeight) {
    aDesiredSize.height = aReflowState.mComputedHeight;
  }
  else {
    aDesiredSize.height = NSIntPixelsToTwips(150, p2t);
  }
  aDesiredSize.ascent = aDesiredSize.height;
  aDesiredSize.descent = 0;

  // For unknown reasons, the maxElementSize for the InnerFrame is used, but the
  // maxElementSize for the OuterFrame is ignored, the following is not used!
  if (aDesiredSize.maxElementSize) {
    aDesiredSize.maxElementSize->width = aDesiredSize.width;
    aDesiredSize.maxElementSize->height = aDesiredSize.height;
  }
}

PRBool nsHTMLFrameOuterFrame::IsInline()
{ 
  return mIsInline;
}

NS_IMETHODIMP
nsHTMLFrameOuterFrame::Paint(nsIPresContext*      aPresContext,
                             nsIRenderingContext& aRenderingContext,
                             const nsRect&        aDirtyRect,
                             nsFramePaintLayer    aWhichLayer,
                             PRUint32             aFlags)
{
  PRBool isVisible;
  if (NS_SUCCEEDED(IsVisibleForPainting(aPresContext, aRenderingContext, PR_TRUE, &isVisible)) && !isVisible) {
    return NS_OK;
  }

  //printf("outer paint %X (%d,%d,%d,%d) \n", this, aDirtyRect.x, aDirtyRect.y, aDirtyRect.width, aDirtyRect.height);
  nsIFrame* firstChild = mFrames.FirstChild();
  if (nsnull != firstChild) {
    firstChild->Paint(aPresContext, aRenderingContext, aDirtyRect,
                      aWhichLayer);
  }
  if (IsInline()) {
    return nsHTMLContainerFrame::Paint(aPresContext, aRenderingContext,
                                       aDirtyRect, aWhichLayer);
  } else {
    return NS_OK;
  }
}

#ifdef DEBUG
NS_IMETHODIMP nsHTMLFrameOuterFrame::GetFrameName(nsAString& aResult) const
{
  return MakeFrameName(NS_LITERAL_STRING("FrameOuter"), aResult);
}
#endif

NS_IMETHODIMP
nsHTMLFrameOuterFrame::GetFrameType(nsIAtom** aType) const
{
  NS_PRECONDITION(nsnull != aType, "null OUT parameter pointer");
  *aType = nsLayoutAtoms::htmlFrameOuterFrame; 
  NS_ADDREF(*aType);
  return NS_OK;
}

NS_IMETHODIMP
nsHTMLFrameOuterFrame::Reflow(nsIPresContext*          aPresContext,
                              nsHTMLReflowMetrics&     aDesiredSize,
                              const nsHTMLReflowState& aReflowState,
                              nsReflowStatus&          aStatus)
{
  DO_GLOBAL_REFLOW_COUNT("nsHTMLFrameOuterFrame", aReflowState.reason);
  DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
  //printf("OuterFrame::Reflow %X (%d,%d) \n", this, aReflowState.availableWidth, aReflowState.availableHeight); 
  NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
     ("enter nsHTMLFrameOuterFrame::Reflow: maxSize=%d,%d reason=%d",
      aReflowState.availableWidth, aReflowState.availableHeight, aReflowState.reason));

  if (IsInline()) {
    GetDesiredSize(aPresContext, aReflowState, aDesiredSize); // IFRAME
  } else {
    aDesiredSize.width  = aReflowState.availableWidth; // FRAME
    aDesiredSize.height = aReflowState.availableHeight;
    if (aDesiredSize.maxElementSize) { // Probably not used...
      aDesiredSize.maxElementSize->width = aDesiredSize.width;
      aDesiredSize.maxElementSize->height = aDesiredSize.height;
    }
  }

  nsSize innerSize(aDesiredSize.width, aDesiredSize.height);
  nsPoint offset(0,0);
  nsMargin border = aReflowState.mComputedBorderPadding;
  if (IsInline()) {
    offset.x = border.left;
    offset.y = border.top;
    // XXX Don't subtract the border!!! The size we are given does not include our
    // border! -EDV
    //innerSize.width  -= border.left + border.right;
    //innerSize.height -= border.top  + border.bottom;

    // we now need to add our border in. -EDV
    aDesiredSize.width += border.left + border.right;
    aDesiredSize.height += border.top + border.bottom;
  }

  // Reflow the child and get its desired size
  nsIFrame* firstChild = mFrames.FirstChild();
  nsHTMLReflowMetrics kidMetrics(aDesiredSize.maxElementSize);
  nsHTMLReflowState   kidReflowState(aPresContext, aReflowState, firstChild,
                                     innerSize);
  ReflowChild(firstChild, aPresContext, kidMetrics, kidReflowState,
              offset.x, offset.y, 0, aStatus);
  NS_ASSERTION(NS_FRAME_IS_COMPLETE(aStatus), "bad status");

  // For unknown reasons, the maxElementSize for the InnerFrame is used, but the
  // maxElementSize for the OuterFrame is ignored, add in border here to prevent
  // a table from shrinking inside the iframe's border when resized.
  if (IsInline()) {
    if (kidMetrics.maxElementSize) {
      kidMetrics.maxElementSize->width += border.left + border.right;
      kidMetrics.maxElementSize->height += border.top + border.bottom;
    }
  }

  // Place and size the child
  FinishReflowChild(firstChild, aPresContext, nsnull, 
                    kidMetrics, offset.x, offset.y, 0);

  NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
     ("exit nsHTMLFrameOuterFrame::Reflow: size=%d,%d status=%x",
      aDesiredSize.width, aDesiredSize.height, aStatus));

  return NS_OK;
}

NS_IMETHODIMP
nsHTMLFrameOuterFrame::VerifyTree() const
{
  // XXX Completely disabled for now; once pseud-frames are reworked
  // then we can turn it back on.
  return NS_OK;
}

NS_IMETHODIMP
nsHTMLFrameOuterFrame::AttributeChanged(nsIPresContext* aPresContext,
                                        nsIContent* aChild,
                                        PRInt32 aNameSpaceID,
                                        nsIAtom* aAttribute,
                                        PRInt32 aModType, 
                                        PRInt32 aHint)
{
  nsCOMPtr<nsIAtom> type;
  aChild->GetTag(*getter_AddRefs(type));

  if (((nsHTMLAtoms::src == aAttribute) && (nsHTMLAtoms::object != type)) ||
     ((nsHTMLAtoms::data == aAttribute) && (nsHTMLAtoms::object == type))) {
    nsHTMLFrameInnerFrame* firstChild = NS_STATIC_CAST(nsHTMLFrameInnerFrame*,
                                        mFrames.FirstChild());
    if (firstChild) {
      firstChild->ReloadURL(aPresContext);
    }
  }
  // If the noResize attribute changes, dis/allow frame to be resized
  else if (nsHTMLAtoms::noresize == aAttribute) {
    nsCOMPtr<nsIContent> parentContent;
    mContent->GetParent(*getter_AddRefs(parentContent));

    nsCOMPtr<nsIAtom> parentTag;
    parentContent->GetTag(*getter_AddRefs(parentTag));

    if (nsHTMLAtoms::frameset == parentTag) {
      nsIFrame* parentFrame = nsnull;
      GetParent(&parentFrame);

      if (parentFrame) {
        // There is no interface for kIFramesetFrameIID
        // so QI'ing to concrete class, yay!
        nsHTMLFramesetFrame* framesetFrame = nsnull;
        parentFrame->QueryInterface(kIFramesetFrameIID, (void **)&framesetFrame);
        if (framesetFrame) {
          framesetFrame->RecalculateBorderResize();
        }
      }
    }
  }
  else if (aAttribute == nsHTMLAtoms::type) {
    nsHTMLFrameInnerFrame* firstChild = NS_STATIC_CAST(nsHTMLFrameInnerFrame*,
                                        mFrames.FirstChild());
    if (!firstChild)
      return NS_OK;

    nsAutoString value;
    aChild->GetAttr(kNameSpaceID_None, nsHTMLAtoms::type, value);
    
    // Notify our enclosing chrome that the primary content shell
    // has changed.
    nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(firstChild->mSubShell));
    nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(firstChild->mSubShell));
  
    // If our container is a web-shell, inform it that it has a new
    // child. If it's not a web-shell then some things will not operate
    // properly.
    nsCOMPtr<nsISupports> container;
    aPresContext->GetContainer(getter_AddRefs(container));
    if (container) {
      nsCOMPtr<nsIDocShellTreeNode> parentAsNode(do_QueryInterface(container));
      if (parentAsNode) {
        nsCOMPtr<nsIDocShellTreeItem> parentAsItem(do_QueryInterface(parentAsNode));
        
        nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner;
        parentAsItem->GetTreeOwner(getter_AddRefs(parentTreeOwner));
        if (parentTreeOwner)
          parentTreeOwner->ContentShellAdded(docShellAsItem, 
            value.EqualsIgnoreCase("content-primary") ? PR_TRUE : PR_FALSE, 
            value.get());
      }
    }
  }
  return NS_OK;
}

nsresult
NS_NewHTMLFrameOuterFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame)
{
  NS_PRECONDITION(aNewFrame, "null OUT ptr");
  if (nsnull == aNewFrame) {
    return NS_ERROR_NULL_POINTER;
  }
  nsHTMLFrameOuterFrame* it = new (aPresShell) nsHTMLFrameOuterFrame;
  if (!it) {
    return NS_ERROR_OUT_OF_MEMORY;
  }
  *aNewFrame = it;
  return NS_OK;
}

/*******************************************************************************
 * nsHTMLFrameInnerFrame
 ******************************************************************************/
nsHTMLFrameInnerFrame::nsHTMLFrameInnerFrame()
  : nsLeafFrame()
{
  mCreatingViewer = PR_FALSE;
  mPresShellWeak = nsnull;
}


NS_IMETHODIMP
nsHTMLFrameInnerFrame::Destroy(nsIPresContext* aPresContext)
{
   //printf("nsHTMLFrameInnerFrame destructor %X \n", this);

  nsCOMPtr<nsIDOMWindow> win(do_GetInterface(mSubShell));
  nsCOMPtr<nsIDOMEventTarget> eventTarget(do_QueryInterface(win));
  nsCOMPtr<nsIDOMEventListener> eventListener(do_QueryInterface(mContent));

  if (eventTarget && eventListener) {
    eventTarget->RemoveEventListener(NS_LITERAL_STRING("load"), eventListener,
                                     PR_FALSE);
  }

  if(mSubShell) {
  // notify the pres shell that a docshell has been destroyed
    if (mPresShellWeak) {
      nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak);
      if (ps) {
        ps->SetSubShellFor(mContent, nsnull);
      }
    }
    mSubShell->Destroy();
  }
  mSubShell = nsnull; // This is the location it was released before...
                      // Not sure if there is ordering depending on this.

  return nsLeafFrame::Destroy(aPresContext);
}

PRBool nsHTMLFrameInnerFrame::GetURL(nsIContent* aContent, nsString& aResult)
{
  aResult.SetLength(0);    
  nsCOMPtr<nsIAtom> type;
  aContent->GetTag(*getter_AddRefs(type));
  
  if (type.get() == nsHTMLAtoms::object) {
    if (NS_CONTENT_ATTR_HAS_VALUE == (aContent->GetAttr(kNameSpaceID_None, nsHTMLAtoms::data, aResult)))
      if (aResult.Length() > 0)
        return PR_TRUE;
  }else
    if (NS_CONTENT_ATTR_HAS_VALUE == (aContent->GetAttr(kNameSpaceID_None, nsHTMLAtoms::src, aResult)))
      if (aResult.Length() > 0)
        return PR_TRUE;

  return PR_FALSE;
}

PRBool nsHTMLFrameInnerFrame::GetName(nsIContent* aContent, nsString& aResult)
{
  aResult.SetLength(0);     

  if (NS_CONTENT_ATTR_HAS_VALUE == (aContent->GetAttr(kNameSpaceID_None, nsHTMLAtoms::name, aResult))) {
    if (aResult.Length() > 0) {
      return PR_TRUE;
    }
  }

  return PR_FALSE;
}

PRInt32 nsHTMLFrameInnerFrame::GetScrolling(nsIContent* aContent)
{
  PRInt32 returnValue = -1;
  nsresult rv = NS_OK;
  nsCOMPtr<nsIHTMLContent> content = do_QueryInterface(mContent, &rv);

  if (NS_SUCCEEDED(rv) && content) {
    nsHTMLValue value;
    if (NS_CONTENT_ATTR_HAS_VALUE == content->GetHTMLAttribute(nsHTMLAtoms::scrolling, value)) {
      if (eHTMLUnit_Enumerated == value.GetUnit()) {
        switch (value.GetIntValue()) {
          case NS_STYLE_FRAME_ON:
          case NS_STYLE_FRAME_SCROLL:
          case NS_STYLE_FRAME_YES:
            returnValue = NS_STYLE_OVERFLOW_SCROLL;
            break;

          case NS_STYLE_FRAME_OFF:
          case NS_STYLE_FRAME_NOSCROLL:
          case NS_STYLE_FRAME_NO:
            returnValue = NS_STYLE_OVERFLOW_HIDDEN;
            break;
        
          case NS_STYLE_FRAME_AUTO:
          default:
            returnValue = NS_STYLE_OVERFLOW_AUTO;
            break;
        }
      }      
    }

    // Check style for overflow
    const nsStyleDisplay* display;
    GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)display));
    if (display->mOverflow)
      returnValue = display->mOverflow;
  }
  return returnValue;
}

nsFrameborder nsHTMLFrameInnerFrame::GetFrameBorder()
{
  nsFrameborder rv = eFrameborder_Notset;
  nsresult res = NS_OK;
  nsCOMPtr<nsIHTMLContent> content = do_QueryInterface(mContent, &res);
  if (NS_SUCCEEDED(res) && content) {
    nsHTMLValue value;
    if (NS_CONTENT_ATTR_HAS_VALUE == (content->GetHTMLAttribute(nsHTMLAtoms::frameborder, value))) {
      if (eHTMLUnit_Enumerated == value.GetUnit()) {
        switch (value.GetIntValue())
        {
          case NS_STYLE_FRAME_1:
          case NS_STYLE_FRAME_YES:
            rv = eFrameborder_Yes;
            break;
          
          case NS_STYLE_FRAME_0:
          case NS_STYLE_FRAME_NO:
            rv = eFrameborder_No;
            break;
        }
      }
    }
  }
  // XXX if we get here, check for nsIDOMFRAMESETElement interface
  return rv;
}


PRInt32 nsHTMLFrameInnerFrame::GetMarginWidth(nsIPresContext* aPresContext, nsIContent* aContent)
{
  PRInt32 marginWidth = -1;
  nsresult rv = NS_OK;
  nsCOMPtr<nsIHTMLContent> content = do_QueryInterface(mContent, &rv);
  if (NS_SUCCEEDED(rv) && content) {
    nsHTMLValue value;
    content->GetHTMLAttribute(nsHTMLAtoms::marginwidth, value);
    if (eHTMLUnit_Pixel == value.GetUnit())
      return value.GetPixelValue();
  }
  return marginWidth;
}

PRInt32 nsHTMLFrameInnerFrame::GetMarginHeight(nsIPresContext* aPresContext, nsIContent* aContent)
{
  PRInt32 marginHeight = -1;
  nsresult rv = NS_OK;
  nsCOMPtr<nsIHTMLContent> content = do_QueryInterface(mContent, &rv);
  if (NS_SUCCEEDED(rv) && content) {
    nsHTMLValue value;
    content->GetHTMLAttribute(nsHTMLAtoms::marginheight, value);
    if (eHTMLUnit_Pixel == value.GetUnit())
      return value.GetPixelValue();
  }
  return marginHeight;
}

NS_IMETHODIMP
nsHTMLFrameInnerFrame::QueryInterface(REFNSIID aIID, void** aInstancePtr)
{
  NS_ENSURE_ARG_POINTER(aInstancePtr);

  if (aIID.Equals(NS_GET_IID(nsIWebProgressListener))) {
    nsISupports *tmp = NS_STATIC_CAST(nsIWebProgressListener *, this);
    *aInstancePtr = tmp;
    return NS_OK;
  }

  if (aIID.Equals(NS_GET_IID(nsISupportsWeakReference))) {
    nsISupports *tmp = NS_STATIC_CAST(nsISupportsWeakReference *, this);
    *aInstancePtr = tmp;
    return NS_OK;
  }

  return nsLeafFrame::QueryInterface(aIID, aInstancePtr);
}

NS_IMETHODIMP
nsHTMLFrameInnerFrame::OnStateChange(nsIWebProgress *aWebProgress,
                                     nsIRequest *aRequest,
                                     PRUint32 aStateFlags, nsresult aStatus)
{
  if (!((~aStateFlags) & (nsIWebProgressListener::STATE_IS_DOCUMENT |
                          nsIWebProgressListener::STATE_TRANSFERRING))) {
    nsCOMPtr<nsIDOMWindow> win(do_GetInterface(mSubShell));
    nsCOMPtr<nsIDOMEventTarget> eventTarget(do_QueryInterface(win));
    nsCOMPtr<nsIDOMEventListener> eventListener(do_QueryInterface(mContent));

    if (eventTarget && eventListener) {
      eventTarget->AddEventListener(NS_LITERAL_STRING("load"), eventListener,
                                    PR_FALSE);
    }
  }

  return NS_OK;
}

NS_IMETHODIMP
nsHTMLFrameInnerFrame::OnProgressChange(nsIWebProgress *aWebProgress,
                                        nsIRequest *aRequest,
                                        PRInt32 aCurSelfProgress,
                                        PRInt32 aMaxSelfProgress,
                                        PRInt32 aCurTotalProgress,
                                        PRInt32 aMaxTotalProgress)
{
  return NS_OK;
}

NS_IMETHODIMP
nsHTMLFrameInnerFrame::OnLocationChange(nsIWebProgress *aWebProgress,
                                        nsIRequest *aRequest, nsIURI *location)
{
  return NS_OK;
}

NS_IMETHODIMP
nsHTMLFrameInnerFrame::OnStatusChange(nsIWebProgress *aWebProgress,
                                      nsIRequest *aRequest,
                                      nsresult aStatus,
                                      const PRUnichar *aMessage)
{
  return NS_OK;
}

NS_IMETHODIMP
nsHTMLFrameInnerFrame::OnSecurityChange(nsIWebProgress *aWebProgress,
                                        nsIRequest *aRequest, PRUint32 state)
{
  return NS_OK;
}

#ifdef DEBUG
NS_IMETHODIMP nsHTMLFrameInnerFrame::GetFrameName(nsAString& aResult) const
{
  return MakeFrameName(NS_LITERAL_STRING("FrameInner"), aResult);
}
#endif

NS_IMETHODIMP
nsHTMLFrameInnerFrame::GetFrameType(nsIAtom** aType) const
{
  NS_PRECONDITION(nsnull != aType, "null OUT parameter pointer");
  *aType = nsLayoutAtoms::htmlFrameInnerFrame; 
  NS_ADDREF(*aType);
  return NS_OK;
}

NS_IMETHODIMP
nsHTMLFrameInnerFrame::Paint(nsIPresContext*      aPresContext,
                             nsIRenderingContext& aRenderingContext,
                             const nsRect&        aDirtyRect,
                             nsFramePaintLayer    aWhichLayer,
                             PRUint32             aFlags)
{
  //printf("inner paint %X (%d,%d,%d,%d) \n", this, aDirtyRect.x, aDirtyRect.y, aDirtyRect.width, aDirtyRect.height);
  // if there is not web shell paint based on our background color, 
  // otherwise let the web shell paint the sub document 

  // isPaginated is a temporary fix for Bug 75737 
  // and this should all be fixed correctly by Bug 75739
  PRBool isPaginated;
  aPresContext->IsPaginated(&isPaginated);
   if (!mSubShell && !isPaginated) {
    const nsStyleBackground* color =
      (const nsStyleBackground*)mStyleContext->GetStyleData(eStyleStruct_Background);
    aRenderingContext.SetColor(color->mBackgroundColor);
    aRenderingContext.FillRect(mRect);
  }
  DO_GLOBAL_REFLOW_COUNT_DSP("nsHTMLFrameInnerFrame", &aRenderingContext);
  return NS_OK;
}

NS_IMETHODIMP
nsHTMLFrameInnerFrame::GetParentContent(nsIContent*& aContent)
{
  nsHTMLFrameOuterFrame* parent;
  nsresult rv = GetParent((nsIFrame**)&parent);
  if (NS_SUCCEEDED(rv) && parent) {
    rv = parent->GetContent(&aContent);
  }
  return rv;
}

NS_IMETHODIMP
nsHTMLFrameInnerFrame::DidReflow(nsIPresContext*           aPresContext,
                                 const nsHTMLReflowState*  aReflowState,
                                 nsDidReflowStatus         aStatus)
{
  nsresult rv = nsLeafFrame::DidReflow(aPresContext, nsnull, aStatus);


  // The view is created hidden; once we have reflowed it and it has been
  // positioned then we show it.
  if (NS_FRAME_REFLOW_FINISHED == aStatus) {
    nsIView* view = nsnull;
    GetView(aPresContext, &view);
    if (view) {
      const nsStyleVisibility* vis;
      GetStyleData(eStyleStruct_Visibility, ((const nsStyleStruct *&)vis));
      nsViewVisibility newVis = vis->IsVisible() ? nsViewVisibility_kShow : nsViewVisibility_kHide;
      nsViewVisibility oldVis;
      // only change if different.
      view->GetVisibility(oldVis);
      if (newVis != oldVis) {
        nsCOMPtr<nsIViewManager> vm;
        view->GetViewManager(*getter_AddRefs(vm));
        if (vm != nsnull) {
          vm->SetViewVisibility(view, newVis);
        }
      }
    }
  }
  
  return rv;
}

nsresult
nsHTMLFrameInnerFrame::CreateDocShell(nsIPresContext* aPresContext)
{
  nsresult rv;
  nsCOMPtr<nsIContent> parentContent;
  GetParentContent(*getter_AddRefs(parentContent));

  // Bug 8065: Don't exceed some maximum depth in content frames (MAX_DEPTH_CONTENT_FRAMES)
  PRInt32 depth = 0;
  nsCOMPtr<nsISupports> parentAsSupports;
  aPresContext->GetContainer(getter_AddRefs(parentAsSupports));
  if (parentAsSupports) {
    nsCOMPtr<nsIDocShellTreeItem> parentAsItem(do_QueryInterface(parentAsSupports));
    while (parentAsItem) {
      depth++;
      if (MAX_DEPTH_CONTENT_FRAMES < depth) {
        NS_WARNING("Too many nested content frames so giving up");
        return NS_ERROR_UNEXPECTED; // Too deep, give up!  (silently?)
      }

      // Only count depth on content, not chrome.
      // If we wanted to limit total depth, skip the following check:
      PRInt32 parentType;
      parentAsItem->GetItemType(&parentType);
      if (nsIDocShellTreeItem::typeContent == parentType) {
        nsIDocShellTreeItem* temp = parentAsItem;
        temp->GetParent(getter_AddRefs(parentAsItem));
      } else {
        break; // we have exited content, stop counting, depth is OK!
      }
    }
  }

  mSubShell = do_CreateInstance(kWebShellCID);
  NS_ENSURE_TRUE(mSubShell, NS_ERROR_FAILURE);

  // notify the pres shell that a docshell has been created
  nsCOMPtr<nsIPresShell> presShell;
  aPresContext->GetShell(getter_AddRefs(presShell));
  if (presShell)
  {
    nsCOMPtr<nsISupports> subShellAsSupports(do_QueryInterface(mSubShell));
    NS_ENSURE_TRUE(subShellAsSupports, NS_ERROR_FAILURE);
    presShell->SetSubShellFor(mContent, subShellAsSupports);
    //We need to be able to get back to the presShell to unset the subshell at destruction
    mPresShellWeak = getter_AddRefs(NS_GetWeakReference(presShell));   
  }
  
  nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(mSubShell));
  NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
  // pass along marginwidth, marginheight, scrolling so sub document can use it
  docShell->SetMarginWidth(GetMarginWidth(aPresContext, parentContent));
  docShell->SetMarginHeight(GetMarginHeight(aPresContext, parentContent));

  // Current and initial scrolling is set so that all succeeding docs
  // will use the scrolling value set here, regardless if scrolling is
  // set by viewing a particular document (e.g. XUL turns off scrolling)
  nsCOMPtr<nsIScrollable> scrollableContainer(do_QueryInterface(mSubShell));
  if (scrollableContainer) {
    scrollableContainer->SetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_Y,
      GetScrolling(parentContent));
    scrollableContainer->SetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_X,
      GetScrolling(parentContent));
  }

  nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mSubShell));
  NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE);
  nsString frameName;
  if (GetName(parentContent, frameName)) {
    docShellAsItem->SetName(frameName.get());
  }

  // If our container is a web-shell, inform it that it has a new
  // child. If it's not a web-shell then some things will not operate
  // properly.
  nsCOMPtr<nsISupports> container;
  aPresContext->GetContainer(getter_AddRefs(container));
  if (container) {
    nsCOMPtr<nsIDocShellTreeNode> parentAsNode(do_QueryInterface(container));
    if (parentAsNode) {
      nsCOMPtr<nsIDocShellTreeItem> parentAsItem(do_QueryInterface(parentAsNode));
      PRInt32 parentType;
      parentAsItem->GetItemType(&parentType);

      nsIAtom* typeAtom = NS_NewAtom("type");
      nsAutoString value, valuePiece;
      PRBool isContent;

      isContent = PR_FALSE;
      if (NS_SUCCEEDED(parentContent->GetAttr(kNameSpaceID_None,
         typeAtom, value))) {

        // we accept "content" and "content-xxx" values.
        // at time of writing, we expect "xxx" to be "primary", but
        // someday it might be an integer expressing priority
        value.Left(valuePiece, 7);
        if (valuePiece.EqualsIgnoreCase("content") &&
           (value.Length() == 7 ||
              value.Mid(valuePiece, 7, 1) == 1 && valuePiece.Equals(NS_LITERAL_STRING("-"))))
            isContent = PR_TRUE;
      }
      NS_IF_RELEASE(typeAtom);
      if (isContent) {
        // The web shell's type is content.
        docShellAsItem->SetItemType(nsIDocShellTreeItem::typeContent);
      } else {
        // Inherit our type from our parent webshell.  If it is
        // chrome, we'll be chrome.  If it is content, we'll be
        // content.
        docShellAsItem->SetItemType(parentType);
      }
      
      parentAsNode->AddChild(docShellAsItem);

      if (isContent) {
        nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner;
        parentAsItem->GetTreeOwner(getter_AddRefs(parentTreeOwner));
        if(parentTreeOwner)
          parentTreeOwner->ContentShellAdded(docShellAsItem, 
            value.EqualsIgnoreCase("content-primary") ? PR_TRUE : PR_FALSE, 
            value.get());
      }
      // connect the container...
      nsCOMPtr<nsIWebShell> webShell(do_QueryInterface(mSubShell));
      nsCOMPtr<nsIWebShellContainer> outerContainer(do_QueryInterface(container));
      if (outerContainer)
        webShell->SetContainer(outerContainer);


      // Make sure all shells have links back to the content element in the
      // nearest enclosing chrome shell.
      nsCOMPtr<nsIDocShell> parentShell(do_QueryInterface(parentAsNode));
      nsCOMPtr<nsIChromeEventHandler> chromeEventHandler;
      if (parentType == nsIDocShellTreeItem::typeChrome) {
        // Our parent shell is a chrome shell. It is therefore our nearest
        // enclosing chrome shell.
        chromeEventHandler = do_QueryInterface(mContent);
        NS_WARN_IF_FALSE(chromeEventHandler, "This mContent should implement this.");
      }
      else {
        // Our parent shell is a content shell. Get the chrome info from
        // it and use that for our shell as well.
        parentShell->GetChromeEventHandler(getter_AddRefs(chromeEventHandler));
      }

      docShell->SetChromeEventHandler(chromeEventHandler);
    }
  }

  nsCOMPtr<nsIWidget> widget;
  rv = CreateViewAndWidget(aPresContext, getter_AddRefs(widget));
  if (NS_FAILED(rv)) {
    return rv;
  }

  mSubShell->InitWindow(nsnull, widget, 0, 0, 10, 10);
  mSubShell->Create();

  mSubShell->SetVisibility(PR_TRUE);

  return NS_OK;
}

nsresult
nsHTMLFrameInnerFrame::DoLoadURL(nsIPresContext* aPresContext)
{
  // Bug 8065: Preventing frame nesting recursion - if the frames are
  //           too deep we don't create a mSubShell, so this isn't an assert:
  if (!mSubShell) return NS_OK;

  // Prevent recursion
  mCreatingViewer=PR_TRUE;

  // Get the URL to load
  nsCOMPtr<nsIContent> parentContent;
  nsresult rv = GetParentContent(*getter_AddRefs(parentContent));
  NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && parentContent, rv);

  nsAutoString url;
  GetURL(parentContent, url);
  url.Trim(" \t\n\r");
  if (url.IsEmpty())  // Load about:blank into a frame if not URL is specified (bug 35986)
    url = NS_LITERAL_STRING("about:blank");

  // Make an absolute URL
  nsCOMPtr<nsIURI> baseURL;
  nsCOMPtr<nsIHTMLContent> htmlContent = do_QueryInterface(parentContent, &rv);
  nsCOMPtr<nsIDocument> doc;
  if (NS_SUCCEEDED(rv) && htmlContent) {
    htmlContent->GetBaseURL(*getter_AddRefs(baseURL));
    (void) htmlContent->GetDocument(*getter_AddRefs(doc));
  }
  else {
    rv = parentContent->GetDocument(*getter_AddRefs(doc));
    if (NS_SUCCEEDED(rv) && doc) {
      doc->GetBaseURL(*getter_AddRefs(baseURL));
    }
  }
  if (!baseURL) return NS_ERROR_NULL_POINTER;

  nsAutoString docCharset;
  if (doc)
    (void) doc->GetDocumentCharacterSet(docCharset);

  nsAutoString absURL;
  rv = NS_MakeAbsoluteURI(absURL, url, baseURL);
  NS_ENSURE_SUCCESS(rv, rv);

  nsCOMPtr<nsIURI> uri;
  NS_NewURI(getter_AddRefs(uri), absURL, 
            docCharset.IsEmpty() ? nsnull : NS_ConvertUCS2toUTF8(docCharset).get());

  // Check for security
  nsCOMPtr<nsIScriptSecurityManager> secMan = 
           do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
  NS_ENSURE_SUCCESS(rv, rv);

  // Get base URL
  nsCOMPtr<nsIURI> baseURI;
  rv = aPresContext->GetBaseURL(getter_AddRefs(baseURI));

  // Get docshell and create load info
  nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(mSubShell));
  NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
  nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
  docShell->CreateLoadInfo(getter_AddRefs(loadInfo));
  NS_ENSURE_TRUE(loadInfo, NS_ERROR_FAILURE);

  // Get referring URL
  nsCOMPtr<nsIURI> referrer;
  nsCOMPtr<nsIPrincipal> principal;
  rv = secMan->GetSubjectPrincipal(getter_AddRefs(principal));
  NS_ENSURE_SUCCESS(rv, rv);
  // If we were called from script, get the referring URL from the script
  if (principal) {
    nsCOMPtr<nsICodebasePrincipal> codebase = do_QueryInterface(principal);
    if (codebase) {
      rv = codebase->GetURI(getter_AddRefs(referrer));
      NS_ENSURE_SUCCESS(rv, rv);
    }
    // Pass the script principal to the docshell
    nsCOMPtr<nsISupports> owner = do_QueryInterface(principal);
    loadInfo->SetOwner(owner);
  }
  if (!referrer) { // We're not being called form script, tell the docshell
                   // to inherit an owner from the current document.
    loadInfo->SetInheritOwner(PR_TRUE);
    referrer = baseURI;
  }

  loadInfo->SetReferrer(referrer);

  // Check if we are allowed to load absURL
  nsCOMPtr<nsIURI> newURI;
  rv = NS_NewURI(getter_AddRefs(newURI), absURL, nsnull, baseURI);
  NS_ENSURE_SUCCESS(rv, rv);
  rv = secMan->CheckLoadURI(referrer, newURI, nsIScriptSecurityManager::STANDARD);
  if (NS_FAILED(rv))
    return rv; // We're not

  nsCOMPtr<nsIWebProgress> webProgress(do_GetInterface(mSubShell));

  if (webProgress) {
    webProgress->AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_DOCUMENT);
  }

  rv = docShell->LoadURI(uri, loadInfo, nsIWebNavigation::LOAD_FLAGS_NONE, PR_FALSE);
  NS_ASSERTION(NS_SUCCEEDED(rv), "failed to load URL");

  return rv;
}


nsresult
nsHTMLFrameInnerFrame::CreateViewAndWidget(nsIPresContext* aPresContext,
                                           nsIWidget**     aWidget)
{
  NS_ENSURE_ARG_POINTER(aPresContext);
  NS_ENSURE_ARG_POINTER(aWidget);

  nsCOMPtr<nsIPresShell> presShell;
  aPresContext->GetShell(getter_AddRefs(presShell));
  if (!presShell) return NS_ERROR_FAILURE;

  float t2p;
  aPresContext->GetTwipsToPixels(&t2p);

  // create, init, set the parent of the view
  nsIView* view;
  nsresult rv = nsComponentManager::CreateInstance(kCViewCID, nsnull, NS_GET_IID(nsIView),
                                        (void **)&view);

  if (NS_OK != rv) {
    NS_ASSERTION(0, "Could not create view for nsHTMLFrame");
    return rv;
  }

  nsIView* parView;
  nsPoint origin;
  GetOffsetFromView(aPresContext, origin, &parView);  
  nsRect viewBounds(origin.x, origin.y, 10, 10);

  nsCOMPtr<nsIViewManager> viewMan;
  presShell->GetViewManager(getter_AddRefs(viewMan));  
  rv = view->Init(viewMan, viewBounds, parView);
  // XXX put it at the end of the document order until we can do better
  viewMan->InsertChild(parView, view, nsnull, PR_TRUE);

  nsWidgetInitData initData;
  initData.clipChildren = PR_TRUE;
  initData.clipSiblings = PR_TRUE;

  rv = view->CreateWidget(kCChildCID, &initData);
  SetView(aPresContext, view);

  // if the visibility is hidden, reflect that in the view
  const nsStyleVisibility* vis;
  GetStyleData(eStyleStruct_Visibility, ((const nsStyleStruct *&)vis));
  if (!vis->IsVisible()) {
    viewMan->SetViewVisibility(view, nsViewVisibility_kHide);
  }
  view->GetWidget(*aWidget);
  return rv;
}

NS_IMETHODIMP
nsHTMLFrameInnerFrame::Init(nsIPresContext*  aPresContext,
                            nsIContent*      aContent,
                            nsIFrame*        aParent,
                            nsIStyleContext* aContext,
                            nsIFrame*        aPrevInFlow)
{
  nsresult rv = nsLeafFrame::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow);
  if (NS_FAILED(rv))
    return rv;

  // determine if we are a printcontext
  PRBool shouldCreateDoc = PR_TRUE;
  nsCOMPtr<nsIPrintContext> thePrinterContext = do_QueryInterface(aPresContext);
  if  (thePrinterContext) {
    // we are printing
    shouldCreateDoc = PR_FALSE;
  }

  // for print preview we want to create the view and widget but 
  // we do not want to load the document, it is alerady loaded.
  nsCOMPtr<nsIPrintPreviewContext> thePrintPreviewContext = do_QueryInterface(aPresContext);
  if  (thePrintPreviewContext) {
    nsCOMPtr<nsIWidget> widget;
    rv = CreateViewAndWidget(aPresContext, getter_AddRefs(widget));
    if (NS_FAILED(rv)) {
      return rv;
    }
    // we are in PrintPreview
    shouldCreateDoc = PR_FALSE;
  }
  
  if (!mCreatingViewer && shouldCreateDoc) {
    // create the web shell
    // we do this even if the size is not positive (bug 11762)
    // we do this even if there is no src (bug 16218)
    if (!mSubShell)
      rv = CreateDocShell(aPresContext);
    // Whether or not we had to create a webshell, load the document
    if (NS_SUCCEEDED(rv)) {
      DoLoadURL(aPresContext);
    }
  }

  return NS_OK;
}

NS_IMETHODIMP
nsHTMLFrameInnerFrame::Reflow(nsIPresContext*          aPresContext,
                              nsHTMLReflowMetrics&     aDesiredSize,
                              const nsHTMLReflowState& aReflowState,
                              nsReflowStatus&          aStatus)
{
  DO_GLOBAL_REFLOW_COUNT("nsHTMLFrameInnerFrame", aReflowState.reason);
  NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
     ("enter nsHTMLFrameInnerFrame::Reflow: maxSize=%d,%d reason=%d",
      aReflowState.availableWidth,
      aReflowState.availableHeight,
      aReflowState.reason));

  nsresult rv = NS_OK;

  // use the max size set in aReflowState by the nsHTMLFrameOuterFrame as our size

  GetDesiredSize(aPresContext, aReflowState, aDesiredSize);

  aStatus = NS_FRAME_COMPLETE;

  // resize the sub document
  if(mSubShell) {
    float t2p;
    aPresContext->GetTwipsToPixels(&t2p);

    PRInt32 x = 0;
    PRInt32 y = 0;

    mSubShell->GetPositionAndSize(&x, &y, nsnull, nsnull);
    PRInt32 cx  = NSToCoordRound(aDesiredSize.width * t2p);
    PRInt32 cy = NSToCoordRound(aDesiredSize.height * t2p);
    mSubShell->SetPositionAndSize(x, y, cx, cy, PR_FALSE);

    NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
      ("exit nsHTMLFrameInnerFrame::Reflow: size=%d,%d rv=%x",
      aDesiredSize.width, aDesiredSize.height, aStatus));
  }
    
  return rv;
}

// load a new url
nsresult
nsHTMLFrameInnerFrame::ReloadURL(nsIPresContext* aPresContext)
{
  return DoLoadURL(aPresContext);
}

void 
nsHTMLFrameInnerFrame::GetDesiredSize(nsIPresContext* aPresContext,
                                      const nsHTMLReflowState& aReflowState,
                                      nsHTMLReflowMetrics& aDesiredSize)
{
  aDesiredSize.width  = aReflowState.availableWidth;
  aDesiredSize.height = aReflowState.availableHeight;
  aDesiredSize.ascent = aDesiredSize.height;
  aDesiredSize.descent = 0;

  // For unknown reasons, the maxElementSize for the InnerFrame is used, but the
  // maxElementSize for the OuterFrame is ignored, make sure to get it right here!
  if (aDesiredSize.maxElementSize) {
    if ((NS_UNCONSTRAINEDSIZE == aReflowState.availableWidth) ||
        (eStyleUnit_Percent == aReflowState.mStylePosition->mWidth.GetUnit())) {
      aDesiredSize.maxElementSize->width = 0; // percent width springy down to 0 px
    }
    else {
      aDesiredSize.maxElementSize->width = aDesiredSize.width;
    }
    if ((NS_UNCONSTRAINEDSIZE == aReflowState.availableHeight) ||
        (eStyleUnit_Percent == aReflowState.mStylePosition->mHeight.GetUnit())) {
      aDesiredSize.maxElementSize->height = 0; // percent height springy down to 0px
    }
    else {
      aDesiredSize.maxElementSize->height = aDesiredSize.height;
    }
  }
}

/*******************************************************************************
 * FrameLoadingInfo
 ******************************************************************************/
FrameLoadingInfo::FrameLoadingInfo(const nsSize& aSize)
{
  NS_INIT_REFCNT();

  mFrameSize = aSize;
}

/*
 * Implementation of ISupports methods...
 */
NS_IMPL_ISUPPORTS0(FrameLoadingInfo)

