gecko-dev/layout/base/nsPresShell.cpp

2524 lines
71 KiB
C++
Raw Normal View History

1998-04-13 20:24:54 +00:00
/* -*- 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 "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsIPresShell.h"
1999-05-21 23:11:16 +00:00
#include "nsIPresContext.h"
1998-04-13 20:24:54 +00:00
#include "nsIContent.h"
#include "nsIDocument.h"
#include "nsIDocumentObserver.h"
1998-04-13 20:24:54 +00:00
#include "nsIStyleSet.h"
1998-11-26 01:34:53 +00:00
#include "nsICSSStyleSheet.h" // XXX for UA sheet loading hack, can this go away please?
1998-04-13 20:24:54 +00:00
#include "nsIStyleContext.h"
1998-05-20 16:24:54 +00:00
#include "nsFrame.h"
1998-06-09 04:51:44 +00:00
#include "nsIReflowCommand.h"
1998-04-13 20:24:54 +00:00
#include "nsIViewManager.h"
#include "nsCRT.h"
#include "plhash.h"
#include "prlog.h"
#include "prthread.h"
#include "prinrval.h"
1998-06-09 04:51:44 +00:00
#include "nsVoidArray.h"
#include "nsIPref.h"
1998-08-28 02:54:06 +00:00
#include "nsIViewObserver.h"
#include "nsContainerFrame.h"
#include "nsHTMLIIDs.h"
#include "nsIDeviceContext.h"
#include "nsIEventStateManager.h"
#include "nsDOMEvent.h"
#include "nsHTMLParts.h"
#include "nsIDOMSelection.h"
1998-12-08 18:26:06 +00:00
#include "nsLayoutCID.h"
1998-12-14 18:34:14 +00:00
#include "nsIDOMRange.h"
#include "nsIDOMDocument.h"
#include "nsIDOMNode.h"
#include "nsIDOMElement.h"
#include "nsHTMLAtoms.h"
1999-01-22 18:58:14 +00:00
#include "nsCOMPtr.h"
#include "nsIEventQueueService.h"
#include "nsIServiceManager.h"
#include "nsICaret.h"
#include "nsCaretProperties.h"
1999-02-12 05:39:33 +00:00
#include "nsIDOMHTMLDocument.h"
#include "nsIXMLDocument.h"
1999-02-12 05:39:33 +00:00
#include "nsIScrollableView.h"
#include "nsIDOMSelectionListener.h"
#include "nsIParser.h"
#include "nsParserCIID.h"
#include "nsHTMLContentSinkStream.h"
#include "nsHTMLToTXTSinkStream.h"
#include "nsXIFDTD.h"
#include "nsIFrameSelection.h"
1999-04-03 18:58:04 +00:00
#include "nsViewsCID.h"
#include "nsLayoutAtoms.h"
#include "nsPlaceholderFrame.h"
// Drag & Drop, Clipboard
#include "nsWidgetsCID.h"
#include "nsIClipboard.h"
#include "nsITransferable.h"
#include "nsIFormatConverter.h"
#include "nsIWebShell.h"
// Drag & Drop, Clipboard Support
static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
static NS_DEFINE_CID(kCTransferableCID, NS_TRANSFERABLE_CID);
static NS_DEFINE_IID(kCXIFConverterCID, NS_XIFFORMATCONVERTER_CID);
1998-04-13 20:24:54 +00:00
static PRBool gsNoisyRefs = PR_FALSE;
1998-04-13 20:24:54 +00:00
#undef NOISY
// comment out to hide caret
#define SHOW_CARET
static PLHashNumber
HashKey(nsIFrame* key)
1998-04-13 20:24:54 +00:00
{
return (PLHashNumber) key;
}
static PRIntn
CompareKeys(nsIFrame* key1, nsIFrame* key2)
1998-04-13 20:24:54 +00:00
{
return key1 == key2;
}
class FrameHashTable {
public:
FrameHashTable();
~FrameHashTable();
void* Get(nsIFrame* aKey);
void* Put(nsIFrame* aKey, void* aValue);
void* Remove(nsIFrame* aKey);
protected:
PLHashTable* mTable;
};
FrameHashTable::FrameHashTable()
{
mTable = PL_NewHashTable(8, (PLHashFunction) HashKey,
(PLHashComparator) CompareKeys,
(PLHashComparator) nsnull,
nsnull, nsnull);
}
FrameHashTable::~FrameHashTable()
{
PL_HashTableDestroy(mTable);
}
/**
* Get the data associated with a frame.
*/
void*
FrameHashTable::Get(nsIFrame* aKey)
1998-04-13 20:24:54 +00:00
{
PRInt32 hashCode = (PRInt32) aKey;
PLHashEntry** hep = PL_HashTableRawLookup(mTable, hashCode, aKey);
PLHashEntry* he = *hep;
if (nsnull != he) {
return he->value;
}
return nsnull;
}
/**
* Create an association between a frame and some data. This call
* returns an old association if there was one (or nsnull if there
* wasn't).
*/
void*
FrameHashTable::Put(nsIFrame* aKey, void* aData)
1998-04-13 20:24:54 +00:00
{
PRInt32 hashCode = (PRInt32) aKey;
PLHashEntry** hep = PL_HashTableRawLookup(mTable, hashCode, aKey);
PLHashEntry* he = *hep;
if (nsnull != he) {
void* oldValue = he->value;
he->value = aData;
return oldValue;
}
PL_HashTableRawAdd(mTable, hep, hashCode, aKey, aData);
return nsnull;
}
/**
* Remove an association between a frame and it's data. This returns
* the old associated data.
*/
void*
FrameHashTable::Remove(nsIFrame* aKey)
1998-04-13 20:24:54 +00:00
{
PRInt32 hashCode = (PRInt32) aKey;
PLHashEntry** hep = PL_HashTableRawLookup(mTable, hashCode, aKey);
PLHashEntry* he = *hep;
void* oldValue = nsnull;
if (nsnull != he) {
oldValue = he->value;
PL_HashTableRawRemove(mTable, hep, he);
}
return oldValue;
}
//----------------------------------------------------------------------
// Class IID's
static NS_DEFINE_IID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
static NS_DEFINE_IID(kRangeListCID, NS_RANGELIST_CID);
static NS_DEFINE_IID(kCRangeCID, NS_RANGE_CID);
// IID's
1998-04-13 20:24:54 +00:00
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
static NS_DEFINE_IID(kIPresShellIID, NS_IPRESSHELL_IID);
static NS_DEFINE_IID(kIDocumentObserverIID, NS_IDOCUMENT_OBSERVER_IID);
1998-08-28 02:54:06 +00:00
static NS_DEFINE_IID(kIViewObserverIID, NS_IVIEWOBSERVER_IID);
static NS_DEFINE_IID(kIFrameSelectionIID, NS_IFRAMESELECTION_IID);
static NS_DEFINE_IID(kIDOMSelectionIID, NS_IDOMSELECTION_IID);
1998-12-14 18:34:14 +00:00
static NS_DEFINE_IID(kIDOMNodeIID, NS_IDOMNODE_IID);
static NS_DEFINE_IID(kIDOMRangeIID, NS_IDOMRANGE_IID);
static NS_DEFINE_IID(kIDOMDocumentIID, NS_IDOMDOCUMENT_IID);
static NS_DEFINE_IID(kIFocusTrackerIID, NS_IFOCUSTRACKER_IID);
static NS_DEFINE_IID(kIDomSelectionListenerIID, NS_IDOMSELECTIONLISTENER_IID);
static NS_DEFINE_IID(kIEventQueueServiceIID, NS_IEVENTQUEUESERVICE_IID);
static NS_DEFINE_IID(kICaretIID, NS_ICARET_IID);
static NS_DEFINE_IID(kICaretID, NS_ICARET_IID);
1999-02-12 05:39:33 +00:00
static NS_DEFINE_IID(kIDOMHTMLDocumentIID, NS_IDOMHTMLDOCUMENT_IID);
static NS_DEFINE_IID(kIXMLDocumentIID, NS_IXMLDOCUMENT_IID);
1999-02-12 05:39:33 +00:00
static NS_DEFINE_IID(kIContentIID, NS_ICONTENT_IID);
static NS_DEFINE_IID(kIScrollableViewIID, NS_ISCROLLABLEVIEW_IID);
1999-04-03 18:58:04 +00:00
static NS_DEFINE_IID(kViewCID, NS_VIEW_CID);
static NS_DEFINE_IID(kIWebShellIID, NS_IWEB_SHELL_IID);
1998-04-13 20:24:54 +00:00
1998-08-28 02:54:06 +00:00
class PresShell : public nsIPresShell, public nsIViewObserver,
private nsIDocumentObserver, public nsIFocusTracker,
public nsIDOMSelectionListener
1998-08-28 02:54:06 +00:00
{
1998-04-13 20:24:54 +00:00
public:
PresShell();
1999-02-26 20:02:06 +00:00
NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
1998-04-13 20:24:54 +00:00
// nsISupports
NS_DECL_ISUPPORTS
// nsIDocumentObserver
NS_IMETHOD BeginUpdate(nsIDocument *aDocument);
NS_IMETHOD EndUpdate(nsIDocument *aDocument);
NS_IMETHOD BeginLoad(nsIDocument *aDocument);
NS_IMETHOD EndLoad(nsIDocument *aDocument);
NS_IMETHOD BeginReflow(nsIDocument *aDocument, nsIPresShell* aShell);
NS_IMETHOD EndReflow(nsIDocument *aDocument, nsIPresShell* aShell);
NS_IMETHOD ContentChanged(nsIDocument *aDocument,
nsIContent* aContent,
nsISupports* aSubContent);
1999-04-20 00:06:58 +00:00
NS_IMETHOD ContentStatesChanged(nsIDocument* aDocument,
nsIContent* aContent1,
nsIContent* aContent2);
NS_IMETHOD AttributeChanged(nsIDocument *aDocument,
nsIContent* aContent,
nsIAtom* aAttribute,
PRInt32 aHint);
NS_IMETHOD ContentAppended(nsIDocument *aDocument,
nsIContent* aContainer,
PRInt32 aNewIndexInContainer);
NS_IMETHOD ContentInserted(nsIDocument *aDocument,
nsIContent* aContainer,
nsIContent* aChild,
PRInt32 aIndexInContainer);
NS_IMETHOD ContentReplaced(nsIDocument *aDocument,
nsIContent* aContainer,
nsIContent* aOldChild,
nsIContent* aNewChild,
PRInt32 aIndexInContainer);
NS_IMETHOD ContentRemoved(nsIDocument *aDocument,
nsIContent* aContainer,
nsIContent* aChild,
PRInt32 aIndexInContainer);
NS_IMETHOD StyleSheetAdded(nsIDocument *aDocument,
nsIStyleSheet* aStyleSheet);
NS_IMETHOD StyleSheetRemoved(nsIDocument *aDocument,
nsIStyleSheet* aStyleSheet);
NS_IMETHOD StyleSheetDisabledStateChanged(nsIDocument *aDocument,
nsIStyleSheet* aStyleSheet,
PRBool aDisabled);
1998-11-26 01:34:53 +00:00
NS_IMETHOD StyleRuleChanged(nsIDocument *aDocument,
nsIStyleSheet* aStyleSheet,
nsIStyleRule* aStyleRule,
PRInt32 aHint);
NS_IMETHOD StyleRuleAdded(nsIDocument *aDocument,
nsIStyleSheet* aStyleSheet,
nsIStyleRule* aStyleRule);
NS_IMETHOD StyleRuleRemoved(nsIDocument *aDocument,
nsIStyleSheet* aStyleSheet,
nsIStyleRule* aStyleRule);
NS_IMETHOD DocumentWillBeDestroyed(nsIDocument *aDocument);
1998-04-13 20:24:54 +00:00
// nsIPresShell
NS_IMETHOD Init(nsIDocument* aDocument,
nsIPresContext* aPresContext,
nsIViewManager* aViewManager,
nsIStyleSet* aStyleSet);
NS_IMETHOD GetDocument(nsIDocument** aResult);
NS_IMETHOD GetPresContext(nsIPresContext** aResult);
NS_IMETHOD GetViewManager(nsIViewManager** aResult);
NS_IMETHOD GetStyleSet(nsIStyleSet** aResult);
NS_IMETHOD GetActiveAlternateStyleSheet(nsString& aSheetTitle);
NS_IMETHOD SelectAlternateStyleSheet(const nsString& aSheetTitle);
NS_IMETHOD ListAlternateStyleSheets(nsStringArray& aTitleList);
NS_IMETHOD GetSelection(nsIDOMSelection** aSelection);
NS_IMETHOD EnterReflowLock();
NS_IMETHOD ExitReflowLock();
NS_IMETHOD BeginObservingDocument();
NS_IMETHOD EndObservingDocument();
NS_IMETHOD InitialReflow(nscoord aWidth, nscoord aHeight);
1998-08-28 02:54:06 +00:00
NS_IMETHOD ResizeReflow(nscoord aWidth, nscoord aHeight);
NS_IMETHOD StyleChangeReflow();
NS_IMETHOD GetRootFrame(nsIFrame** aFrame) const;
NS_IMETHOD GetPageSequenceFrame(nsIPageSequenceFrame** aResult) const;
NS_IMETHOD GetPrimaryFrameFor(nsIContent* aContent,
nsIFrame** aPrimaryFrame) const;
NS_IMETHOD SetPrimaryFrameFor(nsIContent* aContent,
nsIFrame* aPrimaryFrame);
NS_IMETHOD ClearPrimaryFrameMap();
1999-02-25 19:55:06 +00:00
NS_IMETHOD GetStyleContextFor(nsIFrame* aFrame,
nsIStyleContext** aStyleContext) const;
NS_IMETHOD GetLayoutObjectFor(nsIContent* aContent,
nsISupports** aResult) const;
NS_IMETHOD GetPlaceholderFrameFor(nsIFrame* aFrame,
nsIFrame** aPlaceholderFrame) const;
NS_IMETHOD SetPlaceholderFrameFor(nsIFrame* aFrame,
nsIFrame* aPlaceholderFrame);
NS_IMETHOD ClearPlaceholderFrameMap();
NS_IMETHOD AppendReflowCommand(nsIReflowCommand* aReflowCommand);
NS_IMETHOD CancelReflowCommand(nsIFrame* aTargetFrame);
NS_IMETHOD ProcessReflowCommands();
NS_IMETHOD ClearFrameRefs(nsIFrame* aFrame);
NS_IMETHOD CreateRenderingContext(nsIFrame *aFrame,
nsIRenderingContext** aContext);
NS_IMETHOD CantRenderReplacedElement(nsIPresContext* aPresContext,
nsIFrame* aFrame);
1999-02-12 05:39:33 +00:00
NS_IMETHOD GoToAnchor(const nsString& aAnchorName) const;
1998-08-28 02:54:06 +00:00
NS_IMETHOD ScrollFrameIntoView(nsIFrame *aFrame,
PRInt32 aVOffsetPercent,
PRUint32 aVFlags,
PRInt32 aHOffsetPercent,
PRUint32 aHFlags) const;
NS_IMETHOD DoCopy();
1998-08-28 02:54:06 +00:00
//nsIViewObserver interface
NS_IMETHOD Paint(nsIView *aView,
nsIRenderingContext& aRenderingContext,
const nsRect& aDirtyRect);
NS_IMETHOD HandleEvent(nsIView* aView,
nsGUIEvent* aEvent,
nsEventStatus& aEventStatus);
NS_IMETHOD Scrolled(nsIView *aView);
NS_IMETHOD ResizeReflow(nsIView *aView, nscoord aWidth, nscoord aHeight);
1998-12-14 18:34:14 +00:00
//nsIFocusTracker interface
NS_IMETHOD ScrollFrameIntoView(nsIFrame *aFrame);
// caret handling
NS_IMETHOD GetCaret(nsICaret **outCaret);
NS_IMETHOD SetCaretEnabled(PRBool inEnable);
NS_IMETHOD SetDisplayNonTextSelection(PRBool inEnable);
NS_IMETHOD GetDisplayNonTextSelection(PRBool *inEnable);
// nsIDOMSelectionListener interface
NS_IMETHOD NotifySelectionChanged();
// implementation
void HandleCantRenderReplacedElementEvent(nsIFrame* aFrame);
1998-04-13 20:24:54 +00:00
protected:
virtual ~PresShell();
1998-04-13 20:24:54 +00:00
1998-11-26 01:34:53 +00:00
nsresult ReconstructFrames(void);
// turn the caret on and off.
nsresult RefreshCaret(nsIView *aView,
nsIRenderingContext& aRendContext,
const nsRect& aDirtyRect);
nsresult SuspendCaret();
nsresult ResumeCaret();
PRBool mCaretEnabled;
1998-07-13 19:49:42 +00:00
#ifdef NS_DEBUG
1999-04-03 18:58:04 +00:00
nsresult CloneStyleSet(nsIStyleSet* aSet, nsIStyleSet** aResult);
1998-07-13 19:49:42 +00:00
void VerifyIncrementalReflow();
PRBool mInVerifyReflow;
1998-07-13 19:49:42 +00:00
#endif
1998-05-20 16:24:54 +00:00
// IMPORTANT: The ownership implicit in the following member variables has been
// explicitly checked and set using nsCOMPtr for owning pointers and raw COM interface
// pointers for weak (ie, non owning) references. If you add any members to this
// class, please make the ownership explicit (pinkerton, scc).
// these are the same Document and PresContext owned by the DocViewer.
// we must share ownership.
nsCOMPtr<nsIDocument> mDocument;
nsCOMPtr<nsIPresContext> mPresContext;
nsCOMPtr<nsIStyleSet> mStyleSet;
1998-04-13 20:24:54 +00:00
nsIFrame* mRootFrame;
nsIViewManager* mViewManager; // [WEAK] docViewer owns it so I don't have to
1998-04-13 20:24:54 +00:00
PRUint32 mUpdateCount;
nsVoidArray mReflowCommands;
PRUint32 mReflowLockCount;
PRBool mIsDestroying;
nsIFrame* mCurrentEventFrame;
nsIContent* mCurrentEventContent;
nsCOMPtr<nsIFrameSelection> mSelection;
nsCOMPtr<nsICaret> mCaret;
PRBool mDisplayNonTextSelection;
PRBool mScrollingEnabled; //used to disable programmable scrolling from outside
FrameHashTable* mPlaceholderMap;
private:
//helper funcs for disabing autoscrolling
void DisableScrolling(){mScrollingEnabled = PR_FALSE;}
void EnableScrolling(){mScrollingEnabled = PR_TRUE;}
PRBool IsScrollingEnabled(){return mScrollingEnabled;}
nsIFrame* GetCurrentEventFrame();
1998-04-13 20:24:54 +00:00
};
1998-07-13 19:49:42 +00:00
#ifdef NS_DEBUG
/**
* Note: the log module is created during library initialization which
* means that you cannot perform logging before then.
*/
static PRLogModuleInfo* gLogModule;
1998-07-13 19:49:42 +00:00
#endif
static PRBool gVerifyReflow = PRBool(0x55);
1999-04-27 22:14:17 +00:00
#ifdef NS_DEBUG
1998-11-25 18:41:02 +00:00
static PRBool gVerifyReflowAll;
1999-04-27 22:14:17 +00:00
#endif
1998-07-13 19:49:42 +00:00
NS_LAYOUT PRBool
nsIPresShell::GetVerifyReflowEnable()
{
#ifdef NS_DEBUG
if (gVerifyReflow == PRBool(0x55)) {
gLogModule = PR_NewLogModule("verifyreflow");
1998-07-13 19:49:42 +00:00
gVerifyReflow = 0 != gLogModule->level;
1998-11-25 18:41:02 +00:00
if (gLogModule->level > 1) {
gVerifyReflowAll = PR_TRUE;
}
printf("Note: verifyreflow is %sabled",
1998-07-13 19:49:42 +00:00
gVerifyReflow ? "en" : "dis");
1998-11-25 18:41:02 +00:00
if (gVerifyReflowAll) {
printf(" (diff all enabled)\n");
}
else {
printf("\n");
}
1998-07-13 19:49:42 +00:00
}
#endif
return gVerifyReflow;
}
NS_LAYOUT void
nsIPresShell::SetVerifyReflowEnable(PRBool aEnabled)
{
gVerifyReflow = aEnabled;
}
1998-04-13 20:24:54 +00:00
//----------------------------------------------------------------------
1998-07-13 19:49:42 +00:00
NS_LAYOUT nsresult
NS_NewPresShell(nsIPresShell** aInstancePtrResult)
{
NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr");
if (nsnull == aInstancePtrResult) {
return NS_ERROR_NULL_POINTER;
}
PresShell* it = new PresShell();
if (nsnull == it) {
return NS_ERROR_OUT_OF_MEMORY;
}
return it->QueryInterface(kIPresShellIID, (void **) aInstancePtrResult);
}
1998-04-13 20:24:54 +00:00
PresShell::PresShell()
{
//XXX joki 11/17 - temporary event hack.
mIsDestroying = PR_FALSE;
mCaretEnabled = PR_FALSE;
mDisplayNonTextSelection = PR_FALSE;
mCurrentEventContent = nsnull;
EnableScrolling();
1998-04-13 20:24:54 +00:00
}
#ifdef NS_DEBUG
// for debugging only
nsrefcnt PresShell::AddRef(void)
{
if (gsNoisyRefs) {
printf("PresShell: AddRef: %p, cnt = %d \n",this, mRefCnt+1);
}
return ++mRefCnt;
}
// for debugging only
nsrefcnt PresShell::Release(void)
{
if (gsNoisyRefs) {
printf("PresShell Release: %p, cnt = %d \n",this, mRefCnt-1);
}
if (--mRefCnt == 0) {
if (gsNoisyRefs) {
printf("PresShell Delete: %p, \n",this);
}
delete this;
return 0;
}
return mRefCnt;
}
#else
NS_IMPL_ADDREF(PresShell)
NS_IMPL_RELEASE(PresShell)
#endif
1998-04-13 20:24:54 +00:00
nsresult
PresShell::QueryInterface(const nsIID& aIID, void** aInstancePtr)
1998-04-13 20:24:54 +00:00
{
if (aIID.Equals(kIPresShellIID)) {
nsIPresShell* tmp = this;
*aInstancePtr = (void*) tmp;
NS_ADDREF_THIS();
1998-04-13 20:24:54 +00:00
return NS_OK;
}
if (aIID.Equals(kIDocumentObserverIID)) {
nsIDocumentObserver* tmp = this;
*aInstancePtr = (void*) tmp;
NS_ADDREF_THIS();
1998-04-13 20:24:54 +00:00
return NS_OK;
}
1998-08-28 02:54:06 +00:00
if (aIID.Equals(kIViewObserverIID)) {
nsIViewObserver* tmp = this;
*aInstancePtr = (void*) tmp;
NS_ADDREF_THIS();
1998-08-28 02:54:06 +00:00
return NS_OK;
}
1998-12-14 18:34:14 +00:00
if (aIID.Equals(kIFocusTrackerIID)) {
nsIFocusTracker* tmp = this;
*aInstancePtr = (void*) tmp;
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(kIDomSelectionListenerIID)) {
nsIDOMSelectionListener* tmp = this;
*aInstancePtr = (void*) tmp;
NS_ADDREF_THIS();
return NS_OK;
}
1998-04-13 20:24:54 +00:00
if (aIID.Equals(kISupportsIID)) {
nsIPresShell* tmp = this;
nsISupports* tmp2 = tmp;
*aInstancePtr = (void*) tmp2;
NS_ADDREF_THIS();
1998-04-13 20:24:54 +00:00
return NS_OK;
}
return NS_NOINTERFACE;
}
PresShell::~PresShell()
{
mRefCnt = 99;/* XXX hack! get around re-entrancy bugs */
mIsDestroying = PR_TRUE;
NS_IF_RELEASE(mCurrentEventContent);
if (mViewManager) {
// Disable paints during tear down of the frame tree
mViewManager->DisableRefresh();
}
if (mRootFrame)
1998-08-28 02:54:06 +00:00
mRootFrame->DeleteFrame(*mPresContext);
if (mDocument)
mDocument->DeleteShell(this);
mRefCnt = 0;
delete mPlaceholderMap;
1998-04-13 20:24:54 +00:00
}
/**
* Initialize the presentation shell. Create view manager and style
* manager.
*/
nsresult
PresShell::Init(nsIDocument* aDocument,
nsIPresContext* aPresContext,
nsIViewManager* aViewManager,
nsIStyleSet* aStyleSet)
1998-04-13 20:24:54 +00:00
{
NS_PRECONDITION(nsnull != aDocument, "null ptr");
NS_PRECONDITION(nsnull != aPresContext, "null ptr");
NS_PRECONDITION(nsnull != aViewManager, "null ptr");
if ((nsnull == aDocument) || (nsnull == aPresContext) ||
(nsnull == aViewManager)) {
return NS_ERROR_NULL_POINTER;
}
if (mDocument) {
1998-04-13 20:24:54 +00:00
return NS_ERROR_ALREADY_INITIALIZED;
}
mDocument = dont_QueryInterface(aDocument);
1998-04-13 20:24:54 +00:00
mViewManager = aViewManager;
1998-08-28 02:54:06 +00:00
//doesn't add a ref since we own it... MMP
mViewManager->SetViewObserver((nsIViewObserver *)this);
1998-04-13 20:24:54 +00:00
// Bind the context to the presentation shell.
mPresContext = dont_QueryInterface(aPresContext);
1998-04-13 20:24:54 +00:00
aPresContext->SetShell(this);
mStyleSet = dont_QueryInterface(aStyleSet);
1998-04-13 20:24:54 +00:00
nsCOMPtr<nsIDOMSelection>domselection;
nsresult result = nsComponentManager::CreateInstance(kRangeListCID, nsnull,
kIDOMSelectionIID,
getter_AddRefs(domselection));
1998-12-14 18:34:14 +00:00
if (!NS_SUCCEEDED(result))
return result;
result = domselection->QueryInterface(kIFrameSelectionIID,
getter_AddRefs(mSelection));
if (!NS_SUCCEEDED(result))
return result;
domselection->AddSelectionListener(this);//possible circular reference
result = mSelection->Init((nsIFocusTracker *) this);
if (!NS_SUCCEEDED(result))
return result;
// Important: this has to happen after the selection has been set up
#ifdef SHOW_CARET
nsCaretProperties *caretProperties = NewCaretProperties();
// make the caret
nsresult err = NS_NewCaret(getter_AddRefs(mCaret));
if (NS_SUCCEEDED(err))
{
mCaret->Init(this, caretProperties);
}
delete caretProperties;
caretProperties = nsnull;
// do this when we have a way of figuring out how to tell chrome
// from content
//SetCaretEnabled(PR_TRUE); // make it show in browser windows
#endif
//set up selection to be displayed in document
nsCOMPtr<nsISupports> container;
result = aPresContext->GetContainer(getter_AddRefs(container));
if (NS_SUCCEEDED(result) && container) {
nsCOMPtr<nsIWebShell> webShell;
webShell = do_QueryInterface(container,&result);
if (NS_SUCCEEDED(result) && webShell){
nsWebShellType webShellType;
result = webShell->GetWebShellType(webShellType);
if (NS_SUCCEEDED(result)){
if (nsWebShellContent == webShellType){
mDocument->SetDisplaySelection(PR_TRUE);
}
}
}
}
1998-04-13 20:24:54 +00:00
return NS_OK;
}
NS_IMETHODIMP
PresShell::EnterReflowLock()
{
++mReflowLockCount;
return NS_OK;
}
NS_IMETHODIMP
PresShell::ExitReflowLock()
{
PRUint32 newReflowLockCount = mReflowLockCount - 1;
if (newReflowLockCount == 0) {
ProcessReflowCommands();
}
mReflowLockCount = newReflowLockCount;
return NS_OK;
}
NS_IMETHODIMP
PresShell::GetDocument(nsIDocument** aResult)
1998-04-13 20:24:54 +00:00
{
NS_PRECONDITION(nsnull != aResult, "null ptr");
if (nsnull == aResult) {
return NS_ERROR_NULL_POINTER;
}
*aResult = mDocument;
NS_IF_ADDREF(*aResult);
return NS_OK;
1998-04-13 20:24:54 +00:00
}
NS_IMETHODIMP
PresShell::GetPresContext(nsIPresContext** aResult)
1998-04-13 20:24:54 +00:00
{
NS_PRECONDITION(nsnull != aResult, "null ptr");
if (nsnull == aResult) {
return NS_ERROR_NULL_POINTER;
}
*aResult = mPresContext;
NS_IF_ADDREF(*aResult);
return NS_OK;
1998-04-13 20:24:54 +00:00
}
NS_IMETHODIMP
PresShell::GetViewManager(nsIViewManager** aResult)
1998-04-13 20:24:54 +00:00
{
NS_PRECONDITION(nsnull != aResult, "null ptr");
if (nsnull == aResult) {
return NS_ERROR_NULL_POINTER;
}
*aResult = mViewManager;
1998-04-13 20:24:54 +00:00
NS_IF_ADDREF(mViewManager);
return NS_OK;
1998-04-13 20:24:54 +00:00
}
NS_IMETHODIMP
PresShell::GetStyleSet(nsIStyleSet** aResult)
1998-04-13 20:24:54 +00:00
{
NS_PRECONDITION(nsnull != aResult, "null ptr");
if (nsnull == aResult) {
return NS_ERROR_NULL_POINTER;
}
*aResult = mStyleSet;
NS_IF_ADDREF(*aResult);
return NS_OK;
1998-04-13 20:24:54 +00:00
}
NS_IMETHODIMP
PresShell::GetActiveAlternateStyleSheet(nsString& aSheetTitle)
{ // first non-html sheet in style set that has title
if (mStyleSet) {
PRInt32 count = mStyleSet->GetNumberOfDocStyleSheets();
PRInt32 index;
nsAutoString textHtml("text/html");
for (index = 0; index < count; index++) {
nsIStyleSheet* sheet = mStyleSet->GetDocStyleSheetAt(index);
if (nsnull != sheet) {
nsAutoString type;
sheet->GetType(type);
if (PR_FALSE == type.Equals(textHtml)) {
nsAutoString title;
sheet->GetTitle(title);
if (0 < title.Length()) {
aSheetTitle = title;
index = count; // stop looking
}
}
NS_RELEASE(sheet);
}
}
}
return NS_OK;
}
NS_IMETHODIMP
PresShell::SelectAlternateStyleSheet(const nsString& aSheetTitle)
{
if (mDocument && mStyleSet) {
PRInt32 count = mDocument->GetNumberOfStyleSheets();
PRInt32 index;
nsAutoString textHtml("text/html");
for (index = 0; index < count; index++) {
nsIStyleSheet* sheet = mDocument->GetStyleSheetAt(index);
if (nsnull != sheet) {
nsAutoString type;
sheet->GetType(type);
if (PR_FALSE == type.Equals(textHtml)) {
nsAutoString title;
sheet->GetTitle(title);
if (0 < title.Length()) {
if (title.EqualsIgnoreCase(aSheetTitle)) {
mStyleSet->AddDocStyleSheet(sheet, mDocument);
}
else {
mStyleSet->RemoveDocStyleSheet(sheet);
}
}
}
NS_RELEASE(sheet);
}
}
ReconstructFrames();
}
return NS_OK;
}
NS_IMETHODIMP
PresShell::ListAlternateStyleSheets(nsStringArray& aTitleList)
{
if (mDocument) {
PRInt32 count = mDocument->GetNumberOfStyleSheets();
PRInt32 index;
nsAutoString textHtml("text/html");
for (index = 0; index < count; index++) {
nsIStyleSheet* sheet = mDocument->GetStyleSheetAt(index);
if (nsnull != sheet) {
nsAutoString type;
sheet->GetType(type);
if (PR_FALSE == type.Equals(textHtml)) {
nsAutoString title;
sheet->GetTitle(title);
if (0 < title.Length()) {
if (-1 == aTitleList.IndexOfIgnoreCase(title)) {
aTitleList.AppendString(title);
}
}
}
NS_RELEASE(sheet);
}
}
}
return NS_OK;
}
1998-12-08 18:26:06 +00:00
NS_IMETHODIMP
PresShell::GetSelection(nsIDOMSelection **aSelection)
1998-12-08 18:26:06 +00:00
{
if (!aSelection || !mSelection)
return NS_ERROR_NULL_POINTER;
return mSelection->QueryInterface(kIDOMSelectionIID,(void **)aSelection);
1998-12-08 18:26:06 +00:00
}
1998-04-13 20:24:54 +00:00
// Make shell be a document observer
NS_IMETHODIMP
PresShell::BeginObservingDocument()
1998-04-13 20:24:54 +00:00
{
if (mDocument) {
1998-04-13 20:24:54 +00:00
mDocument->AddObserver(this);
}
return NS_OK;
1998-04-13 20:24:54 +00:00
}
// Make shell stop being a document observer
NS_IMETHODIMP
PresShell::EndObservingDocument()
1998-04-13 20:24:54 +00:00
{
if (mDocument) {
1998-04-13 20:24:54 +00:00
mDocument->RemoveObserver(this);
}
if (mSelection){
nsCOMPtr<nsIDOMSelection> domselection;
nsresult result;
domselection = do_QueryInterface(mSelection , &result);
if (NS_FAILED(result))
return result;
if (!domselection)
return NS_ERROR_UNEXPECTED;
domselection->RemoveSelectionListener(this);
mSelection->ShutDown();
}
return NS_OK;
1998-04-13 20:24:54 +00:00
}
1998-08-28 02:54:06 +00:00
NS_IMETHODIMP
PresShell::InitialReflow(nscoord aWidth, nscoord aHeight)
1998-04-13 20:24:54 +00:00
{
nsIContent* root = nsnull;
SuspendCaret();
EnterReflowLock();
if (mPresContext) {
1998-04-13 20:24:54 +00:00
nsRect r(0, 0, aWidth, aHeight);
mPresContext->SetVisibleArea(r);
}
if (mDocument) {
root = mDocument->GetRootContent();
}
if (nsnull != root) {
if (nsnull == mRootFrame) {
// Have style sheet processor construct a frame for the
// precursors to the root content object's frame
mStyleSet->ConstructRootFrame(mPresContext, root, mRootFrame);
1998-04-13 20:24:54 +00:00
}
// Have the style sheet processor construct frame for the root
// content object down
mStyleSet->ContentInserted(mPresContext, nsnull, root, 0);
NS_RELEASE(root);
1998-04-13 20:24:54 +00:00
}
if (nsnull != mRootFrame) {
// Kick off a top-down reflow
NS_FRAME_LOG(NS_FRAME_TRACE_CALLS,
("enter nsPresShell::InitialReflow: %d,%d", aWidth, aHeight));
#ifdef NS_DEBUG
if (nsIFrame::GetVerifyTreeEnable()) {
mRootFrame->VerifyTree();
}
#endif
nsRect bounds;
mPresContext->GetVisibleArea(bounds);
nsSize maxSize(bounds.width, bounds.height);
nsHTMLReflowMetrics desiredSize(nsnull);
nsReflowStatus status;
nsIHTMLReflow* htmlReflow;
nsIRenderingContext* rcx = nsnull;
CreateRenderingContext(mRootFrame, &rcx);
nsHTMLReflowState reflowState(*mPresContext, mRootFrame,
1999-03-05 04:29:11 +00:00
eReflowReason_Initial, rcx, maxSize);
if (NS_OK == mRootFrame->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow)) {
htmlReflow->Reflow(*mPresContext, desiredSize, reflowState, status);
mRootFrame->SizeTo(desiredSize.width, desiredSize.height);
#ifdef NS_DEBUG
if (nsIFrame::GetVerifyTreeEnable()) {
mRootFrame->VerifyTree();
}
#endif
}
NS_IF_RELEASE(rcx);
NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, ("exit nsPresShell::InitialReflow"));
}
ExitReflowLock();
ResumeCaret();
return NS_OK; //XXX this needs to be real. MMP
}
NS_IMETHODIMP
PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight)
{
SuspendCaret();
EnterReflowLock();
if (mPresContext) {
nsRect r(0, 0, aWidth, aHeight);
mPresContext->SetVisibleArea(r);
}
// If we don't have a root frame yet, that means we haven't had our initial
// reflow...
1998-04-13 20:24:54 +00:00
if (nsnull != mRootFrame) {
// Kick off a top-down reflow
1998-05-20 16:24:54 +00:00
NS_FRAME_LOG(NS_FRAME_TRACE_CALLS,
("enter nsPresShell::ResizeReflow: %d,%d", aWidth, aHeight));
1998-04-13 20:24:54 +00:00
#ifdef NS_DEBUG
1998-05-20 16:24:54 +00:00
if (nsIFrame::GetVerifyTreeEnable()) {
mRootFrame->VerifyTree();
}
1998-04-13 20:24:54 +00:00
#endif
nsRect bounds;
mPresContext->GetVisibleArea(bounds);
nsSize maxSize(bounds.width, bounds.height);
nsHTMLReflowMetrics desiredSize(nsnull);
nsReflowStatus status;
nsIHTMLReflow* htmlReflow;
nsIRenderingContext* rcx = nsnull;
CreateRenderingContext(mRootFrame, &rcx);
nsHTMLReflowState reflowState(*mPresContext, mRootFrame,
1999-03-05 04:29:11 +00:00
eReflowReason_Resize, rcx, maxSize);
if (NS_OK == mRootFrame->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow)) {
htmlReflow->Reflow(*mPresContext, desiredSize, reflowState, status);
mRootFrame->SizeTo(desiredSize.width, desiredSize.height);
1998-04-13 20:24:54 +00:00
#ifdef NS_DEBUG
if (nsIFrame::GetVerifyTreeEnable()) {
mRootFrame->VerifyTree();
}
1998-04-13 20:24:54 +00:00
#endif
}
NS_IF_RELEASE(rcx);
1998-05-20 16:24:54 +00:00
NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, ("exit nsPresShell::ResizeReflow"));
1998-04-13 20:24:54 +00:00
// XXX if debugging then we should assert that the cache is empty
} else {
#ifdef NOISY
printf("PresShell::ResizeReflow: null root frame\n");
#endif
}
ExitReflowLock();
ResumeCaret();
1998-08-28 02:54:06 +00:00
return NS_OK; //XXX this needs to be real. MMP
1998-04-13 20:24:54 +00:00
}
NS_IMETHODIMP PresShell::ScrollFrameIntoView(nsIFrame *aFrame){
if (!aFrame)
return NS_ERROR_NULL_POINTER;
if (IsScrollingEnabled())
return ScrollFrameIntoView(aFrame,
0, NS_PRESSHELL_SCROLL_TOP |NS_PRESSHELL_SCROLL_ANYWHERE,
0, NS_PRESSHELL_SCROLL_LEFT|NS_PRESSHELL_SCROLL_ANYWHERE);
return NS_OK;
}
NS_IMETHODIMP PresShell::GetCaret(nsICaret **outCaret)
{
if (!outCaret || !mCaret)
return NS_ERROR_NULL_POINTER;
return mCaret->QueryInterface(kICaretIID,(void **)outCaret);
}
1999-04-02 01:14:30 +00:00
nsresult PresShell::RefreshCaret(nsIView *aView, nsIRenderingContext& aRendContext, const nsRect& aDirtyRect)
{
if (mCaret)
mCaret->Refresh(aView, aRendContext, aDirtyRect);
return NS_OK;
}
NS_IMETHODIMP PresShell::SetCaretEnabled(PRBool inEnable)
{
nsresult result = NS_OK;
PRBool oldEnabled = mCaretEnabled;
mCaretEnabled = inEnable;
if (mCaret && (mCaretEnabled != oldEnabled))
{
if (mCaretEnabled)
result = mCaret->SetCaretVisible(PR_TRUE);
else
result = mCaret->SetCaretVisible(PR_FALSE);
}
return result;
}
NS_IMETHODIMP PresShell::SetDisplayNonTextSelection(PRBool inEnable)
{
mDisplayNonTextSelection = PR_TRUE;
return NS_OK;
}
NS_IMETHODIMP PresShell::GetDisplayNonTextSelection(PRBool *inEnable)
{
if (!inEnable)
return NS_ERROR_NULL_POINTER;
*inEnable = mDisplayNonTextSelection;
return NS_OK;
}
/*implementation of the nsIDOMSelectionListener
it will invoke the resetselection to update the presentation shell's frames
*/
NS_IMETHODIMP PresShell::NotifySelectionChanged()
{
if (!mSelection)
return NS_ERROR_NULL_POINTER;
return NS_ERROR_NULL_POINTER;
}
nsresult PresShell::SuspendCaret()
{
if (mCaret)
return mCaret->SetCaretVisible(PR_FALSE);
return NS_OK;
}
nsresult PresShell::ResumeCaret()
{
if (mCaret && mCaretEnabled)
return mCaret->SetCaretVisible(PR_TRUE);
return NS_OK;
}
NS_IMETHODIMP
PresShell::StyleChangeReflow()
{
EnterReflowLock();
if (nsnull != mRootFrame) {
// Kick off a top-down reflow
NS_FRAME_LOG(NS_FRAME_TRACE_CALLS,
("enter nsPresShell::StyleChangeReflow"));
#ifdef NS_DEBUG
if (nsIFrame::GetVerifyTreeEnable()) {
mRootFrame->VerifyTree();
}
#endif
nsRect bounds;
mPresContext->GetVisibleArea(bounds);
nsSize maxSize(bounds.width, bounds.height);
nsHTMLReflowMetrics desiredSize(nsnull);
nsReflowStatus status;
nsIHTMLReflow* htmlReflow;
nsIRenderingContext* rcx = nsnull;
CreateRenderingContext(mRootFrame, &rcx);
// XXX We should be using eReflowReason_StyleChange
nsHTMLReflowState reflowState(*mPresContext, mRootFrame,
1999-03-05 04:29:11 +00:00
eReflowReason_Resize, rcx, maxSize);
if (NS_OK == mRootFrame->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow)) {
htmlReflow->Reflow(*mPresContext, desiredSize, reflowState, status);
mRootFrame->SizeTo(desiredSize.width, desiredSize.height);
#ifdef NS_DEBUG
if (nsIFrame::GetVerifyTreeEnable()) {
mRootFrame->VerifyTree();
}
#endif
}
NS_IF_RELEASE(rcx);
NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, ("exit nsPresShell::StyleChangeReflow"));
}
ExitReflowLock();
return NS_OK; //XXX this needs to be real. MMP
}
NS_IMETHODIMP
PresShell::GetRootFrame(nsIFrame** aResult) const
1998-04-13 20:24:54 +00:00
{
NS_PRECONDITION(nsnull != aResult, "null ptr");
if (nsnull == aResult) {
return NS_ERROR_NULL_POINTER;
}
*aResult = mRootFrame;
return NS_OK;
1998-04-13 20:24:54 +00:00
}
NS_IMETHODIMP
PresShell::GetPageSequenceFrame(nsIPageSequenceFrame** aResult) const
{
NS_PRECONDITION(nsnull != aResult, "null ptr");
if (nsnull == aResult) {
return NS_ERROR_NULL_POINTER;
}
nsIFrame* child;
nsIPageSequenceFrame* pageSequence;
// The page sequence frame should be either the immediate child or
// its child
mRootFrame->FirstChild(nsnull, &child);
if (nsnull != child) {
if (NS_SUCCEEDED(child->QueryInterface(kIPageSequenceFrameIID, (void**)&pageSequence))) {
*aResult = pageSequence;
return NS_OK;
}
child->FirstChild(nsnull, &child);
if (nsnull != child) {
if (NS_SUCCEEDED(child->QueryInterface(kIPageSequenceFrameIID, (void**)&pageSequence))) {
*aResult = pageSequence;
return NS_OK;
}
}
}
*aResult = nsnull;
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
PresShell::BeginUpdate(nsIDocument *aDocument)
1998-04-13 20:24:54 +00:00
{
mUpdateCount++;
return NS_OK;
1998-04-13 20:24:54 +00:00
}
NS_IMETHODIMP
PresShell::EndUpdate(nsIDocument *aDocument)
1998-04-13 20:24:54 +00:00
{
NS_PRECONDITION(0 != mUpdateCount, "too many EndUpdate's");
if (--mUpdateCount == 0) {
// XXX do something here
}
return NS_OK;
}
NS_IMETHODIMP
PresShell::BeginLoad(nsIDocument *aDocument)
{
return NS_OK;
}
NS_IMETHODIMP
PresShell::EndLoad(nsIDocument *aDocument)
{
return NS_OK;
}
NS_IMETHODIMP
PresShell::BeginReflow(nsIDocument *aDocument, nsIPresShell* aShell)
{
return NS_OK;
}
NS_IMETHODIMP
PresShell::EndReflow(nsIDocument *aDocument, nsIPresShell* aShell)
{
return NS_OK;
1998-04-13 20:24:54 +00:00
}
NS_IMETHODIMP
1998-06-09 04:51:44 +00:00
PresShell::AppendReflowCommand(nsIReflowCommand* aReflowCommand)
1998-04-13 20:24:54 +00:00
{
#ifdef NS_DEBUG
if (mInVerifyReflow) {
return NS_OK;
}
#endif
1998-06-09 04:51:44 +00:00
NS_ADDREF(aReflowCommand);
return mReflowCommands.AppendElement(aReflowCommand);
1998-04-13 20:24:54 +00:00
}
NS_IMETHODIMP
PresShell::CancelReflowCommand(nsIFrame* aTargetFrame)
{
PRInt32 i, n = mReflowCommands.Count();
for (i = 0; i < n; i++) {
nsIReflowCommand* rc = (nsIReflowCommand*) mReflowCommands.ElementAt(0);
if (rc) {
nsIFrame* target;
if (NS_SUCCEEDED(rc->GetTarget(target))) {
if (target == aTargetFrame) {
mReflowCommands.RemoveElementAt(i);
n--;
i--;
continue;
}
}
}
}
return NS_OK;
}
NS_IMETHODIMP
PresShell::ProcessReflowCommands()
1998-04-13 20:24:54 +00:00
{
if (0 != mReflowCommands.Count()) {
nsHTMLReflowMetrics desiredSize(nsnull);
nsIRenderingContext* rcx;
CreateRenderingContext(mRootFrame, &rcx);
1998-04-13 20:24:54 +00:00
while (0 != mReflowCommands.Count()) {
1998-06-09 04:51:44 +00:00
nsIReflowCommand* rc = (nsIReflowCommand*) mReflowCommands.ElementAt(0);
1998-04-13 20:24:54 +00:00
mReflowCommands.RemoveElementAt(0);
// Dispatch the reflow command
nsSize maxSize;
mRootFrame->GetSize(maxSize);
1998-06-09 04:51:44 +00:00
#ifdef NS_DEBUG
nsIReflowCommand::ReflowType type;
1998-06-09 04:51:44 +00:00
rc->GetType(type);
NS_FRAME_LOG(NS_FRAME_TRACE_CALLS,
("PresShell::ProcessReflowCommands: begin reflow command type=%d",
type));
1998-06-09 04:51:44 +00:00
#endif
rc->Dispatch(*mPresContext, desiredSize, maxSize, *rcx);
1998-06-09 04:51:44 +00:00
NS_RELEASE(rc);
NS_FRAME_LOG(NS_FRAME_TRACE_CALLS,
("PresShell::ProcessReflowCommands: end reflow command"));
1998-04-13 20:24:54 +00:00
}
NS_IF_RELEASE(rcx);
1998-04-13 20:24:54 +00:00
#ifdef NS_DEBUG
1998-05-20 16:24:54 +00:00
if (nsIFrame::GetVerifyTreeEnable()) {
mRootFrame->VerifyTree();
}
1998-07-13 19:49:42 +00:00
if (GetVerifyReflowEnable()) {
// First synchronously render what we have so far so that we can
// see it.
1999-04-20 00:24:21 +00:00
// if (gVerifyReflowAll) {
// printf("Before verify-reflow\n");
nsIView* rootView;
mViewManager->GetRootView(rootView);
mViewManager->UpdateView(rootView, nsnull, NS_VMREFRESH_IMMEDIATE);
1999-04-20 00:24:21 +00:00
// PR_Sleep(PR_SecondsToInterval(3));
// }
mInVerifyReflow = PR_TRUE;
1998-07-13 19:49:42 +00:00
VerifyIncrementalReflow();
mInVerifyReflow = PR_FALSE;
if (gVerifyReflowAll) {
printf("After verify-reflow\n");
}
if (0 != mReflowCommands.Count()) {
printf("XXX yikes!\n");
}
1998-07-13 19:49:42 +00:00
}
1998-04-13 20:24:54 +00:00
#endif
}
return NS_OK;
}
NS_IMETHODIMP
PresShell::ClearFrameRefs(nsIFrame* aFrame)
{
nsIEventStateManager *manager;
if (NS_OK == mPresContext->GetEventStateManager(&manager)) {
manager->ClearFrameRefs(aFrame);
NS_RELEASE(manager);
}
if (mCaret) {
mCaret->ClearFrameRefs(aFrame);
}
if (aFrame == mCurrentEventFrame) {
mCurrentEventFrame->GetContent(&mCurrentEventContent);
mCurrentEventFrame = nsnull;
}
return NS_OK;
}
NS_IMETHODIMP
PresShell::CreateRenderingContext(nsIFrame *aFrame,
nsIRenderingContext** aResult)
{
NS_PRECONDITION(nsnull != aResult, "null ptr");
if (nsnull == aResult) {
return NS_ERROR_NULL_POINTER;
}
nsIWidget *widget = nsnull;
nsIView *view = nsnull;
nsPoint pt;
nsresult rv;
aFrame->GetView(&view);
if (nsnull == view)
aFrame->GetOffsetFromView(pt, &view);
while (nsnull != view)
{
view->GetWidget(widget);
if (nsnull != widget)
{
NS_RELEASE(widget);
break;
}
view->GetParent(view);
1998-04-13 20:24:54 +00:00
}
nsCOMPtr<nsIDeviceContext> dx;
1998-11-14 01:52:27 +00:00
nsIRenderingContext* result = nsnull;
rv = mPresContext->GetDeviceContext(getter_AddRefs(dx));
if (NS_SUCCEEDED(rv) && dx) {
if (nsnull != view) {
rv = dx->CreateRenderingContext(view, result);
}
else {
rv = dx->CreateRenderingContext(result);
}
}
*aResult = result;
return rv;
1998-04-13 20:24:54 +00:00
}
void
PresShell::HandleCantRenderReplacedElementEvent(nsIFrame* aFrame)
{
// Double-check that we haven't deleted the frame hierarchy
// XXX If we stay with this model we approach, then we need to observe
// aFrame and if it's deleted null out the pointer in the PL event struct
if (nsnull != mRootFrame) {
mStyleSet->CantRenderReplacedElement(mPresContext, aFrame);
ProcessReflowCommands();
}
}
struct CantRenderReplacedElementEvent : public PLEvent {
CantRenderReplacedElementEvent(PresShell* aShell, nsIFrame* aFrame);
~CantRenderReplacedElementEvent();
PresShell* mShell;
1999-05-05 01:10:25 +00:00
nsIContent* mContent; // using content rather than frame, see bug #3605
};
static void PR_CALLBACK
HandlePLEvent(CantRenderReplacedElementEvent* aEvent)
{
1999-05-05 01:10:25 +00:00
nsIFrame* frame;
if (NS_SUCCEEDED(aEvent->mShell->GetPrimaryFrameFor(aEvent->mContent, &frame))) {
aEvent->mShell->HandleCantRenderReplacedElementEvent(frame);
}
}
static void PR_CALLBACK
DestroyPLEvent(CantRenderReplacedElementEvent* aEvent)
{
delete aEvent;
}
CantRenderReplacedElementEvent::CantRenderReplacedElementEvent(PresShell* aShell,
nsIFrame* aFrame)
{
1999-05-05 01:10:25 +00:00
nsIContent* content;
mShell = aShell;
NS_ADDREF(mShell);
1999-05-05 01:10:25 +00:00
aFrame->GetContent(&content);
mContent = content;
PL_InitEvent(this, nsnull, (PLHandleEventProc)::HandlePLEvent,
(PLDestroyEventProc)::DestroyPLEvent);
}
CantRenderReplacedElementEvent::~CantRenderReplacedElementEvent()
{
NS_RELEASE(mShell);
1999-05-05 01:10:25 +00:00
NS_RELEASE(mContent);
}
NS_IMETHODIMP
PresShell::CantRenderReplacedElement(nsIPresContext* aPresContext,
nsIFrame* aFrame)
{
nsIEventQueueService* eventService;
nsresult rv;
// Notify the style set, but post the notification so it doesn't happen
// now
rv = nsServiceManager::GetService(kEventQueueServiceCID,
kIEventQueueServiceIID,
(nsISupports **)&eventService);
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIEventQueue> eventQueue;
rv = eventService->GetThreadEventQueue(PR_GetCurrentThread(),
getter_AddRefs(eventQueue));
nsServiceManager::ReleaseService(kEventQueueServiceCID, eventService);
if (NS_SUCCEEDED(rv) && eventQueue) {
CantRenderReplacedElementEvent* ev;
ev = new CantRenderReplacedElementEvent(this, aFrame);
eventQueue->PostEvent(ev);
}
}
return rv;
}
1999-02-12 05:39:33 +00:00
NS_IMETHODIMP
PresShell::GoToAnchor(const nsString& aAnchorName) const
{
nsCOMPtr<nsIDOMHTMLDocument> htmlDoc;
nsCOMPtr<nsIXMLDocument> xmlDoc;
nsresult rv = NS_OK;
nsCOMPtr<nsIContent> content;
1999-02-12 05:39:33 +00:00
if (NS_SUCCEEDED(mDocument->QueryInterface(kIDOMHTMLDocumentIID,
getter_AddRefs(htmlDoc)))) {
1999-02-12 05:39:33 +00:00
nsCOMPtr<nsIDOMElement> element;
// Find the element with the specified id
rv = htmlDoc->GetElementById(aAnchorName, getter_AddRefs(element));
if (NS_SUCCEEDED(rv) && element) {
1999-02-12 05:39:33 +00:00
// Get the nsIContent interface, because that's what we need to
// get the primary frame
rv = element->QueryInterface(kIContentIID, getter_AddRefs(content));
}
}
else if (NS_SUCCEEDED(mDocument->QueryInterface(kIXMLDocumentIID,
getter_AddRefs(xmlDoc)))) {
rv = xmlDoc->GetContentById(aAnchorName, getter_AddRefs(content));
}
1999-02-12 05:39:33 +00:00
if (NS_SUCCEEDED(rv) && content) {
nsIFrame* frame;
// Get the primary frame
if (NS_SUCCEEDED(GetPrimaryFrameFor(content, &frame))) {
1999-05-21 23:11:16 +00:00
rv = ScrollFrameIntoView(frame, 0, NS_PRESSHELL_SCROLL_TOP, 0, NS_PRESSHELL_SCROLL_LEFT);
1999-02-12 05:39:33 +00:00
}
} else {
rv = NS_ERROR_FAILURE;
}
return rv;
}
// XXX: all arguments except aFrame are currently ignored!
NS_IMETHODIMP
PresShell::ScrollFrameIntoView(nsIFrame *aFrame,
PRInt32 aVOffsetPercent,
PRUint32 aVFlags,
PRInt32 aHOffsetPercent,
PRUint32 aHFlags) const
{
nsresult rv = NS_ERROR_UNEXPECTED;
if (!aFrame)
return NS_ERROR_NULL_POINTER;
if (nsnull != mViewManager) {
nsIScrollableView* scrollingView;
mViewManager->GetRootScrollableView(&scrollingView);
if (scrollingView) {
// Determine the offset for the given frame relative to the
// scrolled view
nsIView* scrolledView;
nsPoint offset;
nsIView* view;
scrollingView->GetScrolledView(scrolledView);
aFrame->GetOffsetFromView(offset, &view);
if (aVFlags & NS_PRESSHELL_SCROLL_ANYWHERE)
{ // if we just care that the frame is somewhere in the view port,
// check to see if it is already visible
nsRect frameRect (offset, nsSize(1,1)); // XXX: this is biased toward showing the top of the frame
nsRect viewBounds; // the bounds of the view containing the frame
view->GetBounds(viewBounds);
// walk up the view hierarchy looking for the scrolling view
nsIView *parentView;
view->GetParent(parentView);
nsRect bounds;
nscoord visHeight=0;
while (parentView)
{
nsIScrollableView *parentScrollableView=nsnull;
nsresult result = parentView->QueryInterface(kIScrollableViewIID, (void**)&parentScrollableView);
if (NS_SUCCEEDED(result))
{
if (parentScrollableView==scrollingView)
{ // found the scrolling view, get it's height
parentView->GetBounds(bounds);
visHeight = bounds.height;
break;
}
}
parentView->GetParent(parentView);
}
if (0!=visHeight)
{ // there was a scrolling view, calc the visible rect
nsRect visArea(viewBounds.x, -(viewBounds.y), viewBounds.width, visHeight);
// is the frame within the visible rect?
PRBool alreadyVisible = visArea.Intersects(frameRect);
if (PR_FALSE==alreadyVisible) { // if not, scroll it into view
scrollingView->ScrollTo(0, offset.y, NS_VMREFRESH_IMMEDIATE);
}
}
}
else
{
// XXX If view != scrolledView, then there is a scrolled frame,
// e.g., a DIV with 'overflow' of 'scroll', somewhere in the middle,
// or maybe an absolutely positioned element that has a view. We
// need to handle these cases...
scrollingView->ScrollTo(0, offset.y, NS_VMREFRESH_IMMEDIATE);
}
rv = NS_OK;
}
}
return rv;
}
NS_IMETHODIMP
PresShell::DoCopy()
{
nsCOMPtr<nsIDocument> doc;
GetDocument(getter_AddRefs(doc));
if (doc) {
nsString buffer;
nsIDOMSelection* sel = nsnull;
GetSelection(&sel);
if (sel != nsnull)
doc->CreateXIF(buffer,sel);
NS_IF_RELEASE(sel);
// Get the Clipboard
nsIClipboard* clipboard;
nsresult rv = nsServiceManager::GetService(kCClipboardCID,
nsIClipboard::GetIID(),
(nsISupports **)&clipboard);
if (NS_OK == rv) {
// Create a data flavor to tell the transferable
// that it is about to receive XIF
nsAutoString flavor(kXIFMime);
// Create a transferable for putting data on the Clipboard
nsCOMPtr<nsITransferable> trans;
rv = nsComponentManager::CreateInstance(kCTransferableCID, nsnull,
nsITransferable::GetIID(),
(void**) getter_AddRefs(trans));
if (NS_OK == rv) {
// The data on the clipboard will be in "XIF" format
// so give the clipboard transferable a "XIFConverter" for
// converting from XIF to other formats
nsCOMPtr<nsIFormatConverter> xifConverter;
rv = nsComponentManager::CreateInstance(kCXIFConverterCID, nsnull,
nsIFormatConverter::GetIID(), (void**) getter_AddRefs(xifConverter));
if (NS_OK == rv) {
// Add the XIF DataFlavor to the transferable
// this tells the transferable that it can handle receiving the XIF format
trans->AddDataFlavor(&flavor);
// Add the converter for going from XIF to other formats
trans->SetConverter(xifConverter);
// Now add the XIF data to the transferable
trans->SetTransferData(&flavor, buffer.ToNewCString(), buffer.Length());
// put the transferable on the clipboard
clipboard->SetData(trans, nsnull);
}
}
1999-04-23 17:15:53 +00:00
nsServiceManager::ReleaseService(kCClipboardCID, clipboard);
}
}
return NS_OK;
}
NS_IMETHODIMP
PresShell::ContentChanged(nsIDocument *aDocument,
nsIContent* aContent,
nsISupports* aSubContent)
1998-04-13 20:24:54 +00:00
{
NS_PRECONDITION(nsnull != mRootFrame, "null root frame");
EnterReflowLock();
nsresult rv = mStyleSet->ContentChanged(mPresContext, aContent, aSubContent);
ExitReflowLock();
return rv;
1998-04-13 20:24:54 +00:00
}
1999-02-27 07:15:09 +00:00
NS_IMETHODIMP
1999-04-20 00:06:58 +00:00
PresShell::ContentStatesChanged(nsIDocument* aDocument,
nsIContent* aContent1,
nsIContent* aContent2)
1999-02-27 07:15:09 +00:00
{
NS_PRECONDITION(nsnull != mRootFrame, "null root frame");
EnterReflowLock();
1999-04-20 00:06:58 +00:00
nsresult rv = mStyleSet->ContentStatesChanged(mPresContext, aContent1, aContent2);
1999-02-27 07:15:09 +00:00
ExitReflowLock();
return rv;
}
NS_IMETHODIMP
PresShell::AttributeChanged(nsIDocument *aDocument,
nsIContent* aContent,
nsIAtom* aAttribute,
PRInt32 aHint)
{
NS_PRECONDITION(nsnull != mRootFrame, "null root frame");
EnterReflowLock();
nsresult rv = mStyleSet->AttributeChanged(mPresContext, aContent, aAttribute, aHint);
ExitReflowLock();
return rv;
}
NS_IMETHODIMP
PresShell::ContentAppended(nsIDocument *aDocument,
nsIContent* aContainer,
PRInt32 aNewIndexInContainer)
1998-04-13 20:24:54 +00:00
{
EnterReflowLock();
nsresult rv = mStyleSet->ContentAppended(mPresContext, aContainer, aNewIndexInContainer);
ExitReflowLock();
return rv;
1998-04-13 20:24:54 +00:00
}
NS_IMETHODIMP
PresShell::ContentInserted(nsIDocument* aDocument,
nsIContent* aContainer,
nsIContent* aChild,
PRInt32 aIndexInContainer)
1998-04-13 20:24:54 +00:00
{
EnterReflowLock();
nsresult rv = mStyleSet->ContentInserted(mPresContext, aContainer, aChild, aIndexInContainer);
ExitReflowLock();
return rv;
1998-04-13 20:24:54 +00:00
}
NS_IMETHODIMP
PresShell::ContentReplaced(nsIDocument* aDocument,
nsIContent* aContainer,
nsIContent* aOldChild,
nsIContent* aNewChild,
PRInt32 aIndexInContainer)
1998-04-13 20:24:54 +00:00
{
EnterReflowLock();
nsresult rv = mStyleSet->ContentReplaced(mPresContext, aContainer, aOldChild,
aNewChild, aIndexInContainer);
ExitReflowLock();
return rv;
1998-04-13 20:24:54 +00:00
}
NS_IMETHODIMP
PresShell::ContentRemoved(nsIDocument *aDocument,
nsIContent* aContainer,
nsIContent* aChild,
PRInt32 aIndexInContainer)
1998-04-13 20:24:54 +00:00
{
EnterReflowLock();
nsresult rv = mStyleSet->ContentRemoved(mPresContext, aContainer,
aChild, aIndexInContainer);
ExitReflowLock();
return rv;
1998-04-13 20:24:54 +00:00
}
1998-11-26 01:34:53 +00:00
nsresult
PresShell::ReconstructFrames(void)
{
nsresult rv = NS_OK;
EnterReflowLock();
rv = mStyleSet->ReconstructDocElementHierarchy(mPresContext);
ExitReflowLock();
return rv;
}
1998-11-26 01:34:53 +00:00
NS_IMETHODIMP
PresShell::StyleSheetAdded(nsIDocument *aDocument,
nsIStyleSheet* aStyleSheet)
{
return ReconstructFrames();
}
NS_IMETHODIMP
PresShell::StyleSheetRemoved(nsIDocument *aDocument,
nsIStyleSheet* aStyleSheet)
{
return ReconstructFrames();
}
1998-11-26 01:34:53 +00:00
NS_IMETHODIMP
PresShell::StyleSheetDisabledStateChanged(nsIDocument *aDocument,
nsIStyleSheet* aStyleSheet,
PRBool aDisabled)
{
return ReconstructFrames();
}
NS_IMETHODIMP
PresShell::StyleRuleChanged(nsIDocument *aDocument,
nsIStyleSheet* aStyleSheet,
nsIStyleRule* aStyleRule,
PRInt32 aHint)
{
EnterReflowLock();
nsresult rv = mStyleSet->StyleRuleChanged(mPresContext, aStyleSheet,
aStyleRule, aHint);
ExitReflowLock();
return rv;
}
NS_IMETHODIMP
PresShell::StyleRuleAdded(nsIDocument *aDocument,
nsIStyleSheet* aStyleSheet,
nsIStyleRule* aStyleRule)
{
EnterReflowLock();
1999-04-03 18:58:04 +00:00
nsresult rv = mStyleSet->StyleRuleAdded(mPresContext, aStyleSheet,
aStyleRule);
1998-11-26 01:34:53 +00:00
ExitReflowLock();
1999-04-03 18:58:04 +00:00
if (NS_FAILED(rv)) {
return rv;
}
// XXX For now reconstruct everything
return ReconstructFrames();
1998-11-26 01:34:53 +00:00
}
NS_IMETHODIMP
PresShell::StyleRuleRemoved(nsIDocument *aDocument,
nsIStyleSheet* aStyleSheet,
nsIStyleRule* aStyleRule)
{
EnterReflowLock();
1999-04-03 18:58:04 +00:00
nsresult rv = mStyleSet->StyleRuleRemoved(mPresContext, aStyleSheet,
aStyleRule);
1998-11-26 01:34:53 +00:00
ExitReflowLock();
1999-04-03 18:58:04 +00:00
if (NS_FAILED(rv)) {
return rv;
}
// XXX For now reconstruct everything
return ReconstructFrames();
1998-11-26 01:34:53 +00:00
}
NS_IMETHODIMP
PresShell::DocumentWillBeDestroyed(nsIDocument *aDocument)
1998-04-13 20:24:54 +00:00
{
return NS_OK;
1998-04-13 20:24:54 +00:00
}
static nsIFrame*
FindFrameWithContent(nsIFrame* aFrame, nsIContent* aContent)
1998-04-13 20:24:54 +00:00
{
nsIContent* frameContent;
PRBool hasSameContent;
NS_ASSERTION(aFrame, "No frame to search!");
if (!aFrame) return nsnull;
// See if the frame points to the same content object
aFrame->GetContent(&frameContent);
hasSameContent = (frameContent == aContent);
NS_IF_RELEASE(frameContent);
if (hasSameContent) {
nsIAtom* frameType;
PRBool isPlaceholder;
// See if it's a placeholder frame
aFrame->GetFrameType(&frameType);
isPlaceholder = (nsLayoutAtoms::placeholderFrame == frameType);
NS_IF_RELEASE(frameType);
if (isPlaceholder) {
// Ignore the placeholder and return the out-of-flow frame instead
return ((nsPlaceholderFrame*)aFrame)->GetOutOfFlowFrame();
}
// Also ignore frames associated with generated content
nsFrameState frameState;
aFrame->GetFrameState(&frameState);
if ((frameState & NS_FRAME_GENERATED_CONTENT) == 0) {
return aFrame;
}
1998-04-13 20:24:54 +00:00
}
1998-11-17 01:03:28 +00:00
// Search for the frame in each child list that aFrame supports
nsIAtom* listName = nsnull;
PRInt32 listIndex = 0;
do {
nsIFrame* kid;
aFrame->FirstChild(listName, &kid);
1998-11-17 01:03:28 +00:00
while (nsnull != kid) {
nsIFrame* result = FindFrameWithContent(kid, aContent);
if (nsnull != result) {
NS_IF_RELEASE(listName);
return result;
}
kid->GetNextSibling(&kid);
1998-04-13 20:24:54 +00:00
}
1998-11-17 01:03:28 +00:00
NS_IF_RELEASE(listName);
aFrame->GetAdditionalChildListName(listIndex++, &listName);
1998-11-17 01:03:28 +00:00
} while(nsnull != listName);
1998-04-13 20:24:54 +00:00
return nsnull;
}
NS_IMETHODIMP
PresShell::GetPrimaryFrameFor(nsIContent* aContent,
nsIFrame** aResult) const
1998-04-13 20:24:54 +00:00
{
NS_PRECONDITION(nsnull != aResult, "null ptr");
if (nsnull == aResult) {
return NS_ERROR_NULL_POINTER;
}
1998-04-13 20:24:54 +00:00
// For the time being do a brute force depth-first search of
// the frame tree
*aResult = ::FindFrameWithContent(mRootFrame, aContent);
return NS_OK;
1998-04-13 20:24:54 +00:00
}
NS_IMETHODIMP
PresShell::SetPrimaryFrameFor(nsIContent* aContent,
nsIFrame* aPrimaryFrame)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
PresShell::ClearPrimaryFrameMap()
{
return NS_ERROR_NOT_IMPLEMENTED;
}
1999-02-25 19:55:06 +00:00
NS_IMETHODIMP
PresShell::GetStyleContextFor(nsIFrame* aFrame,
nsIStyleContext** aStyleContext) const
{
if (!aFrame || !aStyleContext) {
return NS_ERROR_NULL_POINTER;
}
return (aFrame->GetStyleContext(aStyleContext));
}
NS_IMETHODIMP
PresShell::GetLayoutObjectFor(nsIContent* aContent,
nsISupports** aResult) const
{
nsresult result = NS_ERROR_NULL_POINTER;
if ((nsnull!=aResult) && (nsnull!=aContent))
{
*aResult = nsnull;
nsIFrame *primaryFrame=nsnull;
result = GetPrimaryFrameFor(aContent, &primaryFrame);
if ((NS_SUCCEEDED(result)) && (nsnull!=primaryFrame))
{
result = primaryFrame->QueryInterface(kISupportsIID, (void**)aResult);
}
}
return result;
}
NS_IMETHODIMP
PresShell::GetPlaceholderFrameFor(nsIFrame* aFrame,
nsIFrame** aResult) const
{
NS_PRECONDITION(nsnull != aResult, "null ptr");
NS_PRECONDITION(nsnull != aFrame, "no frame");
if ((nsnull == aResult) || (nsnull == aFrame)) {
return NS_ERROR_NULL_POINTER;
}
if (nsnull == mPlaceholderMap) {
*aResult = nsnull;
} else {
*aResult = (nsIFrame*) mPlaceholderMap->Get(aFrame);
}
return NS_OK;
}
NS_IMETHODIMP
PresShell::SetPlaceholderFrameFor(nsIFrame* aFrame,
nsIFrame* aPlaceholderFrame)
{
NS_PRECONDITION(nsnull != aFrame, "no frame");
#ifdef NS_DEBUG
// Verify that the placeholder frame is of the correct type
if (aPlaceholderFrame) {
nsIAtom* frameType;
aPlaceholderFrame->GetFrameType(&frameType);
NS_PRECONDITION(nsLayoutAtoms::placeholderFrame == frameType, "unexpected frame type");
NS_IF_RELEASE(frameType);
}
#endif
if (nsnull == mPlaceholderMap) {
mPlaceholderMap = new FrameHashTable;
if (nsnull == mPlaceholderMap) {
return NS_ERROR_OUT_OF_MEMORY;
}
}
if (nsnull == aPlaceholderFrame) {
mPlaceholderMap->Remove(aFrame);
} else {
mPlaceholderMap->Put(aFrame, (void*)aPlaceholderFrame);
}
return NS_OK;
}
NS_IMETHODIMP
PresShell::ClearPlaceholderFrameMap()
{
return NS_ERROR_NOT_IMPLEMENTED;
}
1998-08-28 02:54:06 +00:00
//nsIViewObserver
1998-12-18 15:54:23 +00:00
NS_IMETHODIMP
PresShell::Paint(nsIView *aView,
nsIRenderingContext& aRenderingContext,
const nsRect& aDirtyRect)
1998-08-28 02:54:06 +00:00
{
void* clientData;
nsIFrame* frame;
nsresult rv = NS_OK;
1998-08-28 02:54:06 +00:00
NS_ASSERTION(!(nsnull == aView), "null view");
aView->GetClientData(clientData);
frame = (nsIFrame *)clientData;
1998-08-28 02:54:06 +00:00
if (nsnull != frame) {
1998-12-18 15:54:23 +00:00
rv = frame->Paint(*mPresContext, aRenderingContext, aDirtyRect,
NS_FRAME_PAINT_LAYER_BACKGROUND);
1998-12-18 15:54:23 +00:00
rv = frame->Paint(*mPresContext, aRenderingContext, aDirtyRect,
NS_FRAME_PAINT_LAYER_FLOATERS);
1998-12-18 15:54:23 +00:00
rv = frame->Paint(*mPresContext, aRenderingContext, aDirtyRect,
NS_FRAME_PAINT_LAYER_FOREGROUND);
#ifdef NS_DEBUG
// Draw a border around the frame
if (nsIFrame::GetShowFrameBorders()) {
nsRect r;
frame->GetRect(r);
aRenderingContext.SetColor(NS_RGB(0,0,255));
aRenderingContext.DrawRect(0, 0, r.width, r.height);
}
#endif
// ensure the caret gets redrawn
RefreshCaret(aView, aRenderingContext, aDirtyRect);
}
1998-08-28 02:54:06 +00:00
return rv;
}
nsIFrame*
PresShell::GetCurrentEventFrame()
{
if (!mCurrentEventFrame && mCurrentEventContent) {
GetPrimaryFrameFor(mCurrentEventContent, &mCurrentEventFrame);
}
return mCurrentEventFrame;
}
1998-12-18 15:54:23 +00:00
NS_IMETHODIMP
PresShell::HandleEvent(nsIView *aView,
nsGUIEvent* aEvent,
nsEventStatus& aEventStatus)
1998-08-28 02:54:06 +00:00
{
void* clientData;
nsIFrame* frame;
nsresult rv = NS_OK;
1998-08-28 02:54:06 +00:00
NS_ASSERTION(!(nsnull == aView), "null view");
if (mIsDestroying || mReflowLockCount > 0) {
return NS_OK;
}
aView->GetClientData(clientData);
frame = (nsIFrame *)clientData;
1998-08-28 02:54:06 +00:00
if (nsnull != frame) {
nsIWebShell* webShell = nsnull;
nsISupports* container;
mPresContext->GetContainer(&container);
if (nsnull != container) {
if (NS_OK != container->QueryInterface(kIWebShellIID, (void**)&webShell)) {
NS_ASSERTION(webShell, "No webshell to grab during event dispatch");
}
NS_RELEASE(container);
}
if (mSelection && aEvent->eventStructType == NS_KEY_EVENT)
1998-12-08 18:26:06 +00:00
{
mSelection->EnableFrameNotification(PR_FALSE);
mSelection->HandleKeyEvent(aEvent);
mSelection->EnableFrameNotification(PR_TRUE); //prevents secondary reset selection called since
//we are a listener now.
1998-12-08 18:26:06 +00:00
}
frame->GetFrameForPoint(aEvent->point, &mCurrentEventFrame);
NS_IF_RELEASE(mCurrentEventContent);
if (nsnull != GetCurrentEventFrame()) {
//Once we have the targetFrame, handle the event in this order
nsIEventStateManager *manager;
if (NS_OK == mPresContext->GetEventStateManager(&manager)) {
//1. Give event to event manager for pre event state changes and generation of synthetic events.
rv = manager->PreHandleEvent(*mPresContext, aEvent, mCurrentEventFrame, aEventStatus, aView);
//2. Give event to the DOM for third party and JS use.
if (nsnull != GetCurrentEventFrame() && NS_OK == rv) {
nsIContent* targetContent;
if (NS_OK == mCurrentEventFrame->GetContent(&targetContent) && nsnull != targetContent) {
rv = targetContent->HandleDOMEvent(*mPresContext, (nsEvent*)aEvent, nsnull,
NS_EVENT_FLAG_INIT, aEventStatus);
NS_RELEASE(targetContent);
}
//3. Give event to the Frames for browser default processing.
// XXX The event isn't translated into the local coordinate space
// of the frame...
if (nsnull != GetCurrentEventFrame() && NS_OK == rv) {
rv = mCurrentEventFrame->HandleEvent(*mPresContext, aEvent, aEventStatus);
//4. Give event to event manager for post event state changes and generation of synthetic events.
if (nsnull != GetCurrentEventFrame() && NS_OK == rv) {
rv = manager->PostHandleEvent(*mPresContext, aEvent, mCurrentEventFrame, aEventStatus, aView);
}
}
}
NS_RELEASE(manager);
}
}
NS_IF_RELEASE(webShell);
}
else {
1998-08-28 02:54:06 +00:00
rv = NS_OK;
}
1998-08-28 02:54:06 +00:00
return rv;
}
1998-12-18 15:54:23 +00:00
NS_IMETHODIMP
PresShell::Scrolled(nsIView *aView)
1998-08-28 02:54:06 +00:00
{
void* clientData;
nsIFrame* frame;
1998-08-28 02:54:06 +00:00
nsresult rv;
NS_ASSERTION(!(nsnull == aView), "null view");
aView->GetClientData(clientData);
frame = (nsIFrame *)clientData;
1998-08-28 02:54:06 +00:00
if (nsnull != frame)
rv = frame->Scrolled(aView);
1998-08-28 02:54:06 +00:00
else
rv = NS_OK;
return rv;
}
1998-12-18 15:54:23 +00:00
NS_IMETHODIMP
PresShell::ResizeReflow(nsIView *aView, nscoord aWidth, nscoord aHeight)
1998-08-28 02:54:06 +00:00
{
return ResizeReflow(aWidth, aHeight);
}
1998-07-13 19:49:42 +00:00
#ifdef NS_DEBUG
#include "nsViewsCID.h"
#include "nsWidgetsCID.h"
#include "nsIScrollableView.h"
#include "nsIDeviceContext.h"
#include "nsIURL.h"
#include "nsILinkHandler.h"
1998-07-13 19:49:42 +00:00
static NS_DEFINE_IID(kViewManagerCID, NS_VIEW_MANAGER_CID);
static NS_DEFINE_IID(kIViewManagerIID, NS_IVIEWMANAGER_IID);
static NS_DEFINE_IID(kScrollingViewCID, NS_SCROLLING_VIEW_CID);
static NS_DEFINE_IID(kIViewIID, NS_IVIEW_IID);
static NS_DEFINE_IID(kScrollViewIID, NS_ISCROLLABLEVIEW_IID);
static NS_DEFINE_IID(kWidgetCID, NS_CHILD_CID);
static NS_DEFINE_IID(kILinkHandlerIID, NS_ILINKHANDLER_IID);
1998-07-13 19:49:42 +00:00
static void
1998-11-25 18:41:02 +00:00
LogVerifyMessage(nsIFrame* k1, nsIFrame* k2, const char* aMsg)
{
printf("verifyreflow: ");
nsAutoString name;
if (nsnull != k1) {
k1->GetFrameName(name);
}
else {
name = "(null)";
}
fputs(name, stdout);
printf(" != ");
if (nsnull != k2) {
k2->GetFrameName(name);
}
else {
name = "(null)";
}
fputs(name, stdout);
printf(" %s", aMsg);
}
static void
LogVerifyMessage(nsIFrame* k1, nsIFrame* k2, const char* aMsg,
const nsRect& r1, const nsRect& r2)
1998-07-13 19:49:42 +00:00
{
printf("verifyreflow: ");
nsAutoString name;
k1->GetFrameName(name);
fputs(name, stdout);
1998-07-13 19:49:42 +00:00
stdout << r1;
1998-11-25 18:41:02 +00:00
1998-07-13 19:49:42 +00:00
printf(" != ");
1998-11-25 18:41:02 +00:00
k2->GetFrameName(name);
fputs(name, stdout);
1998-07-13 19:49:42 +00:00
stdout << r2;
1998-11-25 18:41:02 +00:00
printf(" %s\n", aMsg);
1998-07-13 19:49:42 +00:00
}
1998-04-13 20:24:54 +00:00
1999-04-03 18:58:04 +00:00
static PRBool
1998-07-13 19:49:42 +00:00
CompareTrees(nsIFrame* aA, nsIFrame* aB)
1998-04-13 20:24:54 +00:00
{
1999-04-03 18:58:04 +00:00
PRBool ok = PR_TRUE;
1998-11-25 18:41:02 +00:00
PRBool whoops = PR_FALSE;
nsIAtom* listName = nsnull;
PRInt32 listIndex = 0;
do {
nsIFrame* k1, *k2;
aA->FirstChild(listName, &k1);
aB->FirstChild(listName, &k2);
1998-11-25 18:41:02 +00:00
PRInt32 l1 = nsContainerFrame::LengthOf(k1);
PRInt32 l2 = nsContainerFrame::LengthOf(k2);
if (l1 != l2) {
1999-04-03 18:58:04 +00:00
ok = PR_FALSE;
1998-11-25 18:41:02 +00:00
LogVerifyMessage(k1, k2, "child counts don't match: ");
printf("%d != %d\n", l1, l2);
if (!gVerifyReflowAll) {
break;
1998-07-13 19:49:42 +00:00
}
}
1998-11-25 18:41:02 +00:00
nsRect r1, r2;
nsIView* v1, *v2;
nsIWidget* w1, *w2;
for (;;) {
if (((nsnull == k1) && (nsnull != k2)) ||
((nsnull != k1) && (nsnull == k2))) {
1999-04-03 18:58:04 +00:00
ok = PR_FALSE;
1998-11-25 18:41:02 +00:00
LogVerifyMessage(k1, k2, "child lists are different\n");
whoops = PR_TRUE;
break;
}
else if (nsnull != k1) {
// Verify that the frames are the same size
k1->GetRect(r1);
k2->GetRect(r2);
if (r1 != r2) {
1999-04-03 18:58:04 +00:00
ok = PR_FALSE;
1998-11-25 18:41:02 +00:00
LogVerifyMessage(k1, k2, "(frame rects)", r1, r2);
whoops = PR_TRUE;
}
1998-07-13 19:49:42 +00:00
1998-11-25 18:41:02 +00:00
// Make sure either both have views or neither have views; if they
// do have views, make sure the views are the same size. If the
// views have widgets, make sure they both do or neither does. If
// they do, make sure the widgets are the same size.
k1->GetView(&v1);
k2->GetView(&v2);
1998-11-25 18:41:02 +00:00
if (((nsnull == v1) && (nsnull != v2)) ||
((nsnull != v1) && (nsnull == v2))) {
1999-04-03 18:58:04 +00:00
ok = PR_FALSE;
1998-11-25 18:41:02 +00:00
LogVerifyMessage(k1, k2, "child views are not matched\n");
whoops = PR_TRUE;
}
else if (nsnull != v1) {
v1->GetBounds(r1);
v2->GetBounds(r2);
if (r1 != r2) {
1999-04-03 18:58:04 +00:00
// ok = PR_FALSE;
1998-11-25 18:41:02 +00:00
LogVerifyMessage(k1, k2, "(view rects)", r1, r2);
1999-04-03 18:58:04 +00:00
// whoops = PR_TRUE;
1998-11-25 18:41:02 +00:00
}
1998-07-13 19:49:42 +00:00
1998-11-25 18:41:02 +00:00
v1->GetWidget(w1);
v2->GetWidget(w2);
if (((nsnull == w1) && (nsnull != w2)) ||
((nsnull != w1) && (nsnull == w2))) {
1999-04-03 18:58:04 +00:00
ok = PR_FALSE;
1998-11-25 18:41:02 +00:00
LogVerifyMessage(k1, k2, "child widgets are not matched\n");
whoops = PR_TRUE;
}
else if (nsnull != w1) {
w1->GetBounds(r1);
w2->GetBounds(r2);
if (r1 != r2) {
1999-04-03 18:58:04 +00:00
// ok = PR_FALSE;
1998-11-25 18:41:02 +00:00
LogVerifyMessage(k1, k2, "(widget rects)", r1, r2);
1999-04-03 18:58:04 +00:00
// whoops = PR_TRUE;
1998-11-25 18:41:02 +00:00
}
1998-07-13 19:49:42 +00:00
}
}
1998-11-25 18:41:02 +00:00
if (whoops && !gVerifyReflowAll) {
break;
}
// Compare the sub-trees too
1999-04-03 18:58:04 +00:00
if (!CompareTrees(k1, k2)) {
if (!gVerifyReflowAll) {
ok = PR_FALSE;
whoops = PR_TRUE;
break;
}
}
1998-11-25 18:41:02 +00:00
// Advance to next sibling
k1->GetNextSibling(&k1);
k2->GetNextSibling(&k2);
1998-07-13 19:49:42 +00:00
}
else {
1998-11-25 18:41:02 +00:00
break;
1998-07-13 19:49:42 +00:00
}
}
1998-11-25 18:41:02 +00:00
if (whoops && !gVerifyReflowAll) {
break;
1998-07-13 19:49:42 +00:00
}
1998-11-25 18:41:02 +00:00
NS_IF_RELEASE(listName);
nsIAtom* listName1;
nsIAtom* listName2;
aA->GetAdditionalChildListName(listIndex, &listName1);
aB->GetAdditionalChildListName(listIndex, &listName2);
1998-11-25 18:41:02 +00:00
listIndex++;
if (listName1 != listName2) {
1999-04-03 18:58:04 +00:00
ok = PR_FALSE;
1998-11-25 18:41:02 +00:00
LogVerifyMessage(k1, k2, "child list names are not matched: ");
nsAutoString tmp;
if (nsnull != listName1) {
listName1->ToString(tmp);
fputs(tmp, stdout);
}
else
fputs("(null)", stdout);
printf(" != ");
if (nsnull != listName2) {
listName2->ToString(tmp);
fputs(tmp, stdout);
}
else
fputs("(null)", stdout);
printf("\n");
NS_IF_RELEASE(listName1);
NS_IF_RELEASE(listName2);
break;
1998-07-13 19:49:42 +00:00
}
1998-11-25 18:41:02 +00:00
NS_IF_RELEASE(listName2);
listName = listName1;
1999-04-03 18:58:04 +00:00
} while (ok && (listName != nsnull));
return ok;
}
#if 0
static nsIFrame*
FindTopFrame(nsIFrame* aRoot)
{
if (nsnull != aRoot) {
nsIContent* content;
aRoot->GetContent(&content);
if (nsnull != content) {
nsIAtom* tag;
content->GetTag(tag);
if (nsnull != tag) {
NS_RELEASE(tag);
NS_RELEASE(content);
return aRoot;
}
NS_RELEASE(content);
}
// Try one of the children
nsIFrame* kid;
aRoot->FirstChild(nsnull, &kid);
while (nsnull != kid) {
nsIFrame* result = FindTopFrame(kid);
if (nsnull != result) {
return result;
}
kid->GetNextSibling(&kid);
}
}
return nsnull;
}
#endif
nsresult
PresShell::CloneStyleSet(nsIStyleSet* aSet, nsIStyleSet** aResult)
{
nsIStyleSet* clone;
nsresult rv = NS_NewStyleSet(&clone);
if (NS_FAILED(rv)) {
return rv;
}
PRInt32 i, n;
n = aSet->GetNumberOfOverrideStyleSheets();
for (i = 0; i < n; i++) {
nsIStyleSheet* ss;
ss = aSet->GetOverrideStyleSheetAt(i);
if (nsnull != ss) {
clone->AppendOverrideStyleSheet(ss);
NS_RELEASE(ss);
}
}
n = aSet->GetNumberOfDocStyleSheets();
for (i = 0; i < n; i++) {
nsIStyleSheet* ss;
ss = aSet->GetDocStyleSheetAt(i);
if (nsnull != ss) {
clone->AddDocStyleSheet(ss, mDocument);
NS_RELEASE(ss);
}
}
n = aSet->GetNumberOfBackstopStyleSheets();
for (i = 0; i < n; i++) {
nsIStyleSheet* ss;
ss = aSet->GetBackstopStyleSheetAt(i);
if (nsnull != ss) {
clone->AppendBackstopStyleSheet(ss);
NS_RELEASE(ss);
}
}
*aResult = clone;
return NS_OK;
1998-07-13 19:49:42 +00:00
}
// After an incremental reflow, we verify the correctness by doing a
// full reflow into a fresh frame tree.
void
PresShell::VerifyIncrementalReflow()
{
// All the stuff we are creating that needs releasing
nsIPresContext* cx;
nsIViewManager* vm;
nsIPresShell* sh;
// Create a presentation context to view the new frame tree
nsresult rv;
PRBool isPaginated = PR_FALSE;
mPresContext->IsPaginated(&isPaginated);
if (isPaginated) {
1998-07-13 19:49:42 +00:00
rv = NS_NewPrintPreviewContext(&cx);
}
else {
rv = NS_NewGalleyContext(&cx);
}
1999-04-03 18:58:04 +00:00
#if 1
nsISupports* container;
if (NS_SUCCEEDED(mPresContext->GetContainer(&container)) &&
(nsnull != container)) {
cx->SetContainer(container);
nsILinkHandler* lh;
if (NS_SUCCEEDED(container->QueryInterface(kILinkHandlerIID,
(void**)&lh))) {
cx->SetLinkHandler(lh);
NS_RELEASE(lh);
}
1999-04-03 18:58:04 +00:00
NS_RELEASE(container);
}
#endif
1998-07-13 19:49:42 +00:00
NS_ASSERTION(NS_OK == rv, "failed to create presentation context");
nsCOMPtr<nsIDeviceContext> dc;
mPresContext->GetDeviceContext(getter_AddRefs(dc));
nsCOMPtr<nsIPref> prefs;
mPresContext->GetPrefs(getter_AddRefs(prefs));
cx->Init(dc, prefs);
1998-07-13 19:49:42 +00:00
// Get our scrolling preference
nsScrollPreference scrolling;
nsIView* rootView;
mViewManager->GetRootView(rootView);
1998-07-13 19:49:42 +00:00
nsIScrollableView* scrollView;
rv = rootView->QueryInterface(kScrollViewIID, (void**)&scrollView);
if (NS_OK == rv) {
scrollView->GetScrollPreference(scrolling);
1998-07-13 19:49:42 +00:00
}
nsIWidget* rootWidget;
rootView->GetWidget(rootWidget);
1998-07-13 19:49:42 +00:00
void* nativeParentWidget = rootWidget->GetNativeData(NS_NATIVE_WIDGET);
// Create a new view manager.
1999-04-03 18:58:04 +00:00
rv = nsComponentManager::CreateInstance(kViewManagerCID, nsnull,
kIViewManagerIID, (void**) &vm);
if (NS_FAILED(rv)) {
1998-07-13 19:49:42 +00:00
NS_ASSERTION(NS_OK == rv, "failed to create view manager");
}
1999-04-03 18:58:04 +00:00
rv = vm->Init(dc);
if (NS_FAILED(rv)) {
NS_ASSERTION(NS_OK == rv, "failed to init view manager");
}
1998-08-28 02:54:06 +00:00
1998-07-13 19:49:42 +00:00
// Create a child window of the parent that is our "root view/window"
// Create a view
nsRect tbounds;
mPresContext->GetVisibleArea(tbounds);
1999-04-03 18:58:04 +00:00
nsIView* view;
rv = nsComponentManager::CreateInstance(kViewCID, nsnull,
kIViewIID, (void **) &view);
if (NS_FAILED(rv)) {
1998-07-13 19:49:42 +00:00
NS_ASSERTION(NS_OK == rv, "failed to create scroll view");
}
1999-04-03 18:58:04 +00:00
rv = view->Init(vm, tbounds, nsnull);
if (NS_FAILED(rv)) {
NS_ASSERTION(NS_OK == rv, "failed to init scroll view");
}
//now create the widget for the view
rv = view->CreateWidget(kWidgetCID, nsnull, nativeParentWidget);
if (NS_OK != rv) {
NS_ASSERTION(NS_OK == rv, "failed to create scroll view widget");
}
1998-07-13 19:49:42 +00:00
// Setup hierarchical relationship in view manager
vm->SetRootView(view);
// Make the new presentation context the same size as our
// presentation context.
nsRect r;
mPresContext->GetVisibleArea(r);
cx->SetVisibleArea(r);
1999-04-03 18:58:04 +00:00
1998-11-25 18:41:02 +00:00
// Create a new presentation shell to view the document. Use the
// exact same style information that this document has.
nsCOMPtr<nsIStyleSet> newSet;
rv = CloneStyleSet(mStyleSet, getter_AddRefs(newSet));
1999-04-03 18:58:04 +00:00
NS_ASSERTION(NS_SUCCEEDED(rv), "failed to clone style set");
rv = mDocument->CreateShell(cx, vm, newSet, &sh);
1998-07-13 19:49:42 +00:00
NS_ASSERTION(NS_OK == rv, "failed to create presentation shell");
1999-04-03 18:58:04 +00:00
vm->SetViewObserver((nsIViewObserver *)((PresShell*)sh));
1998-11-25 18:41:02 +00:00
sh->InitialReflow(r.width, r.height);
1998-07-13 19:49:42 +00:00
// Now that the document has been reflowed, use its frame tree to
// compare against our frame tree.
nsIFrame* root1;
GetRootFrame(&root1);
1999-04-03 18:58:04 +00:00
nsIFrame* root2;
sh->GetRootFrame(&root2);
1999-04-03 18:58:04 +00:00
#if 0
root1 = FindTopFrame(root1);
root2 = FindTopFrame(root2);
#endif
if (!CompareTrees(root1, root2)) {
1999-04-20 00:24:21 +00:00
printf("Verify reflow failed, primary tree:\n");
root1->List(stdout, 0);
printf("Verification tree:\n");
root2->List(stdout, 0);
1999-04-03 18:58:04 +00:00
}
1998-07-13 19:49:42 +00:00
1999-04-03 18:58:04 +00:00
// printf("Incremental reflow doomed view tree:\n");
// view->List(stdout, 1);
1999-04-20 00:24:21 +00:00
// view->SetVisibility(nsViewVisibility_kHide);
cx->Stop();
1999-04-03 18:58:04 +00:00
cx->SetContainer(nsnull);
1998-07-13 19:49:42 +00:00
NS_RELEASE(cx);
1999-04-03 18:58:04 +00:00
sh->EndObservingDocument();
1998-07-13 19:49:42 +00:00
NS_RELEASE(sh);
1999-04-03 18:58:04 +00:00
NS_RELEASE(vm);
1998-07-13 19:49:42 +00:00
}
#endif