gecko-dev/layout/base/nsPresShell.cpp

3337 lines
97 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.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/
1998-04-13 20:24:54 +00:00
*
* 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.
1998-04-13 20:24:54 +00:00
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
1998-04-13 20:24:54 +00:00
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
#define PL_ARENA_CONST_ALIGN_MASK 3
1998-04-13 20:24:54 +00:00
#include "nsIPresShell.h"
#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"
#include "nsIServiceManager.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 "prlog.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"
#include "nsISelectionController.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 "nsWeakReference.h"
#include "nsICaret.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 "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"
1999-08-04 04:02:40 +00:00
#include "nsIFrameManager.h"
#include "nsISupportsPrimitives.h"
#include "nsILayoutHistoryState.h"
Fix for bug #15360: Drag Selecting, Clicking, then Clicking leaves caret cruft. r=troy@netscape.com,kipp@netscape.com,evaughan@netscape.com,beard@netscape.com layout/html/base/src/nsGfxScrollFrame.cpp - Renamed all occurrences of ScrollPositionChanged() to to ScrollPositionDidChange() to match changes made to nsIScrollPositionListener. - Added ScrollPositionWillChange() stub method. layout/html/base/src/nsPresShell.cpp - Added PresShellViewEventListener class that implements the nsIScrollPositionListener and nsICompositeListener view interfaces. This allows us to turn caret rendering on and off when scrolling and repainting to prevent leaving caret cruft on the screen. - PresShellViewEventListener is created in InitialReflow(), and released in ~PresShell(). view/public/Makefile.in view/public/makefile.win view/public/MANIFEST - Added nsICompositeListener to list of files to be exported. view/public/nsICompositeListener.h - New file. Implementers of this interface can register themselves with the view manager to receive notification before and after a view is composited/refreshed. view/public/nsIScrollPositionListener.h - Added a ScrollPositionWillChange() method. - Changed ScrollPositionChanged() to ScrollPositionDidChange(). view/public/nsIViewManager.h - Added AddCompositeListener() and RemoveCompositeListener methods. view/src/nsScrollingView.cpp view/src/nsScrollingView.h - Added NotifyScrollPositionWillChange() and NotifyScrollPositionDidChange() methods. - Modified HandleScrollEvent() to call NotifyScrollPositionWill/DidChange() methods. Added temporary offsetX and offsetY variables to allow us to calculate new offsets without changing mOffsetX and mOffsetY before notifications are sent out. view/src/nsScrollPortView.cpp - Changed ScrollPositionChanged() to ScrollPositionDidChange(). - Modified ScrollTo() to call the listener's ScrollPositionWillChange() method. view/src/nsViewManager.cpp view/src/nsViewManager.h - Added AddCompositeListener() and RemoveCompositeListener() methods. - Added support for CompositeListener notifications in the Refresh() methods for regions and rects. - Fix for bug #15901: [DOGFOOD] Selected text does not clear when you type Modified UpdateView() so that rects with zero width and height are no longer added to our damage region. r=beard@netscape.com
1999-10-15 04:29:30 +00:00
#include "nsIScrollPositionListener.h"
#include "nsICompositeListener.h"
#include "nsTimer.h"
#include "nsWeakPtr.h"
#include "plarena.h"
#ifdef MOZ_PERF_METRICS
#include "nsITimeRecorder.h"
#endif
#ifdef NS_DEBUG
#include "nsIFrameDebug.h"
#endif
// Drag & Drop, Clipboard
#include "nsWidgetsCID.h"
#include "nsIClipboard.h"
#include "nsITransferable.h"
#include "nsIFormatConverter.h"
#include "nsIDocShellTreeItem.h"
#include "nsIBrowserWindow.h"
#include "nsIURI.h"
#include "nsIEventQueue.h"
#include "nsIEventQueueService.h"
1999-12-07 05:28:32 +00:00
#include "nsIScrollableFrame.h"
#include "prtime.h"
#include "prlong.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
#undef NOISY
// comment out to hide caret
#define SHOW_CARET
1998-04-13 20:24:54 +00:00
//----------------------------------------------------------------------
// Class IID's
static NS_DEFINE_IID(kFrameSelectionCID, NS_FRAMESELECTION_CID);
static NS_DEFINE_IID(kCRangeCID, NS_RANGE_CID);
static NS_DEFINE_IID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
static NS_DEFINE_CID(kPrefServiceCID, NS_PREF_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(kISelectionControllerIID, NS_ISELECTIONCONTROLLER_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);
1999-12-07 05:28:32 +00:00
static NS_DEFINE_IID(kIScrollableFrameIID, NS_ISCROLLABLE_FRAME_IID);
1998-04-13 20:24:54 +00:00
// The upper bound on the amount of time to spend reflowing. When this bound is exceeded
// and reflow commands are still queued up, a reflow event is posted. The idea is for reflow
// to not hog the processor beyond the time specifed in gMaxRCProcessingTime.
// This data member is initialized from the layout.reflow.timeslice pref.
// It is used only when asynchronous reflow is enabled by setting gDoAsyncReflow to PR_TRUE.
#define NS_MAX_REFLOW_TIME 1000000
static PRInt32 gMaxRCProcessingTime = -1;
// Largest chunk size we recycle
static const int gMaxRecycledSize = 200;
// Flag for enabling/disabling asynchronous reflow
// Set via the "layout.reflow.async" pref
static PRBool gDoAsyncReflow = PR_FALSE;
// Memory is allocated 4-byte aligned. We have recyclers for chunks up to
// 200 bytes
class FrameArena {
public:
FrameArena(PRUint32 aArenaSize = 2048);
~FrameArena();
// Memory management functions
nsresult AllocateFrame(size_t aSize, void** aResult);
nsresult FreeFrame(size_t aSize, void* aPtr);
private:
// Underlying arena pool
PLArenaPool mPool;
// The recycler array is sparse with the indices being multiples of 4,
// i.e., 0, 4, 8, 12, 16, 20, ...
void* mRecyclers[gMaxRecycledSize >> 2];
};
FrameArena::FrameArena(PRUint32 aArenaSize)
{
// Initialize the arena pool
PL_INIT_ARENA_POOL(&mPool, "FrameArena", aArenaSize);
// Zero out the recyclers array
nsCRT::memset(mRecyclers, 0, sizeof(mRecyclers));
}
FrameArena::~FrameArena()
{
// Free the arena in the pool and finish using it
PL_FinishArenaPool(&mPool);
}
nsresult
FrameArena::AllocateFrame(size_t aSize, void** aResult)
{
void* result = nsnull;
// Round size to multiple of 4
PR_ROUNDUP(aSize, 4);
// Check recyclers first
if (aSize < gMaxRecycledSize) {
const int index = aSize >> 2;
result = mRecyclers[index];
if (result) {
// Need to move to the next object
void* next = *((void**)result);
mRecyclers[index] = next;
}
}
if (!result) {
// Allocate a new chunk from the arena
PL_ARENA_ALLOCATE(result, &mPool, aSize);
}
*aResult = result;
return NS_OK;
}
nsresult
FrameArena::FreeFrame(size_t aSize, void* aPtr)
{
// Round size to multiple of 4
PR_ROUNDUP(aSize, 4);
// See if it's a size that we recycle
if (aSize < gMaxRecycledSize) {
const int index = aSize >> 2;
void* currentTop = mRecyclers[index];
mRecyclers[index] = aPtr;
*((void**)aPtr) = currentTop;
}
return NS_OK;
}
Fix for bug #15360: Drag Selecting, Clicking, then Clicking leaves caret cruft. r=troy@netscape.com,kipp@netscape.com,evaughan@netscape.com,beard@netscape.com layout/html/base/src/nsGfxScrollFrame.cpp - Renamed all occurrences of ScrollPositionChanged() to to ScrollPositionDidChange() to match changes made to nsIScrollPositionListener. - Added ScrollPositionWillChange() stub method. layout/html/base/src/nsPresShell.cpp - Added PresShellViewEventListener class that implements the nsIScrollPositionListener and nsICompositeListener view interfaces. This allows us to turn caret rendering on and off when scrolling and repainting to prevent leaving caret cruft on the screen. - PresShellViewEventListener is created in InitialReflow(), and released in ~PresShell(). view/public/Makefile.in view/public/makefile.win view/public/MANIFEST - Added nsICompositeListener to list of files to be exported. view/public/nsICompositeListener.h - New file. Implementers of this interface can register themselves with the view manager to receive notification before and after a view is composited/refreshed. view/public/nsIScrollPositionListener.h - Added a ScrollPositionWillChange() method. - Changed ScrollPositionChanged() to ScrollPositionDidChange(). view/public/nsIViewManager.h - Added AddCompositeListener() and RemoveCompositeListener methods. view/src/nsScrollingView.cpp view/src/nsScrollingView.h - Added NotifyScrollPositionWillChange() and NotifyScrollPositionDidChange() methods. - Modified HandleScrollEvent() to call NotifyScrollPositionWill/DidChange() methods. Added temporary offsetX and offsetY variables to allow us to calculate new offsets without changing mOffsetX and mOffsetY before notifications are sent out. view/src/nsScrollPortView.cpp - Changed ScrollPositionChanged() to ScrollPositionDidChange(). - Modified ScrollTo() to call the listener's ScrollPositionWillChange() method. view/src/nsViewManager.cpp view/src/nsViewManager.h - Added AddCompositeListener() and RemoveCompositeListener() methods. - Added support for CompositeListener notifications in the Refresh() methods for regions and rects. - Fix for bug #15901: [DOGFOOD] Selected text does not clear when you type Modified UpdateView() so that rects with zero width and height are no longer added to our damage region. r=beard@netscape.com
1999-10-15 04:29:30 +00:00
class PresShellViewEventListener : public nsIScrollPositionListener,
public nsICompositeListener
{
public:
PresShellViewEventListener();
virtual ~PresShellViewEventListener();
NS_DECL_ISUPPORTS
// nsIScrollPositionListener methods
NS_IMETHOD ScrollPositionWillChange(nsIScrollableView *aView, nscoord aX, nscoord aY);
NS_IMETHOD ScrollPositionDidChange(nsIScrollableView *aView, nscoord aX, nscoord aY);
// nsICompositeListener methods
NS_IMETHOD WillRefreshRegion(nsIViewManager *aViewManager,
nsIView *aView,
nsIRenderingContext *aContext,
nsIRegion *aRegion,
PRUint32 aUpdateFlags);
NS_IMETHOD DidRefreshRegion(nsIViewManager *aViewManager,
nsIView *aView,
nsIRenderingContext *aContext,
nsIRegion *aRegion,
PRUint32 aUpdateFlags);
NS_IMETHOD WillRefreshRect(nsIViewManager *aViewManager,
nsIView *aView,
nsIRenderingContext *aContext,
const nsRect *aRect,
PRUint32 aUpdateFlags);
NS_IMETHOD DidRefreshRect(nsIViewManager *aViewManager,
nsIView *aView,
nsIRenderingContext *aContext,
const nsRect *aRect,
PRUint32 aUpdateFlags);
nsresult SetPresShell(nsIPresShell *aPresShell);
private:
nsresult HideCaret();
nsresult RestoreCaretVisibility();
nsIPresShell *mPresShell;
PRBool mWasVisible;
PRInt32 mCallCount;
};
1998-08-28 02:54:06 +00:00
class PresShell : public nsIPresShell, public nsIViewObserver,
private nsIDocumentObserver, public nsIFocusTracker,
public nsISelectionController,
public nsSupportsWeakReference
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
// nsIPresShell
NS_IMETHOD Init(nsIDocument* aDocument,
nsIPresContext* aPresContext,
nsIViewManager* aViewManager,
nsIStyleSet* aStyleSet);
NS_IMETHOD AllocateFrame(size_t aSize, void** aResult);
NS_IMETHOD FreeFrame(size_t aSize, void* aFreeChunk);
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(SelectionType aType, nsIDOMSelection** aSelection);
NS_IMETHOD ScrollSelectionIntoView(SelectionType aType, SelectionRegion aRegion);
NS_IMETHOD RepaintSelection(SelectionType aType);
NS_IMETHOD GetFrameSelection(nsIFrameSelection** aSelection);
NS_IMETHOD EnterReflowLock();
NS_IMETHOD ExitReflowLock(PRBool aTryToReflow, PRBool aDoSynchronousReflow);
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;
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 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,
PRIntn aVPercent,
PRIntn aHPercent) const;
NS_IMETHOD NotifyDestroyingFrame(nsIFrame* aFrame);
1999-08-04 04:02:40 +00:00
NS_IMETHOD GetFrameManager(nsIFrameManager** aFrameManager) const;
NS_IMETHOD DoCopy();
// XXX This function needs to be renamed to something better.
// It is not simply a getter for the layout history state. It
// creates a new state object and captures frame state onto it
NS_IMETHOD GetHistoryState(nsILayoutHistoryState** aLayoutHistoryState);
NS_IMETHOD SetHistoryState(nsILayoutHistoryState* aLayoutHistoryState);
NS_IMETHOD GetReflowEventStatus(PRBool* aPending);
NS_IMETHOD SetReflowEventStatus(PRBool aPending);
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);
1998-08-28 02:54:06 +00:00
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 **aOutCaret);
NS_IMETHOD SetCaretEnabled(PRBool aaInEnable);
NS_IMETHOD GetCaretEnabled(PRBool *aOutEnabled);
NS_IMETHOD SetDisplayNonTextSelection(PRBool aaInEnable);
NS_IMETHOD GetDisplayNonTextSelection(PRBool *aOutEnable);
// nsISelectionController
NS_IMETHOD CharacterMove(PRBool aForward, PRBool aExtend);
NS_IMETHOD WordMove(PRBool aForward, PRBool aExtend);
NS_IMETHOD LineMove(PRBool aForward, PRBool aExtend);
NS_IMETHOD IntraLineMove(PRBool aForward, PRBool aExtend);
NS_IMETHOD PageMove(PRBool aForward, PRBool aExtend);
NS_IMETHOD ScrollPage(PRBool aForward);
NS_IMETHOD ScrollLine(PRBool aForward);
NS_IMETHOD ScrollHorizontal(PRBool aLeft);
NS_IMETHOD CompleteScroll(PRBool aForward);
NS_IMETHOD CompleteMove(PRBool aForward, PRBool aExtend);
NS_IMETHOD SelectAll();
1999-07-14 17:30:07 +00:00
// 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);
NS_IMETHOD ContentStatesChanged(nsIDocument* aDocument,
nsIContent* aContent1,
nsIContent* aContent2);
NS_IMETHOD AttributeChanged(nsIDocument *aDocument,
nsIContent* aContent,
PRInt32 aNameSpaceID,
1999-07-14 17:30:07 +00:00
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);
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
protected:
virtual ~PresShell();
1998-04-13 20:24:54 +00:00
1998-11-26 01:34:53 +00:00
nsresult ReconstructFrames(void);
PRBool mCaretEnabled;
1999-04-03 18:58:04 +00:00
nsresult CloneStyleSet(nsIStyleSet* aSet, nsIStyleSet** aResult);
#ifdef NS_DEBUG
PRBool 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;
nsIViewManager* mViewManager; // [WEAK] docViewer owns it so I don't have to
nsILayoutHistoryState* mHistoryState; // [WEAK] session history owns this
1998-04-13 20:24:54 +00:00
PRUint32 mUpdateCount;
nsVoidArray mReflowCommands;
PRUint32 mReflowLockCount;
PRBool mIsDestroying;
nsIFrame* mCurrentEventFrame;
nsIContent* mCurrentEventContent;
nsVoidArray mCurrentEventFrameStack;
nsCOMPtr<nsIFrameSelection> mSelection;
nsCOMPtr<nsICaret> mCaret;
PRBool mDisplayNonTextSelection;
PRBool mScrollingEnabled; //used to disable programmable scrolling from outside
nsIFrameManager* mFrameManager; // we hold a reference
Fix for bug #15360: Drag Selecting, Clicking, then Clicking leaves caret cruft. r=troy@netscape.com,kipp@netscape.com,evaughan@netscape.com,beard@netscape.com layout/html/base/src/nsGfxScrollFrame.cpp - Renamed all occurrences of ScrollPositionChanged() to to ScrollPositionDidChange() to match changes made to nsIScrollPositionListener. - Added ScrollPositionWillChange() stub method. layout/html/base/src/nsPresShell.cpp - Added PresShellViewEventListener class that implements the nsIScrollPositionListener and nsICompositeListener view interfaces. This allows us to turn caret rendering on and off when scrolling and repainting to prevent leaving caret cruft on the screen. - PresShellViewEventListener is created in InitialReflow(), and released in ~PresShell(). view/public/Makefile.in view/public/makefile.win view/public/MANIFEST - Added nsICompositeListener to list of files to be exported. view/public/nsICompositeListener.h - New file. Implementers of this interface can register themselves with the view manager to receive notification before and after a view is composited/refreshed. view/public/nsIScrollPositionListener.h - Added a ScrollPositionWillChange() method. - Changed ScrollPositionChanged() to ScrollPositionDidChange(). view/public/nsIViewManager.h - Added AddCompositeListener() and RemoveCompositeListener methods. view/src/nsScrollingView.cpp view/src/nsScrollingView.h - Added NotifyScrollPositionWillChange() and NotifyScrollPositionDidChange() methods. - Modified HandleScrollEvent() to call NotifyScrollPositionWill/DidChange() methods. Added temporary offsetX and offsetY variables to allow us to calculate new offsets without changing mOffsetX and mOffsetY before notifications are sent out. view/src/nsScrollPortView.cpp - Changed ScrollPositionChanged() to ScrollPositionDidChange(). - Modified ScrollTo() to call the listener's ScrollPositionWillChange() method. view/src/nsViewManager.cpp view/src/nsViewManager.h - Added AddCompositeListener() and RemoveCompositeListener() methods. - Added support for CompositeListener notifications in the Refresh() methods for regions and rects. - Fix for bug #15901: [DOGFOOD] Selected text does not clear when you type Modified UpdateView() so that rects with zero width and height are no longer added to our damage region. r=beard@netscape.com
1999-10-15 04:29:30 +00:00
PresShellViewEventListener *mViewEventListener;
PRBool mPendingReflowEvent;
nsCOMPtr<nsIEventQueue> mEventQueue;
FrameArena mFrameArena;
PRInt32 mAccumulatedReflowTime; // Time spent in reflow command processing so far
MOZ_TIMER_DECLARE(mReflowWatch) // Used for measuring time spent in reflow
MOZ_TIMER_DECLARE(mFrameCreationWatch) // Used for measuring time spent in frame creation
#ifdef DEBUG_nisheeth
PRInt32 mReflows;
PRInt32 mDiscardedReflowCommands;
#endif
private:
//helper funcs for disabing autoscrolling
void DisableScrolling(){mScrollingEnabled = PR_FALSE;}
void EnableScrolling(){mScrollingEnabled = PR_TRUE;}
PRBool IsScrollingEnabled(){return mScrollingEnabled;}
//helper funcs for event handling
nsIFrame* GetCurrentEventFrame();
void PushCurrentEventFrame();
void PopCurrentEventFrame();
// helper function for posting reflow events
void PostReflowEvent();
PRBool AlreadyInQueue(nsIReflowCommand* aReflowCommand);
1998-04-13 20:24:54 +00:00
};
1999-09-21 07:53:49 +00:00
#ifdef NS_DEBUG
static void
VerifyStyleTree(nsIFrameManager* aFrameManager)
1999-09-21 07:53:49 +00:00
{
if (aFrameManager && nsIFrameDebug::GetVerifyStyleTreeEnable()) {
nsIFrame* rootFrame;
aFrameManager->GetRootFrame(&rootFrame);
aFrameManager->DebugVerifyStyleTree(rootFrame);
1999-09-21 07:53:49 +00:00
}
}
#define VERIFY_STYLE_TREE VerifyStyleTree(mFrameManager)
1999-09-21 07:53:49 +00:00
#else
#define VERIFY_STYLE_TREE
#endif
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
static PRUint32 gVerifyReflowFlags;
1999-10-05 14:51:12 +00:00
#define VERIFY_REFLOW_ON 0x01
#define VERIFY_REFLOW_NOISY 0x02
#define VERIFY_REFLOW_ALL 0x04
#define VERIFY_REFLOW_DUMP_COMMANDS 0x08
#define VERIFY_REFLOW_NOISY_RC 0x10
#define VERIFY_REFLOW_REALLY_NOISY_RC 0x20
1999-04-27 22:14:17 +00:00
#endif
1998-07-13 19:49:42 +00:00
static PRBool gVerifyReflowEnabled;
1998-07-13 19:49:42 +00:00
NS_LAYOUT PRBool
nsIPresShell::GetVerifyReflowEnable()
{
#ifdef NS_DEBUG
static PRBool firstTime = PR_TRUE;
if (firstTime) {
firstTime = PR_FALSE;
gLogModule = PR_NewLogModule("verifyreflow");
gVerifyReflowFlags = gLogModule->level;
if (VERIFY_REFLOW_ON & gVerifyReflowFlags) {
gVerifyReflowEnabled = PR_TRUE;
1998-11-25 18:41:02 +00:00
}
printf("Note: verifyreflow is %sabled",
gVerifyReflowEnabled ? "en" : "dis");
if (VERIFY_REFLOW_NOISY & gVerifyReflowFlags) {
printf(" (noisy)");
1998-11-25 18:41:02 +00:00
}
if (VERIFY_REFLOW_ALL & gVerifyReflowFlags) {
printf(" (all)");
1998-11-25 18:41:02 +00:00
}
if (VERIFY_REFLOW_DUMP_COMMANDS & gVerifyReflowFlags) {
printf(" (show reflow commands)");
}
if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) {
printf(" (noisy reflow commands)");
1999-10-05 14:51:12 +00:00
if (VERIFY_REFLOW_REALLY_NOISY_RC & gVerifyReflowFlags) {
printf(" (REALLY noisy reflow commands)");
}
}
printf("\n");
1998-07-13 19:49:42 +00:00
}
#endif
return gVerifyReflowEnabled;
1998-07-13 19:49:42 +00:00
}
NS_LAYOUT void
nsIPresShell::SetVerifyReflowEnable(PRBool aEnabled)
{
gVerifyReflowEnabled = aEnabled;
1998-07-13 19:49:42 +00:00
}
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()
{
mIsDestroying = PR_FALSE;
mCaretEnabled = PR_FALSE;
mDisplayNonTextSelection = PR_FALSE;
mCurrentEventContent = nsnull;
mCurrentEventFrame = nsnull;
EnableScrolling();
mPendingReflowEvent = PR_FALSE;
#ifdef DEBUG_nisheeth
mReflows = 0;
mDiscardedReflowCommands = 0;
#endif
1998-04-13 20:24:54 +00:00
}
NS_IMPL_ADDREF(PresShell)
NS_IMPL_RELEASE(PresShell)
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(kISelectionControllerIID)) {
nsISelectionController* tmp = this;
*aInstancePtr = (void*) tmp;
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(nsCOMTypeInfo<nsISupportsWeakReference>::GetIID())) {
nsISupportsWeakReference* 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;
// Clobber weak leaks in case of re-entrancy during tear down
mHistoryState = nsnull;
NS_IF_RELEASE(mCurrentEventContent);
if (mViewManager) {
// Disable paints during tear down of the frame tree
mViewManager->DisableRefresh();
mViewManager = nsnull;
}
// Destroy the frame manager. This will destroy the frame hierarchy
NS_IF_RELEASE(mFrameManager);
if (mDocument) {
mDocument->DeleteShell(this);
}
// We hold a reference to the pres context, and it holds a weak link back
// to us. To avoid the pres context having a dangling reference, set its
// pres shell to NULL
if (mPresContext) {
mPresContext->SetShell(nsnull);
}
mRefCnt = 0;
Fix for bug #15360: Drag Selecting, Clicking, then Clicking leaves caret cruft. r=troy@netscape.com,kipp@netscape.com,evaughan@netscape.com,beard@netscape.com layout/html/base/src/nsGfxScrollFrame.cpp - Renamed all occurrences of ScrollPositionChanged() to to ScrollPositionDidChange() to match changes made to nsIScrollPositionListener. - Added ScrollPositionWillChange() stub method. layout/html/base/src/nsPresShell.cpp - Added PresShellViewEventListener class that implements the nsIScrollPositionListener and nsICompositeListener view interfaces. This allows us to turn caret rendering on and off when scrolling and repainting to prevent leaving caret cruft on the screen. - PresShellViewEventListener is created in InitialReflow(), and released in ~PresShell(). view/public/Makefile.in view/public/makefile.win view/public/MANIFEST - Added nsICompositeListener to list of files to be exported. view/public/nsICompositeListener.h - New file. Implementers of this interface can register themselves with the view manager to receive notification before and after a view is composited/refreshed. view/public/nsIScrollPositionListener.h - Added a ScrollPositionWillChange() method. - Changed ScrollPositionChanged() to ScrollPositionDidChange(). view/public/nsIViewManager.h - Added AddCompositeListener() and RemoveCompositeListener methods. view/src/nsScrollingView.cpp view/src/nsScrollingView.h - Added NotifyScrollPositionWillChange() and NotifyScrollPositionDidChange() methods. - Modified HandleScrollEvent() to call NotifyScrollPositionWill/DidChange() methods. Added temporary offsetX and offsetY variables to allow us to calculate new offsets without changing mOffsetX and mOffsetY before notifications are sent out. view/src/nsScrollPortView.cpp - Changed ScrollPositionChanged() to ScrollPositionDidChange(). - Modified ScrollTo() to call the listener's ScrollPositionWillChange() method. view/src/nsViewManager.cpp view/src/nsViewManager.h - Added AddCompositeListener() and RemoveCompositeListener() methods. - Added support for CompositeListener notifications in the Refresh() methods for regions and rects. - Fix for bug #15901: [DOGFOOD] Selected text does not clear when you type Modified UpdateView() so that rects with zero width and height are no longer added to our damage region. r=beard@netscape.com
1999-10-15 04:29:30 +00:00
if (mViewEventListener) {
mViewEventListener->SetPresShell((nsIPresShell*)nsnull);
NS_RELEASE(mViewEventListener);
}
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");
1998-04-13 20:24:54 +00:00
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
mHistoryState = nsnull;
nsresult result = nsComponentManager::CreateInstance(kFrameSelectionCID, nsnull,
nsIFrameSelection::GetIID(),
getter_AddRefs(mSelection));
1998-12-14 18:34:14 +00:00
if (!NS_SUCCEEDED(result))
return result;
1999-08-04 04:02:40 +00:00
// Create and initialize the frame manager
result = NS_NewFrameManager(&mFrameManager);
if (NS_FAILED(result)) {
return result;
}
result = mFrameManager->Init(this, mStyleSet);
if (NS_FAILED(result)) {
return result;
}
1999-08-04 04:02:40 +00:00
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
// make the caret
nsresult err = NS_NewCaret(getter_AddRefs(mCaret));
if (NS_SUCCEEDED(err))
{
1999-07-14 22:18:29 +00:00
mCaret->Init(this);
}
//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<nsIDocShellTreeItem> docShell(do_QueryInterface(container, &result));
if (NS_SUCCEEDED(result) && docShell){
PRInt32 docShellType;
result = docShell->GetItemType(&docShellType);
if (NS_SUCCEEDED(result)){
if (nsIDocShellTreeItem::typeContent == docShellType){
mDocument->SetDisplaySelection(PR_TRUE);
}
}
}
}
1999-11-30 00:32:43 +00:00
// Cache the event queue of the current UI thread
NS_WITH_SERVICE(nsIEventQueueService, eventService, kEventQueueServiceCID, &result);
1999-11-30 00:32:43 +00:00
if (NS_SUCCEEDED(result)) // XXX this implies that the UI is the current thread.
result = eventService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(mEventQueue));
if (gMaxRCProcessingTime == -1) {
// First, set the defaults
gMaxRCProcessingTime = NS_MAX_REFLOW_TIME;
gDoAsyncReflow = PR_FALSE;
// Get the prefs service
NS_WITH_SERVICE(nsIPref, prefs, kPrefServiceCID, &result);
if (NS_SUCCEEDED(result)) {
PRInt32 timeSlice;
prefs->GetIntPref("layout.reflow.timeslice", &timeSlice);
// Enable after fixing the Mac build
// LL_I2L(gMaxRCProcessingTime, timeSlice);
prefs->GetBoolPref("layout.reflow.async", &gDoAsyncReflow);
}
}
1998-04-13 20:24:54 +00:00
return NS_OK;
}
NS_IMETHODIMP
PresShell::FreeFrame(size_t aSize, void* aPtr)
{
mFrameArena.FreeFrame(aSize, aPtr);
return NS_OK;
}
NS_IMETHODIMP
PresShell::AllocateFrame(size_t aSize, void** aResult)
{
return mFrameArena.AllocateFrame(aSize, aResult);
}
NS_IMETHODIMP
PresShell::EnterReflowLock()
{
++mReflowLockCount;
return NS_OK;
}
NS_IMETHODIMP
PresShell::ExitReflowLock(PRBool aTryToReflow, PRBool aDoSynchronousReflow)
{
PRUint32 newReflowLockCount = mReflowLockCount - 1;
if (newReflowLockCount == 0 && aTryToReflow) {
if (aDoSynchronousReflow)
ProcessReflowCommands();
else
PostReflowEvent();
}
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(SelectionType aType, nsIDOMSelection **aSelection)
1998-12-08 18:26:06 +00:00
{
if (!aSelection || !mSelection)
return NS_ERROR_NULL_POINTER;
return mSelection->GetSelection(aType, aSelection);
1998-12-08 18:26:06 +00:00
}
NS_IMETHODIMP
PresShell::ScrollSelectionIntoView(SelectionType aType, SelectionRegion aRegion)
{
if (!mSelection)
return NS_ERROR_NULL_POINTER;
return mSelection->ScrollSelectionIntoView(aType, aRegion);
}
NS_IMETHODIMP
PresShell::RepaintSelection(SelectionType aType)
{
if (!mSelection)
return NS_ERROR_NULL_POINTER;
return mSelection->RepaintSelection(mPresContext, aType);
}
NS_IMETHODIMP
PresShell::GetFrameSelection(nsIFrameSelection** aSelection)
{
if (!aSelection || !mSelection)
return NS_ERROR_NULL_POINTER;
*aSelection = mSelection;
(*aSelection)->AddRef();
return NS_OK;
}
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;
result = mSelection->GetSelection(SELECTION_NORMAL, getter_AddRefs(domselection));
if (NS_FAILED(result))
return result;
if (!domselection)
return NS_ERROR_UNEXPECTED;
mSelection->ShutDown();
}
return NS_OK;
1998-04-13 20:24:54 +00:00
}
#ifdef DEBUG_kipp
char* nsPresShell_ReflowStackPointerTop;
#endif
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;
#ifdef NS_DEBUG
if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) {
nsCOMPtr<nsIURI> uri;
if (mDocument) {
uri = dont_AddRef(mDocument->GetDocumentURL());
if (uri) {
char* url = nsnull;
uri->GetSpec(&url);
printf("*** PresShell::InitialReflow (this=%p, url='%s')\n", this, url);
Recycle(url);
}
}
}
#endif
StCaretHider caretHider(this); // stack-based class hides caret until dtor.
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();
}
// Get the root frame from the frame manager
nsIFrame* rootFrame;
mFrameManager->GetRootFrame(&rootFrame);
if (nsnull != root) {
MOZ_TIMER_DEBUGLOG(("Reset and start: Frame Creation: PresShell::InitialReflow(), this=%p\n", this));
MOZ_TIMER_RESET(mFrameCreationWatch);
MOZ_TIMER_START(mFrameCreationWatch);
if (!rootFrame) {
// Have style sheet processor construct a frame for the
// precursors to the root content object's frame
mStyleSet->ConstructRootFrame(mPresContext, root, rootFrame);
mFrameManager->SetRootFrame(rootFrame);
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);
1999-09-21 07:53:49 +00:00
VERIFY_STYLE_TREE;
MOZ_TIMER_DEBUGLOG(("Stop: Frame Creation: PresShell::InitialReflow(), this=%p\n", this));
MOZ_TIMER_STOP(mFrameCreationWatch);
1998-04-13 20:24:54 +00:00
}
if (rootFrame) {
MOZ_TIMER_DEBUGLOG(("Reset and start: Reflow: PresShell::InitialReflow(), this=%p\n", this));
MOZ_TIMER_RESET(mReflowWatch);
MOZ_TIMER_START(mReflowWatch);
// Kick off a top-down reflow
NS_FRAME_LOG(NS_FRAME_TRACE_CALLS,
("enter nsPresShell::InitialReflow: %d,%d", aWidth, aHeight));
#ifdef NS_DEBUG
if (nsIFrameDebug::GetVerifyTreeEnable()) {
nsIFrameDebug* frameDebug;
if (NS_SUCCEEDED(rootFrame->QueryInterface(nsIFrameDebug::GetIID(), (void**)&frameDebug))) {
frameDebug->VerifyTree();
}
}
#endif
#ifdef DEBUG_kipp
nsPresShell_ReflowStackPointerTop = (char*) &aWidth;
#endif
nsRect bounds;
mPresContext->GetVisibleArea(bounds);
nsSize maxSize(bounds.width, bounds.height);
nsHTMLReflowMetrics desiredSize(nsnull);
nsReflowStatus status;
nsIRenderingContext* rcx = nsnull;
CreateRenderingContext(rootFrame, &rcx);
nsHTMLReflowState reflowState(mPresContext, rootFrame,
1999-03-05 04:29:11 +00:00
eReflowReason_Initial, rcx, maxSize);
nsIView* view;
rootFrame->WillReflow(mPresContext);
rootFrame->GetView(mPresContext, &view);
if (view) {
nsContainerFrame::PositionFrameView(mPresContext, rootFrame, view);
}
rootFrame->Reflow(mPresContext, desiredSize, reflowState, status);
rootFrame->SizeTo(mPresContext, desiredSize.width, desiredSize.height);
mPresContext->SetVisibleArea(nsRect(0,0,desiredSize.width,desiredSize.height));
if (view) {
nsContainerFrame::SyncFrameViewAfterReflow(mPresContext, rootFrame, view,
nsnull);
}
rootFrame->DidReflow(mPresContext, NS_FRAME_REFLOW_FINISHED);
#ifdef NS_DEBUG
if (nsIFrameDebug::GetVerifyTreeEnable()) {
nsIFrameDebug* frameDebug;
if (NS_SUCCEEDED(rootFrame->QueryInterface(nsIFrameDebug::GetIID(), (void**)&frameDebug))) {
frameDebug->VerifyTree();
}
}
#endif
VERIFY_STYLE_TREE;
NS_IF_RELEASE(rcx);
NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, ("exit nsPresShell::InitialReflow"));
MOZ_TIMER_DEBUGLOG(("Stop: Reflow: PresShell::InitialReflow(), this=%p\n", this));
MOZ_TIMER_STOP(mReflowWatch);
}
ExitReflowLock(PR_TRUE, PR_TRUE);
Fix for bug #15360: Drag Selecting, Clicking, then Clicking leaves caret cruft. r=troy@netscape.com,kipp@netscape.com,evaughan@netscape.com,beard@netscape.com layout/html/base/src/nsGfxScrollFrame.cpp - Renamed all occurrences of ScrollPositionChanged() to to ScrollPositionDidChange() to match changes made to nsIScrollPositionListener. - Added ScrollPositionWillChange() stub method. layout/html/base/src/nsPresShell.cpp - Added PresShellViewEventListener class that implements the nsIScrollPositionListener and nsICompositeListener view interfaces. This allows us to turn caret rendering on and off when scrolling and repainting to prevent leaving caret cruft on the screen. - PresShellViewEventListener is created in InitialReflow(), and released in ~PresShell(). view/public/Makefile.in view/public/makefile.win view/public/MANIFEST - Added nsICompositeListener to list of files to be exported. view/public/nsICompositeListener.h - New file. Implementers of this interface can register themselves with the view manager to receive notification before and after a view is composited/refreshed. view/public/nsIScrollPositionListener.h - Added a ScrollPositionWillChange() method. - Changed ScrollPositionChanged() to ScrollPositionDidChange(). view/public/nsIViewManager.h - Added AddCompositeListener() and RemoveCompositeListener methods. view/src/nsScrollingView.cpp view/src/nsScrollingView.h - Added NotifyScrollPositionWillChange() and NotifyScrollPositionDidChange() methods. - Modified HandleScrollEvent() to call NotifyScrollPositionWill/DidChange() methods. Added temporary offsetX and offsetY variables to allow us to calculate new offsets without changing mOffsetX and mOffsetY before notifications are sent out. view/src/nsScrollPortView.cpp - Changed ScrollPositionChanged() to ScrollPositionDidChange(). - Modified ScrollTo() to call the listener's ScrollPositionWillChange() method. view/src/nsViewManager.cpp view/src/nsViewManager.h - Added AddCompositeListener() and RemoveCompositeListener() methods. - Added support for CompositeListener notifications in the Refresh() methods for regions and rects. - Fix for bug #15901: [DOGFOOD] Selected text does not clear when you type Modified UpdateView() so that rects with zero width and height are no longer added to our damage region. r=beard@netscape.com
1999-10-15 04:29:30 +00:00
if (mViewManager && mCaret && !mViewEventListener) {
nsIScrollableView* scrollingView = nsnull;
mViewManager->GetRootScrollableView(&scrollingView);
if (scrollingView) {
mViewEventListener = new PresShellViewEventListener;
if (!mViewEventListener)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(mViewEventListener);
mViewEventListener->SetPresShell(this);
scrollingView->AddScrollPositionListener((nsIScrollPositionListener *)mViewEventListener);
mViewManager->AddCompositeListener((nsICompositeListener *)mViewEventListener);
}
}
return NS_OK; //XXX this needs to be real. MMP
}
NS_IMETHODIMP
PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight)
{
StCaretHider caretHider(this); // stack-based class hides caret until dtor.
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...
nsIFrame* rootFrame;
mFrameManager->GetRootFrame(&rootFrame);
if (rootFrame) {
1998-04-13 20:24:54 +00:00
// 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
if (nsIFrameDebug::GetVerifyTreeEnable()) {
nsIFrameDebug* frameDebug;
if (NS_SUCCEEDED(rootFrame->QueryInterface(nsIFrameDebug::GetIID(), (void**)&frameDebug))) {
frameDebug->VerifyTree();
}
1998-05-20 16:24:54 +00:00
}
#endif
#ifdef DEBUG_kipp
nsPresShell_ReflowStackPointerTop = (char*) &aWidth;
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;
nsIRenderingContext* rcx = nsnull;
CreateRenderingContext(rootFrame, &rcx);
nsHTMLReflowState reflowState(mPresContext, rootFrame,
1999-03-05 04:29:11 +00:00
eReflowReason_Resize, rcx, maxSize);
nsIView* view;
rootFrame->WillReflow(mPresContext);
rootFrame->GetView(mPresContext, &view);
if (view) {
nsContainerFrame::PositionFrameView(mPresContext, rootFrame, view);
}
rootFrame->Reflow(mPresContext, desiredSize, reflowState, status);
rootFrame->SizeTo(mPresContext, desiredSize.width, desiredSize.height);
if (view) {
nsContainerFrame::SyncFrameViewAfterReflow(mPresContext, rootFrame, view,
nsnull);
}
rootFrame->DidReflow(mPresContext, NS_FRAME_REFLOW_FINISHED);
1998-04-13 20:24:54 +00:00
#ifdef NS_DEBUG
if (nsIFrameDebug::GetVerifyTreeEnable()) {
nsIFrameDebug* frameDebug;
if (NS_SUCCEEDED(rootFrame->QueryInterface(nsIFrameDebug::GetIID(), (void**)&frameDebug))) {
frameDebug->VerifyTree();
}
}
#endif
VERIFY_STYLE_TREE;
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(PR_TRUE, PR_TRUE);
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, NS_PRESSHELL_SCROLL_ANYWHERE,
NS_PRESSHELL_SCROLL_ANYWHERE);
return NS_OK;
}
NS_IMETHODIMP
PresShell::NotifyDestroyingFrame(nsIFrame* aFrame)
{
// Cancel any pending reflow commands targeted at this frame
CancelReflowCommand(aFrame);
// Notify the frame manager
if (mFrameManager) {
mFrameManager->NotifyDestroyingFrame(aFrame);
}
return NS_OK;
}
1999-08-04 04:02:40 +00:00
NS_IMETHODIMP
PresShell::GetFrameManager(nsIFrameManager** aFrameManager) const
{
*aFrameManager = mFrameManager;
NS_IF_ADDREF(mFrameManager);
return NS_OK;
}
NS_IMETHODIMP PresShell::GetCaret(nsICaret **outCaret)
{
if (!outCaret || !mCaret)
return NS_ERROR_NULL_POINTER;
return mCaret->QueryInterface(kICaretIID,(void **)outCaret);
}
NS_IMETHODIMP PresShell::SetCaretEnabled(PRBool aInEnable)
{
nsresult result = NS_OK;
PRBool oldEnabled = mCaretEnabled;
mCaretEnabled = aInEnable;
if (mCaret && (mCaretEnabled != oldEnabled))
{
if (mCaretEnabled)
result = mCaret->SetCaretVisible(PR_TRUE);
else
result = mCaret->SetCaretVisible(PR_FALSE);
}
return result;
}
NS_IMETHODIMP PresShell::GetCaretEnabled(PRBool *aOutEnabled)
{
if (!aOutEnabled) { return NS_ERROR_INVALID_ARG; }
*aOutEnabled = mCaretEnabled;
return NS_OK;
}
NS_IMETHODIMP PresShell::SetDisplayNonTextSelection(PRBool aInEnable)
{
mDisplayNonTextSelection = PR_TRUE;
return NS_OK;
}
NS_IMETHODIMP PresShell::GetDisplayNonTextSelection(PRBool *aOutEnable)
{
if (!aOutEnable)
return NS_ERROR_INVALID_ARG;
*aOutEnable = mDisplayNonTextSelection;
return NS_OK;
}
//implementation of nsISelectionController
NS_IMETHODIMP
PresShell::CharacterMove(PRBool aForward, PRBool aExtend)
{
return mSelection->CharacterMove(aForward, aExtend);
}
NS_IMETHODIMP
PresShell::WordMove(PRBool aForward, PRBool aExtend)
{
return mSelection->WordMove(aForward, aExtend);
}
NS_IMETHODIMP
PresShell::LineMove(PRBool aForward, PRBool aExtend)
{
return mSelection->LineMove(aForward, aExtend);
}
NS_IMETHODIMP
PresShell::IntraLineMove(PRBool aForward, PRBool aExtend)
{
return mSelection->IntraLineMove(aForward, aExtend);
}
NS_IMETHODIMP
PresShell::PageMove(PRBool aForward, PRBool aExtend)
{
return ScrollPage(aForward);
#if 0
nsCOMPtr<nsIViewManager> viewManager;
nsresult result = GetViewManager(getter_AddRefs(viewManager));
if (NS_SUCCEEDED(result) && viewManager)
{
nsIScrollableView *scrollView;
result = viewManager->GetRootScrollableView(&scrollView);
if (NS_SUCCEEDED(result) && scrollView)
{
}
}
return result;
#endif //0
}
NS_IMETHODIMP
PresShell::ScrollPage(PRBool aForward)
{
nsCOMPtr<nsIViewManager> viewManager;
nsresult result = GetViewManager(getter_AddRefs(viewManager));
if (NS_SUCCEEDED(result) && viewManager)
{
nsIScrollableView *scrollView;
result = viewManager->GetRootScrollableView(&scrollView);
if (NS_SUCCEEDED(result) && scrollView)
{
scrollView->ScrollByPages(aForward ? 1 : -1);
}
}
return result;
}
NS_IMETHODIMP
PresShell::ScrollLine(PRBool aForward)
{
nsCOMPtr<nsIViewManager> viewManager;
nsresult result = GetViewManager(getter_AddRefs(viewManager));
if (NS_SUCCEEDED(result) && viewManager)
{
nsIScrollableView *scrollView;
result = viewManager->GetRootScrollableView(&scrollView);
if (NS_SUCCEEDED(result) && scrollView)
{
scrollView->ScrollByLines(aForward ? 1 : -1);
//NEW FOR LINES
// force the update to happen now, otherwise multiple scrolls can
// occur before the update is processed. (bug #7354)
// I'd use Composite here, but it doesn't always work.
// vm->Composite();
nsIView* rootView = nsnull;
if (NS_OK == viewManager->GetRootView(rootView) && nsnull != rootView)
{
nsCOMPtr<nsIWidget> rootWidget;
if (NS_OK == rootView->GetWidget(*getter_AddRefs(rootWidget)) && rootWidget!= nsnull)
{
rootWidget->Update();
}
}
}
}
return result;
}
NS_IMETHODIMP
PresShell::ScrollHorizontal(PRBool aLeft)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
PresShell::CompleteScroll(PRBool aForward)
{
nsCOMPtr<nsIViewManager> viewManager;
nsresult result = GetViewManager(getter_AddRefs(viewManager));
if (NS_SUCCEEDED(result) && viewManager)
{
nsIScrollableView *scrollView;
result = viewManager->GetRootScrollableView(&scrollView);
if (NS_SUCCEEDED(result) && scrollView)
{
scrollView->ScrollByWhole(!aForward);//TRUE = top, aForward TRUE=bottom
}
}
return result;
}
NS_IMETHODIMP
PresShell::CompleteMove(PRBool aForward, PRBool aExtend)
{
return CompleteScroll(aForward);
}
NS_IMETHODIMP
PresShell::SelectAll()
{
return mSelection->SelectAll();
}
//end implementations nsISelectionController
NS_IMETHODIMP
PresShell::StyleChangeReflow()
{
EnterReflowLock();
nsIFrame* rootFrame;
mFrameManager->GetRootFrame(&rootFrame);
if (rootFrame) {
// Kick off a top-down reflow
NS_FRAME_LOG(NS_FRAME_TRACE_CALLS,
("enter nsPresShell::StyleChangeReflow"));
#ifdef NS_DEBUG
if (nsIFrameDebug::GetVerifyTreeEnable()) {
nsIFrameDebug* frameDebug;
if (NS_SUCCEEDED(rootFrame->QueryInterface(nsIFrameDebug::GetIID(), (void**)&frameDebug))) {
frameDebug->VerifyTree();
}
}
#endif
nsRect bounds;
mPresContext->GetVisibleArea(bounds);
nsSize maxSize(bounds.width, bounds.height);
nsHTMLReflowMetrics desiredSize(nsnull);
nsReflowStatus status;
nsIRenderingContext* rcx = nsnull;
CreateRenderingContext(rootFrame, &rcx);
// XXX We should be using eReflowReason_StyleChange
nsHTMLReflowState reflowState(mPresContext, rootFrame,
1999-03-05 04:29:11 +00:00
eReflowReason_Resize, rcx, maxSize);
nsIView* view;
rootFrame->WillReflow(mPresContext);
rootFrame->GetView(mPresContext, &view);
if (view) {
nsContainerFrame::PositionFrameView(mPresContext, rootFrame, view);
}
rootFrame->Reflow(mPresContext, desiredSize, reflowState, status);
rootFrame->SizeTo(mPresContext, desiredSize.width, desiredSize.height);
mPresContext->SetVisibleArea(nsRect(0,0,desiredSize.width,desiredSize.height));
if (view) {
nsContainerFrame::SyncFrameViewAfterReflow(mPresContext, rootFrame, view,
nsnull);
}
rootFrame->DidReflow(mPresContext, NS_FRAME_REFLOW_FINISHED);
#ifdef NS_DEBUG
if (nsIFrameDebug::GetVerifyTreeEnable()) {
nsIFrameDebug* frameDebug;
if (NS_SUCCEEDED(rootFrame->QueryInterface(nsIFrameDebug::GetIID(), (void**)&frameDebug))) {
frameDebug->VerifyTree();
}
}
#endif
VERIFY_STYLE_TREE;
NS_IF_RELEASE(rcx);
NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, ("exit nsPresShell::StyleChangeReflow"));
}
ExitReflowLock(PR_TRUE, !gDoAsyncReflow);
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
{
return mFrameManager->GetRootFrame(aResult);
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* rootFrame;
nsIFrame* child;
1999-12-07 05:28:32 +00:00
nsIPageSequenceFrame* pageSequence = nsnull;
1999-12-07 05:28:32 +00:00
// The page sequence frame is the child of the rootFrame
mFrameManager->GetRootFrame(&rootFrame);
rootFrame->FirstChild(nsnull, &child);
1999-12-07 05:28:32 +00:00
if (nsnull != child) {
1999-12-07 05:28:32 +00:00
// but the child could be wrapped in a scrollframe so lets check
nsIScrollableFrame* scrollable = nsnull;
nsresult rv = child->QueryInterface(kIScrollableFrameIID, (void **)&scrollable);
if (NS_SUCCEEDED(rv) && (nsnull != scrollable)) {
// if it is then get the scrolled frame
scrollable->GetScrolledFrame(nsnull, child);
}
// make sure the child is a pageSequence
rv = child->QueryInterface(kIPageSequenceFrameIID, (void**)&pageSequence);
NS_ASSERTION(NS_SUCCEEDED(rv),"Error: Could not find pageSequence!");
*aResult = pageSequence;
return NS_OK;
}
1999-12-07 05:28:32 +00:00
*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)
{
#ifdef MOZ_PERF_METRICS
// Reset style resolution stopwatch maintained by style set
nsresult rv = NS_OK;
nsCOMPtr<nsITimeRecorder> watch = do_QueryInterface(mStyleSet, &rv);
if (NS_SUCCEEDED(rv) && watch) {
MOZ_TIMER_DEBUGLOG(("Reset: Style Resolution: PresShell::BeginLoad(), this=%p\n", this));
watch->ResetTimer(NS_TIMER_STYLE_RESOLUTION);
}
#endif
return NS_OK;
}
NS_IMETHODIMP
PresShell::EndLoad(nsIDocument *aDocument)
{
#ifdef DEBUG_nisheeth
if (aDocument) {
nsIURI* uri = nsnull;
if ((uri = aDocument->GetDocumentURL())) {
char* spec = nsnull;
if (NS_SUCCEEDED(uri->GetSpec(&spec))) {
printf("**** Url: '%s', Reflows: %d, Discarded Reflows: %d\n", spec, mReflows, mDiscardedReflowCommands);
Recycle(spec);
}
}
NS_RELEASE(uri);
}
#endif
#ifdef MOZ_PERF_METRICS
// Dump reflow, style resolution and frame construction times here.
MOZ_TIMER_DEBUGLOG(("Stop: Reflow: PresShell::EndLoad(), this=%p\n", this));
MOZ_TIMER_STOP(mReflowWatch);
MOZ_TIMER_LOG(("Reflow time (this=%p): ", this));
MOZ_TIMER_PRINT(mReflowWatch);
MOZ_TIMER_DEBUGLOG(("Stop: Frame Creation: PresShell::EndLoad(), this=%p\n", this));
MOZ_TIMER_STOP(mFrameCreationWatch);
MOZ_TIMER_LOG(("Frame construction plus style resolution time (this=%p): ", this));
MOZ_TIMER_PRINT(mFrameCreationWatch);
// Print style resolution stopwatch maintained by style set
nsresult rv = NS_OK;
nsCOMPtr<nsITimeRecorder> watch = do_QueryInterface(mStyleSet, &rv);
if (NS_SUCCEEDED(rv) && watch) {
MOZ_TIMER_DEBUGLOG(("Stop: Style Resolution: PresShell::EndLoad(), this=%p\n", this));
watch->StopTimer(NS_TIMER_STYLE_RESOLUTION);
MOZ_TIMER_LOG(("Style resolution time (this=%p): ", this));
watch->PrintTimer(NS_TIMER_STYLE_RESOLUTION);
}
#endif
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
}
// aReflowCommand is considered to be already in the queue if the
// frame it targets is targeted by a pre-existing reflow command in
// the queue.
PRBool
PresShell::AlreadyInQueue(nsIReflowCommand* aReflowCommand)
{
PRInt32 i, n = mReflowCommands.Count();
nsIFrame* targetFrame;
PRBool inQueue = PR_FALSE;
if (!gDoAsyncReflow)
return PR_FALSE;
if (NS_SUCCEEDED(aReflowCommand->GetTarget(targetFrame))) {
// Iterate over the reflow commands and compare the targeted frames.
for (i = 0; i < n; i++) {
nsIReflowCommand* rc = (nsIReflowCommand*) mReflowCommands.ElementAt(i);
if (rc) {
nsIFrame* targetOfQueuedRC;
if (NS_SUCCEEDED(rc->GetTarget(targetOfQueuedRC))) {
nsIReflowCommand::ReflowType RCType;
nsIReflowCommand::ReflowType queuedRCType;
aReflowCommand->GetType(RCType);
rc->GetType(queuedRCType);
if (targetFrame == targetOfQueuedRC &&
RCType == queuedRCType) {
#ifdef DEBUG_nisheeth
mDiscardedReflowCommands++;
#endif
#ifdef DEBUG
if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) {
printf("*** PresShell::AlreadyInQueue(): Discarding reflow command: this=%p\n", this);
aReflowCommand->List(stdout);
}
#endif
inQueue = PR_TRUE;
break;
}
}
}
}
}
return inQueue;
}
NS_IMETHODIMP
1998-06-09 04:51:44 +00:00
PresShell::AppendReflowCommand(nsIReflowCommand* aReflowCommand)
1998-04-13 20:24:54 +00:00
{
#ifdef DEBUG
if (mInVerifyReflow) {
return NS_OK;
}
if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) {
printf("\nPresShell@%p: adding reflow command\n", this);
aReflowCommand->List(stdout);
if (VERIFY_REFLOW_REALLY_NOISY_RC & gVerifyReflowFlags) {
printf("Current content model:\n");
nsCOMPtr<nsIContent> rootContent;
rootContent = getter_AddRefs(mDocument->GetRootContent());
if (rootContent) {
rootContent->List(stdout, 0);
}
}
}
#endif
nsresult rv = NS_OK;
if (!AlreadyInQueue(aReflowCommand)) {
NS_ADDREF(aReflowCommand);
rv = (mReflowCommands.AppendElement(aReflowCommand) ? NS_OK : NS_ERROR_OUT_OF_MEMORY);
}
return rv;
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(i);
if (rc) {
nsIFrame* target;
if (NS_SUCCEEDED(rc->GetTarget(target))) {
if (target == aTargetFrame) {
#ifdef DEBUG
if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) {
printf("PresShell: removing rc=%p for frame ", rc);
nsFrame::ListTag(stdout, aTargetFrame);
printf("\n");
}
#endif
mReflowCommands.RemoveElementAt(i);
NS_RELEASE(rc);
n--;
i--;
continue;
}
}
}
}
return NS_OK;
}
//-------------- Begin Reflow Event Definition ------------------------
struct ReflowEvent : public PLEvent {
ReflowEvent(nsIPresShell* aPresShell, nsIEventQueue* aQueue);
~ReflowEvent() { }
void HandleEvent() {
nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShell);
if (presShell) {
#ifdef DEBUG
if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) {
printf("\n*** Handling reflow event: PresShell=%p, event=%p\n", presShell, this);
}
#endif
presShell->SetReflowEventStatus(PR_FALSE);
presShell->EnterReflowLock();
presShell->ProcessReflowCommands();
presShell->ExitReflowLock(PR_FALSE, PR_TRUE);
}
else
mPresShell = 0;
}
nsWeakPtr mPresShell;
};
static void PR_CALLBACK HandlePLEvent(ReflowEvent* aEvent)
{
aEvent->HandleEvent();
}
static void PR_CALLBACK DestroyPLEvent(ReflowEvent* aEvent)
{
delete aEvent;
}
ReflowEvent::ReflowEvent(nsIPresShell* aPresShell, nsIEventQueue* aQueue)
{
NS_ASSERTION(aPresShell && aQueue, "Null parameters!");
mPresShell = getter_AddRefs(NS_GetWeakReference(aPresShell));
PL_InitEvent(this, nsnull,
(PLHandleEventProc) ::HandlePLEvent,
(PLDestroyEventProc) ::DestroyPLEvent);
aQueue->PostEvent(this);
}
//-------------- End Reflow Event Definition ---------------------------
void
PresShell::PostReflowEvent()
{
if (!mPendingReflowEvent && mReflowCommands.Count() > 0) {
ReflowEvent* ev;
ev = new ReflowEvent((nsIPresShell*) this, mEventQueue);
#ifdef DEBUG
if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) {
printf("\n*** PresShell::PostReflowEvent(), this=%p, event=%p\n", this, ev);
}
#endif
mPendingReflowEvent = PR_TRUE;
}
}
NS_IMETHODIMP
PresShell::ProcessReflowCommands()
1998-04-13 20:24:54 +00:00
{
MOZ_TIMER_DEBUGLOG(("Start: Reflow: PresShell::ProcessReflowCommands(), this=%p\n", this));
MOZ_TIMER_START(mReflowWatch);
PRTime beforeReflow, afterReflow;
PRInt64 diff;
1998-04-13 20:24:54 +00:00
if (0 != mReflowCommands.Count()) {
nsHTMLReflowMetrics desiredSize(nsnull);
nsIRenderingContext* rcx;
nsIFrame* rootFrame;
#ifdef DEBUG_nisheeth
mReflows++;
#endif
mFrameManager->GetRootFrame(&rootFrame);
CreateRenderingContext(rootFrame, &rcx);
1998-04-13 20:24:54 +00:00
#ifdef DEBUG
if (GetVerifyReflowEnable()) {
if (VERIFY_REFLOW_ALL & gVerifyReflowFlags) {
printf("ProcessReflowCommands: begin incremental reflow\n");
}
}
if (VERIFY_REFLOW_DUMP_COMMANDS & gVerifyReflowFlags) {
PRInt32 i, n = mReflowCommands.Count();
printf("\nPresShell::ProcessReflowCommands: this=%p, count=%d\n", this, n);
for (i = 0; i < n; i++) {
nsIReflowCommand* rc = (nsIReflowCommand*)
mReflowCommands.ElementAt(i);
rc->List(stdout);
}
}
#endif
1998-04-13 20:24:54 +00:00
while (0 != mReflowCommands.Count()) {
// Use RemoveElementAt in case the reflowcommand dispatches a
// new one during its execution.
1998-06-09 04:51:44 +00:00
nsIReflowCommand* rc = (nsIReflowCommand*) mReflowCommands.ElementAt(0);
mReflowCommands.RemoveElementAt(0);
1998-04-13 20:24:54 +00:00
// Dispatch the reflow command
nsSize maxSize;
rootFrame->GetSize(maxSize);
if (gDoAsyncReflow) beforeReflow = PR_Now();
rc->Dispatch(mPresContext, desiredSize, maxSize, *rcx);
if (gDoAsyncReflow) afterReflow = PR_Now();
1998-06-09 04:51:44 +00:00
NS_RELEASE(rc);
1999-09-21 07:53:49 +00:00
VERIFY_STYLE_TREE;
if (gDoAsyncReflow) {
// Enable after fixing the Mac build
// LL_SUB(diff, afterReflow, beforeReflow);
// LL_ADD(mAccumulatedReflowTime, mAccumulatedReflowTime, diff);
// if (LL_CMP(mAccumulatedReflowTime, >, gMaxRCProcessingTime))
break;
}
1998-04-13 20:24:54 +00:00
}
NS_IF_RELEASE(rcx);
1998-04-13 20:24:54 +00:00
if (gDoAsyncReflow) {
if (mReflowCommands.Count() > 0) {
// Reflow Commands are still queued up.
// Schedule a reflow event to handle them asynchronously.
PostReflowEvent();
}
#ifdef DEBUG
if (VERIFY_REFLOW_DUMP_COMMANDS & gVerifyReflowFlags) {
PRInt32 reflowTime;
// Enable after fixing the Mac build
// LL_L2I(reflowTime, mAccumulatedReflowTime);
printf("Time spent in PresShell::ProcessReflowCommands(), this=%p, time=%d micro seconds\n", this, reflowTime);
}
#endif
mAccumulatedReflowTime = 0;
}
#ifdef DEBUG
if (VERIFY_REFLOW_DUMP_COMMANDS & gVerifyReflowFlags) {
printf("\nPresShell::ProcessReflowCommands() finished: this=%p\n", this);
}
if (nsIFrameDebug::GetVerifyTreeEnable()) {
nsIFrameDebug* frameDebug;
if (NS_SUCCEEDED(rootFrame->QueryInterface(nsIFrameDebug::GetIID(), (void**)&frameDebug))) {
frameDebug->VerifyTree();
}
1998-05-20 16:24:54 +00:00
}
1998-07-13 19:49:42 +00:00
if (GetVerifyReflowEnable()) {
// First synchronously render what we have so far so that we can
// see it.
nsIView* rootView;
mViewManager->GetRootView(rootView);
mViewManager->UpdateView(rootView, NS_VMREFRESH_IMMEDIATE);
mInVerifyReflow = PR_TRUE;
PRBool ok = VerifyIncrementalReflow();
mInVerifyReflow = PR_FALSE;
if (VERIFY_REFLOW_ALL & gVerifyReflowFlags) {
printf("ProcessReflowCommands: finished (%s)\n",
ok ? "ok" : "failed");
}
if (0 != mReflowCommands.Count()) {
printf("XXX yikes! reflow commands queued during verify-reflow\n");
}
1998-07-13 19:49:42 +00:00
}
1998-04-13 20:24:54 +00:00
#endif
}
MOZ_TIMER_DEBUGLOG(("Stop: Reflow: PresShell::ProcessReflowCommands(), this=%p\n", this));
MOZ_TIMER_STOP(mReflowWatch);
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;
}
for (int i=0; i<mCurrentEventFrameStack.Count(); i++) {
if (aFrame == (nsIFrame*)mCurrentEventFrameStack.ElementAt(i)) {
mCurrentEventFrameStack.ReplaceElementAt(nsnull, i);
}
}
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(mPresContext, &view);
if (nsnull == view)
aFrame->GetOffsetFromView(mPresContext, 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
}
NS_IMETHODIMP
PresShell::CantRenderReplacedElement(nsIPresContext* aPresContext,
nsIFrame* aFrame)
{
if (mFrameManager) {
return mFrameManager->CantRenderReplacedElement(aPresContext, aFrame);
}
return NS_OK;
}
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))) {
rv = ScrollFrameIntoView(frame, NS_PRESSHELL_SCROLL_TOP,
NS_PRESSHELL_SCROLL_ANYWHERE);
1999-02-12 05:39:33 +00:00
}
} else {
rv = NS_ERROR_FAILURE;
}
return rv;
}
NS_IMETHODIMP
PresShell::ScrollFrameIntoView(nsIFrame *aFrame,
PRIntn aVPercent,
PRIntn aHPercent) const
{
nsresult rv = NS_OK;
if (!aFrame) {
return NS_ERROR_NULL_POINTER;
}
if (mViewManager) {
// Get the viewport scroller
nsIScrollableView* scrollingView;
mViewManager->GetRootScrollableView(&scrollingView);
if (scrollingView) {
nsIView* scrolledView;
nsPoint offset;
nsIView* closestView;
// Determine the offset from aFrame to the scrolled view. We do that by
// getting the offset from its closest view and then walking up
scrollingView->GetScrolledView(scrolledView);
aFrame->GetOffsetFromView(mPresContext, offset, &closestView);
// XXX Deal with the case where there is a scrolled element, e.g., a
// DIV in the middle...
while ((closestView != nsnull) && (closestView != scrolledView)) {
nscoord x, y;
// Update the offset
closestView->GetPosition(&x, &y);
offset.MoveBy(x, y);
// Get its parent view
closestView->GetParent(closestView);
}
// Determine the visible rect in the scrolled view's coordinate space.
// The size of the visible area is the clip view size
const nsIView* clipView;
nsRect visibleRect;
scrollingView->GetScrollPosition(visibleRect.x, visibleRect.y);
scrollingView->GetClipView(&clipView);
clipView->GetDimensions(&visibleRect.width, &visibleRect.height);
// The actual scroll offsets
nscoord scrollOffsetX = visibleRect.x;
nscoord scrollOffsetY = visibleRect.y;
// The frame's bounds in the coordinate space of the scrolled frame
nsRect frameBounds;
aFrame->GetRect(frameBounds);
frameBounds.x = offset.x;
frameBounds.y = offset.y;
// See how the frame should be positioned vertically
if (NS_PRESSHELL_SCROLL_ANYWHERE == aVPercent) {
// The caller doesn't care where the frame is positioned vertically,
// so long as it's fully visible
if (frameBounds.y < visibleRect.y) {
// Scroll up so the frame's top edge is visible
scrollOffsetY = frameBounds.y;
} else if (frameBounds.YMost() > visibleRect.YMost()) {
// Scroll down so the frame's bottom edge is visible. Make sure the
// frame's top edge is still visible
scrollOffsetY += frameBounds.YMost() - visibleRect.YMost();
if (scrollOffsetY > frameBounds.y) {
scrollOffsetY = frameBounds.y;
}
}
} else {
// Align the frame edge according to the specified percentage
nscoord frameAlignY = frameBounds.y + (frameBounds.height * aVPercent) / 100;
scrollOffsetY = frameAlignY - (visibleRect.height * aVPercent) / 100;
}
// See how the frame should be positioned horizontally
if (NS_PRESSHELL_SCROLL_ANYWHERE == aHPercent) {
// The caller doesn't care where the frame is positioned horizontally,
// so long as it's fully visible
if (frameBounds.x < visibleRect.x) {
// Scroll left so the frame's left edge is visible
scrollOffsetX = frameBounds.x;
} else if (frameBounds.XMost() > visibleRect.XMost()) {
// Scroll right so the frame's right edge is visible. Make sure the
// frame's left edge is still visible
scrollOffsetX += frameBounds.XMost() - visibleRect.XMost();
if (scrollOffsetX > frameBounds.x) {
scrollOffsetX = frameBounds.x;
}
}
} else {
// Align the frame edge according to the specified percentage
nscoord frameAlignX = frameBounds.x + (frameBounds.width * aHPercent) / 100;
scrollOffsetX = frameAlignX - (visibleRect.width * aHPercent) / 100;
}
scrollingView->ScrollTo(scrollOffsetX, scrollOffsetY, NS_VMREFRESH_IMMEDIATE);
}
}
return rv;
}
NS_IMETHODIMP
PresShell::DoCopy()
{
nsCOMPtr<nsIDocument> doc;
GetDocument(getter_AddRefs(doc));
if (doc) {
nsString buffer;
nsresult rv;
nsIDOMSelection* sel;
GetSelection(SELECTION_NORMAL, &sel);
if (sel != nsnull)
doc->CreateXIF(buffer,sel);
NS_IF_RELEASE(sel);
// Get the Clipboard
NS_WITH_SERVICE(nsIClipboard, clipboard, kCClipboardCID, &rv);
if (NS_FAILED(rv)) return rv;
if ( clipboard ) {
// Create a transferable for putting data on the Clipboard
nsCOMPtr<nsITransferable> trans;
rv = nsComponentManager::CreateInstance(kCTransferableCID, nsnull,
nsITransferable::GetIID(),
(void**) getter_AddRefs(trans));
if ( trans ) {
// 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,
NS_GET_IID(nsIFormatConverter), getter_AddRefs(xifConverter));
if ( xifConverter ) {
// Add the XIF DataFlavor to the transferable
// this tells the transferable that it can handle receiving the XIF format
trans->AddDataFlavor(kXIFMime);
// Add the converter for going from XIF to other formats
trans->SetConverter(xifConverter);
// Now add the XIF data to the transferable, placing it into a nsISupportsWString object.
// the transferable wants the number bytes for the data and since it is double byte
// we multiply by 2.
nsCOMPtr<nsISupportsWString> dataWrapper;
rv = nsComponentManager::CreateInstance(NS_SUPPORTS_WSTRING_PROGID, nsnull,
NS_GET_IID(nsISupportsWString), getter_AddRefs(dataWrapper));
if ( dataWrapper ) {
dataWrapper->SetData ( NS_CONST_CAST(PRUnichar*,buffer.GetUnicode()) );
// QI the data object an |nsISupports| so that when the transferable holds
// onto it, it will addref the correct interface.
nsCOMPtr<nsISupports> genericDataObj ( do_QueryInterface(dataWrapper) );
trans->SetTransferData(kXIFMime, genericDataObj, buffer.Length()*2);
}
// put the transferable on the clipboard
clipboard->SetData(trans, nsnull);
}
}
}
}
return NS_OK;
}
// XXX This function needs to be renamed to something better.
// It is not simply a getter for the layout history state. It
// creates a new state object and captures frame state onto it.
NS_IMETHODIMP
PresShell::GetHistoryState(nsILayoutHistoryState** aState)
{
nsresult rv = NS_OK;
NS_PRECONDITION(nsnull != aState, "null state pointer");
// Create the document state object
rv = NS_NewLayoutHistoryState(aState);
if (NS_FAILED(rv)) {
*aState = nsnull;
return rv;
}
// Capture frame state for the entire frame hierarchy
nsIFrame* rootFrame = nsnull;
rv = GetRootFrame(&rootFrame);
if (NS_FAILED(rv) || nsnull == rootFrame) return rv;
rv = mFrameManager->CaptureFrameState(mPresContext, rootFrame, *aState);
return rv;
}
NS_IMETHODIMP
PresShell::SetHistoryState(nsILayoutHistoryState* aLayoutHistoryState)
{
mHistoryState = aLayoutHistoryState;
return NS_OK;
}
NS_IMETHODIMP
PresShell::GetReflowEventStatus(PRBool* aPending)
{
if (aPending)
*aPending = mPendingReflowEvent;
return NS_OK;
}
NS_IMETHODIMP
PresShell::SetReflowEventStatus(PRBool aPending)
{
mPendingReflowEvent = aPending;
return NS_OK;
}
NS_IMETHODIMP
PresShell::ContentChanged(nsIDocument *aDocument,
nsIContent* aContent,
nsISupports* aSubContent)
1998-04-13 20:24:54 +00:00
{
EnterReflowLock();
nsresult rv = mStyleSet->ContentChanged(mPresContext, aContent, aSubContent);
1999-09-21 07:53:49 +00:00
VERIFY_STYLE_TREE;
ExitReflowLock(PR_TRUE, !gDoAsyncReflow);
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
{
EnterReflowLock();
1999-04-20 00:06:58 +00:00
nsresult rv = mStyleSet->ContentStatesChanged(mPresContext, aContent1, aContent2);
1999-09-21 07:53:49 +00:00
VERIFY_STYLE_TREE;
ExitReflowLock(PR_TRUE, !gDoAsyncReflow);
1999-02-27 07:15:09 +00:00
return rv;
}
NS_IMETHODIMP
PresShell::AttributeChanged(nsIDocument *aDocument,
nsIContent* aContent,
PRInt32 aNameSpaceID,
nsIAtom* aAttribute,
PRInt32 aHint)
{
EnterReflowLock();
nsresult rv = mStyleSet->AttributeChanged(mPresContext, aContent, aNameSpaceID, aAttribute, aHint);
1999-09-21 07:53:49 +00:00
VERIFY_STYLE_TREE;
ExitReflowLock(PR_TRUE, !gDoAsyncReflow);
return rv;
}
NS_IMETHODIMP
PresShell::ContentAppended(nsIDocument *aDocument,
nsIContent* aContainer,
PRInt32 aNewIndexInContainer)
1998-04-13 20:24:54 +00:00
{
EnterReflowLock();
MOZ_TIMER_DEBUGLOG(("Start: Frame Creation: PresShell::ContentAppended(), this=%p\n", this));
MOZ_TIMER_START(mFrameCreationWatch);
nsresult rv = mStyleSet->ContentAppended(mPresContext, aContainer, aNewIndexInContainer);
1999-09-21 07:53:49 +00:00
VERIFY_STYLE_TREE;
if (NS_SUCCEEDED(rv) && nsnull != mHistoryState) {
// If history state has been set by session history, ask the frame manager
// to restore frame state for the frame hierarchy created for the chunk of
// content that just came in.
nsIFrame* frame;
rv = GetPrimaryFrameFor(aContainer, &frame);
if (NS_SUCCEEDED(rv) && nsnull != frame)
mFrameManager->RestoreFrameState(mPresContext, frame, mHistoryState);
}
MOZ_TIMER_DEBUGLOG(("Stop: Frame Creation: PresShell::ContentAppended(), this=%p\n", this));
MOZ_TIMER_STOP(mFrameCreationWatch);
ExitReflowLock(PR_TRUE, !gDoAsyncReflow);
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);
1999-09-21 07:53:49 +00:00
VERIFY_STYLE_TREE;
ExitReflowLock(PR_TRUE, !gDoAsyncReflow);
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);
1999-09-21 07:53:49 +00:00
VERIFY_STYLE_TREE;
ExitReflowLock(PR_TRUE, PR_TRUE);
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);
1999-09-21 07:53:49 +00:00
VERIFY_STYLE_TREE;
ExitReflowLock(PR_TRUE, PR_TRUE);
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);
1999-09-21 07:53:49 +00:00
VERIFY_STYLE_TREE;
ExitReflowLock(PR_TRUE, PR_TRUE);
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);
1999-09-21 07:53:49 +00:00
VERIFY_STYLE_TREE;
ExitReflowLock(PR_TRUE, PR_TRUE);
1998-11-26 01:34:53 +00:00
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);
1999-09-21 07:53:49 +00:00
VERIFY_STYLE_TREE;
ExitReflowLock(PR_TRUE, PR_TRUE);
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);
1999-09-21 07:53:49 +00:00
VERIFY_STYLE_TREE;
ExitReflowLock(PR_TRUE, PR_TRUE);
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
}
NS_IMETHODIMP
PresShell::GetPrimaryFrameFor(nsIContent* aContent,
nsIFrame** aResult) const
1998-04-13 20:24:54 +00:00
{
nsresult rv;
if (mFrameManager) {
rv = mFrameManager->GetPrimaryFrameFor(aContent, aResult);
} else {
*aResult = nsnull;
rv = NS_OK;
}
return rv;
1998-04-13 20:24:54 +00:00
}
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
{
nsresult rv;
if (mFrameManager) {
rv = mFrameManager->GetPlaceholderFrameFor(aFrame, aResult);
} else {
*aResult = nsnull;
rv = NS_OK;
}
return rv;
}
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;
if (nsnull != frame)
{
StCaretHider caretHider(this); // stack-based class hides caret until dtor.
1998-08-28 02:54:06 +00:00
rv = frame->Paint(mPresContext, aRenderingContext, aDirtyRect,
NS_FRAME_PAINT_LAYER_BACKGROUND);
rv = frame->Paint(mPresContext, aRenderingContext, aDirtyRect,
NS_FRAME_PAINT_LAYER_FLOATERS);
rv = frame->Paint(mPresContext, aRenderingContext, aDirtyRect,
NS_FRAME_PAINT_LAYER_FOREGROUND);
#ifdef NS_DEBUG
// Draw a border around the frame
if (nsIFrameDebug::GetShowFrameBorders()) {
nsRect r;
frame->GetRect(r);
aRenderingContext.SetColor(NS_RGB(0,0,255));
aRenderingContext.DrawRect(0, 0, r.width, r.height);
}
#endif
}
1998-08-28 02:54:06 +00:00
return rv;
}
nsIFrame*
PresShell::GetCurrentEventFrame()
{
if (!mCurrentEventFrame && mCurrentEventContent) {
// Make sure the content still has a document reference. If not,
// then we assume it is no longer in the content tree and the
// frame shouldn't get an event, nor should we even assume its
// safe to try and find the frame.
nsCOMPtr<nsIDocument> doc;
nsresult result = mCurrentEventContent->GetDocument(*getter_AddRefs(doc));
if (NS_SUCCEEDED(result) && doc) {
GetPrimaryFrameFor(mCurrentEventContent, &mCurrentEventFrame);
}
}
return mCurrentEventFrame;
}
void
PresShell::PushCurrentEventFrame()
{
if (mCurrentEventFrame) {
mCurrentEventFrameStack.InsertElementAt((void*)mCurrentEventFrame, 0);
}
}
void
PresShell::PopCurrentEventFrame()
{
mCurrentEventFrame = nsnull;
1999-09-02 19:21:45 +00:00
if (0 != mCurrentEventFrameStack.Count()) {
mCurrentEventFrame = (nsIFrame*)mCurrentEventFrameStack.ElementAt(0);
mCurrentEventFrameStack.RemoveElementAt(0);
}
}
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 (mSelection && aEvent->eventStructType == NS_KEY_EVENT)
{//KEY HANDLERS WILL GET RID OF THIS
if (mDisplayNonTextSelection && NS_SUCCEEDED(mSelection->HandleKeyEvent(mPresContext, aEvent)))
{
return NS_OK;
}
}
*/
if (nsnull != frame) {
PushCurrentEventFrame();
nsIEventStateManager *manager;
nsIContent* focusContent = nsnull;
if (NS_OK == mPresContext->GetEventStateManager(&manager)) {
if (NS_IS_KEY_EVENT(aEvent)) {
//Key events go to the focused frame, not point based.
manager->GetFocusedContent(&focusContent);
if (focusContent)
GetPrimaryFrameFor(focusContent, &mCurrentEventFrame);
else frame->GetFrameForPoint(mPresContext, aEvent->point, &mCurrentEventFrame);
}
else {
frame->GetFrameForPoint(mPresContext, aEvent->point, &mCurrentEventFrame);
}
NS_IF_RELEASE(mCurrentEventContent);
if (GetCurrentEventFrame() || focusContent) {
//Once we have the targetFrame, handle the event in this order
//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 ((GetCurrentEventFrame() || focusContent) && NS_OK == rv) {
if (focusContent) {
rv = focusContent->HandleDOMEvent(mPresContext, (nsEvent*)aEvent, nsnull,
NS_EVENT_FLAG_INIT, aEventStatus);
}
else {
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 (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 ((GetCurrentEventFrame() || focusContent) && NS_OK == rv) {
rv = manager->PostHandleEvent(mPresContext, aEvent, mCurrentEventFrame, aEventStatus, aView);
}
}
}
NS_RELEASE(manager);
NS_IF_RELEASE(focusContent);
}
PopCurrentEventFrame();
}
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) {
nsIFrameDebug* frameDebug;
if (NS_SUCCEEDED(k1->QueryInterface(nsIFrameDebug::GetIID(), (void**)&frameDebug))) {
frameDebug->GetFrameName(name);
}
1998-11-25 18:41:02 +00:00
}
else {
name = "(null)";
}
fputs(name, stdout);
printf(" != ");
if (nsnull != k2) {
nsIFrameDebug* frameDebug;
if (NS_SUCCEEDED(k2->QueryInterface(nsIFrameDebug::GetIID(), (void**)&frameDebug))) {
frameDebug->GetFrameName(name);
}
1998-11-25 18:41:02 +00:00
}
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;
nsIFrameDebug* frameDebug;
if (NS_SUCCEEDED(k1->QueryInterface(nsIFrameDebug::GetIID(), (void**)&frameDebug))) {
frameDebug->GetFrameName(name);
fputs(name, stdout);
}
printf("{%d, %d, %d, %d}", r1.x, r1.y, r1.width, r1.height);
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
if (NS_SUCCEEDED(k2->QueryInterface(nsIFrameDebug::GetIID(), (void**)&frameDebug))) {
frameDebug->GetFrameName(name);
fputs(name, stdout);
}
printf("{%d, %d, %d, %d}", r2.x, r2.y, r2.width, r2.height);
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
CompareTrees(nsIPresContext* aPresContext, 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
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 (0 == (VERIFY_REFLOW_ALL & gVerifyReflowFlags)) {
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
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");
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);
}
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(aPresContext, &v1);
k2->GetView(aPresContext, &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");
}
else if (nsnull != v1) {
v1->GetBounds(r1);
v2->GetBounds(r2);
if (r1 != r2) {
LogVerifyMessage(k1, k2, "(view rects)", r1, r2);
}
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");
}
else if (nsnull != w1) {
w1->GetBounds(r1);
w2->GetBounds(r2);
if (r1 != r2) {
LogVerifyMessage(k1, k2, "(widget rects)", r1, r2);
}
1998-07-13 19:49:42 +00:00
}
}
if (!ok && (0 == (VERIFY_REFLOW_ALL & gVerifyReflowFlags))) {
1998-11-25 18:41:02 +00:00
break;
}
// Compare the sub-trees too
if (!CompareTrees(aPresContext, k1, k2)) {
ok = PR_FALSE;
if (0 == (VERIFY_REFLOW_ALL & gVerifyReflowFlags)) {
1999-04-03 18:58:04 +00:00
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
}
}
if (!ok && (0 == (VERIFY_REFLOW_ALL & gVerifyReflowFlags))) {
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
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) {
if (0 == (VERIFY_REFLOW_ALL & gVerifyReflowFlags)) {
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;
}
#endif
1999-04-03 18:58:04 +00:00
#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
}
#ifdef DEBUG
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.
PRBool
1998-07-13 19:49:42 +00:00
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
PRBool ok = CompareTrees(mPresContext, root1, root2);
if (!ok && (VERIFY_REFLOW_NOISY & gVerifyReflowFlags)) {
1999-04-20 00:24:21 +00:00
printf("Verify reflow failed, primary tree:\n");
nsIFrameDebug* frameDebug;
if (NS_SUCCEEDED(root1->QueryInterface(nsIFrameDebug::GetIID(), (void**)&frameDebug))) {
frameDebug->List(mPresContext, stdout, 0);
}
1999-04-20 00:24:21 +00:00
printf("Verification tree:\n");
if (NS_SUCCEEDED(root2->QueryInterface(nsIFrameDebug::GetIID(), (void**)&frameDebug))) {
frameDebug->List(mPresContext, 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);
return ok;
1998-07-13 19:49:42 +00:00
}
#endif
Fix for bug #15360: Drag Selecting, Clicking, then Clicking leaves caret cruft. r=troy@netscape.com,kipp@netscape.com,evaughan@netscape.com,beard@netscape.com layout/html/base/src/nsGfxScrollFrame.cpp - Renamed all occurrences of ScrollPositionChanged() to to ScrollPositionDidChange() to match changes made to nsIScrollPositionListener. - Added ScrollPositionWillChange() stub method. layout/html/base/src/nsPresShell.cpp - Added PresShellViewEventListener class that implements the nsIScrollPositionListener and nsICompositeListener view interfaces. This allows us to turn caret rendering on and off when scrolling and repainting to prevent leaving caret cruft on the screen. - PresShellViewEventListener is created in InitialReflow(), and released in ~PresShell(). view/public/Makefile.in view/public/makefile.win view/public/MANIFEST - Added nsICompositeListener to list of files to be exported. view/public/nsICompositeListener.h - New file. Implementers of this interface can register themselves with the view manager to receive notification before and after a view is composited/refreshed. view/public/nsIScrollPositionListener.h - Added a ScrollPositionWillChange() method. - Changed ScrollPositionChanged() to ScrollPositionDidChange(). view/public/nsIViewManager.h - Added AddCompositeListener() and RemoveCompositeListener methods. view/src/nsScrollingView.cpp view/src/nsScrollingView.h - Added NotifyScrollPositionWillChange() and NotifyScrollPositionDidChange() methods. - Modified HandleScrollEvent() to call NotifyScrollPositionWill/DidChange() methods. Added temporary offsetX and offsetY variables to allow us to calculate new offsets without changing mOffsetX and mOffsetY before notifications are sent out. view/src/nsScrollPortView.cpp - Changed ScrollPositionChanged() to ScrollPositionDidChange(). - Modified ScrollTo() to call the listener's ScrollPositionWillChange() method. view/src/nsViewManager.cpp view/src/nsViewManager.h - Added AddCompositeListener() and RemoveCompositeListener() methods. - Added support for CompositeListener notifications in the Refresh() methods for regions and rects. - Fix for bug #15901: [DOGFOOD] Selected text does not clear when you type Modified UpdateView() so that rects with zero width and height are no longer added to our damage region. r=beard@netscape.com
1999-10-15 04:29:30 +00:00
// PresShellViewEventListener
NS_IMPL_ISUPPORTS2(PresShellViewEventListener, nsIScrollPositionListener, nsICompositeListener)
PresShellViewEventListener::PresShellViewEventListener()
{
NS_INIT_ISUPPORTS();
mPresShell = 0;
mWasVisible = PR_FALSE;
mCallCount = 0;
}
PresShellViewEventListener::~PresShellViewEventListener()
{
mPresShell = 0;
}
nsresult
PresShellViewEventListener::SetPresShell(nsIPresShell *aPresShell)
{
mPresShell = aPresShell;
return NS_OK;
}
nsresult
PresShellViewEventListener::HideCaret()
{
nsresult result = NS_OK;
if (mPresShell && 0 == mCallCount)
{
result = mPresShell->GetCaretEnabled(&mWasVisible);
if (NS_SUCCEEDED(result) && mWasVisible)
result = mPresShell->SetCaretEnabled(PR_FALSE);
}
++mCallCount;
return result;
}
nsresult
PresShellViewEventListener::RestoreCaretVisibility()
{
nsresult result = NS_OK;
--mCallCount;
if (mPresShell && 0 == mCallCount && mWasVisible)
result = mPresShell->SetCaretEnabled(PR_TRUE);
return result;
}
NS_IMETHODIMP
PresShellViewEventListener::ScrollPositionWillChange(nsIScrollableView *aView, nscoord aX, nscoord aY)
{
return HideCaret();
}
NS_IMETHODIMP
PresShellViewEventListener::ScrollPositionDidChange(nsIScrollableView *aView, nscoord aX, nscoord aY)
{
return RestoreCaretVisibility();
}
NS_IMETHODIMP
PresShellViewEventListener::WillRefreshRegion(nsIViewManager *aViewManager,
nsIView *aView,
nsIRenderingContext *aContext,
nsIRegion *aRegion,
PRUint32 aUpdateFlags)
{
return HideCaret();
}
NS_IMETHODIMP
PresShellViewEventListener::DidRefreshRegion(nsIViewManager *aViewManager,
nsIView *aView,
nsIRenderingContext *aContext,
nsIRegion *aRegion,
PRUint32 aUpdateFlags)
{
return RestoreCaretVisibility();
}
NS_IMETHODIMP
PresShellViewEventListener::WillRefreshRect(nsIViewManager *aViewManager,
nsIView *aView,
nsIRenderingContext *aContext,
const nsRect *aRect,
PRUint32 aUpdateFlags)
{
return HideCaret();
}
NS_IMETHODIMP
PresShellViewEventListener::DidRefreshRect(nsIViewManager *aViewManager,
nsIView *aView,
nsIRenderingContext *aContext,
const nsRect *aRect,
PRUint32 aUpdateFlags)
{
return RestoreCaretVisibility();
}