зеркало из https://github.com/mozilla/gecko-dev.git
417 строки
12 KiB
C++
417 строки
12 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.0 (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 Communicator client 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.
|
|
*/
|
|
#include "nsHTMLParts.h"
|
|
#include "nsLeafFrame.h"
|
|
#include "nsCSSLayout.h"
|
|
#include "nsIPresContext.h"
|
|
#include "nsIPresShell.h"
|
|
#include "nsWidgetsCID.h"
|
|
#include "nsViewsCID.h"
|
|
#include "nsIView.h"
|
|
#include "nsIViewManager.h"
|
|
#include "nsIPluginHost.h"
|
|
#include "nsplugin.h"
|
|
#include "nsString.h"
|
|
#include "nsIContentViewerContainer.h"
|
|
#include "prmem.h"
|
|
#include "nsHTMLAtoms.h"
|
|
#include "nsIDocument.h"
|
|
#include "nsIURL.h"
|
|
|
|
// XXX For temporary paint code
|
|
#include "nsIStyleContext.h"
|
|
|
|
#define nsObjectFrameSuper nsLeafFrame
|
|
|
|
class nsObjectFrame : public nsObjectFrameSuper {
|
|
public:
|
|
nsObjectFrame(nsIContent* aContent, nsIFrame* aParentFrame);
|
|
|
|
NS_IMETHOD Reflow(nsIPresContext& aPresContext,
|
|
nsReflowMetrics& aDesiredSize,
|
|
const nsReflowState& aReflowState,
|
|
nsReflowStatus& aStatus);
|
|
NS_IMETHOD DidReflow(nsIPresContext& aPresContext,
|
|
nsDidReflowStatus aStatus);
|
|
NS_IMETHOD Paint(nsIPresContext& aPresContext,
|
|
nsIRenderingContext& aRenderingContext,
|
|
const nsRect& aDirtyRect);
|
|
|
|
protected:
|
|
virtual ~nsObjectFrame();
|
|
|
|
virtual void GetDesiredSize(nsIPresContext* aPresContext,
|
|
const nsReflowState& aReflowState,
|
|
nsReflowMetrics& aDesiredSize);
|
|
|
|
nsresult CreateWidget(nsIPresContext* aPresContext,
|
|
nscoord aWidth, nscoord aHeight);
|
|
|
|
nsresult SetURL(const nsString& aURLSpec);
|
|
nsresult SetBaseHREF(const nsString& aBaseHREF);
|
|
|
|
private:
|
|
nsPluginWindow mPluginWindow;
|
|
nsIPluginInstance *mInstance;
|
|
nsString *mURLSpec;
|
|
nsString *mBaseHREF;
|
|
};
|
|
|
|
nsObjectFrame::nsObjectFrame(nsIContent* aContent, nsIFrame* aParentFrame)
|
|
: nsObjectFrameSuper(aContent, aParentFrame)
|
|
{
|
|
}
|
|
|
|
nsObjectFrame::~nsObjectFrame()
|
|
{
|
|
NS_IF_RELEASE(mInstance);
|
|
|
|
if (nsnull != mURLSpec)
|
|
{
|
|
delete mURLSpec;
|
|
mURLSpec = nsnull;
|
|
}
|
|
|
|
if (nsnull != mBaseHREF)
|
|
{
|
|
delete mBaseHREF;
|
|
mBaseHREF = nsnull;
|
|
}
|
|
}
|
|
|
|
static NS_DEFINE_IID(kViewCID, NS_VIEW_CID);
|
|
static NS_DEFINE_IID(kIViewIID, NS_IVIEW_IID);
|
|
static NS_DEFINE_IID(kWidgetCID, NS_CHILD_CID);
|
|
|
|
nsresult
|
|
nsObjectFrame::CreateWidget(nsIPresContext* aPresContext,
|
|
nscoord aWidth, nscoord aHeight)
|
|
{
|
|
nsIView* view;
|
|
|
|
// Create our view and widget
|
|
|
|
nsresult result =
|
|
NSRepository::CreateInstance(kViewCID, nsnull, kIViewIID,
|
|
(void **)&view);
|
|
if (NS_OK != result) {
|
|
return result;
|
|
}
|
|
nsIPresShell *presShell = aPresContext->GetShell(); // need to release
|
|
nsIViewManager *viewMan = presShell->GetViewManager(); // need to release
|
|
|
|
nsRect boundBox(0, 0, aWidth, aHeight);
|
|
|
|
nsIFrame* parWithView;
|
|
nsIView *parView;
|
|
|
|
GetParentWithView(parWithView);
|
|
parWithView->GetView(parView);
|
|
|
|
// nsWidgetInitData* initData = GetWidgetInitData(*aPresContext); // needs to be deleted
|
|
// initialize the view as hidden since we don't know the (x,y) until Paint
|
|
result = view->Init(viewMan, boundBox, parView, &kWidgetCID, nsnull,
|
|
nsnull, 0, nsnull,
|
|
1.0f, nsViewVisibility_kHide);
|
|
// if (nsnull != initData) {
|
|
// delete(initData);
|
|
// }
|
|
if (NS_OK != result) {
|
|
result = NS_OK; //XXX why OK? MMP
|
|
goto exit; //XXX sue me. MMP
|
|
}
|
|
|
|
#if 0
|
|
// set the content's widget, so it can get content modified by the widget
|
|
nsIWidget *widget;
|
|
result = GetWidget(view, &widget);
|
|
if (NS_OK == result) {
|
|
nsInput* content = (nsInput *)mContent; // change this cast to QueryInterface
|
|
content->SetWidget(widget);
|
|
NS_IF_RELEASE(widget);
|
|
} else {
|
|
NS_ASSERTION(0, "could not get widget");
|
|
}
|
|
#endif
|
|
|
|
viewMan->InsertChild(parView, view, 0);
|
|
|
|
SetView(view);
|
|
|
|
exit:
|
|
NS_IF_RELEASE(viewMan);
|
|
NS_IF_RELEASE(presShell);
|
|
|
|
return result;
|
|
}
|
|
|
|
#define EMBED_DEF_DIM 50
|
|
|
|
void
|
|
nsObjectFrame::GetDesiredSize(nsIPresContext* aPresContext,
|
|
const nsReflowState& aReflowState,
|
|
nsReflowMetrics& aMetrics)
|
|
{
|
|
// Determine our size stylistically
|
|
nsSize styleSize;
|
|
PRIntn ss = nsCSSLayout::GetStyleSize(aPresContext, aReflowState, styleSize);
|
|
PRBool haveWidth = PR_FALSE;
|
|
PRBool haveHeight = PR_FALSE;
|
|
if (0 != (ss & NS_SIZE_HAS_WIDTH)) {
|
|
aMetrics.width = styleSize.width;
|
|
haveWidth = PR_TRUE;
|
|
}
|
|
if (0 != (ss & NS_SIZE_HAS_HEIGHT)) {
|
|
aMetrics.height = styleSize.height;
|
|
haveHeight = PR_TRUE;
|
|
}
|
|
|
|
// XXX Temporary auto-sizing logic
|
|
if (!haveWidth) {
|
|
if (haveHeight) {
|
|
aMetrics.width = aMetrics.height;
|
|
}
|
|
else {
|
|
float p2t = aPresContext->GetPixelsToTwips();
|
|
aMetrics.width = NSIntPixelsToTwips(EMBED_DEF_DIM, p2t);
|
|
}
|
|
}
|
|
if (!haveHeight) {
|
|
if (haveWidth) {
|
|
aMetrics.height = aMetrics.width;
|
|
}
|
|
else {
|
|
float p2t = aPresContext->GetPixelsToTwips();
|
|
aMetrics.height = NSIntPixelsToTwips(EMBED_DEF_DIM, p2t);
|
|
}
|
|
}
|
|
aMetrics.ascent = aMetrics.height;
|
|
aMetrics.descent = 0;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsObjectFrame::Reflow(nsIPresContext& aPresContext,
|
|
nsReflowMetrics& aMetrics,
|
|
const nsReflowState& aReflowState,
|
|
nsReflowStatus& aStatus)
|
|
{
|
|
// Get our desired size
|
|
GetDesiredSize(&aPresContext, aReflowState, aMetrics);
|
|
if (nsnull != aMetrics.maxElementSize) {
|
|
aMetrics.maxElementSize->width = aMetrics.width;
|
|
aMetrics.maxElementSize->height = aMetrics.height;
|
|
}
|
|
|
|
// XXX deal with border and padding the usual way...wrap it up!
|
|
|
|
nsIAtom* atom;
|
|
mContent->GetTag(atom);
|
|
if (nsnull != atom) {
|
|
//don't make a view for an applet since we know we can't support them yet...
|
|
if (atom != nsHTMLAtoms::applet) {
|
|
static NS_DEFINE_IID(kIPluginHostIID, NS_IPLUGINHOST_IID);
|
|
static NS_DEFINE_IID(kIContentViewerContainerIID, NS_ICONTENT_VIEWER_CONTAINER_IID);
|
|
|
|
nsISupports *container;
|
|
nsIPluginHost *pm;
|
|
nsIContentViewerContainer *cv;
|
|
nsresult rv;
|
|
|
|
rv = aPresContext.GetContainer(&container);
|
|
|
|
if (NS_OK == rv) {
|
|
rv = container->QueryInterface(kIContentViewerContainerIID, (void **)&cv);
|
|
|
|
if (NS_OK == rv) {
|
|
rv = cv->QueryCapability(kIPluginHostIID, (void **)&pm);
|
|
|
|
if (NS_OK == rv) {
|
|
// Create view if necessary
|
|
nsIView* view;
|
|
GetView(view);
|
|
if (nsnull == view) {
|
|
rv = CreateWidget(&aPresContext, aMetrics.width,
|
|
aMetrics.height);
|
|
if (NS_OK == rv) {
|
|
nsAutoString type;
|
|
char *buf = nsnull;
|
|
PRInt32 buflen;
|
|
|
|
mContent->GetAttribute(nsString("type"), type);
|
|
|
|
buflen = type.Length();
|
|
|
|
if (buflen > 0) {
|
|
buf = (char *)PR_Malloc(buflen + 1);
|
|
|
|
if (nsnull != buf)
|
|
type.ToCString(buf, buflen + 1);
|
|
}
|
|
|
|
nsIView *view;
|
|
nsIWidget *widget;
|
|
nsRect wrect;
|
|
|
|
GetView(view);
|
|
|
|
view->GetWidget(widget);
|
|
widget->GetBounds(wrect);
|
|
|
|
nsAutoString src, base, fullurl;
|
|
|
|
//stream in the object source if there is one...
|
|
|
|
if (NS_CONTENT_ATTR_HAS_VALUE == mContent->GetAttribute("SRC", src)) {
|
|
SetURL(src);
|
|
|
|
if (NS_CONTENT_ATTR_HAS_VALUE == mContent->GetAttribute(NS_HTML_BASE_HREF, base))
|
|
SetBaseHREF(base);
|
|
|
|
nsIPresShell *shell = aPresContext.GetShell();
|
|
nsIDocument *doc = shell->GetDocument();
|
|
nsIURL *docURL = doc->GetDocumentURL();
|
|
|
|
// Create an absolute URL
|
|
nsresult rv = NS_MakeAbsoluteURL(docURL, base, *mURLSpec, fullurl);
|
|
|
|
NS_RELEASE(shell);
|
|
NS_RELEASE(docURL);
|
|
NS_RELEASE(doc);
|
|
}
|
|
|
|
mPluginWindow.window = (nsPluginPort *)widget->GetNativeData(NS_NATIVE_WINDOW);
|
|
mPluginWindow.x = wrect.x;
|
|
mPluginWindow.y = wrect.y;
|
|
mPluginWindow.width = wrect.width;
|
|
mPluginWindow.height = wrect.height;
|
|
mPluginWindow.clipRect.top = wrect.y;
|
|
mPluginWindow.clipRect.left = wrect.x;
|
|
mPluginWindow.clipRect.bottom = wrect.YMost();
|
|
mPluginWindow.clipRect.right = wrect.XMost();
|
|
#ifdef XP_UNIX
|
|
mPluginWindow.ws_info = nsnull; //XXX need to figure out what this is. MMP
|
|
#endif
|
|
//this will change with support for windowless plugins... MMP
|
|
mPluginWindow.type = nsPluginWindowType_Window;
|
|
|
|
rv = pm->InstantiatePlugin(buf, &mInstance, &mPluginWindow, fullurl);
|
|
|
|
PR_Free((void *)buf);
|
|
|
|
//since the plugin is holding on to private data in the widget,
|
|
//we probably need to keep around the ref on the view and/or widget.
|
|
//(i.e. this is bad...) MMP
|
|
NS_RELEASE(widget);
|
|
}
|
|
}
|
|
NS_RELEASE(pm);
|
|
}
|
|
NS_RELEASE(cv);
|
|
}
|
|
NS_RELEASE(container);
|
|
}
|
|
}
|
|
NS_RELEASE(atom);
|
|
}
|
|
|
|
aStatus = NS_FRAME_COMPLETE;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsObjectFrame::DidReflow(nsIPresContext& aPresContext,
|
|
nsDidReflowStatus aStatus)
|
|
{
|
|
nsresult rv = nsObjectFrameSuper::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(view);
|
|
if (nsnull != view) {
|
|
view->SetVisibility(nsViewVisibility_kShow);
|
|
}
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsObjectFrame::Paint(nsIPresContext& aPresContext,
|
|
nsIRenderingContext& aRenderingContext,
|
|
const nsRect& aDirtyRect)
|
|
{
|
|
const nsStyleFont* font =
|
|
(const nsStyleFont*)mStyleContext->GetStyleData(eStyleStruct_Font);
|
|
|
|
aRenderingContext.SetFont(font->mFont);
|
|
aRenderingContext.SetColor(NS_RGB(192, 192, 192));
|
|
aRenderingContext.FillRect(0, 0, mRect.width, mRect.height);
|
|
aRenderingContext.SetColor(NS_RGB(0, 0, 0));
|
|
aRenderingContext.DrawRect(0, 0, mRect.width, mRect.height);
|
|
float p2t = aPresContext.GetPixelsToTwips();
|
|
nscoord px3 = NSIntPixelsToTwips(3, p2t);
|
|
nsAutoString tmp;
|
|
nsIAtom* atom;
|
|
mContent->GetTag(atom);
|
|
if (nsnull != atom) {
|
|
atom->ToString(tmp);
|
|
NS_RELEASE(atom);
|
|
aRenderingContext.DrawString(tmp, px3, px3, 0);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
NS_NewObjectFrame(nsIFrame*& aFrameResult, nsIContent* aContent,
|
|
nsIFrame* aParentFrame)
|
|
{
|
|
aFrameResult = new nsObjectFrame(aContent, aParentFrame);
|
|
if (nsnull == aFrameResult) {
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsObjectFrame::SetURL(const nsString& aURLSpec)
|
|
{
|
|
if (nsnull != mURLSpec) {
|
|
delete mURLSpec;
|
|
}
|
|
mURLSpec = new nsString(aURLSpec);
|
|
if (nsnull == mURLSpec) {
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsObjectFrame::SetBaseHREF(const nsString& aBaseHREF)
|
|
{
|
|
if (nsnull != mBaseHREF) {
|
|
delete mBaseHREF;
|
|
}
|
|
mBaseHREF = new nsString(aBaseHREF);
|
|
if (nsnull == mBaseHREF) {
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
return NS_OK;
|
|
}
|