gecko-dev/layout/generic/nsFrameFrame.cpp
buster%netscape.com 8076fee6b0 fixed bug 27161 by adding interfacs onto nsIPresShell to get/set the "subshell" for an nsIContent
this part of the fix is temporary, but sufficient for beta.  it calls the pres shell to do the initial association.
after beta, this will be done by the frame construction code.
r=travis
a=jar
2000-03-03 23:16:43 +00:00

1007 lines
33 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* 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 Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Travis Bogard <travis@netscape.com>
*/
#include "nsCOMPtr.h"
#include "nsLeafFrame.h"
#include "nsHTMLContainerFrame.h"
#include "nsIHTMLContent.h"
#include "nsIWebShell.h"
#include "nsIDocShell.h"
#include "nsIDocShellTreeItem.h"
#include "nsIDocShellTreeNode.h"
#include "nsIDocShellTreeOwner.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 "nsGenericHTMLElement.h"
#include "nsLayoutAtoms.h"
#include "nsIChromeEventHandler.h"
#include "nsIScriptSecurityManager.h"
#include "nsIScrollable.h"
class nsHTMLFrame;
static NS_DEFINE_IID(kIWebShellContainerIID, NS_IWEB_SHELL_CONTAINER_IID);
static NS_DEFINE_IID(kIStreamObserverIID, NS_ISTREAMOBSERVER_IID);
static NS_DEFINE_IID(kIWebShellIID, NS_IWEB_SHELL_IID);
static NS_DEFINE_IID(kWebShellCID, NS_WEB_SHELL_CID);
static NS_DEFINE_IID(kIViewIID, NS_IVIEW_IID);
static NS_DEFINE_IID(kCViewCID, NS_VIEW_CID);
static NS_DEFINE_IID(kCChildCID, NS_CHILD_CID);
static NS_DEFINE_IID(kIDOMHTMLFrameElementIID, NS_IDOMHTMLFRAMEELEMENT_IID);
static NS_DEFINE_IID(kIDOMHTMLIFrameElementIID, NS_IDOMHTMLIFRAMEELEMENT_IID);
/*******************************************************************************
* 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(nsString& aResult) const;
#endif
NS_IMETHOD GetFrameType(nsIAtom** aType) const;
NS_IMETHOD Paint(nsIPresContext* aPresContext,
nsIRenderingContext& aRenderingContext,
const nsRect& aDirtyRect,
nsFramePaintLayer aWhichLayer);
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 aHint);
NS_IMETHOD VerifyTree() const;
PRBool HasBorder();
PRBool IsInline();
protected:
virtual ~nsHTMLFrameOuterFrame();
virtual void GetDesiredSize(nsIPresContext* aPresContext,
const nsHTMLReflowState& aReflowState,
nsHTMLReflowMetrics& aDesiredSize);
virtual PRIntn GetSkipSides() const;
PRBool mIsInline;
};
/*******************************************************************************
* nsHTMLFrameInnerFrame
******************************************************************************/
class nsHTMLFrameInnerFrame : public nsLeafFrame {
public:
nsHTMLFrameInnerFrame();
#ifdef DEBUG
NS_IMETHOD GetFrameName(nsString& aResult) const;
#endif
NS_IMETHOD GetFrameType(nsIAtom** aType) const;
/**
* @see nsIFrame::Paint
*/
NS_IMETHOD Paint(nsIPresContext* aPresContext,
nsIRenderingContext& aRenderingContext,
const nsRect& aDirtyRect,
nsFramePaintLayer aWhichLayer);
/**
* @see nsIFrame::Reflow
*/
NS_IMETHOD Reflow(nsIPresContext* aCX,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus);
NS_IMETHOD DidReflow(nsIPresContext* aPresContext,
nsDidReflowStatus aStatus);
NS_IMETHOD GetParentContent(nsIContent*& aContent);
PRBool GetURL(nsIContent* aContent, nsString& aResult);
PRBool GetName(nsIContent* aContent, nsString& aResult);
PRInt32 GetScrolling(nsIContent* aContent, PRBool aStandardMode);
nsFrameborder GetFrameBorder(PRBool aStandardMode);
PRInt32 GetMarginWidth(nsIPresContext* aPresContext, nsIContent* aContent);
PRInt32 GetMarginHeight(nsIPresContext* aPresContext, nsIContent* aContent);
nsresult ReloadURL();
protected:
nsresult CreateWebShell(nsIPresContext* aPresContext, const nsSize& aSize);
virtual ~nsHTMLFrameInnerFrame();
virtual void GetDesiredSize(nsIPresContext* aPresContext,
const nsHTMLReflowState& aReflowState,
nsHTMLReflowMetrics& aDesiredSize);
nsCOMPtr<nsIWebShell> mWebShell;
PRBool mCreatingViewer;
};
/*******************************************************************************
* nsHTMLFrameOuterFrame
******************************************************************************/
nsHTMLFrameOuterFrame::nsHTMLFrameOuterFrame()
: nsHTMLContainerFrame()
{
mIsInline = PR_FALSE;
}
nsHTMLFrameOuterFrame::~nsHTMLFrameOuterFrame()
{
//printf("nsHTMLFrameOuterFrame destructor %X \n", this);
}
NS_IMETHODIMP
nsHTMLFrameOuterFrame::Init(nsIPresContext* aPresContext,
nsIContent* aContent,
nsIFrame* aParent,
nsIStyleContext* aContext,
nsIFrame* aPrevInFlow)
{
// determine if we are a <frame> or <iframe>
if (aContent) {
nsCOMPtr<nsIDOMHTMLFrameElement> frameElem = do_QueryInterface(aContent);
mIsInline = frameElem ? PR_FALSE : PR_TRUE;
}
return nsHTMLFrameOuterFrameSuper::Init(aPresContext, aContent, aParent,
aContext, aPrevInFlow);
}
PRBool
nsHTMLFrameOuterFrame::HasBorder()
{
if (IsInline()) {
nsIFrame* firstChild = mFrames.FirstChild();
if (nsnull != firstChild) {
if (eFrameborder_No != ((nsHTMLFrameInnerFrame*)firstChild)->GetFrameBorder(eCompatibility_Standard)) {
return PR_TRUE;
}
}
}
return PR_FALSE;
}
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);
// XXX this needs to be changed from (200,200) to a better default
// for inline frames
if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedWidth) {
aDesiredSize.width = aReflowState.mComputedWidth;
}
else {
aDesiredSize.width = NSIntPixelsToTwips(200, p2t);
}
if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedHeight) {
aDesiredSize.height = aReflowState.mComputedHeight;
}
else {
aDesiredSize.height = NSIntPixelsToTwips(200, p2t);
}
aDesiredSize.ascent = aDesiredSize.height;
aDesiredSize.descent = 0;
}
PRBool nsHTMLFrameOuterFrame::IsInline()
{
return mIsInline;
}
NS_IMETHODIMP
nsHTMLFrameOuterFrame::Paint(nsIPresContext* aPresContext,
nsIRenderingContext& aRenderingContext,
const nsRect& aDirtyRect,
nsFramePaintLayer aWhichLayer)
{
//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(nsString& aResult) const
{
return MakeFrameName("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)
{
//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);
} else {
aDesiredSize.width = aReflowState.availableWidth;
aDesiredSize.height = aReflowState.availableHeight;
}
nsIFrame* firstChild = mFrames.FirstChild();
if (nsnull == firstChild) {
nsCOMPtr<nsIPresShell> shell;
aPresContext->GetShell(getter_AddRefs(shell));
firstChild = new (shell.get()) nsHTMLFrameInnerFrame;
mFrames.SetFrames(firstChild);
// XXX temporary! use style system to get correct style!
firstChild->Init(aPresContext, mContent, this, mStyleContext, nsnull);
}
nsSize innerSize(aDesiredSize.width, aDesiredSize.height);
nsPoint offset(0,0);
if (IsInline() && HasBorder()) {
const nsStyleSpacing* spacing =
(const nsStyleSpacing*)mStyleContext->GetStyleData(eStyleStruct_Spacing);
nsMargin border;
spacing->CalcBorderFor(this, border);
offset.x = border.left;
offset.y = border.right;
// 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
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");
// Place and size the child
FinishReflowChild(firstChild, aPresContext, kidMetrics, offset.x, offset.y, 0);
// XXX what should the max-element-size of an iframe be? Shouldn't
// iframe's normally shrink wrap around their content when they
// don't have a specified width/height?
if (nsnull != aDesiredSize.maxElementSize) {
aDesiredSize.maxElementSize->width = aDesiredSize.width;
aDesiredSize.maxElementSize->height = aDesiredSize.height;
}
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 aHint)
{
if (nsHTMLAtoms::src == aAttribute) {
printf("got a request\n");
nsIFrame* firstChild = mFrames.FirstChild();
if (nsnull != firstChild) {
((nsHTMLFrameInnerFrame*)firstChild)->ReloadURL();
}
}
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;
}
nsHTMLFrameInnerFrame::~nsHTMLFrameInnerFrame()
{
//printf("nsHTMLFrameInnerFrame destructor %X \n", this);
nsCOMPtr<nsIBaseWindow> webShellWin(do_QueryInterface(mWebShell));
if(webShellWin)
webShellWin->Destroy();
mWebShell = nsnull; // This is the location it was released before...
// Not sure if there is ordering depending on this.
}
PRBool nsHTMLFrameInnerFrame::GetURL(nsIContent* aContent, nsString& aResult)
{
aResult.SetLength(0);
if (NS_CONTENT_ATTR_HAS_VALUE == (aContent->GetAttribute(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->GetAttribute(kNameSpaceID_None, nsHTMLAtoms::name, aResult))) {
if (aResult.Length() > 0) {
return PR_TRUE;
}
}
return PR_FALSE;
}
PRInt32 nsHTMLFrameInnerFrame::GetScrolling(nsIContent* aContent, PRBool aStandardMode)
{
nsIHTMLContent* content = nsnull;
aContent->QueryInterface(kIHTMLContentIID, (void**) &content);
if (nsnull != content) {
nsHTMLValue value;
if (NS_CONTENT_ATTR_HAS_VALUE == (content->GetHTMLAttribute(nsHTMLAtoms::scrolling, value))) {
if (eHTMLUnit_Enumerated == value.GetUnit()) {
PRInt32 returnValue;
PRInt32 intValue;
intValue = value.GetIntValue();
if (!aStandardMode) {
if ((NS_STYLE_FRAME_ON == intValue) || (NS_STYLE_FRAME_SCROLL == intValue)) {
intValue = NS_STYLE_FRAME_YES;
} else if ((NS_STYLE_FRAME_OFF == intValue) || (NS_STYLE_FRAME_NOSCROLL == intValue)) {
intValue = NS_STYLE_FRAME_NO;
}
}
if (NS_STYLE_FRAME_YES == intValue) {
returnValue = NS_STYLE_OVERFLOW_SCROLL;
} else if (NS_STYLE_FRAME_NO == intValue) {
returnValue = NS_STYLE_OVERFLOW_HIDDEN;
} else if (NS_STYLE_FRAME_AUTO == intValue) {
returnValue = NS_STYLE_OVERFLOW_AUTO;
}
NS_RELEASE(content);
return returnValue;
}
}
NS_RELEASE(content);
}
return -1;
}
nsFrameborder nsHTMLFrameInnerFrame::GetFrameBorder(PRBool aStandardMode)
{
nsIHTMLContent* content = nsnull;
mContent->QueryInterface(kIHTMLContentIID, (void**) &content);
if (nsnull != content) {
nsHTMLValue value;
if (NS_CONTENT_ATTR_HAS_VALUE == (content->GetHTMLAttribute(nsHTMLAtoms::frameborder, value))) {
if (eHTMLUnit_Enumerated == value.GetUnit()) {
PRInt32 intValue;
intValue = value.GetIntValue();
if (!aStandardMode) {
if (NS_STYLE_FRAME_YES == intValue) {
intValue = NS_STYLE_FRAME_0;
}
else if (NS_STYLE_FRAME_NO == intValue) {
intValue = NS_STYLE_FRAME_1;
}
}
if (NS_STYLE_FRAME_0 == intValue) {
NS_RELEASE(content);
return eFrameborder_No;
}
else if (NS_STYLE_FRAME_1 == intValue) {
NS_RELEASE(content);
return eFrameborder_Yes;
}
}
}
NS_RELEASE(content);
}
// XXX if we get here, check for nsIDOMFRAMESETElement interface
return eFrameborder_Notset;
}
PRInt32 nsHTMLFrameInnerFrame::GetMarginWidth(nsIPresContext* aPresContext, nsIContent* aContent)
{
PRInt32 marginWidth = -1;
nsIHTMLContent* content = nsnull;
if (NS_SUCCEEDED(mContent->QueryInterface(kIHTMLContentIID, (void**) &content))) {
float p2t;
aPresContext->GetScaledPixelsToTwips(&p2t);
nsHTMLValue value;
content->GetHTMLAttribute(nsHTMLAtoms::marginwidth, value);
if (eHTMLUnit_Pixel == value.GetUnit()) {
marginWidth = NSIntPixelsToTwips(value.GetPixelValue(), p2t);
if (marginWidth < 0) {
marginWidth = 0;
}
}
NS_RELEASE(content);
}
return marginWidth;
}
PRInt32 nsHTMLFrameInnerFrame::GetMarginHeight(nsIPresContext* aPresContext, nsIContent* aContent)
{
PRInt32 marginHeight = -1;
nsIHTMLContent* content = nsnull;
if (NS_SUCCEEDED(mContent->QueryInterface(kIHTMLContentIID, (void**) &content))) {
float p2t;
aPresContext->GetScaledPixelsToTwips(&p2t);
nsHTMLValue value;
content->GetHTMLAttribute(nsHTMLAtoms::marginheight, value);
if (eHTMLUnit_Pixel == value.GetUnit()) {
marginHeight = NSIntPixelsToTwips(value.GetPixelValue(), p2t);
if (marginHeight < 0) {
marginHeight = 0;
}
}
NS_RELEASE(content);
}
return marginHeight;
}
#ifdef DEBUG
NS_IMETHODIMP nsHTMLFrameInnerFrame::GetFrameName(nsString& aResult) const
{
return MakeFrameName("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)
{
//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
if (!mWebShell) {
const nsStyleColor* color =
(const nsStyleColor*)mStyleContext->GetStyleData(eStyleStruct_Color);
aRenderingContext.SetColor(color->mBackgroundColor);
aRenderingContext.FillRect(mRect);
}
return NS_OK;
}
NS_IMETHODIMP
nsHTMLFrameInnerFrame::GetParentContent(nsIContent*& aContent)
{
nsHTMLFrameOuterFrame* parent;
GetParent((nsIFrame**)&parent);
nsIContent* content;
nsresult rv = parent->GetContent(&content);
aContent = content;
return rv;
}
static
void TempMakeAbsURL(nsIContent* aContent, nsString& aRelURL, nsString& aAbsURL)
{
nsIURI* baseURL = nsnull;
nsIHTMLContent* htmlContent;
if (NS_SUCCEEDED(aContent->QueryInterface(kIHTMLContentIID, (void**)&htmlContent))) {
htmlContent->GetBaseURL(baseURL);
NS_RELEASE(htmlContent);
}
else {
nsIDocument* doc;
if (NS_SUCCEEDED(aContent->GetDocument(doc))) {
doc->GetBaseURL(baseURL);
NS_RELEASE(doc);
}
}
nsString empty;
nsresult rv = NS_MakeAbsoluteURI(aRelURL, baseURL, aAbsURL);
NS_ASSERTION(NS_SUCCEEDED(rv), "XXX make this function return an nsresult, like it should!");
NS_IF_RELEASE(baseURL);
}
NS_IMETHODIMP
nsHTMLFrameInnerFrame::DidReflow(nsIPresContext* aPresContext,
nsDidReflowStatus aStatus)
{
nsresult rv = nsLeafFrame::DidReflow(aPresContext, 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 nsStyleDisplay* display;
GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)display));
nsViewVisibility newVis = NS_STYLE_VISIBILITY_VISIBLE == display->mVisible ? nsViewVisibility_kShow : nsViewVisibility_kHide;
nsViewVisibility oldVis;
// only change if different.
view->GetVisibility(oldVis);
if (newVis != oldVis)
view->SetVisibility(newVis);
}
}
return rv;
}
nsresult
nsHTMLFrameInnerFrame::CreateWebShell(nsIPresContext* aPresContext,
const nsSize& aSize)
{
nsresult rv;
nsIContent* content;
GetParentContent(content);
mWebShell = do_CreateInstance(kWebShellCID);
NS_ENSURE_TRUE(mWebShell, NS_ERROR_FAILURE);
nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mWebShell));
NS_ENSURE_TRUE(docShellAsItem, 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> webShellAsSupports(do_QueryInterface(mWebShell));
NS_ENSURE_TRUE(webShellAsSupports, NS_ERROR_FAILURE);
presShell->SetSubShellFor(mContent, webShellAsSupports);
}
// pass along marginwidth, marginheight, scrolling so sub document can use it
mWebShell->SetMarginWidth(GetMarginWidth(aPresContext, content));
mWebShell->SetMarginHeight(GetMarginHeight(aPresContext, content));
nsCompatibility mode;
aPresContext->GetCompatibilityMode(&mode);
// 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(mWebShell, &rv);
if (NS_SUCCEEDED(rv) && scrollableContainer) {
scrollableContainer->SetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_Y, GetScrolling(content, mode));
scrollableContainer->SetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_X, GetScrolling(content, mode));
}
nsString frameName;
if (GetName(content, frameName)) {
docShellAsItem->SetName(frameName.GetUnicode());
}
// 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.
nsISupports* container;
aPresContext->GetContainer(&container);
if (nsnull != 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(content->GetAttribute(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("-")))
isContent = PR_TRUE;
}
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.GetUnicode());
}
// connect the container...
nsCOMPtr<nsIWebShellContainer> outerContainer(do_QueryInterface(container));
if (outerContainer)
mWebShell->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));
}
mWebShell->SetChromeEventHandler(chromeEventHandler);
}
NS_RELEASE(container);
}
float t2p;
aPresContext->GetTwipsToPixels(&t2p);
// create, init, set the parent of the view
nsIView* view;
rv = nsComponentManager::CreateInstance(kCViewCID, nsnull, kIViewIID,
(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, aSize.width, aSize.height);
nsCOMPtr<nsIViewManager> viewMan;
presShell->GetViewManager(getter_AddRefs(viewMan));
rv = view->Init(viewMan, viewBounds, parView);
viewMan->InsertChild(parView, view, 0);
rv = view->CreateWidget(kCChildCID);
SetView(aPresContext, view);
// if the visibility is hidden, reflect that in the view
const nsStyleDisplay* display;
GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)display));
if (NS_STYLE_VISIBILITY_VISIBLE != display->mVisible) {
view->SetVisibility(nsViewVisibility_kHide);
}
nsCOMPtr<nsIBaseWindow> webShellWin(do_QueryInterface(mWebShell));
NS_ENSURE_TRUE(webShellWin, NS_ERROR_FAILURE);
nsCOMPtr<nsIWidget> widget;
view->GetWidget(*getter_AddRefs(widget));
nsRect webBounds(0, 0, NSToCoordRound(aSize.width * t2p),
NSToCoordRound(aSize.height * t2p));
mWebShell->Init(widget->GetNativeData(NS_NATIVE_WIDGET),
webBounds.x, webBounds.y,
webBounds.width, webBounds.height);
//GetScrolling(content, PR_FALSE));
NS_RELEASE(content);
webShellWin->SetVisibility(PR_TRUE);
return NS_OK;
}
NS_IMETHODIMP
nsHTMLFrameInnerFrame::Reflow(nsIPresContext* aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus)
{
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
if (!mCreatingViewer) {
nsIContent* content;
GetParentContent(content);
nsAutoString url;
PRBool hasURL = GetURL(content, url);
// 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 (!mWebShell) {
nsSize maxSize(aReflowState.availableWidth, aReflowState.availableHeight);
rv = CreateWebShell(aPresContext, maxSize);
#ifdef INCLUDE_XUL
// The URL can be destructively altered when a content shell is made.
// Refetch it to ensure we have the actual URL to load.
hasURL = GetURL(content, url);
#endif // INCLUDE_XUL
}
if (mWebShell) {
mCreatingViewer=PR_TRUE;
if (hasURL) {
// load the document
nsString absURL;
TempMakeAbsURL(content, url, absURL);
// Check we can load 'absURL'
nsCOMPtr<nsIURI> baseURI, newURI;
NS_WITH_SERVICE(nsIScriptSecurityManager, securityManager,
NS_SCRIPTSECURITYMANAGER_PROGID, &rv);
if (NS_SUCCEEDED(rv))
rv = aPresContext->GetBaseURL(getter_AddRefs(baseURI));
if (NS_SUCCEEDED(rv))
rv = NS_NewURI(getter_AddRefs(newURI), absURL, baseURI);
if (NS_SUCCEEDED(rv))
rv = securityManager->CheckLoadURI(baseURI, newURI, PR_FALSE);
if (NS_SUCCEEDED(rv)) {
rv = mWebShell->LoadURL(absURL.GetUnicode()); // URL string with a default nsnull value for post Data
}
}
}
NS_RELEASE(content);
}
aDesiredSize.width = aReflowState.availableWidth;
aDesiredSize.height = aReflowState.availableHeight;
aDesiredSize.ascent = aDesiredSize.height;
aDesiredSize.descent = 0;
if (nsnull != aDesiredSize.maxElementSize) {
aDesiredSize.maxElementSize->width = aDesiredSize.width;
aDesiredSize.maxElementSize->height = aDesiredSize.height;
}
aStatus = NS_FRAME_COMPLETE;
// resize the sub document
nsCOMPtr<nsIBaseWindow> webShellWin(do_QueryInterface(mWebShell));
if(webShellWin) {
float t2p;
aPresContext->GetTwipsToPixels(&t2p);
nsRect subBounds;
webShellWin->GetPositionAndSize(&subBounds.x, &subBounds.y,
&subBounds.width, &subBounds.height);
subBounds.width = NSToCoordRound(aDesiredSize.width * t2p);
subBounds.height = NSToCoordRound(aDesiredSize.height * t2p);
webShellWin->SetPositionAndSize(subBounds.x, subBounds.y,
subBounds.width, subBounds.height, PR_FALSE);
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
("exit nsHTMLFrameInnerFrame::Reflow: size=%d,%d rv=%x",
aDesiredSize.width, aDesiredSize.height, aStatus));
}
return rv;
}
nsresult
nsHTMLFrameInnerFrame::ReloadURL()
{
nsresult rv = NS_OK;
nsIContent* content;
GetParentContent(content);
if (nsnull != content) {
nsAutoString url;
GetURL(content, url);
// load a new url if the size is not 0
if ((mRect.width > 0) && (mRect.height > 0)) {
if (mWebShell) {
mCreatingViewer=PR_TRUE;
// load the document
nsString absURL;
TempMakeAbsURL(content, url, absURL);
rv = mWebShell->LoadURL(absURL.GetUnicode()); // URL string with a default nsnull value for post Data
}
} else {
mCreatingViewer = PR_TRUE;
}
NS_RELEASE(content);
}
return rv;
}
void
nsHTMLFrameInnerFrame::GetDesiredSize(nsIPresContext* aPresContext,
const nsHTMLReflowState& aReflowState,
nsHTMLReflowMetrics& aDesiredSize)
{
// it must be defined, but not called
NS_ASSERTION(0, "this should never be called");
aDesiredSize.width = 0;
aDesiredSize.height = 0;
aDesiredSize.ascent = 0;
aDesiredSize.descent = 0;
}
/*******************************************************************************
* FrameLoadingInfo
******************************************************************************/
FrameLoadingInfo::FrameLoadingInfo(const nsSize& aSize)
{
NS_INIT_REFCNT();
mFrameSize = aSize;
}
/*
* Implementation of ISupports methods...
*/
NS_IMPL_ISUPPORTS(FrameLoadingInfo,kISupportsIID);