1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=2 sw=2 et tw=78:
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is mozilla.org code.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1998
21 * the Initial Developer. All Rights Reserved.
24 * Steve Clark <buster@netscape.com>
25 * Håkan Waara <hwaara@chello.se>
26 * Dan Rosen <dr@netscape.com>
27 * Daniel Glazman <glazman@netscape.com>
28 * Mats Palmgren <matspal@gmail.com>
29 * Mihai Șucan <mihai.sucan@gmail.com>
31 * Alternatively, the contents of this file may be used under the terms of
32 * either of the GNU General Public License Version 2 or later (the "GPL"),
33 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
34 * in which case the provisions of the GPL or the LGPL are applicable instead
35 * of those above. If you wish to allow use of your version of this file only
36 * under the terms of either the GPL or the LGPL, and not to allow others to
37 * use your version of this file under the terms of the MPL, indicate your
38 * decision by deleting the provisions above and replace them with the notice
39 * and other provisions required by the GPL or the LGPL. If you do not delete
40 * the provisions above, a recipient may use your version of this file under
41 * the terms of any one of the MPL, the GPL or the LGPL.
43 * ***** END LICENSE BLOCK *****
45 * This Original Code has been modified by IBM Corporation.
46 * Modifications made by IBM described herein are
47 * Copyright (c) International Business Machines
50 * Modifications to Mozilla code or documentation
51 * identified per MPL Section 3.3
53 * Date Modified by Description of modification
54 * 05/03/2000 IBM Corp. Observer events for reflow states
57 /* a presentation of a document, part 2 */
59 #include "nsIPresShell.h"
60 #include "nsPresContext.h"
61 #include "nsIContent.h"
62 #include "mozilla/dom/Element.h"
63 #include "nsIDocument.h"
64 #include "nsIDOMXULDocument.h"
65 #include "nsStubDocumentObserver.h"
66 #include "nsStyleSet.h"
67 #include "nsCSSStyleSheet.h" // XXX for UA sheet loading hack, can this go away please?
68 #include "nsIDOMCSSStyleSheet.h" // for Pref-related rule management (bugs 22963,20760,31816)
69 #include "nsINameSpaceManager.h" // for Pref-related rule management (bugs 22963,20760,31816)
70 #include "nsIServiceManager.h"
72 #include "nsIViewManager.h"
74 #include "nsCRTGlue.h"
80 #include "nsCOMArray.h"
81 #include "nsHashtable.h"
82 #include "nsIViewObserver.h"
83 #include "nsContainerFrame.h"
84 #include "nsIDeviceContext.h"
85 #include "nsEventStateManager.h"
86 #include "nsDOMEvent.h"
87 #include "nsGUIEvent.h"
88 #include "nsHTMLParts.h"
89 #include "nsContentUtils.h"
90 #include "nsISelection.h"
91 #include "nsISelectionController.h"
92 #include "nsISelectionPrivate.h"
93 #include "nsLayoutCID.h"
94 #include "nsGkAtoms.h"
95 #include "nsIDOMRange.h"
96 #include "nsIDOMDocument.h"
97 #include "nsIDOMNode.h"
98 #include "nsIDOM3Node.h"
99 #include "nsIDOMNodeList.h"
100 #include "nsIDOMElement.h"
102 #include "nsCSSPseudoElements.h"
103 #include "nsCOMPtr.h"
104 #include "nsAutoPtr.h"
105 #include "nsReadableUtils.h"
106 #include "nsUnicharUtils.h"
107 #include "nsWeakReference.h"
108 #include "nsIPageSequenceFrame.h"
110 #include "nsIDOMHTMLDocument.h"
111 #include "nsIXPointer.h"
112 #include "nsIDOMXMLDocument.h"
113 #include "nsIParser.h"
114 #include "nsParserCIID.h"
115 #include "nsFrameSelection.h"
116 #include "nsIDOMNSHTMLTextAreaElement.h"
117 #include "nsViewsCID.h"
118 #include "nsPresArena.h"
119 #include "nsFrameManager.h"
121 #include "nsISupportsPrimitives.h"
122 #include "nsILayoutHistoryState.h"
123 #include "nsILineIterator.h" // for ScrollContentIntoView
124 #include "nsWeakPtr.h"
126 #include "nsIObserverService.h"
127 #include "nsIObserver.h"
128 #include "nsIDocShell.h" // for reflow observation
129 #include "nsIBaseWindow.h"
130 #include "nsLayoutErrors.h"
131 #include "nsLayoutUtils.h"
132 #include "nsCSSRendering.h"
133 // for |#ifdef DEBUG| code
135 #include "nsIAttribute.h"
136 #include "nsIGlobalHistory2.h"
137 #include "nsDisplayList.h"
138 #include "nsIRegion.h"
139 #include "nsRegion.h"
141 #ifdef MOZ_REFLOW_PERF
142 #include "nsIRenderingContext.h"
143 #include "nsIFontMetrics.h"
146 #include "nsIReflowCallback.h"
148 #include "nsPIDOMWindow.h"
149 #include "nsFocusManager.h"
150 #include "nsIPluginInstance.h"
151 #include "nsIObjectFrame.h"
152 #include "nsIObjectLoadingContent.h"
153 #include "nsNetUtil.h"
154 #include "nsEventDispatcher.h"
155 #include "nsThreadUtils.h"
156 #include "nsStyleSheetService.h"
157 #include "gfxImageSurface.h"
158 #include "gfxContext.h"
160 #include "nsHTMLMediaElement.h"
163 #include "nsSMILAnimationController.h"
166 #include "nsRefreshDriver.h"
168 // Drag & Drop, Clipboard
169 #include "nsWidgetsCID.h"
170 #include "nsIClipboard.h"
171 #include "nsIClipboardHelper.h"
172 #include "nsIDocShellTreeItem.h"
174 #include "nsIScrollableFrame.h"
177 #include "nsIDragService.h"
178 #include "nsCopySupport.h"
179 #include "nsIDOMHTMLAnchorElement.h"
180 #include "nsIDOMHTMLAreaElement.h"
181 #include "nsIDOMHTMLLinkElement.h"
182 #include "nsITimer.h"
184 #include "nsIAccessibilityService.h"
185 #include "nsAccessible.h"
188 // For style data reconstruction
189 #include "nsStyleChangeList.h"
190 #include "nsCSSFrameConstructor.h"
192 #include "nsMenuFrame.h"
193 #include "nsTreeBodyFrame.h"
194 #include "nsIBoxObject.h"
195 #include "nsITreeBoxObject.h"
196 #include "nsMenuPopupFrame.h"
197 #include "nsITreeColumns.h"
198 #include "nsIDOMXULMultSelectCntrlEl.h"
199 #include "nsIDOMXULSelectCntrlItemEl.h"
200 #include "nsIDOMXULMenuListElement.h"
203 #include "nsPlaceholderFrame.h"
204 #include "nsCanvasFrame.h"
206 // Content viewer interfaces
207 #include "nsIContentViewer.h"
208 #include "imgIEncoder.h"
209 #include "gfxPlatform.h"
211 #include "mozilla/FunctionTimer.h"
215 #ifdef NS_FUNCTION_TIMER
216 #define NS_TIME_FUNCTION_DECLARE_DOCURL \
217 nsCAutoString docURL__("N/A"); \
218 nsIURI *uri__ = mDocument->GetDocumentURI(); \
219 if (uri__) uri__->GetSpec(docURL__);
220 #define NS_TIME_FUNCTION_WITH_DOCURL \
221 NS_TIME_FUNCTION_DECLARE_DOCURL \
222 NS_TIME_FUNCTION_MIN_FMT(1.0, \
223 "%s (line %d) (document: %s)", MOZ_FUNCTION_NAME, \
224 __LINE__, docURL__.get())
226 #define NS_TIME_FUNCTION_WITH_DOCURL do{} while(0)
229 #include "nsContentCID.h"
230 static NS_DEFINE_IID(kRangeCID
, NS_RANGE_CID
);
232 /* for NS_MEMORY_REPORTER_IMPLEMENT */
233 #include "nsIMemoryReporter.h"
235 using namespace mozilla
;
236 using namespace mozilla::dom
;
237 using namespace mozilla::layers
;
239 PRBool
nsIPresShell::gIsAccessibilityActive
= PR_FALSE
;
240 CapturingContentInfo
nsIPresShell::gCaptureInfo
=
241 { PR_FALSE
/* mAllowed */, PR_FALSE
/* mRetargetToElement */,
242 PR_FALSE
/* mPreventDrag */, nsnull
/* mContent */ };
243 nsIContent
* nsIPresShell::gKeyDownTarget
;
246 ChangeFlag(PRUint32 aFlags
, PRBool aOnOff
, PRUint32 aFlag
)
250 flags
= (aFlags
| aFlag
);
252 flags
= (aFlag
& ~aFlag
);
257 // convert a color value to a string, in the CSS format #RRGGBB
258 // * - initially created for bugs 31816, 20760, 22963
259 static void ColorToString(nscolor aColor
, nsAutoString
&aString
);
262 static NS_DEFINE_CID(kFrameSelectionCID
, NS_FRAMESELECTION_CID
);
264 // RangePaintInfo is used to paint ranges to offscreen buffers
265 struct RangePaintInfo
{
266 nsCOMPtr
<nsIRange
> mRange
;
267 nsDisplayListBuilder mBuilder
;
270 // offset of builder's reference frame to the root frame
273 RangePaintInfo(nsIRange
* aRange
, nsIFrame
* aFrame
)
274 : mRange(aRange
), mBuilder(aFrame
, nsDisplayListBuilder::PAINTING
, PR_FALSE
)
276 MOZ_COUNT_CTOR(RangePaintInfo
);
282 MOZ_COUNT_DTOR(RangePaintInfo
);
288 // ----------------------------------------------------------------------
291 // Set the environment variable GECKO_VERIFY_REFLOW_FLAGS to one or
292 // more of the following flags (comma separated) for handy debug
294 static PRUint32 gVerifyReflowFlags
;
296 struct VerifyReflowFlags
{
301 static const VerifyReflowFlags gFlags
[] = {
302 { "verify", VERIFY_REFLOW_ON
},
303 { "reflow", VERIFY_REFLOW_NOISY
},
304 { "all", VERIFY_REFLOW_ALL
},
305 { "list-commands", VERIFY_REFLOW_DUMP_COMMANDS
},
306 { "noisy-commands", VERIFY_REFLOW_NOISY_RC
},
307 { "really-noisy-commands", VERIFY_REFLOW_REALLY_NOISY_RC
},
308 { "resize", VERIFY_REFLOW_DURING_RESIZE_REFLOW
},
311 #define NUM_VERIFY_REFLOW_FLAGS (sizeof(gFlags) / sizeof(gFlags[0]))
314 ShowVerifyReflowFlags()
316 printf("Here are the available GECKO_VERIFY_REFLOW_FLAGS:\n");
317 const VerifyReflowFlags
* flag
= gFlags
;
318 const VerifyReflowFlags
* limit
= gFlags
+ NUM_VERIFY_REFLOW_FLAGS
;
319 while (flag
< limit
) {
320 printf(" %s\n", flag
->name
);
323 printf("Note: GECKO_VERIFY_REFLOW_FLAGS is a comma separated list of flag\n");
324 printf("names (no whitespace)\n");
328 //========================================================================
329 //========================================================================
330 //========================================================================
331 #ifdef MOZ_REFLOW_PERF
332 class ReflowCountMgr
;
334 static const char kGrandTotalsStr
[] = "Grand Totals";
337 class ReflowCounter
{
339 ReflowCounter(ReflowCountMgr
* aMgr
= nsnull
);
343 void DisplayTotals(const char * aStr
);
344 void DisplayDiffTotals(const char * aStr
);
345 void DisplayHTMLTotals(const char * aStr
);
347 void Add() { mTotal
++; }
348 void Add(PRUint32 aTotal
) { mTotal
+= aTotal
; }
350 void CalcDiffInTotals();
351 void SetTotalsCache();
353 void SetMgr(ReflowCountMgr
* aMgr
) { mMgr
= aMgr
; }
355 PRUint32
GetTotal() { return mTotal
; }
358 void DisplayTotals(PRUint32 aTotal
, const char * aTitle
);
359 void DisplayHTMLTotals(PRUint32 aTotal
, const char * aTitle
);
362 PRUint32 mCacheTotal
;
364 ReflowCountMgr
* mMgr
; // weak reference (don't delete)
368 class IndiReflowCounter
{
370 IndiReflowCounter(ReflowCountMgr
* aMgr
= nsnull
)
375 mHasBeenOutput(PR_FALSE
)
377 virtual ~IndiReflowCounter() {}
380 nsIFrame
* mFrame
; // weak reference (don't delete)
383 ReflowCountMgr
* mMgr
; // weak reference (don't delete)
385 ReflowCounter mCounter
;
386 PRBool mHasBeenOutput
;
390 //--------------------
392 //--------------------
393 class ReflowCountMgr
{
396 virtual ~ReflowCountMgr();
399 void ClearGrandTotals();
400 void DisplayTotals(const char * aStr
);
401 void DisplayHTMLTotals(const char * aStr
);
402 void DisplayDiffsInTotals(const char * aStr
);
404 void Add(const char * aName
, nsIFrame
* aFrame
);
405 ReflowCounter
* LookUp(const char * aName
);
407 void PaintCount(const char * aName
, nsIRenderingContext
* aRenderingContext
, nsPresContext
* aPresContext
, nsIFrame
* aFrame
, PRUint32 aColor
);
409 FILE * GetOutFile() { return mFD
; }
411 PLHashTable
* GetIndiFrameHT() { return mIndiFrameCounts
; }
413 void SetPresContext(nsPresContext
* aPresContext
) { mPresContext
= aPresContext
; } // weak reference
414 void SetPresShell(nsIPresShell
* aPresShell
) { mPresShell
= aPresShell
; } // weak reference
416 void SetDumpFrameCounts(PRBool aVal
) { mDumpFrameCounts
= aVal
; }
417 void SetDumpFrameByFrameCounts(PRBool aVal
) { mDumpFrameByFrameCounts
= aVal
; }
418 void SetPaintFrameCounts(PRBool aVal
) { mPaintFrameByFrameCounts
= aVal
; }
420 PRBool
IsPaintingFrameCounts() { return mPaintFrameByFrameCounts
; }
423 void DisplayTotals(PRUint32 aTotal
, PRUint32
* aDupArray
, char * aTitle
);
424 void DisplayHTMLTotals(PRUint32 aTotal
, PRUint32
* aDupArray
, char * aTitle
);
426 static PRIntn
RemoveItems(PLHashEntry
*he
, PRIntn i
, void *arg
);
427 static PRIntn
RemoveIndiItems(PLHashEntry
*he
, PRIntn i
, void *arg
);
430 // stdout Output Methods
431 static PRIntn
DoSingleTotal(PLHashEntry
*he
, PRIntn i
, void *arg
);
432 static PRIntn
DoSingleIndi(PLHashEntry
*he
, PRIntn i
, void *arg
);
434 void DoGrandTotals();
435 void DoIndiTotalsTree();
437 // HTML Output Methods
438 static PRIntn
DoSingleHTMLTotal(PLHashEntry
*he
, PRIntn i
, void *arg
);
439 void DoGrandHTMLTotals();
441 // Zero Out the Totals
442 static PRIntn
DoClearTotals(PLHashEntry
*he
, PRIntn i
, void *arg
);
444 // Displays the Diff Totals
445 static PRIntn
DoDisplayDiffTotals(PLHashEntry
*he
, PRIntn i
, void *arg
);
447 PLHashTable
* mCounts
;
448 PLHashTable
* mIndiFrameCounts
;
451 PRBool mDumpFrameCounts
;
452 PRBool mDumpFrameByFrameCounts
;
453 PRBool mPaintFrameByFrameCounts
;
457 // Root Frame for Individual Tracking
458 nsPresContext
* mPresContext
;
459 nsIPresShell
* mPresShell
;
461 // ReflowCountMgr gReflowCountMgr;
464 //========================================================================
466 // comment out to hide caret
469 // The upper bound on the amount of time to spend reflowing, in
470 // microseconds. When this bound is exceeded and reflow commands are
471 // still queued up, a reflow event is posted. The idea is for reflow
472 // to not hog the processor beyond the time specifed in
473 // gMaxRCProcessingTime. This data member is initialized from the
474 // layout.reflow.timeslice pref.
475 #define NS_MAX_REFLOW_TIME 1000000
476 static PRInt32 gMaxRCProcessingTime
= -1;
478 #define MARK_INCREMENT 50
479 #define BLOCK_INCREMENT 4044 /* a bit under 4096, for malloc overhead */
481 /**A block of memory that the stack will
482 * chop up and hand out
486 // a block of memory. Note that this must be first so that it will
488 char mBlock
[BLOCK_INCREMENT
];
490 // another block of memory that would only be created
491 // if our stack overflowed. Yes we have the ability
492 // to grow on a stack overflow
495 StackBlock() : mNext(nsnull
) { }
499 /* we hold an array of marks. A push pushes a mark on the stack
503 // the block of memory we are currently handing out chunks of
506 // our current position in the memory
511 /* A stack arena allows a stack based interface to a block of memory.
512 * It should be used when you need to allocate some temporary memory that
513 * you will immediately return.
520 nsresult
Init() { return mBlocks
? NS_OK
: NS_ERROR_OUT_OF_MEMORY
; }
522 // Memory management functions
523 void* Allocate(size_t aSize
);
529 StackBlock
*block
= mBlocks
;
531 result
+= sizeof(StackBlock
);
532 block
= block
->mNext
;
538 // our current position in memory
541 // a list of memory block. Usually there is only one
542 // but if we overrun our stack size we can get more memory.
545 // the current block of memory we are passing our chucks of
546 StackBlock
* mCurBlock
;
548 // our stack of mark where push has been called
551 // the current top of the mark list
554 // the size of the mark array
555 PRUint32 mMarkLength
;
560 StackArena::StackArena()
565 // allocate our stack memory
566 mBlocks
= new StackBlock();
573 StackArena::~StackArena()
579 StackBlock
* toDelete
= mBlocks
;
580 mBlocks
= mBlocks
->mNext
;
588 // Resize the mark array if we overrun it. Failure to allocate the
589 // mark array is not fatal; we just won't free to that mark. This
590 // allows callers not to worry about error checking.
591 if (mStackTop
>= mMarkLength
)
593 PRUint32 newLength
= mStackTop
+ MARK_INCREMENT
;
594 StackMark
* newMarks
= new StackMark
[newLength
];
597 memcpy(newMarks
, mMarks
, sizeof(StackMark
)*mMarkLength
);
598 // Fill in any marks that we couldn't allocate during a prior call
600 for (; mMarkLength
< mStackTop
; ++mMarkLength
) {
601 NS_NOTREACHED("should only hit this on out-of-memory");
602 newMarks
[mMarkLength
].mBlock
= mCurBlock
;
603 newMarks
[mMarkLength
].mPos
= mPos
;
607 mMarkLength
= newLength
;
611 // set a mark at the top (if we can)
612 NS_ASSERTION(mStackTop
< mMarkLength
, "out of memory");
613 if (mStackTop
< mMarkLength
) {
614 mMarks
[mStackTop
].mBlock
= mCurBlock
;
615 mMarks
[mStackTop
].mPos
= mPos
;
622 StackArena::Allocate(size_t aSize
)
624 NS_ASSERTION(mStackTop
> 0, "Allocate called without Push");
626 // make sure we are aligned. Beard said 8 was safer then 4.
627 // Round size to multiple of 8
628 aSize
= PR_ROUNDUP(aSize
, 8);
630 // if the size makes the stack overflow. Grab another block for the stack
631 if (mPos
+ aSize
>= BLOCK_INCREMENT
)
633 NS_ASSERTION(aSize
<= BLOCK_INCREMENT
,"Requested memory is greater that our block size!!");
634 if (mCurBlock
->mNext
== nsnull
)
635 mCurBlock
->mNext
= new StackBlock();
637 mCurBlock
= mCurBlock
->mNext
;
641 // return the chunk they need.
642 void *result
= mCurBlock
->mBlock
+ mPos
;
652 NS_ASSERTION(mStackTop
> 0, "unmatched pop");
655 if (mStackTop
>= mMarkLength
) {
656 // We couldn't allocate the marks array at the time of the push, so
657 // we don't know where we're freeing to.
658 NS_NOTREACHED("out of memory");
659 if (mStackTop
== 0) {
660 // But we do know if we've completely pushed the stack.
668 // Mark the "freed" memory with 0xdd to help with debugging of memory
669 // allocation problems.
671 StackBlock
*block
= mMarks
[mStackTop
].mBlock
, *block_end
= mCurBlock
;
672 size_t pos
= mMarks
[mStackTop
].mPos
;
673 for (; block
!= block_end
; block
= block
->mNext
, pos
= 0) {
674 memset(block
->mBlock
+ pos
, 0xdd, sizeof(block
->mBlock
) - pos
);
676 memset(block
->mBlock
+ pos
, 0xdd, mPos
- pos
);
680 mCurBlock
= mMarks
[mStackTop
].mBlock
;
681 mPos
= mMarks
[mStackTop
].mPos
;
684 struct nsCallbackEventRequest
686 nsIReflowCallback
* callback
;
687 nsCallbackEventRequest
* next
;
690 // ----------------------------------------------------------------------------
691 #define ASSERT_REFLOW_SCHEDULED_STATE() \
692 NS_ASSERTION(mReflowScheduled == \
693 GetPresContext()->RefreshDriver()-> \
694 IsLayoutFlushObserver(this), "Unexpected state")
696 class nsPresShellEventCB
;
697 class nsAutoCauseReflowNotifier
;
699 class PresShell
: public nsIPresShell
, public nsIViewObserver
,
700 public nsStubDocumentObserver
,
701 public nsISelectionController
, public nsIObserver
,
702 public nsSupportsWeakReference
707 NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
713 virtual NS_HIDDEN_(nsresult
) Init(nsIDocument
* aDocument
,
714 nsPresContext
* aPresContext
,
715 nsIViewManager
* aViewManager
,
716 nsStyleSet
* aStyleSet
,
717 nsCompatibility aCompatMode
);
718 virtual NS_HIDDEN_(void) Destroy();
720 virtual NS_HIDDEN_(void*) AllocateFrame(nsQueryFrame::FrameIID aCode
,
722 virtual NS_HIDDEN_(void) FreeFrame(nsQueryFrame::FrameIID aCode
,
725 virtual NS_HIDDEN_(void*) AllocateMisc(size_t aSize
);
726 virtual NS_HIDDEN_(void) FreeMisc(size_t aSize
, void* aChunk
);
728 // Dynamic stack memory allocation
729 virtual NS_HIDDEN_(void) PushStackMemory();
730 virtual NS_HIDDEN_(void) PopStackMemory();
731 virtual NS_HIDDEN_(void*) AllocateStackMemory(size_t aSize
);
733 virtual NS_HIDDEN_(nsresult
) SetPreferenceStyleRules(PRBool aForceReflow
);
735 NS_IMETHOD
GetSelection(SelectionType aType
, nsISelection
** aSelection
);
736 virtual nsISelection
* GetCurrentSelection(SelectionType aType
);
738 NS_IMETHOD
SetDisplaySelection(PRInt16 aToggle
);
739 NS_IMETHOD
GetDisplaySelection(PRInt16
*aToggle
);
740 NS_IMETHOD
ScrollSelectionIntoView(SelectionType aType
, SelectionRegion aRegion
,
742 NS_IMETHOD
RepaintSelection(SelectionType aType
);
744 virtual NS_HIDDEN_(void) BeginObservingDocument();
745 virtual NS_HIDDEN_(void) EndObservingDocument();
746 virtual NS_HIDDEN_(nsresult
) InitialReflow(nscoord aWidth
, nscoord aHeight
);
747 virtual NS_HIDDEN_(nsresult
) ResizeReflow(nscoord aWidth
, nscoord aHeight
);
748 virtual NS_HIDDEN_(nsresult
) ResizeReflowOverride(nscoord aWidth
, nscoord aHeight
);
749 virtual NS_HIDDEN_(void) StyleChangeReflow();
750 virtual NS_HIDDEN_(nsIPageSequenceFrame
*) GetPageSequenceFrame() const;
751 virtual NS_HIDDEN_(nsIFrame
*) GetRealPrimaryFrameFor(nsIContent
* aContent
) const;
753 virtual NS_HIDDEN_(nsIFrame
*) GetPlaceholderFrameFor(nsIFrame
* aFrame
) const;
754 virtual NS_HIDDEN_(void) FrameNeedsReflow(nsIFrame
*aFrame
, IntrinsicDirty aIntrinsicDirty
,
755 nsFrameState aBitToAdd
);
756 virtual NS_HIDDEN_(void) FrameNeedsToContinueReflow(nsIFrame
*aFrame
);
757 virtual NS_HIDDEN_(void) CancelAllPendingReflows();
758 virtual NS_HIDDEN_(PRBool
) IsSafeToFlush() const;
759 virtual NS_HIDDEN_(void) FlushPendingNotifications(mozFlushType aType
);
762 * Recreates the frames for a node
764 virtual NS_HIDDEN_(nsresult
) RecreateFramesFor(nsIContent
* aContent
);
767 * Post a callback that should be handled after reflow has finished.
769 virtual NS_HIDDEN_(nsresult
) PostReflowCallback(nsIReflowCallback
* aCallback
);
770 virtual NS_HIDDEN_(void) CancelReflowCallback(nsIReflowCallback
* aCallback
);
772 virtual NS_HIDDEN_(void) ClearFrameRefs(nsIFrame
* aFrame
);
773 virtual NS_HIDDEN_(already_AddRefed
<nsIRenderingContext
>) GetReferenceRenderingContext();
774 virtual NS_HIDDEN_(nsresult
) GoToAnchor(const nsAString
& aAnchorName
, PRBool aScroll
);
775 virtual NS_HIDDEN_(nsresult
) ScrollToAnchor();
777 virtual NS_HIDDEN_(nsresult
) ScrollContentIntoView(nsIContent
* aContent
,
781 virtual PRBool
ScrollFrameRectIntoView(nsIFrame
* aFrame
,
786 virtual nsRectVisibility
GetRectVisibility(nsIFrame
*aFrame
,
788 nscoord aMinTwips
) const;
790 virtual NS_HIDDEN_(void) SetIgnoreFrameDestruction(PRBool aIgnore
);
791 virtual NS_HIDDEN_(void) NotifyDestroyingFrame(nsIFrame
* aFrame
);
793 virtual NS_HIDDEN_(nsresult
) GetLinkLocation(nsIDOMNode
* aNode
, nsAString
& aLocationString
) const;
795 virtual NS_HIDDEN_(nsresult
) CaptureHistoryState(nsILayoutHistoryState
** aLayoutHistoryState
, PRBool aLeavingPage
);
797 virtual NS_HIDDEN_(void) UnsuppressPainting();
799 virtual nsresult
GetAgentStyleSheets(nsCOMArray
<nsIStyleSheet
>& aSheets
);
800 virtual nsresult
SetAgentStyleSheets(const nsCOMArray
<nsIStyleSheet
>& aSheets
);
802 virtual nsresult
AddOverrideStyleSheet(nsIStyleSheet
*aSheet
);
803 virtual nsresult
RemoveOverrideStyleSheet(nsIStyleSheet
*aSheet
);
805 virtual NS_HIDDEN_(nsresult
) HandleEventWithTarget(nsEvent
* aEvent
, nsIFrame
* aFrame
,
806 nsIContent
* aContent
,
807 nsEventStatus
* aStatus
);
808 virtual NS_HIDDEN_(nsIFrame
*) GetEventTargetFrame();
809 virtual NS_HIDDEN_(already_AddRefed
<nsIContent
>) GetEventTargetContent(nsEvent
* aEvent
);
812 virtual nsresult
ReconstructFrames(void);
813 virtual void Freeze();
815 virtual void FireOrClearDelayedEvents(PRBool aFireEvents
);
817 virtual nsIFrame
* GetFrameForPoint(nsIFrame
* aFrame
, nsPoint aPt
);
819 virtual NS_HIDDEN_(nsresult
) RenderDocument(const nsRect
& aRect
, PRUint32 aFlags
,
820 nscolor aBackgroundColor
,
821 gfxContext
* aThebesContext
);
823 virtual already_AddRefed
<gfxASurface
> RenderNode(nsIDOMNode
* aNode
,
824 nsIntRegion
* aRegion
,
826 nsIntRect
* aScreenRect
);
828 virtual already_AddRefed
<gfxASurface
> RenderSelection(nsISelection
* aSelection
,
830 nsIntRect
* aScreenRect
);
832 virtual already_AddRefed
<nsPIDOMWindow
> GetRootWindow();
834 virtual LayerManager
* GetLayerManager();
836 virtual void SetIgnoreViewportScrolling(PRBool aIgnore
);
838 virtual void SetDisplayPort(const nsRect
& aDisplayPort
);
840 virtual nsresult
SetResolution(float aXResolution
, float aYResolution
);
842 virtual void SynthesizeMouseMove(PRBool aFromScroll
);
844 //nsIViewObserver interface
846 NS_IMETHOD
Paint(nsIView
* aDisplayRoot
,
847 nsIView
* aViewToPaint
,
849 const nsRegion
& aDirtyRegion
,
850 const nsIntRegion
& aIntDirtyRegion
,
851 PRBool aPaintDefaultBackground
,
852 PRBool aWillSendDidPaint
);
853 NS_IMETHOD
HandleEvent(nsIView
* aView
,
855 nsEventStatus
* aEventStatus
);
856 virtual NS_HIDDEN_(nsresult
) HandleDOMEventWithTarget(nsIContent
* aTargetContent
,
858 nsEventStatus
* aStatus
);
859 virtual NS_HIDDEN_(nsresult
) HandleDOMEventWithTarget(nsIContent
* aTargetContent
,
861 nsEventStatus
* aStatus
);
862 NS_IMETHOD
ResizeReflow(nsIView
*aView
, nscoord aWidth
, nscoord aHeight
);
863 NS_IMETHOD_(PRBool
) ShouldIgnoreInvalidation();
864 NS_IMETHOD_(void) WillPaint(PRBool aWillSendDidPaint
);
865 NS_IMETHOD_(void) DidPaint();
866 NS_IMETHOD_(void) DispatchSynthMouseMove(nsGUIEvent
*aEvent
,
867 PRBool aFlushOnHoverChange
);
868 NS_IMETHOD_(void) ClearMouseCapture(nsIView
* aView
);
871 virtual NS_HIDDEN_(already_AddRefed
<nsCaret
>) GetCaret() const;
872 virtual NS_HIDDEN_(void) MaybeInvalidateCaretPosition();
873 NS_IMETHOD
SetCaretEnabled(PRBool aInEnable
);
874 NS_IMETHOD
SetCaretReadOnly(PRBool aReadOnly
);
875 NS_IMETHOD
GetCaretEnabled(PRBool
*aOutEnabled
);
876 NS_IMETHOD
SetCaretVisibilityDuringSelection(PRBool aVisibility
);
877 NS_IMETHOD
GetCaretVisible(PRBool
*_retval
);
878 virtual void SetCaret(nsCaret
*aNewCaret
);
879 virtual void RestoreCaret();
881 NS_IMETHOD
SetSelectionFlags(PRInt16 aInEnable
);
882 NS_IMETHOD
GetSelectionFlags(PRInt16
*aOutEnable
);
884 // nsISelectionController
886 NS_IMETHOD
CharacterMove(PRBool aForward
, PRBool aExtend
);
887 NS_IMETHOD
CharacterExtendForDelete();
888 NS_IMETHOD
CharacterExtendForBackspace();
889 NS_IMETHOD
WordMove(PRBool aForward
, PRBool aExtend
);
890 NS_IMETHOD
WordExtendForDelete(PRBool aForward
);
891 NS_IMETHOD
LineMove(PRBool aForward
, PRBool aExtend
);
892 NS_IMETHOD
IntraLineMove(PRBool aForward
, PRBool aExtend
);
893 NS_IMETHOD
PageMove(PRBool aForward
, PRBool aExtend
);
894 NS_IMETHOD
ScrollPage(PRBool aForward
);
895 NS_IMETHOD
ScrollLine(PRBool aForward
);
896 NS_IMETHOD
ScrollHorizontal(PRBool aLeft
);
897 NS_IMETHOD
CompleteScroll(PRBool aForward
);
898 NS_IMETHOD
CompleteMove(PRBool aForward
, PRBool aExtend
);
899 NS_IMETHOD
SelectAll();
900 NS_IMETHOD
CheckVisibility(nsIDOMNode
*node
, PRInt16 startOffset
, PRInt16 EndOffset
, PRBool
*_retval
);
902 // nsIDocumentObserver
903 NS_DECL_NSIDOCUMENTOBSERVER_BEGINUPDATE
904 NS_DECL_NSIDOCUMENTOBSERVER_ENDUPDATE
905 NS_DECL_NSIDOCUMENTOBSERVER_BEGINLOAD
906 NS_DECL_NSIDOCUMENTOBSERVER_ENDLOAD
907 NS_DECL_NSIDOCUMENTOBSERVER_CONTENTSTATESCHANGED
908 NS_DECL_NSIDOCUMENTOBSERVER_DOCUMENTSTATESCHANGED
909 NS_DECL_NSIDOCUMENTOBSERVER_STYLESHEETADDED
910 NS_DECL_NSIDOCUMENTOBSERVER_STYLESHEETREMOVED
911 NS_DECL_NSIDOCUMENTOBSERVER_STYLESHEETAPPLICABLESTATECHANGED
912 NS_DECL_NSIDOCUMENTOBSERVER_STYLERULECHANGED
913 NS_DECL_NSIDOCUMENTOBSERVER_STYLERULEADDED
914 NS_DECL_NSIDOCUMENTOBSERVER_STYLERULEREMOVED
916 // nsIMutationObserver
917 NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
918 NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTEWILLCHANGE
919 NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
920 NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
921 NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
922 NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
926 #ifdef MOZ_REFLOW_PERF
927 virtual NS_HIDDEN_(void) DumpReflows();
928 virtual NS_HIDDEN_(void) CountReflows(const char * aName
, nsIFrame
* aFrame
);
929 virtual NS_HIDDEN_(void) PaintCount(const char * aName
,
930 nsIRenderingContext
* aRenderingContext
,
931 nsPresContext
* aPresContext
,
934 virtual NS_HIDDEN_(void) SetPaintFrameCount(PRBool aOn
);
935 virtual PRBool
IsPaintingFrameCounts();
939 virtual void ListStyleContexts(nsIFrame
*aRootFrame
, FILE *out
,
940 PRInt32 aIndent
= 0);
942 virtual void ListStyleSheets(FILE *out
, PRInt32 aIndent
= 0);
943 virtual void VerifyStyleTree();
947 static PRLogModuleInfo
* gLog
;
950 virtual NS_HIDDEN_(void) DisableNonTestMouseEvents(PRBool aDisable
);
952 virtual void UpdateCanvasBackground();
954 virtual nsresult
AddCanvasBackgroundColorItem(nsDisplayListBuilder
& aBuilder
,
955 nsDisplayList
& aList
,
957 const nsRect
& aBounds
,
958 nscolor aBackstopColor
,
961 virtual nsresult
AddPrintPreviewBackgroundItem(nsDisplayListBuilder
& aBuilder
,
962 nsDisplayList
& aList
,
964 const nsRect
& aBounds
);
966 virtual nscolor
ComputeBackstopColor(nsIView
* aDisplayRoot
);
968 virtual NS_HIDDEN_(nsresult
) SetIsActive(PRBool aIsActive
);
971 virtual ~PresShell();
973 void HandlePostedReflowCallbacks(PRBool aInterruptible
);
974 void CancelPostedReflowCallbacks();
976 void UnsuppressAndInvalidate();
978 void WillCauseReflow() {
979 nsContentUtils::AddScriptBlocker();
982 nsresult
DidCauseReflow();
983 friend class nsAutoCauseReflowNotifier
;
986 void DidDoReflow(PRBool aInterruptible
);
987 // ProcessReflowCommands returns whether we processed all our dirty roots
988 // without interruptions.
989 PRBool
ProcessReflowCommands(PRBool aInterruptible
);
990 // MaybeScheduleReflow checks if posting a reflow is needed, then checks if
991 // the last reflow was interrupted. In the interrupted case ScheduleReflow is
992 // called off a timer, otherwise it is called directly.
993 void MaybeScheduleReflow();
994 // Actually schedules a reflow. This should only be called by
995 // MaybeScheduleReflow and the reflow timer ScheduleReflowOffTimer
997 void ScheduleReflow();
999 // Reflow regardless of whether the override bit has been set.
1000 nsresult
ResizeReflowIgnoreOverride(nscoord aWidth
, nscoord aHeight
);
1002 // DoReflow returns whether the reflow finished without interruption
1003 PRBool
DoReflow(nsIFrame
* aFrame
, PRBool aInterruptible
);
1005 void DoVerifyReflow();
1006 void VerifyHasDirtyRootAncestor(nsIFrame
* aFrame
);
1009 // Helper for ScrollContentIntoView
1010 void DoScrollContentIntoView(nsIContent
* aContent
,
1015 friend struct AutoRenderingStateSaveRestore
;
1016 friend struct RenderingState
;
1018 struct RenderingState
{
1019 RenderingState(PresShell
* aPresShell
)
1020 : mRenderFlags(aPresShell
->mRenderFlags
)
1021 , mDisplayPort(aPresShell
->mDisplayPort
)
1022 , mXResolution(aPresShell
->mXResolution
)
1023 , mYResolution(aPresShell
->mYResolution
)
1025 PRUint32 mRenderFlags
;
1026 nsRect mDisplayPort
;
1031 struct AutoSaveRestoreRenderingState
{
1032 AutoSaveRestoreRenderingState(PresShell
* aPresShell
)
1033 : mPresShell(aPresShell
)
1034 , mOldState(aPresShell
)
1037 ~AutoSaveRestoreRenderingState()
1039 mPresShell
->mRenderFlags
= mOldState
.mRenderFlags
;
1040 mPresShell
->mDisplayPort
= mOldState
.mDisplayPort
;
1041 mPresShell
->mXResolution
= mOldState
.mXResolution
;
1042 mPresShell
->mYResolution
= mOldState
.mYResolution
;
1045 PresShell
* mPresShell
;
1046 RenderingState mOldState
;
1049 void SetRenderingState(const RenderingState
& aState
);
1051 friend class nsPresShellEventCB
;
1053 PRBool mCaretEnabled
;
1055 nsresult
CloneStyleSet(nsStyleSet
* aSet
, nsStyleSet
** aResult
);
1056 PRBool
VerifyIncrementalReflow();
1057 PRBool mInVerifyReflow
;
1058 void ShowEventTargetDebug();
1062 * methods that manage rules that are used to implement the associated preferences
1063 * - initially created for bugs 31816, 20760, 22963
1065 nsresult
ClearPreferenceStyleRules(void);
1066 nsresult
CreatePreferenceStyleSheet(void);
1067 nsresult
SetPrefLinkRules(void);
1068 nsresult
SetPrefFocusRules(void);
1069 nsresult
SetPrefNoScriptRule();
1070 nsresult
SetPrefNoFramesRule(void);
1072 // methods for painting a range to an offscreen buffer
1074 // given a display list, clip the items within the list to
1076 nsRect
ClipListToRange(nsDisplayListBuilder
*aBuilder
,
1077 nsDisplayList
* aList
,
1080 // create a RangePaintInfo for the range aRange containing the
1081 // display list needed to paint the range to a surface
1082 RangePaintInfo
* CreateRangePaintInfo(nsIDOMRange
* aRange
,
1083 nsRect
& aSurfaceRect
,
1084 PRBool aForPrimarySelection
);
1087 * Paint the items to a new surface and return it.
1089 * aSelection - selection being painted, if any
1090 * aRegion - clip region, if any
1091 * aArea - area that the surface occupies, relative to the root frame
1092 * aPoint - reference point, typically the mouse position
1093 * aScreenRect - [out] set to the area of the screen the painted area should
1096 already_AddRefed
<gfxASurface
>
1097 PaintRangePaintInfo(nsTArray
<nsAutoPtr
<RangePaintInfo
> >* aItems
,
1098 nsISelection
* aSelection
,
1099 nsIntRegion
* aRegion
,
1102 nsIntRect
* aScreenRect
);
1105 * Methods to handle changes to user and UA sheet lists that we get
1108 void AddUserSheet(nsISupports
* aSheet
);
1109 void AddAgentSheet(nsISupports
* aSheet
);
1110 void RemoveSheet(nsStyleSet::sheetType aType
, nsISupports
* aSheet
);
1112 // Hide a view if it is a popup
1113 void HideViewIfPopup(nsIView
* aView
);
1115 // Utility method to restore the root scrollframe state
1116 void RestoreRootScrollPosition();
1118 void MaybeReleaseCapturingContent()
1120 nsCOMPtr
<nsFrameSelection
> frameSelection
= FrameSelection();
1121 if (frameSelection
) {
1122 frameSelection
->SetMouseDownState(PR_FALSE
);
1124 if (gCaptureInfo
.mContent
&&
1125 gCaptureInfo
.mContent
->GetOwnerDoc() == mDocument
) {
1126 SetCapturingContent(nsnull
, 0);
1130 nsRefPtr
<nsCSSStyleSheet
> mPrefStyleSheet
; // mStyleSet owns it but we
1131 // maintain a ref, may be null
1133 PRUint32 mUpdateCount
;
1135 // reflow roots that need to be reflowed, as both a queue and a hashtable
1136 nsTArray
<nsIFrame
*> mDirtyRoots
;
1138 PRPackedBool mDocumentLoading
;
1140 PRPackedBool mIgnoreFrameDestruction
;
1141 PRPackedBool mHaveShutDown
;
1143 PRPackedBool mViewportOverridden
;
1145 PRPackedBool mLastRootReflowHadUnconstrainedHeight
;
1147 // This is used to protect ourselves from triggering reflow while in the
1148 // middle of frame construction and the like... it really shouldn't be
1149 // needed, one hopes, but it is for now.
1150 PRUint32 mChangeNestCount
;
1152 nsIFrame
* mCurrentEventFrame
;
1153 nsCOMPtr
<nsIContent
> mCurrentEventContent
;
1154 nsTArray
<nsIFrame
*> mCurrentEventFrameStack
;
1155 nsCOMArray
<nsIContent
> mCurrentEventContentStack
;
1157 nsCOMPtr
<nsIContent
> mLastAnchorScrolledTo
;
1158 nscoord mLastAnchorScrollPositionY
;
1159 nsRefPtr
<nsCaret
> mCaret
;
1160 nsRefPtr
<nsCaret
> mOriginalCaret
;
1161 nsPresArena mFrameArena
;
1162 StackArena mStackArena
;
1163 nsCOMPtr
<nsIDragService
> mDragService
;
1166 // The reflow root under which we're currently reflowing. Null when
1168 nsIFrame
* mCurrentReflowRoot
;
1171 // Set of frames that we should mark with NS_FRAME_HAS_DIRTY_CHILDREN after
1172 // we finish reflowing mCurrentReflowRoot.
1173 nsTHashtable
< nsPtrHashKey
<nsIFrame
> > mFramesToDirty
;
1175 // Information needed to properly handle scrolling content into view if the
1176 // pre-scroll reflow flush can be interrupted. mContentToScrollTo is
1177 // non-null between the initial scroll attempt and the first time we finish
1178 // processing all our dirty roots. mContentScrollVPosition and
1179 // mContentScrollHPosition are only used when it's non-null.
1180 nsCOMPtr
<nsIContent
> mContentToScrollTo
;
1181 PRIntn mContentScrollVPosition
;
1182 PRIntn mContentScrollHPosition
;
1184 class nsDelayedEvent
1187 virtual ~nsDelayedEvent() {};
1188 virtual void Dispatch(PresShell
* aShell
) {}
1191 class nsDelayedInputEvent
: public nsDelayedEvent
1194 virtual void Dispatch(PresShell
* aShell
)
1196 if (mEvent
&& mEvent
->widget
) {
1197 nsCOMPtr
<nsIWidget
> w
= mEvent
->widget
;
1198 nsEventStatus status
;
1199 w
->DispatchEvent(mEvent
, status
);
1204 void Init(nsInputEvent
* aEvent
)
1206 mEvent
->time
= aEvent
->time
;
1207 mEvent
->refPoint
= aEvent
->refPoint
;
1208 mEvent
->isShift
= aEvent
->isShift
;
1209 mEvent
->isControl
= aEvent
->isControl
;
1210 mEvent
->isAlt
= aEvent
->isAlt
;
1211 mEvent
->isMeta
= aEvent
->isMeta
;
1214 nsDelayedInputEvent()
1215 : nsDelayedEvent(), mEvent(nsnull
) {}
1217 nsInputEvent
* mEvent
;
1220 class nsDelayedMouseEvent
: public nsDelayedInputEvent
1223 nsDelayedMouseEvent(nsMouseEvent
* aEvent
) : nsDelayedInputEvent()
1225 mEvent
= new nsMouseEvent(NS_IS_TRUSTED_EVENT(aEvent
),
1232 static_cast<nsMouseEvent
*>(mEvent
)->clickCount
= aEvent
->clickCount
;
1236 virtual ~nsDelayedMouseEvent()
1238 delete static_cast<nsMouseEvent
*>(mEvent
);
1242 class nsDelayedKeyEvent
: public nsDelayedInputEvent
1245 nsDelayedKeyEvent(nsKeyEvent
* aEvent
) : nsDelayedInputEvent()
1247 mEvent
= new nsKeyEvent(NS_IS_TRUSTED_EVENT(aEvent
),
1252 static_cast<nsKeyEvent
*>(mEvent
)->keyCode
= aEvent
->keyCode
;
1253 static_cast<nsKeyEvent
*>(mEvent
)->charCode
= aEvent
->charCode
;
1254 static_cast<nsKeyEvent
*>(mEvent
)->alternativeCharCodes
=
1255 aEvent
->alternativeCharCodes
;
1256 static_cast<nsKeyEvent
*>(mEvent
)->isChar
= aEvent
->isChar
;
1260 virtual ~nsDelayedKeyEvent()
1262 delete static_cast<nsKeyEvent
*>(mEvent
);
1266 PRPackedBool mNoDelayedMouseEvents
;
1267 PRPackedBool mNoDelayedKeyEvents
;
1268 nsTArray
<nsAutoPtr
<nsDelayedEvent
> > mDelayedEvents
;
1270 nsCallbackEventRequest
* mFirstCallbackEventRequest
;
1271 nsCallbackEventRequest
* mLastCallbackEventRequest
;
1273 PRPackedBool mIsDocumentGone
; // We've been disconnected from the document.
1274 // We will refuse to paint the document until either
1275 // (a) our timer fires or (b) all frames are constructed.
1276 PRPackedBool mShouldUnsuppressPainting
; // Indicates that it is safe to unlock painting once all pending
1277 // reflows have been processed.
1278 nsCOMPtr
<nsITimer
> mPaintSuppressionTimer
; // This timer controls painting suppression. Until it fires
1279 // or all frames are constructed, we won't paint anything but
1280 // our <body> background and scrollbars.
1281 #define PAINTLOCK_EVENT_DELAY 250 // 250ms. This is actually
1282 // pref-controlled, but we use this
1283 // value if we fail to get the pref
1286 static void sPaintSuppressionCallback(nsITimer
* aTimer
, void* aPresShell
); // A callback for the timer.
1288 // At least on Win32 and Mac after interupting a reflow we need to post
1289 // the resume reflow event off a timer to avoid event starvation because
1290 // posted messages are processed before other messages when the modal
1291 // moving/sizing loop is running, see bug 491700 for details.
1292 nsCOMPtr
<nsITimer
> mReflowContinueTimer
;
1293 static void sReflowContinueCallback(nsITimer
* aTimer
, void* aPresShell
);
1294 PRBool
ScheduleReflowOffTimer();
1296 #ifdef MOZ_REFLOW_PERF
1297 ReflowCountMgr
* mReflowCountMgr
;
1300 static PRBool sDisableNonTestMouseEvents
;
1302 // false if a check should be done for key/ime events that should be
1303 // retargeted to the currently focused presshell
1304 static PRBool sDontRetargetEvents
;
1308 PRBool
InZombieDocument(nsIContent
*aContent
);
1309 already_AddRefed
<nsIPresShell
> GetParentPresShell();
1310 nsresult
RetargetEventToParent(nsGUIEvent
* aEvent
,
1311 nsEventStatus
* aEventStatus
);
1313 //helper funcs for event handling
1315 //protected because nsPresShellEventCB needs this.
1316 nsIFrame
* GetCurrentEventFrame();
1318 void PushCurrentEventInfo(nsIFrame
* aFrame
, nsIContent
* aContent
);
1319 void PopCurrentEventInfo();
1320 nsresult
HandleEventInternal(nsEvent
* aEvent
, nsIView
* aView
,
1321 nsEventStatus
*aStatus
);
1322 nsresult
HandlePositionedEvent(nsIView
* aView
,
1323 nsIFrame
* aTargetFrame
,
1325 nsEventStatus
* aEventStatus
);
1326 // This returns the focused DOM window under our top level window.
1327 // I.e., when we are deactive, this returns the *last* focused DOM window.
1328 already_AddRefed
<nsPIDOMWindow
> GetFocusedDOMWindowInOurWindow();
1331 * This and the next two helper methods are used to target and position the
1332 * context menu when the keyboard shortcut is used to open it.
1334 * If another menu is open, the context menu is opened relative to the
1335 * active menuitem within the menu, or the menu itself if no item is active.
1336 * Otherwise, if the caret is visible, the menu is opened near the caret.
1337 * Otherwise, if a selectable list such as a listbox is focused, the
1338 * current item within the menu is opened relative to this item.
1339 * Otherwise, the context menu is opened at the topleft corner of the
1342 * Returns true if the context menu event should fire and false if it should
1345 PRBool
AdjustContextMenuKeyEvent(nsMouseEvent
* aEvent
);
1348 PRBool
PrepareToUseCaretPosition(nsIWidget
* aEventWidget
, nsIntPoint
& aTargetPt
);
1350 // Get the selected item and coordinates in device pixels relative to root
1351 // document's root view for element, first ensuring the element is onscreen
1352 void GetCurrentItemAndPositionForElement(nsIDOMElement
*aCurrentEl
,
1353 nsIContent
**aTargetToUse
,
1354 nsIntPoint
& aTargetPt
,
1355 nsIWidget
*aRootWidget
);
1357 void FireResizeEvent();
1358 void FireBeforeResizeEvent();
1359 static void AsyncResizeEventCallback(nsITimer
* aTimer
, void* aPresShell
);
1360 nsRevocableEventPtr
<nsRunnableMethod
<PresShell
> > mResizeEvent
;
1361 nsCOMPtr
<nsITimer
> mAsyncResizeEventTimer
;
1362 PRPackedBool mAsyncResizeTimerIsActive
;
1363 PRPackedBool mInResize
;
1367 // Ensure that every allocation from the PresArena is eventually freed.
1368 PRUint32 mPresArenaAllocCount
;
1373 PRUint32
EstimateMemoryUsed() {
1374 PRUint32 result
= 0;
1376 result
+= sizeof(PresShell
);
1377 result
+= mStackArena
.Size();
1378 result
+= mFrameArena
.Size();
1383 static PLDHashOperator
LiveShellSizeEnumerator(PresShellPtrKey
*aEntry
,
1386 PresShell
*aShell
= static_cast<PresShell
*>(aEntry
->GetKey());
1387 PRUint32
*val
= (PRUint32
*)userArg
;
1388 *val
+= aShell
->EstimateMemoryUsed();
1389 *val
+= aShell
->mPresContext
->EstimateMemoryUsed();
1390 return PL_DHASH_NEXT
;
1393 static PLDHashOperator
LiveShellBidiSizeEnumerator(PresShellPtrKey
*aEntry
,
1396 PresShell
*aShell
= static_cast<PresShell
*>(aEntry
->GetKey());
1397 PRUint32
*val
= (PRUint32
*)userArg
;
1398 *val
+= aShell
->mPresContext
->GetBidiMemoryUsed();
1399 return PL_DHASH_NEXT
;
1403 EstimateShellsMemory(nsTHashtable
<PresShellPtrKey
>::Enumerator aEnumerator
)
1405 PRUint32 result
= 0;
1406 sLiveShells
->EnumerateEntries(aEnumerator
, &result
);
1411 static PRInt64
SizeOfLayoutMemoryReporter(void *) {
1412 return EstimateShellsMemory(LiveShellSizeEnumerator
);
1415 static PRInt64
SizeOfBidiMemoryReporter(void *) {
1416 return EstimateShellsMemory(LiveShellBidiSizeEnumerator
);
1420 void QueryIsActive();
1421 nsresult
UpdateImageLockingState();
1424 class nsAutoCauseReflowNotifier
1427 nsAutoCauseReflowNotifier(PresShell
* aShell
)
1430 mShell
->WillCauseReflow();
1432 ~nsAutoCauseReflowNotifier()
1434 // This check should not be needed. Currently the only place that seem
1435 // to need it is the code that deals with bug 337586.
1436 if (!mShell
->mHaveShutDown
) {
1437 mShell
->DidCauseReflow();
1440 nsContentUtils::RemoveScriptBlocker();
1447 class NS_STACK_CLASS nsPresShellEventCB
: public nsDispatchingCallback
1450 nsPresShellEventCB(PresShell
* aPresShell
) : mPresShell(aPresShell
) {}
1452 virtual void HandleEvent(nsEventChainPostVisitor
& aVisitor
)
1454 if (aVisitor
.mPresContext
&& aVisitor
.mEvent
->eventStructType
!= NS_EVENT
) {
1455 nsIFrame
* frame
= mPresShell
->GetCurrentEventFrame();
1457 frame
->HandleEvent(aVisitor
.mPresContext
,
1458 (nsGUIEvent
*) aVisitor
.mEvent
,
1459 &aVisitor
.mEventStatus
);
1464 nsRefPtr
<PresShell
> mPresShell
;
1467 PRBool
PresShell::sDisableNonTestMouseEvents
= PR_FALSE
;
1468 PRBool
PresShell::sDontRetargetEvents
= PR_FALSE
;
1471 PRLogModuleInfo
* PresShell::gLog
;
1476 VerifyStyleTree(nsPresContext
* aPresContext
, nsFrameManager
* aFrameManager
)
1478 if (nsFrame::GetVerifyStyleTreeEnable()) {
1479 nsIFrame
* rootFrame
= aFrameManager
->GetRootFrame();
1480 aFrameManager
->DebugVerifyStyleTree(rootFrame
);
1483 #define VERIFY_STYLE_TREE ::VerifyStyleTree(mPresContext, FrameManager())
1485 #define VERIFY_STYLE_TREE
1488 static PRBool gVerifyReflowEnabled
;
1491 nsIPresShell::GetVerifyReflowEnable()
1494 static PRBool firstTime
= PR_TRUE
;
1496 firstTime
= PR_FALSE
;
1497 char* flags
= PR_GetEnv("GECKO_VERIFY_REFLOW_FLAGS");
1499 PRBool error
= PR_FALSE
;
1502 char* comma
= PL_strchr(flags
, ',');
1506 PRBool found
= PR_FALSE
;
1507 const VerifyReflowFlags
* flag
= gFlags
;
1508 const VerifyReflowFlags
* limit
= gFlags
+ NUM_VERIFY_REFLOW_FLAGS
;
1509 while (flag
< limit
) {
1510 if (PL_strcasecmp(flag
->name
, flags
) == 0) {
1511 gVerifyReflowFlags
|= flag
->bit
;
1529 ShowVerifyReflowFlags();
1532 if (VERIFY_REFLOW_ON
& gVerifyReflowFlags
) {
1533 gVerifyReflowEnabled
= PR_TRUE
;
1535 printf("Note: verifyreflow is enabled");
1536 if (VERIFY_REFLOW_NOISY
& gVerifyReflowFlags
) {
1539 if (VERIFY_REFLOW_ALL
& gVerifyReflowFlags
) {
1542 if (VERIFY_REFLOW_DUMP_COMMANDS
& gVerifyReflowFlags
) {
1543 printf(" (show reflow commands)");
1545 if (VERIFY_REFLOW_NOISY_RC
& gVerifyReflowFlags
) {
1546 printf(" (noisy reflow commands)");
1547 if (VERIFY_REFLOW_REALLY_NOISY_RC
& gVerifyReflowFlags
) {
1548 printf(" (REALLY noisy reflow commands)");
1555 return gVerifyReflowEnabled
;
1559 nsIPresShell::SetVerifyReflowEnable(PRBool aEnabled
)
1561 gVerifyReflowEnabled
= aEnabled
;
1565 nsIPresShell::AddWeakFrameExternal(nsWeakFrame
* aWeakFrame
)
1567 AddWeakFrameInternal(aWeakFrame
);
1571 nsIPresShell::AddWeakFrameInternal(nsWeakFrame
* aWeakFrame
)
1573 if (aWeakFrame
->GetFrame()) {
1574 aWeakFrame
->GetFrame()->AddStateBits(NS_FRAME_EXTERNAL_REFERENCE
);
1576 aWeakFrame
->SetPreviousWeakFrame(mWeakFrames
);
1577 mWeakFrames
= aWeakFrame
;
1581 nsIPresShell::RemoveWeakFrameExternal(nsWeakFrame
* aWeakFrame
)
1583 RemoveWeakFrameInternal(aWeakFrame
);
1587 nsIPresShell::RemoveWeakFrameInternal(nsWeakFrame
* aWeakFrame
)
1589 if (mWeakFrames
== aWeakFrame
) {
1590 mWeakFrames
= aWeakFrame
->GetPreviousWeakFrame();
1593 nsWeakFrame
* nextWeak
= mWeakFrames
;
1594 while (nextWeak
&& nextWeak
->GetPreviousWeakFrame() != aWeakFrame
) {
1595 nextWeak
= nextWeak
->GetPreviousWeakFrame();
1598 nextWeak
->SetPreviousWeakFrame(aWeakFrame
->GetPreviousWeakFrame());
1602 already_AddRefed
<nsFrameSelection
>
1603 nsIPresShell::FrameSelection()
1605 NS_IF_ADDREF(mSelection
);
1609 //----------------------------------------------------------------------
1612 NS_NewPresShell(nsIPresShell
** aInstancePtrResult
)
1614 NS_PRECONDITION(nsnull
!= aInstancePtrResult
, "null ptr");
1616 if (!aInstancePtrResult
)
1617 return NS_ERROR_NULL_POINTER
;
1619 *aInstancePtrResult
= new PresShell();
1620 if (!*aInstancePtrResult
)
1621 return NS_ERROR_OUT_OF_MEMORY
;
1623 NS_ADDREF(*aInstancePtrResult
);
1627 nsTHashtable
<PresShell::PresShellPtrKey
> *nsIPresShell::sLiveShells
= 0;
1629 NS_MEMORY_REPORTER_IMPLEMENT(LayoutPresShell
,
1631 "Memory in use by layout PresShell, PresContext, and other related areas.",
1632 PresShell::SizeOfLayoutMemoryReporter
,
1635 NS_MEMORY_REPORTER_IMPLEMENT(LayoutBidi
,
1637 "Memory in use by layout Bidi processor.",
1638 PresShell::SizeOfBidiMemoryReporter
,
1641 PresShell::PresShell()
1643 mSelection
= nsnull
;
1644 #ifdef MOZ_REFLOW_PERF
1645 mReflowCountMgr
= new ReflowCountMgr();
1646 mReflowCountMgr
->SetPresContext(mPresContext
);
1647 mReflowCountMgr
->SetPresShell(this);
1651 gLog
= PR_NewLogModule("PresShell");
1653 mSelectionFlags
= nsISelectionDisplay::DISPLAY_TEXT
| nsISelectionDisplay::DISPLAY_IMAGES
;
1654 mIsThemeSupportDisabled
= PR_FALSE
;
1655 mIsActive
= PR_TRUE
;
1658 mPresArenaAllocCount
= 0;
1663 mViewportOverridden
= PR_FALSE
;
1665 static bool registeredReporter
= false;
1666 if (!registeredReporter
) {
1667 NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(LayoutPresShell
));
1668 NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(LayoutBidi
));
1669 registeredReporter
= true;
1672 new (this) nsFrameManager();
1674 sLiveShells
->PutEntry(this);
1677 NS_IMPL_ISUPPORTS8(PresShell
, nsIPresShell
, nsIDocumentObserver
,
1678 nsIViewObserver
, nsISelectionController
,
1679 nsISelectionDisplay
, nsIObserver
, nsISupportsWeakReference
,
1680 nsIMutationObserver
)
1682 PresShell::~PresShell()
1684 sLiveShells
->RemoveEntry(this);
1686 if (!mHaveShutDown
) {
1687 NS_NOTREACHED("Someone did not call nsIPresShell::destroy");
1691 NS_ASSERTION(mCurrentEventContentStack
.Count() == 0,
1692 "Huh, event content left on the stack in pres shell dtor!");
1693 NS_ASSERTION(mFirstCallbackEventRequest
== nsnull
&&
1694 mLastCallbackEventRequest
== nsnull
,
1695 "post-reflow queues not empty. This means we're leaking");
1698 NS_ASSERTION(mPresArenaAllocCount
== 0,
1699 "Some pres arena objects were not freed");
1703 delete mFrameConstructor
;
1705 mCurrentEventContent
= nsnull
;
1707 NS_IF_RELEASE(mPresContext
);
1708 NS_IF_RELEASE(mDocument
);
1709 NS_IF_RELEASE(mSelection
);
1713 * Initialize the presentation shell. Create view manager and style
1717 PresShell::Init(nsIDocument
* aDocument
,
1718 nsPresContext
* aPresContext
,
1719 nsIViewManager
* aViewManager
,
1720 nsStyleSet
* aStyleSet
,
1721 nsCompatibility aCompatMode
)
1723 NS_TIME_FUNCTION_MIN(1.0);
1725 NS_PRECONDITION(nsnull
!= aDocument
, "null ptr");
1726 NS_PRECONDITION(nsnull
!= aPresContext
, "null ptr");
1727 NS_PRECONDITION(nsnull
!= aViewManager
, "null ptr");
1730 if ((nsnull
== aDocument
) || (nsnull
== aPresContext
) ||
1731 (nsnull
== aViewManager
)) {
1732 return NS_ERROR_NULL_POINTER
;
1735 NS_WARNING("PresShell double init'ed");
1736 return NS_ERROR_ALREADY_INITIALIZED
;
1738 result
= mStackArena
.Init();
1739 NS_ENSURE_SUCCESS(result
, result
);
1741 if (!mFramesToDirty
.Init()) {
1742 return NS_ERROR_OUT_OF_MEMORY
;
1745 mDocument
= aDocument
;
1746 NS_ADDREF(mDocument
);
1747 mViewManager
= aViewManager
;
1749 // Create our frame constructor.
1750 mFrameConstructor
= new nsCSSFrameConstructor(mDocument
, this);
1751 NS_ENSURE_TRUE(mFrameConstructor
, NS_ERROR_OUT_OF_MEMORY
);
1753 // The document viewer owns both view manager and pres shell.
1754 mViewManager
->SetViewObserver(this);
1756 // Bind the context to the presentation shell.
1757 mPresContext
= aPresContext
;
1758 NS_ADDREF(mPresContext
);
1759 aPresContext
->SetShell(this);
1761 // Now we can initialize the style set.
1762 result
= aStyleSet
->Init(aPresContext
);
1763 NS_ENSURE_SUCCESS(result
, result
);
1765 // From this point on, any time we return an error we need to make
1766 // sure to null out mStyleSet first, since an error return from this
1767 // method will cause the caller to delete the style set, so we don't
1768 // want to delete it in our destructor.
1769 mStyleSet
= aStyleSet
;
1771 // Notify our prescontext that it now has a compatibility mode. Note that
1772 // this MUST happen after we set up our style set but before we create any
1774 mPresContext
->CompatibilityModeChanged();
1776 // setup the preference style rules (no forced reflow), and do it
1777 // before creating any frames.
1778 SetPreferenceStyleRules(PR_FALSE
);
1780 result
= CallCreateInstance(kFrameSelectionCID
, &mSelection
);
1781 if (NS_FAILED(result
)) {
1786 // Create and initialize the frame manager
1787 result
= FrameManager()->Init(this, mStyleSet
);
1788 if (NS_FAILED(result
)) {
1789 NS_WARNING("Frame manager initialization failed");
1794 mSelection
->Init(this, nsnull
);
1796 // Important: this has to happen after the selection has been set up
1799 nsresult err
= NS_NewCaret(getter_AddRefs(mCaret
));
1800 if (NS_SUCCEEDED(err
))
1803 mOriginalCaret
= mCaret
;
1806 //SetCaretEnabled(PR_TRUE); // make it show in browser windows
1808 //set up selection to be displayed in document
1809 // Don't enable selection for print media
1810 nsPresContext::nsPresContextType type
= aPresContext
->Type();
1811 if (type
!= nsPresContext::eContext_PrintPreview
&&
1812 type
!= nsPresContext::eContext_Print
)
1813 SetDisplaySelection(nsISelectionController::SELECTION_DISABLED
);
1815 if (gMaxRCProcessingTime
== -1) {
1816 gMaxRCProcessingTime
=
1817 nsContentUtils::GetIntPref("layout.reflow.timeslice",
1818 NS_MAX_REFLOW_TIME
);
1822 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
1824 os
->AddObserver(this, "agent-sheet-added", PR_FALSE
);
1825 os
->AddObserver(this, "user-sheet-added", PR_FALSE
);
1826 os
->AddObserver(this, "agent-sheet-removed", PR_FALSE
);
1827 os
->AddObserver(this, "user-sheet-removed", PR_FALSE
);
1829 os
->AddObserver(this, "chrome-flush-skin-caches", PR_FALSE
);
1831 #ifdef ACCESSIBILITY
1832 os
->AddObserver(this, "a11y-init-or-shutdown", PR_FALSE
);
1837 // cache the drag service so we can check it during reflows
1838 mDragService
= do_GetService("@mozilla.org/widget/dragservice;1");
1840 #ifdef MOZ_REFLOW_PERF
1841 if (mReflowCountMgr
) {
1842 PRBool paintFrameCounts
=
1843 nsContentUtils::GetBoolPref("layout.reflow.showframecounts");
1845 PRBool dumpFrameCounts
=
1846 nsContentUtils::GetBoolPref("layout.reflow.dumpframecounts");
1848 PRBool dumpFrameByFrameCounts
=
1849 nsContentUtils::GetBoolPref("layout.reflow.dumpframebyframecounts");
1851 mReflowCountMgr
->SetDumpFrameCounts(dumpFrameCounts
);
1852 mReflowCountMgr
->SetDumpFrameByFrameCounts(dumpFrameByFrameCounts
);
1853 mReflowCountMgr
->SetPaintFrameCounts(paintFrameCounts
);
1858 if (mDocument
->HasAnimationController()) {
1859 nsSMILAnimationController
* animCtrl
= mDocument
->GetAnimationController();
1860 animCtrl
->NotifyRefreshDriverCreated(GetPresContext()->RefreshDriver());
1864 // Get our activeness from the docShell.
1871 PresShell::Destroy()
1873 NS_TIME_FUNCTION_MIN(1.0);
1875 NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
1876 "destroy called on presshell while scripts not blocked");
1878 #ifdef MOZ_REFLOW_PERF
1880 if (mReflowCountMgr
) {
1881 delete mReflowCountMgr
;
1882 mReflowCountMgr
= nsnull
;
1889 #ifdef ACCESSIBILITY
1890 if (gIsAccessibilityActive
) {
1891 nsCOMPtr
<nsIAccessibilityService
> accService
=
1892 do_GetService("@mozilla.org/accessibilityService;1");
1894 accService
->PresShellDestroyed(this);
1897 #endif // ACCESSIBILITY
1899 MaybeReleaseCapturingContent();
1901 if (gKeyDownTarget
&& gKeyDownTarget
->GetOwnerDoc() == mDocument
) {
1902 NS_RELEASE(gKeyDownTarget
);
1905 mContentToScrollTo
= nsnull
;
1908 // We need to notify the destroying the nsPresContext to ESM for
1909 // suppressing to use from ESM.
1910 mPresContext
->EventStateManager()->NotifyDestroyPresContext(mPresContext
);
1914 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
1916 os
->RemoveObserver(this, "agent-sheet-added");
1917 os
->RemoveObserver(this, "user-sheet-added");
1918 os
->RemoveObserver(this, "agent-sheet-removed");
1919 os
->RemoveObserver(this, "user-sheet-removed");
1921 os
->RemoveObserver(this, "chrome-flush-skin-caches");
1923 #ifdef ACCESSIBILITY
1924 os
->RemoveObserver(this, "a11y-init-or-shutdown");
1929 // If our paint suppression timer is still active, kill it.
1930 if (mPaintSuppressionTimer
) {
1931 mPaintSuppressionTimer
->Cancel();
1932 mPaintSuppressionTimer
= nsnull
;
1935 // Same for our reflow continuation timer
1936 if (mReflowContinueTimer
) {
1937 mReflowContinueTimer
->Cancel();
1938 mReflowContinueTimer
= nsnull
;
1942 mCaret
->Terminate();
1947 mSelection
->DisconnectFromPresShell();
1950 // release our pref style sheet, if we have one still
1951 ClearPreferenceStyleRules();
1953 mIsDestroying
= PR_TRUE
;
1955 // We can't release all the event content in
1956 // mCurrentEventContentStack here since there might be code on the
1957 // stack that will release the event content too. Double release
1960 // The frames will be torn down, so remove them from the current
1961 // event frame stack (since they'd be dangling references if we'd
1962 // leave them in) and null out the mCurrentEventFrame pointer as
1965 mCurrentEventFrame
= nsnull
;
1967 PRInt32 i
, count
= mCurrentEventFrameStack
.Length();
1968 for (i
= 0; i
< count
; i
++) {
1969 mCurrentEventFrameStack
[i
] = nsnull
;
1972 mFramesToDirty
.Clear();
1975 // Clear the view manager's weak pointer back to |this| in case it
1977 mViewManager
->SetViewObserver(nsnull
);
1978 mViewManager
= nsnull
;
1981 mStyleSet
->BeginShutdown(mPresContext
);
1982 nsRefreshDriver
* rd
= GetPresContext()->RefreshDriver();
1984 // This shell must be removed from the document before the frame
1985 // hierarchy is torn down to avoid finding deleted frames through
1986 // this presshell while the frames are being torn down
1988 NS_ASSERTION(mDocument
->GetShell() == this, "Wrong shell?");
1989 mDocument
->DeleteShell();
1992 if (mDocument
->HasAnimationController()) {
1993 mDocument
->GetAnimationController()->NotifyRefreshDriverDestroying(rd
);
1998 // Revoke any pending events. We need to do this and cancel pending reflows
1999 // before we destroy the frame manager, since apparently frame destruction
2000 // sometimes spins the event queue when plug-ins are involved(!).
2001 rd
->RemoveLayoutFlushObserver(this);
2002 mResizeEvent
.Revoke();
2003 if (mAsyncResizeTimerIsActive
) {
2004 mAsyncResizeEventTimer
->Cancel();
2005 mAsyncResizeTimerIsActive
= PR_FALSE
;
2008 CancelAllPendingReflows();
2009 CancelPostedReflowCallbacks();
2011 // Destroy the frame manager. This will destroy the frame hierarchy
2012 mFrameConstructor
->WillDestroyFrameTree();
2013 FrameManager()->Destroy();
2015 // Destroy all frame properties (whose destruction was suppressed
2016 // while destroying the frame tree, but which might contain more
2017 // frames within the properties.
2019 // Clear out the prescontext's property table -- since our frame tree is
2020 // now dead, we shouldn't be looking up any more properties in that table.
2021 // We want to do this before we call SetShell() on the prescontext, so
2022 // property destructors can usefully call GetPresShell() on the
2024 mPresContext
->PropertyTable()->DeleteAll();
2028 NS_WARN_IF_FALSE(!mWeakFrames
, "Weak frames alive after destroying FrameManager");
2029 while (mWeakFrames
) {
2030 mWeakFrames
->Clear(this);
2033 // Let the style set do its cleanup.
2034 mStyleSet
->Shutdown(mPresContext
);
2037 // We hold a reference to the pres context, and it holds a weak link back
2038 // to us. To avoid the pres context having a dangling reference, set its
2039 // pres shell to NULL
2040 mPresContext
->SetShell(nsnull
);
2042 // Clear the link handler (weak reference) as well
2043 mPresContext
->SetLinkHandler(nsnull
);
2046 mHaveShutDown
= PR_TRUE
;
2049 // Dynamic stack memory allocation
2051 PresShell::PushStackMemory()
2057 PresShell::PopStackMemory()
2063 PresShell::AllocateStackMemory(size_t aSize
)
2065 return mStackArena
.Allocate(aSize
);
2069 PresShell::FreeFrame(nsQueryFrame::FrameIID aCode
, void* aPtr
)
2072 mPresArenaAllocCount
--;
2074 if (PRESARENA_MUST_FREE_DURING_DESTROY
|| !mIsDestroying
)
2075 mFrameArena
.FreeByCode(aCode
, aPtr
);
2079 PresShell::AllocateFrame(nsQueryFrame::FrameIID aCode
, size_t aSize
)
2082 mPresArenaAllocCount
++;
2084 void* result
= mFrameArena
.AllocateByCode(aCode
, aSize
);
2087 memset(result
, 0, aSize
);
2093 PresShell::FreeMisc(size_t aSize
, void* aPtr
)
2096 mPresArenaAllocCount
--;
2098 if (PRESARENA_MUST_FREE_DURING_DESTROY
|| !mIsDestroying
)
2099 mFrameArena
.FreeBySize(aSize
, aPtr
);
2103 PresShell::AllocateMisc(size_t aSize
)
2106 mPresArenaAllocCount
++;
2108 return mFrameArena
.AllocateBySize(aSize
);
2112 nsIPresShell::SetAuthorStyleDisabled(PRBool aStyleDisabled
)
2114 if (aStyleDisabled
!= mStyleSet
->GetAuthorStyleDisabled()) {
2115 mStyleSet
->SetAuthorStyleDisabled(aStyleDisabled
);
2116 ReconstructStyleData();
2121 nsIPresShell::GetAuthorStyleDisabled() const
2123 return mStyleSet
->GetAuthorStyleDisabled();
2127 PresShell::SetPreferenceStyleRules(PRBool aForceReflow
)
2129 NS_TIME_FUNCTION_MIN(1.0);
2132 return NS_ERROR_NULL_POINTER
;
2135 nsPIDOMWindow
*window
= mDocument
->GetWindow();
2137 // If the document doesn't have a window there's no need to notify
2138 // its presshell about changes to preferences since the document is
2139 // in a state where it doesn't matter any more (see
2140 // DocumentViewerImpl::Close()).
2143 return NS_ERROR_NULL_POINTER
;
2146 NS_PRECONDITION(mPresContext
, "presContext cannot be null");
2148 // first, make sure this is not a chrome shell
2149 if (nsContentUtils::IsInChromeDocshell(mDocument
)) {
2153 #ifdef DEBUG_attinasi
2154 printf("Setting Preference Style Rules:\n");
2156 // if here, we need to create rules for the prefs
2157 // - this includes the background-color, the text-color,
2158 // the link color, the visited link color and the link-underlining
2160 // first clear any exising rules
2161 nsresult result
= ClearPreferenceStyleRules();
2163 // now the link rules (must come after the color rules, or links will not be correct color!)
2164 // XXX - when there is both an override and agent pref stylesheet this won't matter,
2165 // as the color rules will be overrides and the links rules will be agent
2166 if (NS_SUCCEEDED(result
)) {
2167 result
= SetPrefLinkRules();
2169 if (NS_SUCCEEDED(result
)) {
2170 result
= SetPrefFocusRules();
2172 if (NS_SUCCEEDED(result
)) {
2173 result
= SetPrefNoScriptRule();
2175 if (NS_SUCCEEDED(result
)) {
2176 result
= SetPrefNoFramesRule();
2178 #ifdef DEBUG_attinasi
2179 printf( "Preference Style Rules set: error=%ld\n", (long)result
);
2182 // Note that this method never needs to force any calculation; the caller
2183 // will recalculate style if needed
2188 return NS_ERROR_NULL_POINTER
;
2191 nsresult
PresShell::ClearPreferenceStyleRules(void)
2193 nsresult result
= NS_OK
;
2194 if (mPrefStyleSheet
) {
2195 NS_ASSERTION(mStyleSet
, "null styleset entirely unexpected!");
2197 // remove the sheet from the styleset:
2198 // - note that we have to check for success by comparing the count before and after...
2200 PRInt32 numBefore
= mStyleSet
->SheetCount(nsStyleSet::eUserSheet
);
2201 NS_ASSERTION(numBefore
> 0, "no user stylesheets in styleset, but we have one!");
2203 mStyleSet
->RemoveStyleSheet(nsStyleSet::eUserSheet
, mPrefStyleSheet
);
2205 #ifdef DEBUG_attinasi
2206 NS_ASSERTION((numBefore
- 1) == mStyleSet
->GetNumberOfUserStyleSheets(),
2207 "Pref stylesheet was not removed");
2208 printf("PrefStyleSheet removed\n");
2210 // clear the sheet pointer: it is strictly historical now
2211 mPrefStyleSheet
= nsnull
;
2217 nsresult
PresShell::CreatePreferenceStyleSheet(void)
2219 NS_TIME_FUNCTION_MIN(1.0);
2221 NS_ASSERTION(!mPrefStyleSheet
, "prefStyleSheet already exists");
2222 nsresult result
= NS_NewCSSStyleSheet(getter_AddRefs(mPrefStyleSheet
));
2223 if (NS_SUCCEEDED(result
)) {
2224 NS_ASSERTION(mPrefStyleSheet
, "null but no error");
2225 nsCOMPtr
<nsIURI
> uri
;
2226 result
= NS_NewURI(getter_AddRefs(uri
), "about:PreferenceStyleSheet", nsnull
);
2227 if (NS_SUCCEEDED(result
)) {
2228 NS_ASSERTION(uri
, "null but no error");
2229 mPrefStyleSheet
->SetURIs(uri
, uri
, uri
);
2230 mPrefStyleSheet
->SetComplete();
2233 mPrefStyleSheet
->InsertRuleInternal(NS_LITERAL_STRING("@namespace url(http://www.w3.org/1999/xhtml);"),
2235 if (NS_SUCCEEDED(result
)) {
2236 mStyleSet
->AppendStyleSheet(nsStyleSet::eUserSheet
, mPrefStyleSheet
);
2241 #ifdef DEBUG_attinasi
2242 printf("CreatePrefStyleSheet completed: error=%ld\n",(long)result
);
2245 if (NS_FAILED(result
)) {
2246 mPrefStyleSheet
= nsnull
;
2252 // XXX We want these after the @namespace rule. Does order matter
2253 // for these rules, or can we call nsICSSStyleRule::StyleRuleCount()
2254 // and just "append"?
2255 static PRUint32 sInsertPrefSheetRulesAt
= 1;
2258 PresShell::SetPrefNoScriptRule()
2260 NS_TIME_FUNCTION_MIN(1.0);
2262 nsresult rv
= NS_OK
;
2264 // also handle the case where print is done from print preview
2265 // see bug #342439 for more details
2266 nsIDocument
* doc
= mDocument
;
2267 if (mPresContext
->Type() == nsPresContext::eContext_PrintPreview
||
2268 mPresContext
->Type() == nsPresContext::eContext_Print
) {
2269 while (doc
->GetOriginalDocument()) {
2270 doc
= doc
->GetOriginalDocument();
2274 PRBool scriptEnabled
= doc
->IsScriptEnabled();
2275 if (scriptEnabled
) {
2276 if (!mPrefStyleSheet
) {
2277 rv
= CreatePreferenceStyleSheet();
2278 NS_ENSURE_SUCCESS(rv
, rv
);
2283 InsertRuleInternal(NS_LITERAL_STRING("noscript{display:none!important}"),
2284 sInsertPrefSheetRulesAt
, &index
);
2290 nsresult
PresShell::SetPrefNoFramesRule(void)
2292 NS_TIME_FUNCTION_MIN(1.0);
2294 NS_ASSERTION(mPresContext
,"null prescontext not allowed");
2295 if (!mPresContext
) {
2296 return NS_ERROR_FAILURE
;
2299 nsresult rv
= NS_OK
;
2301 if (!mPrefStyleSheet
) {
2302 rv
= CreatePreferenceStyleSheet();
2303 NS_ENSURE_SUCCESS(rv
, rv
);
2306 NS_ASSERTION(mPrefStyleSheet
, "prefstylesheet should not be null");
2308 PRBool allowSubframes
= PR_TRUE
;
2309 nsCOMPtr
<nsISupports
> container
= mPresContext
->GetContainer();
2310 nsCOMPtr
<nsIDocShell
> docShell(do_QueryInterface(container
));
2312 docShell
->GetAllowSubframes(&allowSubframes
);
2314 if (!allowSubframes
) {
2316 rv
= mPrefStyleSheet
->
2317 InsertRuleInternal(NS_LITERAL_STRING("noframes{display:block}"),
2318 sInsertPrefSheetRulesAt
, &index
);
2319 NS_ENSURE_SUCCESS(rv
, rv
);
2320 rv
= mPrefStyleSheet
->
2321 InsertRuleInternal(NS_LITERAL_STRING("frame, frameset, iframe {display:none!important}"),
2322 sInsertPrefSheetRulesAt
, &index
);
2327 nsresult
PresShell::SetPrefLinkRules(void)
2329 NS_TIME_FUNCTION_MIN(1.0);
2331 NS_ASSERTION(mPresContext
,"null prescontext not allowed");
2332 if (!mPresContext
) {
2333 return NS_ERROR_FAILURE
;
2336 nsresult rv
= NS_OK
;
2338 if (!mPrefStyleSheet
) {
2339 rv
= CreatePreferenceStyleSheet();
2340 NS_ENSURE_SUCCESS(rv
, rv
);
2343 NS_ASSERTION(mPrefStyleSheet
, "prefstylesheet should not be null");
2345 // support default link colors:
2346 // this means the link colors need to be overridable,
2347 // which they are if we put them in the agent stylesheet,
2348 // though if using an override sheet this will cause authors grief still
2349 // In the agent stylesheet, they are !important when we are ignoring document colors
2351 nscolor
linkColor(mPresContext
->DefaultLinkColor());
2352 nscolor
activeColor(mPresContext
->DefaultActiveLinkColor());
2353 nscolor
visitedColor(mPresContext
->DefaultVisitedLinkColor());
2355 NS_NAMED_LITERAL_STRING(ruleClose
, "}");
2357 nsAutoString strColor
;
2359 // insert a rule to color links: '*|*:link {color: #RRGGBB [!important];}'
2360 ColorToString(linkColor
, strColor
);
2361 rv
= mPrefStyleSheet
->
2362 InsertRuleInternal(NS_LITERAL_STRING("*|*:link{color:") +
2363 strColor
+ ruleClose
,
2364 sInsertPrefSheetRulesAt
, &index
);
2365 NS_ENSURE_SUCCESS(rv
, rv
);
2367 // - visited links: '*|*:visited {color: #RRGGBB [!important];}'
2368 ColorToString(visitedColor
, strColor
);
2369 rv
= mPrefStyleSheet
->
2370 InsertRuleInternal(NS_LITERAL_STRING("*|*:visited{color:") +
2371 strColor
+ ruleClose
,
2372 sInsertPrefSheetRulesAt
, &index
);
2373 NS_ENSURE_SUCCESS(rv
, rv
);
2375 // - active links: '*|*:-moz-any-link:active {color: #RRGGBB [!important];}'
2376 ColorToString(activeColor
, strColor
);
2377 rv
= mPrefStyleSheet
->
2378 InsertRuleInternal(NS_LITERAL_STRING("*|*:-moz-any-link:active{color:") +
2379 strColor
+ ruleClose
,
2380 sInsertPrefSheetRulesAt
, &index
);
2381 NS_ENSURE_SUCCESS(rv
, rv
);
2383 PRBool underlineLinks
=
2384 mPresContext
->GetCachedBoolPref(kPresContext_UnderlineLinks
);
2386 if (underlineLinks
) {
2387 // create a rule to make underlining happen
2388 // '*|*:-moz-any-link {text-decoration:[underline|none];}'
2389 // no need for important, we want these to be overridable
2390 // NOTE: these must go in the agent stylesheet or they cannot be
2391 // overridden by authors
2392 rv
= mPrefStyleSheet
->
2393 InsertRuleInternal(NS_LITERAL_STRING("*|*:-moz-any-link{text-decoration:underline}"),
2394 sInsertPrefSheetRulesAt
, &index
);
2396 rv
= mPrefStyleSheet
->
2397 InsertRuleInternal(NS_LITERAL_STRING("*|*:-moz-any-link{text-decoration:none}"),
2398 sInsertPrefSheetRulesAt
, &index
);
2404 nsresult
PresShell::SetPrefFocusRules(void)
2406 NS_TIME_FUNCTION_MIN(1.0);
2408 NS_ASSERTION(mPresContext
,"null prescontext not allowed");
2409 nsresult result
= NS_OK
;
2412 result
= NS_ERROR_FAILURE
;
2414 if (NS_SUCCEEDED(result
) && !mPrefStyleSheet
)
2415 result
= CreatePreferenceStyleSheet();
2417 if (NS_SUCCEEDED(result
)) {
2418 NS_ASSERTION(mPrefStyleSheet
, "prefstylesheet should not be null");
2420 if (mPresContext
->GetUseFocusColors()) {
2421 nscolor
focusBackground(mPresContext
->FocusBackgroundColor());
2422 nscolor
focusText(mPresContext
->FocusTextColor());
2424 // insert a rule to make focus the preferred color
2426 nsAutoString strRule
, strColor
;
2428 ///////////////////////////////////////////////////////////////
2429 // - focus: '*:focus
2430 ColorToString(focusText
,strColor
);
2431 strRule
.AppendLiteral("*:focus,*:focus>font {color: ");
2432 strRule
.Append(strColor
);
2433 strRule
.AppendLiteral(" !important; background-color: ");
2434 ColorToString(focusBackground
,strColor
);
2435 strRule
.Append(strColor
);
2436 strRule
.AppendLiteral(" !important; } ");
2438 result
= mPrefStyleSheet
->
2439 InsertRuleInternal(strRule
, sInsertPrefSheetRulesAt
, &index
);
2441 PRUint8 focusRingWidth
= mPresContext
->FocusRingWidth();
2442 PRBool focusRingOnAnything
= mPresContext
->GetFocusRingOnAnything();
2443 PRUint8 focusRingStyle
= mPresContext
->GetFocusRingStyle();
2445 if ((NS_SUCCEEDED(result
) && focusRingWidth
!= 1 && focusRingWidth
<= 4 ) || focusRingOnAnything
) {
2447 nsAutoString strRule
;
2448 if (!focusRingOnAnything
)
2449 strRule
.AppendLiteral("*|*:link:focus, *|*:visited"); // If we only want focus rings on the normal things like links
2450 strRule
.AppendLiteral(":focus {outline: "); // For example 3px dotted WindowText (maximum 4)
2451 strRule
.AppendInt(focusRingWidth
);
2452 if (focusRingStyle
== 0) // solid
2453 strRule
.AppendLiteral("px solid -moz-mac-focusring !important; -moz-outline-radius: 3px; outline-offset: 1px; } ");
2455 strRule
.AppendLiteral("px dotted WindowText !important; } ");
2457 result
= mPrefStyleSheet
->
2458 InsertRuleInternal(strRule
, sInsertPrefSheetRulesAt
, &index
);
2459 NS_ENSURE_SUCCESS(result
, result
);
2460 if (focusRingWidth
!= 1) {
2461 // If the focus ring width is different from the default, fix buttons with rings
2462 strRule
.AssignLiteral("button::-moz-focus-inner, input[type=\"reset\"]::-moz-focus-inner,");
2463 strRule
.AppendLiteral("input[type=\"button\"]::-moz-focus-inner, ");
2464 strRule
.AppendLiteral("input[type=\"submit\"]::-moz-focus-inner { padding: 1px 2px 1px 2px; border: ");
2465 strRule
.AppendInt(focusRingWidth
);
2466 if (focusRingStyle
== 0) // solid
2467 strRule
.AppendLiteral("px solid transparent !important; } ");
2469 strRule
.AppendLiteral("px dotted transparent !important; } ");
2470 result
= mPrefStyleSheet
->
2471 InsertRuleInternal(strRule
, sInsertPrefSheetRulesAt
, &index
);
2472 NS_ENSURE_SUCCESS(result
, result
);
2474 strRule
.AssignLiteral("button:focus::-moz-focus-inner, input[type=\"reset\"]:focus::-moz-focus-inner,");
2475 strRule
.AppendLiteral("input[type=\"button\"]:focus::-moz-focus-inner, input[type=\"submit\"]:focus::-moz-focus-inner {");
2476 strRule
.AppendLiteral("border-color: ButtonText !important; }");
2477 result
= mPrefStyleSheet
->
2478 InsertRuleInternal(strRule
, sInsertPrefSheetRulesAt
, &index
);
2486 PresShell::AddUserSheet(nsISupports
* aSheet
)
2488 // Make sure this does what DocumentViewerImpl::CreateStyleSet does wrt
2489 // ordering. We want this new sheet to come after all the existing stylesheet
2490 // service sheets, but before other user sheets; see nsIStyleSheetService.idl
2491 // for the ordering. Just remove and readd all the nsStyleSheetService
2493 nsCOMPtr
<nsIStyleSheetService
> dummy
=
2494 do_GetService(NS_STYLESHEETSERVICE_CONTRACTID
);
2496 mStyleSet
->BeginUpdate();
2498 nsStyleSheetService
*sheetService
= nsStyleSheetService::gInstance
;
2499 nsCOMArray
<nsIStyleSheet
> & userSheets
= *sheetService
->UserStyleSheets();
2501 // Iterate forwards when removing so the searches for RemoveStyleSheet are as
2502 // short as possible.
2503 for (i
= 0; i
< userSheets
.Count(); ++i
) {
2504 mStyleSet
->RemoveStyleSheet(nsStyleSet::eUserSheet
, userSheets
[i
]);
2507 // Now iterate backwards, so that the order of userSheets will be the same as
2508 // the order of sheets from it in the style set.
2509 for (i
= userSheets
.Count() - 1; i
>= 0; --i
) {
2510 mStyleSet
->PrependStyleSheet(nsStyleSet::eUserSheet
, userSheets
[i
]);
2513 mStyleSet
->EndUpdate();
2515 ReconstructStyleData();
2519 PresShell::AddAgentSheet(nsISupports
* aSheet
)
2521 // Make sure this does what DocumentViewerImpl::CreateStyleSet does
2523 nsCOMPtr
<nsIStyleSheet
> sheet
= do_QueryInterface(aSheet
);
2528 mStyleSet
->AppendStyleSheet(nsStyleSet::eAgentSheet
, sheet
);
2529 ReconstructStyleData();
2533 PresShell::RemoveSheet(nsStyleSet::sheetType aType
, nsISupports
* aSheet
)
2535 nsCOMPtr
<nsIStyleSheet
> sheet
= do_QueryInterface(aSheet
);
2540 mStyleSet
->RemoveStyleSheet(aType
, sheet
);
2541 ReconstructStyleData();
2545 PresShell::SetDisplaySelection(PRInt16 aToggle
)
2547 mSelection
->SetDisplaySelection(aToggle
);
2552 PresShell::GetDisplaySelection(PRInt16
*aToggle
)
2554 *aToggle
= mSelection
->GetDisplaySelection();
2559 PresShell::GetSelection(SelectionType aType
, nsISelection
**aSelection
)
2561 if (!aSelection
|| !mSelection
)
2562 return NS_ERROR_NULL_POINTER
;
2564 *aSelection
= mSelection
->GetSelection(aType
);
2567 return NS_ERROR_INVALID_ARG
;
2569 NS_ADDREF(*aSelection
);
2575 PresShell::GetCurrentSelection(SelectionType aType
)
2580 return mSelection
->GetSelection(aType
);
2584 PresShell::ScrollSelectionIntoView(SelectionType aType
, SelectionRegion aRegion
,
2588 return NS_ERROR_NULL_POINTER
;
2590 return mSelection
->ScrollSelectionIntoView(aType
, aRegion
, aFlags
);
2594 PresShell::RepaintSelection(SelectionType aType
)
2597 return NS_ERROR_NULL_POINTER
;
2599 return mSelection
->RepaintSelection(aType
);
2602 // Make shell be a document observer
2604 PresShell::BeginObservingDocument()
2606 if (mDocument
&& !mIsDestroying
) {
2607 mDocument
->AddObserver(this);
2608 if (mIsDocumentGone
) {
2609 NS_WARNING("Adding a presshell that was disconnected from the document "
2610 "as a document observer? Sounds wrong...");
2611 mIsDocumentGone
= PR_FALSE
;
2616 // Make shell stop being a document observer
2618 PresShell::EndObservingDocument()
2620 // XXXbz do we need to tell the frame constructor that the document
2621 // is gone, perhaps? Except for printing it's NOT gone, sometimes.
2622 mIsDocumentGone
= PR_TRUE
;
2624 mDocument
->RemoveObserver(this);
2629 char* nsPresShell_ReflowStackPointerTop
;
2633 PresShell::InitialReflow(nscoord aWidth
, nscoord aHeight
)
2635 if (mIsDestroying
) {
2644 NS_TIME_FUNCTION_WITH_DOCURL
;
2646 NS_ASSERTION(!mDidInitialReflow
, "Why are we being called?");
2648 nsCOMPtr
<nsIPresShell
> kungFuDeathGrip(this);
2649 mDidInitialReflow
= PR_TRUE
;
2652 if (VERIFY_REFLOW_NOISY_RC
& gVerifyReflowFlags
) {
2654 nsIURI
*uri
= mDocument
->GetDocumentURI();
2658 printf("*** PresShell::InitialReflow (this=%p, url='%s')\n", (void*)this, url
.get());
2665 mCaret
->EraseCaret();
2667 // XXX Do a full invalidate at the beginning so that invalidates along
2668 // the way don't have region accumulation issues?
2670 mPresContext
->SetVisibleArea(nsRect(0, 0, aWidth
, aHeight
));
2672 // Get the root frame from the frame manager
2673 // XXXbz it would be nice to move this somewhere else... like frame manager
2674 // Init(), say. But we need to make sure our views are all set up by the
2676 nsIFrame
* rootFrame
= FrameManager()->GetRootFrame();
2677 NS_ASSERTION(!rootFrame
, "How did that happen, exactly?");
2679 nsAutoScriptBlocker scriptBlocker
;
2680 mFrameConstructor
->BeginUpdate();
2681 mFrameConstructor
->ConstructRootFrame(&rootFrame
);
2682 FrameManager()->SetRootFrame(rootFrame
);
2683 mFrameConstructor
->EndUpdate();
2686 NS_ENSURE_STATE(!mHaveShutDown
);
2689 return NS_ERROR_OUT_OF_MEMORY
;
2692 Element
*root
= mDocument
->GetRootElement();
2696 nsAutoCauseReflowNotifier
reflowNotifier(this);
2697 mFrameConstructor
->BeginUpdate();
2699 // Have the style sheet processor construct frame for the root
2700 // content object down
2701 mFrameConstructor
->ContentInserted(nsnull
, root
, nsnull
, PR_FALSE
);
2704 // Something in mFrameConstructor->ContentInserted may have caused
2705 // Destroy() to get called, bug 337586.
2706 NS_ENSURE_STATE(!mHaveShutDown
);
2708 mFrameConstructor
->EndUpdate();
2711 // nsAutoScriptBlocker going out of scope may have killed us too
2712 NS_ENSURE_STATE(!mHaveShutDown
);
2714 // Run the XBL binding constructors for any new frames we've constructed
2715 mDocument
->BindingManager()->ProcessAttachedQueue();
2717 NS_TIME_FUNCTION_MARK("XBL binding constructors fired");
2719 // Constructors may have killed us too
2720 NS_ENSURE_STATE(!mHaveShutDown
);
2722 // Now flush out pending restyles before we actually reflow, in
2723 // case XBL constructors changed styles somewhere.
2725 nsAutoScriptBlocker scriptBlocker
;
2726 mFrameConstructor
->CreateNeededFrames();
2727 mFrameConstructor
->ProcessPendingRestyles();
2730 // And that might have run _more_ XBL constructors
2731 NS_ENSURE_STATE(!mHaveShutDown
);
2734 NS_ASSERTION(rootFrame
, "How did that happen?");
2736 // Note: Because the frame just got created, it has the NS_FRAME_IS_DIRTY
2737 // bit set. Unset it so that FrameNeedsReflow() will work right.
2738 NS_ASSERTION(!mDirtyRoots
.Contains(rootFrame
),
2739 "Why is the root in mDirtyRoots already?");
2741 rootFrame
->RemoveStateBits(NS_FRAME_IS_DIRTY
|
2742 NS_FRAME_HAS_DIRTY_CHILDREN
);
2743 FrameNeedsReflow(rootFrame
, eResize
, NS_FRAME_IS_DIRTY
);
2745 NS_ASSERTION(mDirtyRoots
.Contains(rootFrame
),
2746 "Should be in mDirtyRoots now");
2747 NS_ASSERTION(mReflowScheduled
, "Why no reflow scheduled?");
2749 // Restore our root scroll position now if we're getting here after EndLoad
2750 // got called, since this is our one chance to do it. Note that we need not
2751 // have reflowed for this to work; when the scrollframe is finally reflowed
2752 // it'll puick up the position we store in it here.
2753 if (!mDocumentLoading
) {
2754 RestoreRootScrollPosition();
2757 // For printing, we just immediately unsuppress.
2758 if (!mPresContext
->IsPaginated()) {
2759 // Kick off a one-shot timer based off our pref value. When this timer
2760 // fires, if painting is still locked down, then we will go ahead and
2761 // trigger a full invalidate and allow painting to proceed normally.
2762 mPaintingSuppressed
= PR_TRUE
;
2763 mPaintSuppressionTimer
= do_CreateInstance("@mozilla.org/timer;1");
2764 if (!mPaintSuppressionTimer
)
2765 // Uh-oh. We must be out of memory. No point in keeping painting locked down.
2766 mPaintingSuppressed
= PR_FALSE
;
2768 // Initialize the timer.
2770 // Default to PAINTLOCK_EVENT_DELAY if we can't get the pref value.
2772 nsContentUtils::GetIntPref("nglayout.initialpaint.delay",
2773 PAINTLOCK_EVENT_DELAY
);
2775 mPaintSuppressionTimer
->InitWithFuncCallback(sPaintSuppressionCallback
,
2777 nsITimer::TYPE_ONE_SHOT
);
2781 return NS_OK
; //XXX this needs to be real. MMP
2785 PresShell::sPaintSuppressionCallback(nsITimer
*aTimer
, void* aPresShell
)
2787 nsRefPtr
<PresShell
> self
= static_cast<PresShell
*>(aPresShell
);
2789 self
->UnsuppressPainting();
2793 PresShell::AsyncResizeEventCallback(nsITimer
* aTimer
, void* aPresShell
)
2795 static_cast<PresShell
*>(aPresShell
)->FireResizeEvent();
2799 PresShell::ResizeReflowOverride(nscoord aWidth
, nscoord aHeight
)
2801 mViewportOverridden
= PR_TRUE
;
2802 return ResizeReflowIgnoreOverride(aWidth
, aHeight
);
2806 PresShell::ResizeReflow(nscoord aWidth
, nscoord aHeight
)
2808 if (mViewportOverridden
) {
2809 // The viewport has been overridden, and this reflow request
2810 // didn't ask to ignore the override. Pretend it didn't happen.
2813 return ResizeReflowIgnoreOverride(aWidth
, aHeight
);
2817 PresShell::ResizeReflowIgnoreOverride(nscoord aWidth
, nscoord aHeight
)
2819 NS_PRECONDITION(!mIsReflowing
, "Shouldn't be in reflow here!");
2820 NS_PRECONDITION(aWidth
!= NS_UNCONSTRAINEDSIZE
,
2821 "shouldn't use unconstrained widths anymore");
2823 // If we don't have a root frame yet, that means we haven't had our initial
2824 // reflow... If that's the case, and aWidth or aHeight is unconstrained,
2825 // ignore them altogether.
2826 nsIFrame
* rootFrame
= FrameManager()->GetRootFrame();
2828 if (!rootFrame
&& aHeight
== NS_UNCONSTRAINEDSIZE
) {
2829 // We can't do the work needed for SizeToContent without a root
2830 // frame, and we want to return before setting the visible area.
2831 return NS_ERROR_NOT_AVAILABLE
;
2834 if (!mIsDestroying
&& !mResizeEvent
.IsPending() &&
2835 !mAsyncResizeTimerIsActive
) {
2836 FireBeforeResizeEvent();
2839 mPresContext
->SetVisibleArea(nsRect(0, 0, aWidth
, aHeight
));
2841 // There isn't anything useful we can do if the initial reflow hasn't happened
2845 NS_ASSERTION(mViewManager
, "Must have view manager");
2846 nsCOMPtr
<nsIViewManager
> viewManagerDeathGrip
= mViewManager
;
2847 // Take this ref after viewManager so it'll make sure to go away first
2848 nsCOMPtr
<nsIPresShell
> kungFuDeathGrip(this);
2849 if (!GetPresContext()->SupressingResizeReflow())
2851 nsIViewManager::UpdateViewBatch
batch(mViewManager
);
2853 // Have to make sure that the content notifications are flushed before we
2854 // start messing with the frame model; otherwise we can get content doubling.
2855 mDocument
->FlushPendingNotifications(Flush_ContentAndNotify
);
2857 // Make sure style is up to date
2859 nsAutoScriptBlocker scriptBlocker
;
2860 mFrameConstructor
->CreateNeededFrames();
2861 mFrameConstructor
->ProcessPendingRestyles();
2864 if (!mIsDestroying
) {
2865 // XXX Do a full invalidate at the beginning so that invalidates along
2866 // the way don't have region accumulation issues?
2869 nsAutoCauseReflowNotifier
crNotifier(this);
2872 // Kick off a top-down reflow
2873 AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Reflow
);
2875 mDirtyRoots
.RemoveElement(rootFrame
);
2876 DoReflow(rootFrame
, PR_TRUE
);
2879 DidDoReflow(PR_TRUE
);
2882 batch
.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC
);
2885 if (aHeight
== NS_UNCONSTRAINEDSIZE
) {
2886 mPresContext
->SetVisibleArea(
2887 nsRect(0, 0, aWidth
, rootFrame
->GetRect().height
));
2890 if (!mIsDestroying
&& !mResizeEvent
.IsPending() &&
2891 !mAsyncResizeTimerIsActive
) {
2893 if (!mAsyncResizeEventTimer
) {
2894 mAsyncResizeEventTimer
= do_CreateInstance("@mozilla.org/timer;1");
2896 if (mAsyncResizeEventTimer
) {
2897 mAsyncResizeTimerIsActive
= PR_TRUE
;
2898 mAsyncResizeEventTimer
->InitWithFuncCallback(AsyncResizeEventCallback
,
2900 nsITimer::TYPE_ONE_SHOT
);
2903 nsRefPtr
<nsRunnableMethod
<PresShell
> > resizeEvent
=
2904 NS_NewRunnableMethod(this, &PresShell::FireResizeEvent
);
2905 if (NS_SUCCEEDED(NS_DispatchToCurrentThread(resizeEvent
))) {
2906 mResizeEvent
= resizeEvent
;
2911 return NS_OK
; //XXX this needs to be real. MMP
2915 PresShell::FireBeforeResizeEvent()
2917 if (mIsDocumentGone
)
2920 // Send beforeresize event from here.
2921 nsEvent
event(PR_TRUE
, NS_BEFORERESIZE_EVENT
);
2923 nsPIDOMWindow
*window
= mDocument
->GetWindow();
2925 nsCOMPtr
<nsIPresShell
> kungFuDeathGrip(this);
2926 nsEventDispatcher::Dispatch(window
, mPresContext
, &event
);
2931 PresShell::FireResizeEvent()
2933 if (mAsyncResizeTimerIsActive
) {
2934 mAsyncResizeTimerIsActive
= PR_FALSE
;
2935 mAsyncResizeEventTimer
->Cancel();
2937 mResizeEvent
.Revoke();
2939 if (mIsDocumentGone
)
2942 //Send resize event from here.
2943 nsEvent
event(PR_TRUE
, NS_RESIZE_EVENT
);
2944 nsEventStatus status
= nsEventStatus_eIgnore
;
2946 nsPIDOMWindow
*window
= mDocument
->GetWindow();
2948 nsCOMPtr
<nsIPresShell
> kungFuDeathGrip(this);
2949 mInResize
= PR_TRUE
;
2950 nsEventDispatcher::Dispatch(window
, mPresContext
, &event
, nsnull
, &status
);
2951 mInResize
= PR_FALSE
;
2956 PresShell::SetIgnoreFrameDestruction(PRBool aIgnore
)
2958 mIgnoreFrameDestruction
= aIgnore
;
2962 PresShell::NotifyDestroyingFrame(nsIFrame
* aFrame
)
2964 NS_TIME_FUNCTION_MIN(1.0);
2966 mPresContext
->ForgetUpdatePluginGeometryFrame(aFrame
);
2968 if (!mIgnoreFrameDestruction
) {
2969 mPresContext
->StopImagesFor(aFrame
);
2971 mFrameConstructor
->NotifyDestroyingFrame(aFrame
);
2973 for (PRInt32 idx
= mDirtyRoots
.Length(); idx
; ) {
2975 if (mDirtyRoots
[idx
] == aFrame
) {
2976 mDirtyRoots
.RemoveElementAt(idx
);
2980 // Notify the frame manager
2981 FrameManager()->NotifyDestroyingFrame(aFrame
);
2983 // Remove frame properties
2984 mPresContext
->NotifyDestroyingFrame(aFrame
);
2986 if (aFrame
== mCurrentEventFrame
) {
2987 mCurrentEventContent
= aFrame
->GetContent();
2988 mCurrentEventFrame
= nsnull
;
2992 if (aFrame
== mDrawEventTargetFrame
) {
2993 mDrawEventTargetFrame
= nsnull
;
2997 for (unsigned int i
=0; i
< mCurrentEventFrameStack
.Length(); i
++) {
2998 if (aFrame
== mCurrentEventFrameStack
.ElementAt(i
)) {
2999 //One of our stack frames was deleted. Get its content so that when we
3000 //pop it we can still get its new frame from its content
3001 nsIContent
*currentEventContent
= aFrame
->GetContent();
3002 mCurrentEventContentStack
.ReplaceObjectAt(currentEventContent
, i
);
3003 mCurrentEventFrameStack
[i
] = nsnull
;
3007 mFramesToDirty
.RemoveEntry(aFrame
);
3011 already_AddRefed
<nsCaret
> PresShell::GetCaret() const
3013 nsCaret
* caret
= mCaret
;
3014 NS_IF_ADDREF(caret
);
3018 void PresShell::MaybeInvalidateCaretPosition()
3021 mCaret
->InvalidateOutsideCaret();
3025 void PresShell::SetCaret(nsCaret
*aNewCaret
)
3030 void PresShell::RestoreCaret()
3032 mCaret
= mOriginalCaret
;
3035 NS_IMETHODIMP
PresShell::SetCaretEnabled(PRBool aInEnable
)
3037 PRBool oldEnabled
= mCaretEnabled
;
3039 mCaretEnabled
= aInEnable
;
3041 if (mCaret
&& (mCaretEnabled
!= oldEnabled
))
3043 /* Don't change the caret's selection here! This was an evil side-effect of SetCaretEnabled()
3044 nsCOMPtr<nsIDOMSelection> domSel;
3045 if (NS_SUCCEEDED(GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(domSel))) && domSel)
3046 mCaret->SetCaretDOMSelection(domSel);
3048 mCaret
->SetCaretVisible(mCaretEnabled
);
3054 NS_IMETHODIMP
PresShell::SetCaretReadOnly(PRBool aReadOnly
)
3057 mCaret
->SetCaretReadOnly(aReadOnly
);
3061 NS_IMETHODIMP
PresShell::GetCaretEnabled(PRBool
*aOutEnabled
)
3063 NS_ENSURE_ARG_POINTER(aOutEnabled
);
3064 *aOutEnabled
= mCaretEnabled
;
3068 NS_IMETHODIMP
PresShell::SetCaretVisibilityDuringSelection(PRBool aVisibility
)
3071 mCaret
->SetVisibilityDuringSelection(aVisibility
);
3075 NS_IMETHODIMP
PresShell::GetCaretVisible(PRBool
*aOutIsVisible
)
3077 *aOutIsVisible
= PR_FALSE
;
3079 nsresult rv
= mCaret
->GetCaretVisible(aOutIsVisible
);
3080 NS_ENSURE_SUCCESS(rv
,rv
);
3085 NS_IMETHODIMP
PresShell::SetSelectionFlags(PRInt16 aInEnable
)
3087 mSelectionFlags
= aInEnable
;
3091 NS_IMETHODIMP
PresShell::GetSelectionFlags(PRInt16
*aOutEnable
)
3094 return NS_ERROR_INVALID_ARG
;
3095 *aOutEnable
= mSelectionFlags
;
3099 //implementation of nsISelectionController
3102 PresShell::CharacterMove(PRBool aForward
, PRBool aExtend
)
3104 return mSelection
->CharacterMove(aForward
, aExtend
);
3108 PresShell::CharacterExtendForDelete()
3110 return mSelection
->CharacterExtendForDelete();
3114 PresShell::CharacterExtendForBackspace()
3116 return mSelection
->CharacterExtendForBackspace();
3120 PresShell::WordMove(PRBool aForward
, PRBool aExtend
)
3122 return mSelection
->WordMove(aForward
, aExtend
);
3126 PresShell::WordExtendForDelete(PRBool aForward
)
3128 return mSelection
->WordExtendForDelete(aForward
);
3132 PresShell::LineMove(PRBool aForward
, PRBool aExtend
)
3134 nsresult result
= mSelection
->LineMove(aForward
, aExtend
);
3135 // if we can't go down/up any more we must then move caret completely to
3136 // end/beginning respectively.
3137 if (NS_FAILED(result
))
3138 result
= CompleteMove(aForward
,aExtend
);
3143 PresShell::IntraLineMove(PRBool aForward
, PRBool aExtend
)
3145 return mSelection
->IntraLineMove(aForward
, aExtend
);
3151 PresShell::PageMove(PRBool aForward
, PRBool aExtend
)
3153 nsIScrollableFrame
*scrollableFrame
=
3154 GetFrameToScrollAsScrollable(nsIPresShell::eVertical
);
3155 if (!scrollableFrame
)
3158 mSelection
->CommonPageMove(aForward
, aExtend
, scrollableFrame
);
3159 // After ScrollSelectionIntoView(), the pending notifications might be
3160 // flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
3161 return ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL
,
3162 nsISelectionController::SELECTION_FOCUS_REGION
,
3163 nsISelectionController::SCROLL_SYNCHRONOUS
);
3169 PresShell::ScrollPage(PRBool aForward
)
3171 nsIScrollableFrame
* scrollFrame
=
3172 GetFrameToScrollAsScrollable(nsIPresShell::eVertical
);
3174 scrollFrame
->ScrollBy(nsIntPoint(0, aForward
? 1 : -1),
3175 nsIScrollableFrame::PAGES
,
3176 nsIScrollableFrame::SMOOTH
);
3182 PresShell::ScrollLine(PRBool aForward
)
3184 nsIScrollableFrame
* scrollFrame
=
3185 GetFrameToScrollAsScrollable(nsIPresShell::eVertical
);
3187 PRInt32 lineCount
= 1;
3188 #ifdef MOZ_WIDGET_COCOA
3189 // Emulate the Mac IE behavior of scrolling a minimum of 2 lines
3190 // rather than 1. This vastly improves scrolling speed.
3193 scrollFrame
->ScrollBy(nsIntPoint(0, aForward
? lineCount
: -lineCount
),
3194 nsIScrollableFrame::LINES
,
3195 nsIScrollableFrame::SMOOTH
);
3198 // force the update to happen now, otherwise multiple scrolls can
3199 // occur before the update is processed. (bug #7354)
3201 // I'd use Composite here, but it doesn't always work.
3203 nsIViewManager
* viewManager
= GetViewManager();
3205 viewManager
->ForceUpdate();
3212 PresShell::ScrollHorizontal(PRBool aLeft
)
3214 nsIScrollableFrame
* scrollFrame
=
3215 GetFrameToScrollAsScrollable(nsIPresShell::eHorizontal
);
3217 scrollFrame
->ScrollBy(nsIntPoint(aLeft
? -1 : 1, 0),
3218 nsIScrollableFrame::LINES
,
3219 nsIScrollableFrame::SMOOTH
);
3221 // force the update to happen now, otherwise multiple scrolls can
3222 // occur before the update is processed. (bug #7354)
3224 // I'd use Composite here, but it doesn't always work.
3226 nsIViewManager
* viewManager
= GetViewManager();
3228 viewManager
->ForceUpdate();
3235 PresShell::CompleteScroll(PRBool aForward
)
3237 nsIScrollableFrame
* scrollFrame
=
3238 GetFrameToScrollAsScrollable(nsIPresShell::eVertical
);
3240 scrollFrame
->ScrollBy(nsIntPoint(0, aForward
? 1 : -1),
3241 nsIScrollableFrame::WHOLE
,
3242 nsIScrollableFrame::INSTANT
);
3248 PresShell::CompleteMove(PRBool aForward
, PRBool aExtend
)
3250 // Beware! This may flush notifications via synchronous
3251 // ScrollSelectionIntoView.
3252 nsIContent
* limiter
= mSelection
->GetAncestorLimiter();
3253 nsIFrame
* frame
= limiter
? limiter
->GetPrimaryFrame()
3254 : FrameConstructor()->GetRootElementFrame();
3256 return NS_ERROR_FAILURE
;
3257 nsPeekOffsetStruct pos
= frame
->GetExtremeCaretPosition(!aForward
);
3258 mSelection
->HandleClick(pos
.mResultContent
, pos
.mContentOffset
,
3259 pos
.mContentOffset
, aExtend
, PR_FALSE
, aForward
);
3261 // HandleClick resets ancestorLimiter, so set it again.
3262 mSelection
->SetAncestorLimiter(limiter
);
3265 // After ScrollSelectionIntoView(), the pending notifications might be
3266 // flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
3267 return ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL
,
3268 nsISelectionController::SELECTION_FOCUS_REGION
,
3269 nsISelectionController::SCROLL_SYNCHRONOUS
);
3273 PresShell::SelectAll()
3275 return mSelection
->SelectAll();
3279 PresShell::CheckVisibility(nsIDOMNode
*node
, PRInt16 startOffset
, PRInt16 EndOffset
, PRBool
*_retval
)
3281 if (!node
|| startOffset
>EndOffset
|| !_retval
|| startOffset
<0 || EndOffset
<0)
3282 return NS_ERROR_INVALID_ARG
;
3283 *_retval
= PR_FALSE
; //initialize return parameter
3284 nsCOMPtr
<nsIContent
> content(do_QueryInterface(node
));
3286 return NS_ERROR_FAILURE
;
3287 nsIFrame
*frame
= content
->GetPrimaryFrame();
3288 if (!frame
) //no frame to look at so it must not be visible
3290 //start process now to go through all frames to find startOffset. then check chars after that to see
3291 //if anything until EndOffset is visible.
3292 PRBool finished
= PR_FALSE
;
3293 frame
->CheckVisibility(mPresContext
,startOffset
,EndOffset
,PR_TRUE
,&finished
, _retval
);
3294 return NS_OK
;//dont worry about other return val
3297 //end implementations nsISelectionController
3301 PresShell::StyleChangeReflow()
3303 nsIFrame
* rootFrame
= FrameManager()->GetRootFrame();
3304 // At the moment at least, we don't have a root frame before the initial
3305 // reflow; it's safe to just ignore the request in that case
3309 FrameNeedsReflow(rootFrame
, eStyleChange
, NS_FRAME_IS_DIRTY
);
3313 nsIPresShell::GetRootFrameExternal() const
3315 return FrameManager()->GetRootFrame();
3319 nsIPresShell::GetRootScrollFrame() const
3321 nsIFrame
* rootFrame
= FrameManager()->GetRootFrame();
3322 // Ensure root frame is a viewport frame
3323 if (!rootFrame
|| nsGkAtoms::viewportFrame
!= rootFrame
->GetType())
3325 nsIFrame
* theFrame
= rootFrame
->GetFirstChild(nsnull
);
3326 if (!theFrame
|| nsGkAtoms::scrollFrame
!= theFrame
->GetType())
3332 nsIPresShell::GetRootScrollFrameAsScrollable() const
3334 nsIFrame
* frame
= GetRootScrollFrame();
3337 nsIScrollableFrame
* scrollableFrame
= do_QueryFrame(frame
);
3338 NS_ASSERTION(scrollableFrame
,
3339 "All scroll frames must implement nsIScrollableFrame");
3340 return scrollableFrame
;
3344 nsIPresShell::GetRootScrollFrameAsScrollableExternal() const
3346 return GetRootScrollFrameAsScrollable();
3349 nsIPageSequenceFrame
*
3350 PresShell::GetPageSequenceFrame() const
3352 nsIFrame
* frame
= mFrameConstructor
->GetPageSequenceFrame();
3353 return do_QueryFrame(frame
);
3357 PresShell::GetFrameForPoint(nsIFrame
* aFrame
, nsPoint aPt
)
3359 return nsLayoutUtils::GetFrameForPoint(aFrame
, aPt
);
3363 PresShell::BeginUpdate(nsIDocument
*aDocument
, nsUpdateType aUpdateType
)
3368 mFrameConstructor
->BeginUpdate();
3370 if (aUpdateType
& UPDATE_STYLE
)
3371 mStyleSet
->BeginUpdate();
3375 PresShell::EndUpdate(nsIDocument
*aDocument
, nsUpdateType aUpdateType
)
3378 NS_PRECONDITION(0 != mUpdateCount
, "too many EndUpdate's");
3382 if (aUpdateType
& UPDATE_STYLE
) {
3383 mStyleSet
->EndUpdate();
3384 if (mStylesHaveChanged
)
3385 ReconstructStyleData();
3388 mFrameConstructor
->EndUpdate();
3392 PresShell::RestoreRootScrollPosition()
3394 // Restore frame state for the root scroll frame
3395 nsCOMPtr
<nsILayoutHistoryState
> historyState
=
3396 mDocument
->GetLayoutHistoryState();
3397 // Make sure we don't reenter reflow via the sync paint that happens while
3398 // we're scrolling to our restored position. Entering reflow for the
3399 // scrollable frame will cause it to reenter ScrollToRestoredPosition(), and
3400 // it'll get all confused.
3401 nsAutoScriptBlocker scriptBlocker
;
3405 nsIFrame
* scrollFrame
= GetRootScrollFrame();
3407 nsIScrollableFrame
* scrollableFrame
= do_QueryFrame(scrollFrame
);
3408 if (scrollableFrame
) {
3409 FrameManager()->RestoreFrameStateFor(scrollFrame
, historyState
,
3410 nsIStatefulFrame::eDocumentScrollState
);
3411 scrollableFrame
->ScrollToRestoredPosition();
3420 PresShell::BeginLoad(nsIDocument
*aDocument
)
3422 mDocumentLoading
= PR_TRUE
;
3426 PresShell::EndLoad(nsIDocument
*aDocument
)
3428 NS_PRECONDITION(aDocument
== mDocument
, "Wrong document");
3430 RestoreRootScrollPosition();
3432 mDocumentLoading
= PR_FALSE
;
3437 PresShell::VerifyHasDirtyRootAncestor(nsIFrame
* aFrame
)
3439 // XXXbz due to bug 372769, can't actually assert anything here...
3442 // XXXbz shouldn't need this part; remove it once FrameNeedsReflow
3443 // handles the root frame correctly.
3444 if (!aFrame
->GetParent()) {
3448 // Make sure that there is a reflow root ancestor of |aFrame| that's
3449 // in mDirtyRoots already.
3450 while (aFrame
&& (aFrame
->GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN
)) {
3451 if (((aFrame
->GetStateBits() & NS_FRAME_REFLOW_ROOT
) ||
3452 !aFrame
->GetParent()) &&
3453 mDirtyRoots
.Contains(aFrame
)) {
3457 aFrame
= aFrame
->GetParent();
3459 NS_NOTREACHED("Frame has dirty bits set but isn't scheduled to be "
3465 PresShell::FrameNeedsReflow(nsIFrame
*aFrame
, IntrinsicDirty aIntrinsicDirty
,
3466 nsFrameState aBitToAdd
)
3468 #ifdef NS_FUNCTION_TIMER
3469 NS_TIME_FUNCTION_DECLARE_DOCURL
;
3470 nsCAutoString
frameType__("N/A");
3471 nsIAtom
*atomType__
= aFrame
? aFrame
->GetType() : nsnull
;
3472 if (atomType__
) atomType__
->ToUTF8String(frameType__
);
3473 NS_TIME_FUNCTION_MIN_FMT(1.0, "%s (line %d) (document: %s, frame type: %s)", MOZ_FUNCTION_NAME
,
3474 __LINE__
, docURL__
.get(), frameType__
.get());
3477 NS_PRECONDITION(aBitToAdd
== NS_FRAME_IS_DIRTY
||
3478 aBitToAdd
== NS_FRAME_HAS_DIRTY_CHILDREN
,
3479 "Unexpected bits being added");
3480 NS_PRECONDITION(aIntrinsicDirty
!= eStyleChange
||
3481 aBitToAdd
== NS_FRAME_IS_DIRTY
,
3482 "bits don't correspond to style change reason");
3484 NS_ASSERTION(!mIsReflowing
, "can't mark frame dirty during reflow");
3486 // If we've not yet done the initial reflow, then don't bother
3487 // enqueuing a reflow command yet.
3488 if (! mDidInitialReflow
)
3491 // If we're already destroying, don't bother with this either.
3496 //printf("gShellCounter: %d\n", gShellCounter++);
3497 if (mInVerifyReflow
)
3500 if (VERIFY_REFLOW_NOISY_RC
& gVerifyReflowFlags
) {
3501 printf("\nPresShell@%p: frame %p needs reflow\n", (void*)this, (void*)aFrame
);
3502 if (VERIFY_REFLOW_REALLY_NOISY_RC
& gVerifyReflowFlags
) {
3503 printf("Current content model:\n");
3504 Element
*rootElement
= mDocument
->GetRootElement();
3506 rootElement
->List(stdout
, 0);
3512 nsAutoTArray
<nsIFrame
*, 4> subtrees
;
3513 subtrees
.AppendElement(aFrame
);
3516 nsIFrame
*subtreeRoot
= subtrees
.ElementAt(subtrees
.Length() - 1);
3517 subtrees
.RemoveElementAt(subtrees
.Length() - 1);
3519 // Grab |wasDirty| now so we can go ahead and update the bits on
3521 PRBool wasDirty
= NS_SUBTREE_DIRTY(subtreeRoot
);
3522 subtreeRoot
->AddStateBits(aBitToAdd
);
3524 // Now if subtreeRoot is a reflow root we can cut off this reflow at it if
3525 // the bit being added is NS_FRAME_HAS_DIRTY_CHILDREN.
3526 PRBool targetFrameDirty
= (aBitToAdd
== NS_FRAME_IS_DIRTY
);
3528 #define FRAME_IS_REFLOW_ROOT(_f) \
3529 ((_f->GetStateBits() & NS_FRAME_REFLOW_ROOT) && \
3530 (_f != subtreeRoot || !targetFrameDirty))
3533 // Mark the intrinsic widths as dirty on the frame, all of its ancestors,
3534 // and all of its descendants, if needed:
3536 if (aIntrinsicDirty
!= eResize
) {
3537 // Mark argument and all ancestors dirty. (Unless we hit a reflow
3538 // root that should contain the reflow. That root could be
3539 // subtreeRoot itself if it's not dirty, or it could be some
3540 // ancestor of subtreeRoot.)
3541 for (nsIFrame
*a
= subtreeRoot
;
3542 a
&& !FRAME_IS_REFLOW_ROOT(a
);
3544 a
->MarkIntrinsicWidthsDirty();
3547 if (aIntrinsicDirty
== eStyleChange
) {
3548 // Mark all descendants dirty (using an nsTArray stack rather than
3550 nsAutoTArray
<nsIFrame
*, 32> stack
;
3551 stack
.AppendElement(subtreeRoot
);
3554 nsIFrame
*f
= stack
.ElementAt(stack
.Length() - 1);
3555 stack
.RemoveElementAt(stack
.Length() - 1);
3557 if (f
->GetType() == nsGkAtoms::placeholderFrame
) {
3558 nsIFrame
*oof
= nsPlaceholderFrame::GetRealFrameForPlaceholder(f
);
3559 if (!nsLayoutUtils::IsProperAncestorFrame(subtreeRoot
, oof
)) {
3560 // We have another distinct subtree we need to mark.
3561 subtrees
.AppendElement(oof
);
3565 PRInt32 childListIndex
= 0;
3566 nsIAtom
*childListName
;
3568 childListName
= f
->GetAdditionalChildListName(childListIndex
++);
3569 for (nsIFrame
*kid
= f
->GetFirstChild(childListName
); kid
;
3570 kid
= kid
->GetNextSibling()) {
3571 kid
->MarkIntrinsicWidthsDirty();
3572 stack
.AppendElement(kid
);
3574 } while (childListName
);
3575 } while (stack
.Length() != 0);
3578 // Set NS_FRAME_HAS_DIRTY_CHILDREN bits (via nsIFrame::ChildIsDirty)
3579 // up the tree until we reach either a frame that's already dirty or
3581 nsIFrame
*f
= subtreeRoot
;
3583 if (FRAME_IS_REFLOW_ROOT(f
) || !f
->GetParent()) {
3584 // we've hit a reflow root or the root frame
3586 mDirtyRoots
.AppendElement(f
);
3590 VerifyHasDirtyRootAncestor(f
);
3597 nsIFrame
*child
= f
;
3599 wasDirty
= NS_SUBTREE_DIRTY(f
);
3600 f
->ChildIsDirty(child
);
3601 NS_ASSERTION(f
->GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN
,
3602 "ChildIsDirty didn't do its job");
3604 // This frame was already marked dirty.
3606 VerifyHasDirtyRootAncestor(f
);
3611 } while (subtrees
.Length() != 0);
3613 MaybeScheduleReflow();
3617 PresShell::FrameNeedsToContinueReflow(nsIFrame
*aFrame
)
3619 NS_ASSERTION(mIsReflowing
, "Must be in reflow when marking path dirty.");
3620 NS_PRECONDITION(mCurrentReflowRoot
, "Must have a current reflow root here");
3621 NS_ASSERTION(aFrame
== mCurrentReflowRoot
||
3622 nsLayoutUtils::IsProperAncestorFrame(mCurrentReflowRoot
, aFrame
),
3623 "Frame passed in is not the descendant of mCurrentReflowRoot");
3624 NS_ASSERTION(aFrame
->GetStateBits() & NS_FRAME_IN_REFLOW
,
3625 "Frame passed in not in reflow?");
3627 mFramesToDirty
.PutEntry(aFrame
);
3631 nsIPresShell::GetFrameToScrollAsScrollable(
3632 nsIPresShell::ScrollDirection aDirection
)
3634 nsIScrollableFrame
* scrollFrame
= nsnull
;
3636 nsCOMPtr
<nsIContent
> focusedContent
;
3637 nsIFocusManager
* fm
= nsFocusManager::GetFocusManager();
3638 if (fm
&& mDocument
) {
3639 nsCOMPtr
<nsIDOMWindow
> window
= do_QueryInterface(mDocument
->GetWindow());
3641 nsCOMPtr
<nsIDOMElement
> focusedElement
;
3642 fm
->GetFocusedElementForWindow(window
, PR_FALSE
, nsnull
, getter_AddRefs(focusedElement
));
3643 focusedContent
= do_QueryInterface(focusedElement
);
3645 if (!focusedContent
&& mSelection
) {
3646 nsISelection
* domSelection
= mSelection
->
3647 GetSelection(nsISelectionController::SELECTION_NORMAL
);
3649 nsCOMPtr
<nsIDOMNode
> focusedNode
;
3650 domSelection
->GetFocusNode(getter_AddRefs(focusedNode
));
3651 focusedContent
= do_QueryInterface(focusedNode
);
3654 if (focusedContent
) {
3655 nsIFrame
* startFrame
= focusedContent
->GetPrimaryFrame();
3657 scrollFrame
= startFrame
->GetScrollTargetFrame();
3659 startFrame
= scrollFrame
->GetScrolledFrame();
3661 if (aDirection
== nsIPresShell::eEither
) {
3663 nsLayoutUtils::GetNearestScrollableFrame(startFrame
);
3666 nsLayoutUtils::GetNearestScrollableFrameForDirection(startFrame
,
3667 aDirection
== eVertical
? nsLayoutUtils::eVertical
:
3668 nsLayoutUtils::eHorizontal
);
3673 scrollFrame
= GetRootScrollFrameAsScrollable();
3679 PresShell::CancelAllPendingReflows()
3681 mDirtyRoots
.Clear();
3683 if (mReflowScheduled
) {
3684 GetPresContext()->RefreshDriver()->RemoveLayoutFlushObserver(this);
3685 mReflowScheduled
= PR_FALSE
;
3688 ASSERT_REFLOW_SCHEDULED_STATE();
3692 PresShell::RecreateFramesFor(nsIContent
* aContent
)
3694 NS_TIME_FUNCTION_MIN(1.0);
3696 NS_ENSURE_TRUE(mPresContext
, NS_ERROR_FAILURE
);
3697 if (!mDidInitialReflow
) {
3698 // Nothing to do here. In fact, if we proceed and aContent is the
3699 // root we will crash.
3703 // Don't call RecreateFramesForContent since that is not exported and we want
3704 // to keep the number of entrypoints down.
3706 NS_ASSERTION(mViewManager
, "Should have view manager");
3707 nsIViewManager::UpdateViewBatch
batch(mViewManager
);
3709 // Have to make sure that the content notifications are flushed before we
3710 // start messing with the frame model; otherwise we can get content doubling.
3711 mDocument
->FlushPendingNotifications(Flush_ContentAndNotify
);
3713 nsAutoScriptBlocker scriptBlocker
;
3715 nsStyleChangeList changeList
;
3716 changeList
.AppendChange(nsnull
, aContent
, nsChangeHint_ReconstructFrame
);
3718 // Mark ourselves as not safe to flush while we're doing frame construction.
3720 nsresult rv
= mFrameConstructor
->ProcessRestyledFrames(changeList
);
3723 batch
.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC
);
3728 nsIPresShell::PostRecreateFramesFor(Element
* aElement
)
3730 FrameConstructor()->PostRestyleEvent(aElement
, nsRestyleHint(0),
3731 nsChangeHint_ReconstructFrame
);
3735 nsIPresShell::RestyleForAnimation(Element
* aElement
, nsRestyleHint aHint
)
3737 FrameConstructor()->PostAnimationRestyleEvent(aElement
, aHint
,
3738 NS_STYLE_HINT_NONE
);
3742 PresShell::ClearFrameRefs(nsIFrame
* aFrame
)
3744 mPresContext
->EventStateManager()->ClearFrameRefs(aFrame
);
3746 nsWeakFrame
* weakFrame
= mWeakFrames
;
3748 nsWeakFrame
* prev
= weakFrame
->GetPreviousWeakFrame();
3749 if (weakFrame
->GetFrame() == aFrame
) {
3750 // This removes weakFrame from mWeakFrames.
3751 weakFrame
->Clear(this);
3757 already_AddRefed
<nsIRenderingContext
>
3758 PresShell::GetReferenceRenderingContext()
3760 NS_TIME_FUNCTION_MIN(1.0);
3762 nsIDeviceContext
* devCtx
= mPresContext
->DeviceContext();
3763 nsRefPtr
<nsIRenderingContext
> rc
;
3764 if (mPresContext
->IsScreen()) {
3765 devCtx
->CreateRenderingContextInstance(*getter_AddRefs(rc
));
3767 rc
->Init(devCtx
, gfxPlatform::GetPlatform()->ScreenReferenceSurface());
3770 devCtx
->CreateRenderingContext(*getter_AddRefs(rc
));
3776 PresShell::GoToAnchor(const nsAString
& aAnchorName
, PRBool aScroll
)
3779 return NS_ERROR_FAILURE
;
3782 // Hold a reference to the ESM in case event dispatch tears us down.
3783 nsCOMPtr
<nsIEventStateManager
> esm
= mPresContext
->EventStateManager();
3785 if (aAnchorName
.IsEmpty()) {
3786 NS_ASSERTION(!aScroll
, "can't scroll to empty anchor name");
3787 esm
->SetContentState(nsnull
, NS_EVENT_STATE_URLTARGET
);
3791 nsCOMPtr
<nsIDOMHTMLDocument
> htmlDoc
= do_QueryInterface(mDocument
);
3792 nsresult rv
= NS_OK
;
3793 nsCOMPtr
<nsIContent
> content
;
3795 // Search for an element with a matching "id" attribute
3797 content
= mDocument
->GetElementById(aAnchorName
);
3800 // Search for an anchor element with a matching "name" attribute
3801 if (!content
&& htmlDoc
) {
3802 nsCOMPtr
<nsIDOMNodeList
> list
;
3803 // Find a matching list of named nodes
3804 rv
= htmlDoc
->GetElementsByName(aAnchorName
, getter_AddRefs(list
));
3805 if (NS_SUCCEEDED(rv
) && list
) {
3807 // Loop through the named nodes looking for the first anchor
3808 for (i
= 0; PR_TRUE
; i
++) {
3809 nsCOMPtr
<nsIDOMNode
> node
;
3810 rv
= list
->Item(i
, getter_AddRefs(node
));
3811 if (!node
) { // End of list
3814 // Ensure it's an anchor element
3815 content
= do_QueryInterface(node
);
3817 if (content
->Tag() == nsGkAtoms::a
&& content
->IsHTML()) {
3826 // Search for anchor in the HTML namespace with a matching name
3827 if (!content
&& !htmlDoc
)
3829 nsCOMPtr
<nsIDOMDocument
> doc
= do_QueryInterface(mDocument
);
3830 nsCOMPtr
<nsIDOMNodeList
> list
;
3831 NS_NAMED_LITERAL_STRING(nameSpace
, "http://www.w3.org/1999/xhtml");
3832 // Get the list of anchor elements
3833 rv
= doc
->GetElementsByTagNameNS(nameSpace
, NS_LITERAL_STRING("a"), getter_AddRefs(list
));
3834 if (NS_SUCCEEDED(rv
) && list
) {
3836 // Loop through the named nodes looking for the first anchor
3837 for (i
= 0; PR_TRUE
; i
++) {
3838 nsCOMPtr
<nsIDOMNode
> node
;
3839 rv
= list
->Item(i
, getter_AddRefs(node
));
3840 if (!node
) { // End of list
3843 // Compare the name attribute
3844 nsCOMPtr
<nsIDOMElement
> element
= do_QueryInterface(node
);
3846 if (element
&& NS_SUCCEEDED(element
->GetAttribute(NS_LITERAL_STRING("name"), value
))) {
3847 if (value
.Equals(aAnchorName
)) {
3848 content
= do_QueryInterface(element
);
3856 nsCOMPtr
<nsIDOMRange
> jumpToRange
;
3857 nsCOMPtr
<nsIXPointerResult
> xpointerResult
;
3859 nsCOMPtr
<nsIDOMXMLDocument
> xmldoc
= do_QueryInterface(mDocument
);
3862 xmldoc
->EvaluateXPointer(aAnchorName
, getter_AddRefs(xpointerResult
));
3863 if (xpointerResult
) {
3864 xpointerResult
->Item(0, getter_AddRefs(jumpToRange
));
3866 // We know it was an XPointer, so there is no point in
3867 // trying any other pointer types, let's just return
3869 return NS_ERROR_FAILURE
;
3873 // Finally try FIXptr
3875 xmldoc
->EvaluateFIXptr(aAnchorName
,getter_AddRefs(jumpToRange
));
3879 nsCOMPtr
<nsIDOMNode
> node
;
3880 jumpToRange
->GetStartContainer(getter_AddRefs(node
));
3883 node
->GetNodeType(&nodeType
);
3884 PRInt32 offset
= -1;
3885 jumpToRange
->GetStartOffset(&offset
);
3887 case nsIDOMNode::ATTRIBUTE_NODE
:
3889 // XXX Assuming jumping to the ownerElement is the sanest action.
3890 nsCOMPtr
<nsIAttribute
> attr
= do_QueryInterface(node
);
3891 content
= attr
->GetContent();
3894 case nsIDOMNode::DOCUMENT_NODE
:
3897 nsCOMPtr
<nsIDocument
> document
= do_QueryInterface(node
);
3898 content
= document
->GetChildAt(offset
);
3902 case nsIDOMNode::DOCUMENT_FRAGMENT_NODE
:
3903 case nsIDOMNode::ELEMENT_NODE
:
3904 case nsIDOMNode::ENTITY_REFERENCE_NODE
:
3907 nsCOMPtr
<nsIContent
> parent
= do_QueryInterface(node
);
3908 content
= parent
->GetChildAt(offset
);
3912 case nsIDOMNode::CDATA_SECTION_NODE
:
3913 case nsIDOMNode::COMMENT_NODE
:
3914 case nsIDOMNode::TEXT_NODE
:
3915 case nsIDOMNode::PROCESSING_INSTRUCTION_NODE
:
3917 // XXX This should scroll to a specific position in the text.
3918 content
= do_QueryInterface(node
);
3927 esm
->SetContentState(content
, NS_EVENT_STATE_URLTARGET
);
3929 #ifdef ACCESSIBILITY
3930 nsIContent
*anchorTarget
= content
;
3935 rv
= ScrollContentIntoView(content
, NS_PRESSHELL_SCROLL_TOP
,
3936 NS_PRESSHELL_SCROLL_ANYWHERE
,
3937 SCROLL_OVERFLOW_HIDDEN
);
3938 NS_ENSURE_SUCCESS(rv
, rv
);
3940 nsIScrollableFrame
* rootScroll
= GetRootScrollFrameAsScrollable();
3942 mLastAnchorScrolledTo
= content
;
3943 mLastAnchorScrollPositionY
= rootScroll
->GetScrollPosition().y
;
3947 // Should we select the target? This action is controlled by a
3948 // preference: the default is to not select.
3949 PRBool selectAnchor
= nsContentUtils::GetBoolPref("layout.selectanchor");
3951 // Even if select anchor pref is false, we must still move the
3952 // caret there. That way tabbing will start from the new
3955 jumpToRange
= do_CreateInstance(kRangeCID
);
3957 while (content
&& content
->GetChildCount() > 0) {
3958 content
= content
->GetChildAt(0);
3960 nsCOMPtr
<nsIDOMNode
> node(do_QueryInterface(content
));
3961 NS_ASSERTION(node
, "No nsIDOMNode for descendant of anchor");
3962 jumpToRange
->SelectNodeContents(node
);
3966 // Select the anchor
3967 nsISelection
* sel
= mSelection
->
3968 GetSelection(nsISelectionController::SELECTION_NORMAL
);
3970 sel
->RemoveAllRanges();
3971 sel
->AddRange(jumpToRange
);
3972 if (!selectAnchor
) {
3973 // Use a caret (collapsed selection) at the start of the anchor
3974 sel
->CollapseToStart();
3978 if (selectAnchor
&& xpointerResult
) {
3979 // Select the rest (if any) of the ranges in XPointerResult
3981 xpointerResult
->GetLength(&count
);
3982 for (i
= 1; i
< count
; i
++) { // jumpToRange is i = 0
3983 nsCOMPtr
<nsIDOMRange
> range
;
3984 xpointerResult
->Item(i
, getter_AddRefs(range
));
3985 sel
->AddRange(range
);
3988 // Selection is at anchor.
3989 // Now focus the document itself if focus is on an element within it.
3990 nsPIDOMWindow
*win
= mDocument
->GetWindow();
3992 nsIFocusManager
* fm
= nsFocusManager::GetFocusManager();
3994 nsCOMPtr
<nsIDOMWindow
> focusedWindow
;
3995 fm
->GetFocusedWindow(getter_AddRefs(focusedWindow
));
3996 if (SameCOMIdentity(win
, focusedWindow
))
3997 fm
->ClearFocus(focusedWindow
);
4001 rv
= NS_ERROR_FAILURE
; //changed to NS_OK in quirks mode if ScrollTo is called
4003 // Scroll to the top/left if the anchor can not be
4004 // found and it is labelled top (quirks mode only). @see bug 80784
4005 if ((NS_LossyConvertUTF16toASCII(aAnchorName
).LowerCaseEqualsLiteral("top")) &&
4006 (mPresContext
->CompatibilityMode() == eCompatibility_NavQuirks
)) {
4008 nsIScrollableFrame
* sf
= GetRootScrollFrameAsScrollable();
4009 // Check |aScroll| after setting |rv| so we set |rv| to the same
4010 // thing whether or not |aScroll| is true.
4011 if (aScroll
&& sf
) {
4012 // Scroll to the top of the page
4013 sf
->ScrollTo(nsPoint(0, 0), nsIScrollableFrame::INSTANT
);
4018 #ifdef ACCESSIBILITY
4019 if (anchorTarget
&& gIsAccessibilityActive
) {
4020 nsCOMPtr
<nsIAccessibilityService
> accService
=
4021 do_GetService("@mozilla.org/accessibilityService;1");
4023 accService
->NotifyOfAnchorJumpTo(anchorTarget
);
4031 PresShell::ScrollToAnchor()
4033 if (!mLastAnchorScrolledTo
)
4036 NS_ASSERTION(mDidInitialReflow
, "should have done initial reflow by now");
4038 nsIScrollableFrame
* rootScroll
= GetRootScrollFrameAsScrollable();
4040 mLastAnchorScrollPositionY
!= rootScroll
->GetScrollPosition().y
)
4043 nsresult rv
= ScrollContentIntoView(mLastAnchorScrolledTo
, NS_PRESSHELL_SCROLL_TOP
,
4044 NS_PRESSHELL_SCROLL_ANYWHERE
,
4045 SCROLL_OVERFLOW_HIDDEN
);
4046 mLastAnchorScrolledTo
= nsnull
;
4051 * Helper (per-continuation) for ScrollContentIntoView.
4053 * @param aContainerFrame [in] the frame which aRect is relative to
4054 * @param aFrame [in] Frame whose bounds should be unioned
4055 * @param aUseWholeLineHeightForInlines [in] if true, then for inline frames
4056 * we should include the top of the line in the added rectangle
4057 * @param aRect [inout] rect into which its bounds should be unioned
4058 * @param aHaveRect [inout] whether aRect contains data yet
4061 AccumulateFrameBounds(nsIFrame
* aContainerFrame
,
4063 PRBool aUseWholeLineHeightForInlines
,
4067 nsRect frameBounds
= aFrame
->GetRect() +
4068 aFrame
->GetParent()->GetOffsetTo(aContainerFrame
);
4070 // If this is an inline frame and either the bounds height is 0 (quirks
4071 // layout model) or aUseWholeLineHeightForInlines is set, we need to
4072 // change the top of the bounds to include the whole line.
4073 if (frameBounds
.height
== 0 || aUseWholeLineHeightForInlines
) {
4074 nsIAtom
* frameType
= NULL
;
4075 nsIFrame
*prevFrame
= aFrame
;
4076 nsIFrame
*f
= aFrame
;
4079 (frameType
= f
->GetType()) == nsGkAtoms::inlineFrame
) {
4081 f
= prevFrame
->GetParent();
4086 frameType
== nsGkAtoms::blockFrame
) {
4087 // find the line containing aFrame and increase the top of |offset|.
4088 nsAutoLineIterator lines
= f
->GetLineIterator();
4090 PRInt32 index
= lines
->FindLineContaining(prevFrame
);
4097 if (NS_SUCCEEDED(lines
->GetLine(index
, &trash1
, &trash2
,
4098 lineBounds
, &trash3
))) {
4099 lineBounds
+= f
->GetOffsetTo(aContainerFrame
);
4100 if (lineBounds
.y
< frameBounds
.y
) {
4101 frameBounds
.height
= frameBounds
.YMost() - lineBounds
.y
;
4102 frameBounds
.y
= lineBounds
.y
;
4111 // We can't use nsRect::UnionRect since it drops empty rects on
4112 // the floor, and we need to include them. (Thus we need
4113 // aHaveRect to know when to drop the initial value on the floor.)
4114 aRect
.UnionRectIncludeEmpty(aRect
, frameBounds
);
4116 aHaveRect
= PR_TRUE
;
4117 aRect
= frameBounds
;
4122 * This function takes a scrollable frame, a rect in the coordinate system
4123 * of the scrolled frame, and a desired percentage-based scroll
4124 * position and attempts to scroll the rect to that position in the
4127 * This needs to work even if aRect has a width or height of zero.
4129 static void ScrollToShowRect(nsIScrollableFrame
* aScrollFrame
,
4130 const nsRect
& aRect
,
4135 nsPoint scrollPt
= aScrollFrame
->GetScrollPosition();
4136 nsRect
visibleRect(scrollPt
, aScrollFrame
->GetScrollPortRect().Size());
4137 nsSize lineSize
= aScrollFrame
->GetLineScrollAmount();
4138 nsPresContext::ScrollbarStyles ss
= aScrollFrame
->GetScrollbarStyles();
4140 if ((aFlags
& nsIPresShell::SCROLL_OVERFLOW_HIDDEN
) ||
4141 ss
.mVertical
!= NS_STYLE_OVERFLOW_HIDDEN
) {
4142 // See how the rect should be positioned vertically
4143 if (NS_PRESSHELL_SCROLL_ANYWHERE
== aVPercent
||
4144 (NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE
== aVPercent
&&
4145 aRect
.height
< lineSize
.height
)) {
4146 // The caller doesn't care where the frame is positioned vertically,
4147 // so long as it's fully visible
4148 if (aRect
.y
< visibleRect
.y
) {
4149 // Scroll up so the frame's top edge is visible
4150 scrollPt
.y
= aRect
.y
;
4151 } else if (aRect
.YMost() > visibleRect
.YMost()) {
4152 // Scroll down so the frame's bottom edge is visible. Make sure the
4153 // frame's top edge is still visible
4154 scrollPt
.y
+= aRect
.YMost() - visibleRect
.YMost();
4155 if (scrollPt
.y
> aRect
.y
) {
4156 scrollPt
.y
= aRect
.y
;
4159 } else if (NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE
== aVPercent
) {
4160 // Scroll only if no part of the frame is visible in this view
4161 if (aRect
.YMost() - lineSize
.height
< visibleRect
.y
) {
4162 // Scroll up so the frame's top edge is visible
4163 scrollPt
.y
= aRect
.y
;
4164 } else if (aRect
.y
+ lineSize
.height
> visibleRect
.YMost()) {
4165 // Scroll down so the frame's bottom edge is visible. Make sure the
4166 // frame's top edge is still visible
4167 scrollPt
.y
+= aRect
.YMost() - visibleRect
.YMost();
4168 if (scrollPt
.y
> aRect
.y
) {
4169 scrollPt
.y
= aRect
.y
;
4173 // Align the frame edge according to the specified percentage
4174 nscoord frameAlignY
=
4175 NSToCoordRound(aRect
.y
+ aRect
.height
* (aVPercent
/ 100.0f
));
4177 NSToCoordRound(frameAlignY
- visibleRect
.height
* (aVPercent
/ 100.0f
));
4181 if ((aFlags
& nsIPresShell::SCROLL_OVERFLOW_HIDDEN
) ||
4182 ss
.mHorizontal
!= NS_STYLE_OVERFLOW_HIDDEN
) {
4183 // See how the frame should be positioned horizontally
4184 if (NS_PRESSHELL_SCROLL_ANYWHERE
== aHPercent
||
4185 (NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE
== aHPercent
&&
4186 aRect
.width
< lineSize
.width
)) {
4187 // The caller doesn't care where the frame is positioned horizontally,
4188 // so long as it's fully visible
4189 if (aRect
.x
< visibleRect
.x
) {
4190 // Scroll left so the frame's left edge is visible
4191 scrollPt
.x
= aRect
.x
;
4192 } else if (aRect
.XMost() > visibleRect
.XMost()) {
4193 // Scroll right so the frame's right edge is visible. Make sure the
4194 // frame's left edge is still visible
4195 scrollPt
.x
+= aRect
.XMost() - visibleRect
.XMost();
4196 if (scrollPt
.x
> aRect
.x
) {
4197 scrollPt
.x
= aRect
.x
;
4200 } else if (NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE
== aHPercent
) {
4201 // Scroll only if no part of the frame is visible in this view
4202 if (aRect
.XMost() - lineSize
.width
< visibleRect
.x
) {
4203 // Scroll left so the frame's left edge is visible
4204 scrollPt
.x
= aRect
.x
;
4205 } else if (aRect
.x
+ lineSize
.width
> visibleRect
.XMost()) {
4206 // Scroll right so the frame's right edge is visible. Make sure the
4207 // frame's left edge is still visible
4208 scrollPt
.x
+= aRect
.XMost() - visibleRect
.XMost();
4209 if (scrollPt
.x
> aRect
.x
) {
4210 scrollPt
.x
= aRect
.x
;
4214 // Align the frame edge according to the specified percentage
4215 nscoord frameAlignX
=
4216 NSToCoordRound(aRect
.x
+ (aRect
.width
) * (aHPercent
/ 100.0f
));
4218 NSToCoordRound(frameAlignX
- visibleRect
.width
* (aHPercent
/ 100.0f
));
4222 aScrollFrame
->ScrollTo(scrollPt
, nsIScrollableFrame::INSTANT
);
4226 PresShell::ScrollContentIntoView(nsIContent
* aContent
,
4231 nsCOMPtr
<nsIContent
> content
= aContent
; // Keep content alive while flushing.
4232 NS_ENSURE_TRUE(content
, NS_ERROR_NULL_POINTER
);
4233 nsCOMPtr
<nsIDocument
> currentDoc
= content
->GetCurrentDoc();
4234 NS_ENSURE_STATE(currentDoc
);
4236 NS_ASSERTION(mDidInitialReflow
, "should have done initial reflow by now");
4238 mContentToScrollTo
= aContent
;
4239 mContentScrollVPosition
= aVPercent
;
4240 mContentScrollHPosition
= aHPercent
;
4242 // Flush layout and attempt to scroll in the process.
4243 currentDoc
->FlushPendingNotifications(Flush_InterruptibleLayout
);
4245 // If mContentToScrollTo is non-null, that means we interrupted the reflow
4246 // (or suppressed it altogether because we're suppressing interruptible
4247 // flushes right now) and won't necessarily get the position correct, but do
4248 // a best-effort scroll here. The other option would be to do this inside
4249 // FlushPendingNotifications, but I'm not sure the repeated scrolling that
4250 // could trigger if reflows keep getting interrupted would be more desirable
4251 // than a single best-effort scroll followed by one final scroll on the first
4252 // completed reflow.
4253 if (mContentToScrollTo
) {
4254 DoScrollContentIntoView(content
, aVPercent
, aHPercent
, aFlags
);
4260 PresShell::DoScrollContentIntoView(nsIContent
* aContent
,
4265 NS_ASSERTION(mDidInitialReflow
, "should have done initial reflow by now");
4267 nsIFrame
* frame
= aContent
->GetPrimaryFrame();
4269 mContentToScrollTo
= nsnull
;
4273 if (frame
->GetStateBits() & NS_FRAME_FIRST_REFLOW
) {
4274 // The reflow flush before this scroll got interrupted, and this frame's
4275 // coords and size are all zero, and it has no content showing anyway.
4276 // Don't bother scrolling to it. We'll try again when we finish up layout.
4280 nsIFrame
* container
=
4281 nsLayoutUtils::GetClosestFrameOfType(frame
, nsGkAtoms::scrollFrame
);
4283 // nothing can be scrolled
4287 // This is a two-step process.
4288 // Step 1: Find the bounds of the rect we want to scroll into view. For
4289 // example, for an inline frame we may want to scroll in the whole
4290 // line, or we may want to scroll multiple lines into view.
4291 // Step 2: Walk container frame and its ancestors and scroll them
4293 // frameBounds is relative to container. We're assuming
4294 // that scrollframes don't split so every continuation of frame will
4295 // be a descendant of container. (Things would still mostly work
4296 // even if that assumption was false.)
4298 PRBool haveRect
= PR_FALSE
;
4299 PRBool useWholeLineHeightForInlines
= aVPercent
!= NS_PRESSHELL_SCROLL_ANYWHERE
;
4301 AccumulateFrameBounds(container
, frame
, useWholeLineHeightForInlines
,
4302 frameBounds
, haveRect
);
4303 } while ((frame
= frame
->GetNextContinuation()));
4305 ScrollFrameRectIntoView(container
, frameBounds
, aVPercent
, aHPercent
,
4310 PresShell::ScrollFrameRectIntoView(nsIFrame
* aFrame
,
4311 const nsRect
& aRect
,
4316 PRBool didScroll
= PR_FALSE
;
4317 // This function needs to work even if rect has a width or height of 0.
4318 nsRect rect
= aRect
;
4319 nsIFrame
* container
= aFrame
;
4320 // Walk up the frame hierarchy scrolling the rect into view and
4321 // keeping rect relative to container
4323 nsIScrollableFrame
* sf
= do_QueryFrame(container
);
4325 nsPoint oldPosition
= sf
->GetScrollPosition();
4326 ScrollToShowRect(sf
, rect
- sf
->GetScrolledFrame()->GetPosition(),
4327 aVPercent
, aHPercent
, aFlags
);
4328 nsPoint newPosition
= sf
->GetScrollPosition();
4329 // If the scroll position increased, that means our content moved up,
4330 // so our rect's offset should decrease
4331 rect
+= oldPosition
- newPosition
;
4333 if (oldPosition
!= newPosition
) {
4334 didScroll
= PR_TRUE
;
4337 // only scroll one container when this flag is set
4338 if (aFlags
& nsIPresShell::SCROLL_FIRST_ANCESTOR_ONLY
) {
4342 nsRect scrollPort
= sf
->GetScrollPortRect();
4343 if (rect
.XMost() < scrollPort
.x
||
4344 rect
.x
> scrollPort
.XMost() ||
4345 rect
.YMost() < scrollPort
.y
||
4346 rect
.y
> scrollPort
.YMost()) {
4347 // We tried to show the rectangle, but none of it is visible,
4348 // not even an edge.
4349 // Stop trying to scroll ancestors into view.
4353 // Restrict rect to the area that is actually visible through
4354 // the scrollport. We don't want to try to scroll some clipped-out
4355 // part of 'rect' into view in some ancestor.
4356 rect
.IntersectRect(rect
, sf
->GetScrollPortRect());
4358 rect
+= container
->GetPosition();
4359 nsIFrame
* parent
= container
->GetParent();
4361 nsPoint
extraOffset(0,0);
4362 parent
= nsLayoutUtils::GetCrossDocParentFrame(container
, &extraOffset
);
4364 PRInt32 APD
= container
->PresContext()->AppUnitsPerDevPixel();
4365 PRInt32 parentAPD
= parent
->PresContext()->AppUnitsPerDevPixel();
4366 rect
= rect
.ConvertAppUnitsRoundOut(APD
, parentAPD
);
4367 rect
+= extraOffset
;
4371 } while (container
);
4377 PresShell::GetRectVisibility(nsIFrame
* aFrame
,
4378 const nsRect
&aRect
,
4379 nscoord aMinTwips
) const
4381 NS_ASSERTION(aFrame
->PresContext() == GetPresContext(),
4382 "prescontext mismatch?");
4383 nsIFrame
* rootFrame
= FrameManager()->GetRootFrame();
4384 NS_ASSERTION(rootFrame
,
4385 "How can someone have a frame for this presshell when there's no root?");
4386 nsIScrollableFrame
* sf
= GetRootScrollFrameAsScrollable();
4387 nsRect scrollPortRect
;
4389 scrollPortRect
= sf
->GetScrollPortRect();
4390 nsIFrame
* f
= do_QueryFrame(sf
);
4391 scrollPortRect
+= f
->GetOffsetTo(rootFrame
);
4393 scrollPortRect
= nsRect(nsPoint(0,0), rootFrame
->GetSize());
4396 nsRect r
= aRect
+ aFrame
->GetOffsetTo(rootFrame
);
4397 // If aRect is entirely visible then we don't need to ensure that
4398 // at least aMinTwips of it is visible
4399 if (scrollPortRect
.Contains(r
))
4400 return nsRectVisibility_kVisible
;
4402 nsRect insetRect
= scrollPortRect
;
4403 insetRect
.Deflate(aMinTwips
, aMinTwips
);
4404 if (r
.YMost() <= insetRect
.y
)
4405 return nsRectVisibility_kAboveViewport
;
4406 if (r
.y
>= insetRect
.YMost())
4407 return nsRectVisibility_kBelowViewport
;
4408 if (r
.XMost() <= insetRect
.x
)
4409 return nsRectVisibility_kLeftOfViewport
;
4410 if (r
.x
>= insetRect
.XMost())
4411 return nsRectVisibility_kRightOfViewport
;
4413 return nsRectVisibility_kVisible
;
4416 // GetLinkLocation: copy link location to clipboard
4417 nsresult
PresShell::GetLinkLocation(nsIDOMNode
* aNode
, nsAString
& aLocationString
) const
4420 printf("dr :: PresShell::GetLinkLocation\n");
4423 NS_ENSURE_ARG_POINTER(aNode
);
4425 nsAutoString anchorText
;
4426 static char strippedChars
[] = {'\t','\r','\n'};
4428 // are we an anchor?
4429 nsCOMPtr
<nsIDOMHTMLAnchorElement
> anchor(do_QueryInterface(aNode
));
4430 nsCOMPtr
<nsIDOMHTMLAreaElement
> area
;
4431 nsCOMPtr
<nsIDOMHTMLLinkElement
> link
;
4432 nsAutoString xlinkType
;
4434 rv
= anchor
->GetHref(anchorText
);
4435 NS_ENSURE_SUCCESS(rv
, rv
);
4438 area
= do_QueryInterface(aNode
);
4440 rv
= area
->GetHref(anchorText
);
4441 NS_ENSURE_SUCCESS(rv
, rv
);
4444 link
= do_QueryInterface(aNode
);
4446 rv
= link
->GetHref(anchorText
);
4447 NS_ENSURE_SUCCESS(rv
, rv
);
4450 nsCOMPtr
<nsIDOMElement
> element(do_QueryInterface(aNode
));
4452 NS_NAMED_LITERAL_STRING(xlinkNS
,"http://www.w3.org/1999/xlink");
4453 element
->GetAttributeNS(xlinkNS
,NS_LITERAL_STRING("type"),xlinkType
);
4454 if (xlinkType
.EqualsLiteral("simple")) {
4455 element
->GetAttributeNS(xlinkNS
,NS_LITERAL_STRING("href"),anchorText
);
4456 if (!anchorText
.IsEmpty()) {
4457 // Resolve the full URI using baseURI property
4460 nsCOMPtr
<nsIDOM3Node
> node(do_QueryInterface(aNode
,&rv
));
4461 NS_ENSURE_SUCCESS(rv
, rv
);
4462 node
->GetBaseURI(base
);
4464 nsCOMPtr
<nsIIOService
>
4465 ios(do_GetService("@mozilla.org/network/io-service;1", &rv
));
4466 NS_ENSURE_SUCCESS(rv
, rv
);
4468 nsCOMPtr
<nsIURI
> baseURI
;
4469 rv
= ios
->NewURI(NS_ConvertUTF16toUTF8(base
),nsnull
,nsnull
,getter_AddRefs(baseURI
));
4470 NS_ENSURE_SUCCESS(rv
, rv
);
4473 rv
= baseURI
->Resolve(NS_ConvertUTF16toUTF8(anchorText
),spec
);
4474 NS_ENSURE_SUCCESS(rv
, rv
);
4476 CopyUTF8toUTF16(spec
, anchorText
);
4484 if (anchor
|| area
|| link
|| xlinkType
.EqualsLiteral("simple")) {
4485 //Remove all the '\t', '\r' and '\n' from 'anchorText'
4486 anchorText
.StripChars(strippedChars
);
4488 aLocationString
= anchorText
;
4493 // if no link, fail.
4494 return NS_ERROR_FAILURE
;
4497 NS_IMETHODIMP_(void)
4498 PresShell::DispatchSynthMouseMove(nsGUIEvent
*aEvent
,
4499 PRBool aFlushOnHoverChange
)
4501 PRUint32 hoverGenerationBefore
= mFrameConstructor
->GetHoverGeneration();
4502 nsEventStatus status
;
4503 nsIView
* targetView
= nsIView::GetViewFor(aEvent
->widget
);
4504 targetView
->GetViewManager()->DispatchEvent(aEvent
, targetView
, &status
);
4505 if (aFlushOnHoverChange
&&
4506 hoverGenerationBefore
!= mFrameConstructor
->GetHoverGeneration()) {
4507 // Flush so that the resulting reflow happens now so that our caller
4508 // can suppress any synthesized mouse moves caused by that reflow.
4509 FlushPendingNotifications(Flush_Layout
);
4513 NS_IMETHODIMP_(void)
4514 PresShell::ClearMouseCapture(nsIView
* aView
)
4516 if (gCaptureInfo
.mContent
) {
4518 // if a view was specified, ensure that the captured content is within
4520 nsIFrame
* frame
= gCaptureInfo
.mContent
->GetPrimaryFrame();
4522 nsIView
* view
= frame
->GetClosestView();
4523 // if there is no view, capturing won't be handled any more, so
4524 // just release the capture.
4527 if (view
== aView
) {
4528 NS_RELEASE(gCaptureInfo
.mContent
);
4529 // the view containing the captured content likely disappeared so
4530 // disable capture for now.
4531 gCaptureInfo
.mAllowed
= PR_FALSE
;
4535 view
= view
->GetParent();
4537 // return if the view wasn't found
4543 NS_RELEASE(gCaptureInfo
.mContent
);
4546 // disable mouse capture until the next mousedown as a dialog has opened
4547 // or a drag has started. Otherwise, someone could start capture during
4548 // the modal dialog or drag.
4549 gCaptureInfo
.mAllowed
= PR_FALSE
;
4553 PresShell::CaptureHistoryState(nsILayoutHistoryState
** aState
, PRBool aLeavingPage
)
4555 NS_TIME_FUNCTION_MIN(1.0);
4557 nsresult rv
= NS_OK
;
4559 NS_PRECONDITION(nsnull
!= aState
, "null state pointer");
4561 // We actually have to mess with the docshell here, since we want to
4562 // store the state back in it.
4563 // XXXbz this isn't really right, since this is being called in the
4564 // content viewer's Hide() method... by that point the docshell's
4565 // state could be wrong. We should sort out a better ownership
4566 // model for the layout history state.
4567 nsCOMPtr
<nsISupports
> container
= mPresContext
->GetContainer();
4569 return NS_ERROR_FAILURE
;
4571 nsCOMPtr
<nsIDocShell
> docShell(do_QueryInterface(container
));
4573 return NS_ERROR_FAILURE
;
4575 nsCOMPtr
<nsILayoutHistoryState
> historyState
;
4576 docShell
->GetLayoutHistoryState(getter_AddRefs(historyState
));
4577 if (!historyState
) {
4578 // Create the document state object
4579 rv
= NS_NewLayoutHistoryState(getter_AddRefs(historyState
));
4581 if (NS_FAILED(rv
)) {
4586 docShell
->SetLayoutHistoryState(historyState
);
4589 *aState
= historyState
;
4590 NS_IF_ADDREF(*aState
);
4592 // Capture frame state for the entire frame hierarchy
4593 nsIFrame
* rootFrame
= FrameManager()->GetRootFrame();
4594 if (!rootFrame
) return NS_OK
;
4595 // Capture frame state for the root scroll frame
4596 // Don't capture state when first creating doc element hierarchy
4597 // As the scroll position is 0 and this will cause us to lose
4598 // our previously saved place!
4600 nsIFrame
* scrollFrame
= GetRootScrollFrame();
4602 FrameManager()->CaptureFrameStateFor(scrollFrame
, historyState
,
4603 nsIStatefulFrame::eDocumentScrollState
);
4607 FrameManager()->CaptureFrameState(rootFrame
, historyState
);
4613 PresShell::UnsuppressAndInvalidate()
4615 // Note: We ignore the EnsureVisible check for resource documents, because
4616 // they won't have a docshell, so they'll always fail EnsureVisible.
4617 if ((!mDocument
->IsResourceDoc() && !mPresContext
->EnsureVisible()) ||
4619 // No point; we're about to be torn down anyway.
4623 mPaintingSuppressed
= PR_FALSE
;
4624 nsIFrame
* rootFrame
= FrameManager()->GetRootFrame();
4626 // let's assume that outline on a root frame is not supported
4627 nsRect
rect(nsPoint(0, 0), rootFrame
->GetSize());
4628 rootFrame
->Invalidate(rect
);
4630 if (mCaretEnabled
&& mCaret
) {
4631 mCaret
->CheckCaretDrawingState();
4634 nsRootPresContext
* rootPC
= mPresContext
->GetRootPresContext();
4636 rootPC
->RequestUpdatePluginGeometry(rootFrame
);
4640 // now that painting is unsuppressed, focus may be set on the document
4641 nsPIDOMWindow
*win
= mDocument
->GetWindow();
4643 win
->SetReadyForFocus();
4646 SynthesizeMouseMove(PR_FALSE
);
4650 PresShell::UnsuppressPainting()
4652 if (mPaintSuppressionTimer
) {
4653 mPaintSuppressionTimer
->Cancel();
4654 mPaintSuppressionTimer
= nsnull
;
4657 if (mIsDocumentGone
|| !mPaintingSuppressed
)
4660 // If we have reflows pending, just wait until we process
4661 // the reflows and get all the frames where we want them
4662 // before actually unlocking the painting. Otherwise
4663 // go ahead and unlock now.
4664 if (mDirtyRoots
.Length() > 0)
4665 mShouldUnsuppressPainting
= PR_TRUE
;
4667 UnsuppressAndInvalidate();
4670 // Post a request to handle an arbitrary callback after reflow has finished.
4672 PresShell::PostReflowCallback(nsIReflowCallback
* aCallback
)
4674 void* result
= AllocateMisc(sizeof(nsCallbackEventRequest
));
4675 if (NS_UNLIKELY(!result
)) {
4676 return NS_ERROR_OUT_OF_MEMORY
;
4678 nsCallbackEventRequest
* request
= (nsCallbackEventRequest
*)result
;
4680 request
->callback
= aCallback
;
4681 request
->next
= nsnull
;
4683 if (mLastCallbackEventRequest
) {
4684 mLastCallbackEventRequest
= mLastCallbackEventRequest
->next
= request
;
4686 mFirstCallbackEventRequest
= request
;
4687 mLastCallbackEventRequest
= request
;
4694 PresShell::CancelReflowCallback(nsIReflowCallback
* aCallback
)
4696 nsCallbackEventRequest
* before
= nsnull
;
4697 nsCallbackEventRequest
* node
= mFirstCallbackEventRequest
;
4700 nsIReflowCallback
* callback
= node
->callback
;
4702 if (callback
== aCallback
)
4704 nsCallbackEventRequest
* toFree
= node
;
4705 if (node
== mFirstCallbackEventRequest
) {
4707 mFirstCallbackEventRequest
= node
;
4708 NS_ASSERTION(before
== nsnull
, "impossible");
4711 before
->next
= node
;
4714 if (toFree
== mLastCallbackEventRequest
) {
4715 mLastCallbackEventRequest
= before
;
4718 FreeMisc(sizeof(nsCallbackEventRequest
), toFree
);
4727 PresShell::CancelPostedReflowCallbacks()
4729 while (mFirstCallbackEventRequest
) {
4730 nsCallbackEventRequest
* node
= mFirstCallbackEventRequest
;
4731 mFirstCallbackEventRequest
= node
->next
;
4732 if (!mFirstCallbackEventRequest
) {
4733 mLastCallbackEventRequest
= nsnull
;
4735 nsIReflowCallback
* callback
= node
->callback
;
4736 FreeMisc(sizeof(nsCallbackEventRequest
), node
);
4738 callback
->ReflowCallbackCanceled();
4744 PresShell::HandlePostedReflowCallbacks(PRBool aInterruptible
)
4746 PRBool shouldFlush
= PR_FALSE
;
4748 while (mFirstCallbackEventRequest
) {
4749 nsCallbackEventRequest
* node
= mFirstCallbackEventRequest
;
4750 mFirstCallbackEventRequest
= node
->next
;
4751 if (!mFirstCallbackEventRequest
) {
4752 mLastCallbackEventRequest
= nsnull
;
4754 nsIReflowCallback
* callback
= node
->callback
;
4755 FreeMisc(sizeof(nsCallbackEventRequest
), node
);
4757 if (callback
->ReflowFinished()) {
4758 shouldFlush
= PR_TRUE
;
4763 mozFlushType flushType
=
4764 aInterruptible
? Flush_InterruptibleLayout
: Flush_Layout
;
4766 FlushPendingNotifications(flushType
);
4770 PresShell::IsSafeToFlush() const
4772 // Not safe if we are reflowing or in the middle of frame construction
4773 PRBool isSafeToFlush
= !mIsReflowing
&&
4776 if (isSafeToFlush
) {
4777 // Not safe if we are painting
4778 nsIViewManager
* viewManager
= GetViewManager();
4780 PRBool isPainting
= PR_FALSE
;
4781 viewManager
->IsPainting(isPainting
);
4783 isSafeToFlush
= PR_FALSE
;
4788 return isSafeToFlush
;
4793 PresShell::FlushPendingNotifications(mozFlushType aType
)
4795 #ifdef NS_FUNCTION_TIMER
4796 NS_TIME_FUNCTION_DECLARE_DOCURL
;
4797 static const char *flushTypeNames
[] = {
4799 "Flush_ContentAndNotify",
4801 "Flush_InterruptibleLayout",
4805 NS_TIME_FUNCTION_MIN_FMT(1.0, "%s (line %d) (document: %s, type: %s)", MOZ_FUNCTION_NAME
,
4806 __LINE__
, docURL__
.get(), flushTypeNames
[aType
- 1]);
4809 NS_ASSERTION(aType
>= Flush_Frames
, "Why did we get called?");
4811 PRBool isSafeToFlush
= IsSafeToFlush();
4813 // If layout could possibly trigger scripts, then it's only safe to flush if
4814 // it's safe to run script.
4815 if (mDocument
->GetScriptGlobalObject()) {
4816 isSafeToFlush
= isSafeToFlush
&& nsContentUtils::IsSafeToRunScript();
4819 NS_ASSERTION(!isSafeToFlush
|| mViewManager
, "Must have view manager");
4820 // Make sure the view manager stays alive while batching view updates.
4821 nsCOMPtr
<nsIViewManager
> viewManagerDeathGrip
= mViewManager
;
4822 if (isSafeToFlush
&& mViewManager
) {
4823 // Processing pending notifications can kill us, and some callers only
4824 // hold weak refs when calling FlushPendingNotifications(). :(
4825 nsCOMPtr
<nsIPresShell
> kungFuDeathGrip(this);
4827 if (mResizeEvent
.IsPending()) {
4829 if (mIsDestroying
) {
4834 // Style reresolves not in conjunction with reflows can't cause
4835 // painting or geometry changes, so don't bother with view update
4836 // batching if we only have style reresolve
4837 nsIViewManager::UpdateViewBatch
batch(mViewManager
);
4839 // We need to make sure external resource documents are flushed too (for
4840 // example, svg filters that reference a filter in an external document
4841 // need the frames in the external document to be constructed for the
4842 // filter to work). We only need external resources to be flushed when the
4843 // main document is flushing >= Flush_Frames, so we flush external
4844 // resources here instead of nsDocument::FlushPendingNotifications.
4845 mDocument
->FlushExternalResources(aType
);
4847 // Force flushing of any pending content notifications that might have
4848 // queued up while our event was pending. That will ensure that we don't
4849 // construct frames for content right now that's still waiting to be
4851 mDocument
->FlushPendingNotifications(Flush_ContentAndNotify
);
4853 // Process pending restyles, since any flush of the presshell wants
4854 // up-to-date style data.
4855 if (!mIsDestroying
) {
4856 mViewManager
->FlushDelayedResize(PR_FALSE
);
4857 mPresContext
->FlushPendingMediaFeatureValuesChanged();
4859 // Flush any pending update of the user font set, since that could
4860 // cause style changes (for updating ex/ch units, and to cause a
4862 mPresContext
->FlushUserFontSet();
4865 // Flush any requested SMIL samples.
4866 if (mDocument
->HasAnimationController()) {
4867 mDocument
->GetAnimationController()->FlushResampleRequests();
4871 nsAutoScriptBlocker scriptBlocker
;
4872 mFrameConstructor
->CreateNeededFrames();
4873 mFrameConstructor
->ProcessPendingRestyles();
4876 // Process whatever XBL constructors those restyles queued up. This
4877 // ensures that onload doesn't fire too early and that we won't do extra
4878 // reflows after those constructors run.
4879 if (!mIsDestroying
) {
4880 mDocument
->BindingManager()->ProcessAttachedQueue();
4883 // Now those constructors might have posted restyle events. At the same
4884 // time, we still need up-to-date style data. In particular, reflow
4885 // depends on style being completely up to date. If it's not, then style
4886 // context reparenting, which can happen during reflow, might suddenly pick
4887 // up the new rules and we'll end up with frames whose style doesn't match
4889 if (!mIsDestroying
) {
4890 nsAutoScriptBlocker scriptBlocker
;
4891 mFrameConstructor
->CreateNeededFrames();
4892 mFrameConstructor
->ProcessPendingRestyles();
4896 // There might be more pending constructors now, but we're not going to
4897 // worry about them. They can't be triggered during reflow, so we should
4900 if (aType
>= (mSuppressInterruptibleReflows
? Flush_Layout
: Flush_InterruptibleLayout
) &&
4902 mFrameConstructor
->RecalcQuotesAndCounters();
4903 mViewManager
->FlushDelayedResize(PR_TRUE
);
4904 if (ProcessReflowCommands(aType
< Flush_Layout
) && mContentToScrollTo
) {
4905 // We didn't get interrupted. Go ahead and scroll to our content
4906 DoScrollContentIntoView(mContentToScrollTo
, mContentScrollVPosition
,
4907 mContentScrollHPosition
,
4908 SCROLL_OVERFLOW_HIDDEN
);
4909 mContentToScrollTo
= nsnull
;
4913 if (aType
>= Flush_Layout
) {
4914 // Flush plugin geometry. Don't flush plugin geometry for
4915 // interruptible layouts, since WillPaint does an interruptible
4917 nsRootPresContext
* rootPresContext
= mPresContext
->GetRootPresContext();
4918 if (rootPresContext
) {
4919 rootPresContext
->UpdatePluginGeometry();
4923 PRUint32 updateFlags
= NS_VMREFRESH_NO_SYNC
;
4924 if (aType
>= Flush_Display
) {
4925 // Flushing paints, so perform the invalidates and drawing
4927 updateFlags
= NS_VMREFRESH_IMMEDIATE
;
4929 batch
.EndUpdateViewBatch(updateFlags
);
4934 PresShell::CharacterDataChanged(nsIDocument
*aDocument
,
4935 nsIContent
* aContent
,
4936 CharacterDataChangeInfo
* aInfo
)
4938 NS_PRECONDITION(!mIsDocumentGone
, "Unexpected CharacterDataChanged");
4939 NS_PRECONDITION(aDocument
== mDocument
, "Unexpected aDocument");
4941 nsAutoCauseReflowNotifier
crNotifier(this);
4944 // Invalidate the caret's current location before we call into the frame
4945 // constructor. It is important to do this now, and not wait until the
4946 // resulting reflow, because this call causes continuation frames of the
4947 // text frame the caret is in to forget what part of the content they
4948 // refer to, making it hard for them to return the correct continuation
4949 // frame to the caret.
4950 mCaret
->InvalidateOutsideCaret();
4953 // Call this here so it only happens for real content mutations and
4954 // not cases when the frame constructor calls its own methods to force
4955 // frame reconstruction.
4956 nsIContent
*container
= aContent
->GetParent();
4957 PRUint32 selectorFlags
=
4958 container
? (container
->GetFlags() & NODE_ALL_SELECTOR_FLAGS
) : 0;
4959 if (selectorFlags
!= 0 && !aContent
->IsRootOfAnonymousSubtree()) {
4960 Element
* element
= container
->AsElement();
4961 if (aInfo
->mAppend
&& !aContent
->GetNextSibling())
4962 mFrameConstructor
->RestyleForAppend(element
, aContent
);
4964 mFrameConstructor
->RestyleForInsertOrChange(element
, aContent
);
4967 mFrameConstructor
->CharacterDataChanged(aContent
, aInfo
);
4972 PresShell::ContentStatesChanged(nsIDocument
* aDocument
,
4973 nsIContent
* aContent1
,
4974 nsIContent
* aContent2
,
4975 nsEventStates aStateMask
)
4977 NS_PRECONDITION(!mIsDocumentGone
, "Unexpected ContentStatesChanged");
4978 NS_PRECONDITION(aDocument
== mDocument
, "Unexpected aDocument");
4980 if (mDidInitialReflow
) {
4981 nsAutoCauseReflowNotifier
crNotifier(this);
4982 mFrameConstructor
->ContentStatesChanged(aContent1
, aContent2
, aStateMask
);
4988 PresShell::DocumentStatesChanged(nsIDocument
* aDocument
,
4989 nsEventStates aStateMask
)
4991 NS_PRECONDITION(!mIsDocumentGone
, "Unexpected DocumentStatesChanged");
4992 NS_PRECONDITION(aDocument
== mDocument
, "Unexpected aDocument");
4994 if (mDidInitialReflow
&&
4995 mStyleSet
->HasDocumentStateDependentStyle(mPresContext
,
4996 mDocument
->GetRootElement(),
4998 mFrameConstructor
->PostRestyleEvent(mDocument
->GetRootElement(),
4999 eRestyle_Subtree
, NS_STYLE_HINT_NONE
);
5003 if (aStateMask
.HasState(NS_DOCUMENT_STATE_WINDOW_INACTIVE
)) {
5004 nsIFrame
* root
= FrameManager()->GetRootFrame();
5006 // It's a display root. So, invalidate the layer contents of
5007 // everything we can find. We need to do this because the contents
5008 // of controls etc can depend on whether the window is active,
5009 // and when a window becomes (in)active it just gets repainted
5010 // and we don't specifically invalidate each affected control.
5011 nsIWidget
* widget
= root
->GetNearestWidget();
5013 LayerManager
* layerManager
= widget
->GetLayerManager();
5015 FrameLayerBuilder::InvalidateAllThebesLayerContents(layerManager
);
5023 PresShell::AttributeWillChange(nsIDocument
* aDocument
,
5025 PRInt32 aNameSpaceID
,
5026 nsIAtom
* aAttribute
,
5029 NS_PRECONDITION(!mIsDocumentGone
, "Unexpected AttributeWillChange");
5030 NS_PRECONDITION(aDocument
== mDocument
, "Unexpected aDocument");
5032 // XXXwaterson it might be more elegant to wait until after the
5033 // initial reflow to begin observing the document. That would
5034 // squelch any other inappropriate notifications as well.
5035 if (mDidInitialReflow
) {
5036 nsAutoCauseReflowNotifier
crNotifier(this);
5037 mFrameConstructor
->AttributeWillChange(aElement
, aNameSpaceID
,
5038 aAttribute
, aModType
);
5044 PresShell::AttributeChanged(nsIDocument
* aDocument
,
5046 PRInt32 aNameSpaceID
,
5047 nsIAtom
* aAttribute
,
5050 NS_PRECONDITION(!mIsDocumentGone
, "Unexpected AttributeChanged");
5051 NS_PRECONDITION(aDocument
== mDocument
, "Unexpected aDocument");
5053 // XXXwaterson it might be more elegant to wait until after the
5054 // initial reflow to begin observing the document. That would
5055 // squelch any other inappropriate notifications as well.
5056 if (mDidInitialReflow
) {
5057 nsAutoCauseReflowNotifier
crNotifier(this);
5058 mFrameConstructor
->AttributeChanged(aElement
, aNameSpaceID
,
5059 aAttribute
, aModType
);
5065 PresShell::ContentAppended(nsIDocument
*aDocument
,
5066 nsIContent
* aContainer
,
5067 nsIContent
* aFirstNewContent
,
5068 PRInt32 aNewIndexInContainer
)
5070 NS_PRECONDITION(!mIsDocumentGone
, "Unexpected ContentAppended");
5071 NS_PRECONDITION(aDocument
== mDocument
, "Unexpected aDocument");
5072 NS_PRECONDITION(aContainer
, "must have container");
5074 if (!mDidInitialReflow
) {
5078 nsAutoCauseReflowNotifier
crNotifier(this);
5080 // Call this here so it only happens for real content mutations and
5081 // not cases when the frame constructor calls its own methods to force
5082 // frame reconstruction.
5083 mFrameConstructor
->RestyleForAppend(aContainer
->AsElement(), aFirstNewContent
);
5085 mFrameConstructor
->ContentAppended(aContainer
, aFirstNewContent
, PR_TRUE
);
5090 PresShell::ContentInserted(nsIDocument
* aDocument
,
5091 nsIContent
* aContainer
,
5093 PRInt32 aIndexInContainer
)
5095 NS_PRECONDITION(!mIsDocumentGone
, "Unexpected ContentInserted");
5096 NS_PRECONDITION(aDocument
== mDocument
, "Unexpected aDocument");
5098 if (!mDidInitialReflow
) {
5102 nsAutoCauseReflowNotifier
crNotifier(this);
5104 // Call this here so it only happens for real content mutations and
5105 // not cases when the frame constructor calls its own methods to force
5106 // frame reconstruction.
5108 mFrameConstructor
->RestyleForInsertOrChange(aContainer
->AsElement(), aChild
);
5110 mFrameConstructor
->ContentInserted(aContainer
, aChild
, nsnull
, PR_TRUE
);
5115 PresShell::ContentRemoved(nsIDocument
*aDocument
,
5116 nsIContent
* aContainer
,
5118 PRInt32 aIndexInContainer
,
5119 nsIContent
* aPreviousSibling
)
5121 NS_PRECONDITION(!mIsDocumentGone
, "Unexpected ContentRemoved");
5122 NS_PRECONDITION(aDocument
== mDocument
, "Unexpected aDocument");
5124 // Make sure that the caret doesn't leave a turd where the child used to be.
5126 mCaret
->InvalidateOutsideCaret();
5129 // Notify the ESM that the content has been removed, so that
5130 // it can clean up any state related to the content.
5131 mPresContext
->EventStateManager()->ContentRemoved(aDocument
, aChild
);
5133 nsAutoCauseReflowNotifier
crNotifier(this);
5135 // Call this here so it only happens for real content mutations and
5136 // not cases when the frame constructor calls its own methods to force
5137 // frame reconstruction.
5138 nsIContent
* oldNextSibling
;
5140 oldNextSibling
= aContainer
->GetChildAt(aIndexInContainer
);
5142 oldNextSibling
= nsnull
;
5146 mFrameConstructor
->RestyleForRemove(aContainer
->AsElement(), aChild
,
5149 PRBool didReconstruct
;
5150 mFrameConstructor
->ContentRemoved(aContainer
, aChild
, oldNextSibling
,
5151 nsCSSFrameConstructor::REMOVE_CONTENT
,
5158 PresShell::ReconstructFrames(void)
5160 nsCOMPtr
<nsIPresShell
> kungFuDeathGrip(this);
5162 // Have to make sure that the content notifications are flushed before we
5163 // start messing with the frame model; otherwise we can get content doubling.
5164 mDocument
->FlushPendingNotifications(Flush_ContentAndNotify
);
5166 nsAutoCauseReflowNotifier
crNotifier(this);
5167 mFrameConstructor
->BeginUpdate();
5168 nsresult rv
= mFrameConstructor
->ReconstructDocElementHierarchy();
5170 mFrameConstructor
->EndUpdate();
5176 nsIPresShell::ReconstructStyleDataInternal()
5178 mStylesHaveChanged
= PR_FALSE
;
5180 if (mIsDestroying
) {
5181 // We don't want to mess with restyles at this point
5186 mPresContext
->RebuildUserFontSet();
5189 Element
* root
= mDocument
->GetRootElement();
5190 if (!mDidInitialReflow
) {
5191 // Nothing to do here, since we have no frames yet
5196 // No content to restyle
5200 mFrameConstructor
->PostRestyleEvent(root
, eRestyle_Subtree
, NS_STYLE_HINT_NONE
);
5204 nsIPresShell::ReconstructStyleDataExternal()
5206 ReconstructStyleDataInternal();
5210 PresShell::StyleSheetAdded(nsIDocument
*aDocument
,
5211 nsIStyleSheet
* aStyleSheet
,
5212 PRBool aDocumentSheet
)
5214 // We only care when enabled sheets are added
5215 NS_PRECONDITION(aStyleSheet
, "Must have a style sheet!");
5217 if (aStyleSheet
->IsApplicable() && aStyleSheet
->HasRules()) {
5218 mStylesHaveChanged
= PR_TRUE
;
5223 PresShell::StyleSheetRemoved(nsIDocument
*aDocument
,
5224 nsIStyleSheet
* aStyleSheet
,
5225 PRBool aDocumentSheet
)
5227 // We only care when enabled sheets are removed
5228 NS_PRECONDITION(aStyleSheet
, "Must have a style sheet!");
5230 if (aStyleSheet
->IsApplicable() && aStyleSheet
->HasRules()) {
5231 mStylesHaveChanged
= PR_TRUE
;
5236 PresShell::StyleSheetApplicableStateChanged(nsIDocument
*aDocument
,
5237 nsIStyleSheet
* aStyleSheet
,
5240 if (aStyleSheet
->HasRules()) {
5241 mStylesHaveChanged
= PR_TRUE
;
5246 PresShell::StyleRuleChanged(nsIDocument
*aDocument
,
5247 nsIStyleSheet
* aStyleSheet
,
5248 nsIStyleRule
* aOldStyleRule
,
5249 nsIStyleRule
* aNewStyleRule
)
5251 mStylesHaveChanged
= PR_TRUE
;
5255 PresShell::StyleRuleAdded(nsIDocument
*aDocument
,
5256 nsIStyleSheet
* aStyleSheet
,
5257 nsIStyleRule
* aStyleRule
)
5259 mStylesHaveChanged
= PR_TRUE
;
5263 PresShell::StyleRuleRemoved(nsIDocument
*aDocument
,
5264 nsIStyleSheet
* aStyleSheet
,
5265 nsIStyleRule
* aStyleRule
)
5267 mStylesHaveChanged
= PR_TRUE
;
5271 PresShell::GetRealPrimaryFrameFor(nsIContent
* aContent
) const
5273 if (aContent
->GetDocument() != GetDocument()) {
5276 nsIFrame
*primaryFrame
= aContent
->GetPrimaryFrame();
5279 return nsPlaceholderFrame::GetRealFrameFor(primaryFrame
);
5283 PresShell::GetPlaceholderFrameFor(nsIFrame
* aFrame
) const
5285 return FrameManager()->GetPlaceholderFrameFor(aFrame
);
5289 PresShell::RenderDocument(const nsRect
& aRect
, PRUint32 aFlags
,
5290 nscolor aBackgroundColor
,
5291 gfxContext
* aThebesContext
)
5293 NS_TIME_FUNCTION_WITH_DOCURL
;
5295 NS_ENSURE_TRUE(!(aFlags
& RENDER_IS_UNTRUSTED
), NS_ERROR_NOT_IMPLEMENTED
);
5297 // Set up the rectangle as the path in aThebesContext
5299 nsPresContext::AppUnitsToFloatCSSPixels(aRect
.width
),
5300 nsPresContext::AppUnitsToFloatCSSPixels(aRect
.height
));
5301 aThebesContext
->NewPath();
5302 #ifdef MOZ_GFX_OPTIMIZE_MOBILE
5303 aThebesContext
->Rectangle(r
, PR_TRUE
);
5305 aThebesContext
->Rectangle(r
);
5308 nsIFrame
* rootFrame
= FrameManager()->GetRootFrame();
5310 // Nothing to paint, just fill the rect
5311 aThebesContext
->SetColor(gfxRGBA(aBackgroundColor
));
5312 aThebesContext
->Fill();
5316 gfxContextAutoSaveRestore
save(aThebesContext
);
5318 gfxContext::GraphicsOperator oldOperator
= aThebesContext
->CurrentOperator();
5319 if (oldOperator
== gfxContext::OPERATOR_OVER
) {
5320 // Clip to the destination rectangle before we push the group,
5321 // to limit the size of the temporary surface
5322 aThebesContext
->Clip();
5325 // we want the window to be composited as a single image using
5326 // whatever operator was set; set OPERATOR_OVER here, which is
5327 // either already the case, or overrides the operator in a group.
5328 // the original operator will be present when we PopGroup.
5329 // we can avoid using a temporary surface if we're using OPERATOR_OVER
5330 // and our background color has no alpha (so we'll be compositing on top
5331 // of a fully opaque solid color region)
5332 PRBool needsGroup
= NS_GET_A(aBackgroundColor
) < 0xff ||
5333 oldOperator
!= gfxContext::OPERATOR_OVER
;
5336 aThebesContext
->PushGroup(NS_GET_A(aBackgroundColor
) == 0xff ?
5337 gfxASurface::CONTENT_COLOR
:
5338 gfxASurface::CONTENT_COLOR_ALPHA
);
5339 aThebesContext
->Save();
5341 if (oldOperator
!= gfxContext::OPERATOR_OVER
) {
5342 // Clip now while we paint to the temporary surface. For
5343 // non-source-bounded operators (e.g., SOURCE), we need to do clip
5344 // here after we've pushed the group, so that eventually popping
5345 // the group and painting it will be able to clear the entire
5346 // destination surface.
5347 aThebesContext
->Clip();
5348 aThebesContext
->SetOperator(gfxContext::OPERATOR_OVER
);
5352 aThebesContext
->Translate(gfxPoint(-nsPresContext::AppUnitsToFloatCSSPixels(aRect
.x
),
5353 -nsPresContext::AppUnitsToFloatCSSPixels(aRect
.y
)));
5355 nsIDeviceContext
* devCtx
= mPresContext
->DeviceContext();
5356 gfxFloat scale
= gfxFloat(devCtx
->AppUnitsPerDevPixel())/nsPresContext::AppUnitsPerCSSPixel();
5357 aThebesContext
->Scale(scale
, scale
);
5359 // Since canvas APIs use floats to set up their matrices, we may have
5360 // some slight inaccuracy here. Adjust matrix components that are
5361 // integers up to the accuracy of floats to be those integers.
5362 aThebesContext
->NudgeCurrentMatrixToIntegers();
5364 AutoSaveRestoreRenderingState
_(this);
5366 nsCOMPtr
<nsIRenderingContext
> rc
;
5367 devCtx
->CreateRenderingContextInstance(*getter_AddRefs(rc
));
5368 rc
->Init(devCtx
, aThebesContext
);
5370 PRBool wouldFlushRetainedLayers
= PR_FALSE
;
5371 PRUint32 flags
= nsLayoutUtils::PAINT_IGNORE_SUPPRESSION
;
5372 if (!(aFlags
& RENDER_ASYNC_DECODE_IMAGES
)) {
5373 flags
|= nsLayoutUtils::PAINT_SYNC_DECODE_IMAGES
;
5375 if (aFlags
& RENDER_USE_WIDGET_LAYERS
) {
5376 // We only support using widget layers on display root's with widgets.
5377 nsIView
* view
= rootFrame
->GetView();
5378 if (view
&& view
->GetWidget() &&
5379 nsLayoutUtils::GetDisplayRootFrame(rootFrame
) == rootFrame
) {
5380 flags
|= nsLayoutUtils::PAINT_WIDGET_LAYERS
;
5383 if (!(aFlags
& RENDER_CARET
)) {
5384 wouldFlushRetainedLayers
= PR_TRUE
;
5385 flags
|= nsLayoutUtils::PAINT_HIDE_CARET
;
5387 if (aFlags
& RENDER_IGNORE_VIEWPORT_SCROLLING
) {
5388 wouldFlushRetainedLayers
= !IgnoringViewportScrolling();
5389 mRenderFlags
= ChangeFlag(mRenderFlags
, PR_TRUE
, STATE_IGNORING_VIEWPORT_SCROLLING
);
5391 if (aFlags
& RENDER_DOCUMENT_RELATIVE
) {
5392 // XXX be smarter about this ... drawWindow might want a rect
5393 // that's "pretty close" to what our retained layer tree covers.
5394 // In that case, it wouldn't disturb normal rendering too much,
5395 // and we should allow it.
5396 wouldFlushRetainedLayers
= PR_TRUE
;
5397 flags
|= nsLayoutUtils::PAINT_DOCUMENT_RELATIVE
;
5400 // Don't let drawWindow blow away our retained layer tree
5401 if ((flags
& nsLayoutUtils::PAINT_WIDGET_LAYERS
) && wouldFlushRetainedLayers
) {
5402 flags
&= ~nsLayoutUtils::PAINT_WIDGET_LAYERS
;
5405 nsLayoutUtils::PaintFrame(rc
, rootFrame
, nsRegion(aRect
),
5406 aBackgroundColor
, flags
);
5408 // if we had to use a group, paint it to the destination now
5410 aThebesContext
->Restore();
5411 aThebesContext
->PopGroupToSource();
5412 aThebesContext
->Paint();
5419 * Clip the display list aList to a range. Returns the clipped
5420 * rectangle surrounding the range.
5423 PresShell::ClipListToRange(nsDisplayListBuilder
*aBuilder
,
5424 nsDisplayList
* aList
,
5427 NS_TIME_FUNCTION_WITH_DOCURL
;
5429 // iterate though the display items and add up the bounding boxes of each.
5430 // This will allow the total area of the frames within the range to be
5431 // determined. To do this, remove an item from the bottom of the list, check
5432 // whether it should be part of the range, and if so, append it to the top
5433 // of the temporary list tmpList. If the item is a text frame at the end of
5434 // the selection range, wrap it in an nsDisplayClip to clip the display to
5435 // the portion of the text frame that is part of the selection. Then, append
5436 // the wrapper to the top of the list. Otherwise, just delete the item and
5439 nsDisplayList tmpList
;
5442 while ((i
= aList
->RemoveBottom())) {
5443 // itemToInsert indiciates the item that should be inserted into the
5444 // temporary list. If null, no item should be inserted.
5445 nsDisplayItem
* itemToInsert
= nsnull
;
5446 nsIFrame
* frame
= i
->GetUnderlyingFrame();
5448 nsIContent
* content
= frame
->GetContent();
5450 PRBool atStart
= (content
== aRange
->GetStartParent());
5451 PRBool atEnd
= (content
== aRange
->GetEndParent());
5452 if ((atStart
|| atEnd
) && frame
->GetType() == nsGkAtoms::textFrame
) {
5453 PRInt32 frameStartOffset
, frameEndOffset
;
5454 frame
->GetOffsets(frameStartOffset
, frameEndOffset
);
5456 PRInt32 hilightStart
=
5457 atStart
? NS_MAX(aRange
->StartOffset(), frameStartOffset
) : frameStartOffset
;
5458 PRInt32 hilightEnd
=
5459 atEnd
? NS_MIN(aRange
->EndOffset(), frameEndOffset
) : frameEndOffset
;
5460 if (hilightStart
< hilightEnd
) {
5461 // determine the location of the start and end edges of the range.
5462 nsPoint startPoint
, endPoint
;
5463 frame
->GetPointFromOffset(hilightStart
, &startPoint
);
5464 frame
->GetPointFromOffset(hilightEnd
, &endPoint
);
5466 // the clip rectangle is determined by taking the the start and
5467 // end points of the range, offset from the reference frame.
5468 // Because of rtl, the end point may be to the left of the
5469 // start point, so x is set to the lowest value
5470 nsRect
textRect(aBuilder
->ToReferenceFrame(frame
), frame
->GetSize());
5471 nscoord x
= NS_MIN(startPoint
.x
, endPoint
.x
);
5473 textRect
.width
= NS_MAX(startPoint
.x
, endPoint
.x
) - x
;
5474 surfaceRect
.UnionRect(surfaceRect
, textRect
);
5476 // wrap the item in an nsDisplayClip so that it can be clipped to
5477 // the selection. If the allocation fails, fall through and delete
5479 itemToInsert
= new (aBuilder
)
5480 nsDisplayClip(aBuilder
, frame
, i
, textRect
);
5483 // Don't try to descend into subdocuments.
5484 // If this ever changes we'd need to add handling for subdocuments with
5485 // different zoom levels.
5486 else if (content
->GetCurrentDoc() ==
5487 aRange
->GetStartParent()->GetCurrentDoc()) {
5488 // if the node is within the range, append it to the temporary list
5489 PRBool before
, after
;
5491 nsRange::CompareNodeToRange(content
, aRange
, &before
, &after
);
5492 if (NS_SUCCEEDED(rv
) && !before
&& !after
) {
5494 surfaceRect
.UnionRect(surfaceRect
, i
->GetBounds(aBuilder
));
5500 // insert the item into the list if necessary. If the item has a child
5501 // list, insert that as well
5502 nsDisplayList
* sublist
= i
->GetList();
5503 if (itemToInsert
|| sublist
) {
5504 tmpList
.AppendToTop(itemToInsert
? itemToInsert
: i
);
5505 // if the item is a list, iterate over it as well
5507 surfaceRect
.UnionRect(surfaceRect
,
5508 ClipListToRange(aBuilder
, sublist
, aRange
));
5511 // otherwise, just delete the item and don't readd it to the list
5512 i
->~nsDisplayItem();
5516 // now add all the items back onto the original list again
5517 aList
->AppendToTop(&tmpList
);
5525 static PRBool gDumpRangePaintList
= PR_FALSE
;
5529 PresShell::CreateRangePaintInfo(nsIDOMRange
* aRange
,
5530 nsRect
& aSurfaceRect
,
5531 PRBool aForPrimarySelection
)
5533 NS_TIME_FUNCTION_WITH_DOCURL
;
5535 RangePaintInfo
* info
= nsnull
;
5537 nsCOMPtr
<nsIRange
> range
= do_QueryInterface(aRange
);
5541 nsIFrame
* ancestorFrame
;
5542 nsIFrame
* rootFrame
= GetRootFrame();
5544 // If the start or end of the range is the document, just use the root
5545 // frame, otherwise get the common ancestor of the two endpoints of the
5547 nsINode
* startParent
= range
->GetStartParent();
5548 nsINode
* endParent
= range
->GetEndParent();
5549 nsIDocument
* doc
= startParent
->GetCurrentDoc();
5550 if (startParent
== doc
|| endParent
== doc
) {
5551 ancestorFrame
= rootFrame
;
5554 nsINode
* ancestor
= nsContentUtils::GetCommonAncestor(startParent
, endParent
);
5555 NS_ASSERTION(!ancestor
|| ancestor
->IsNodeOfType(nsINode::eCONTENT
),
5556 "common ancestor is not content");
5557 if (!ancestor
|| !ancestor
->IsNodeOfType(nsINode::eCONTENT
))
5560 nsIContent
* ancestorContent
= static_cast<nsIContent
*>(ancestor
);
5561 ancestorFrame
= ancestorContent
->GetPrimaryFrame();
5563 // use the nearest ancestor frame that includes all continuations as the
5564 // root for building the display list
5565 while (ancestorFrame
&&
5566 nsLayoutUtils::GetNextContinuationOrSpecialSibling(ancestorFrame
))
5567 ancestorFrame
= ancestorFrame
->GetParent();
5573 info
= new RangePaintInfo(range
, ancestorFrame
);
5577 nsRect ancestorRect
= ancestorFrame
->GetVisualOverflowRect();
5579 // get a display list containing the range
5580 if (aForPrimarySelection
) {
5581 info
->mBuilder
.SetSelectedFramesOnly();
5583 info
->mBuilder
.EnterPresShell(ancestorFrame
, ancestorRect
);
5584 ancestorFrame
->BuildDisplayListForStackingContext(&info
->mBuilder
,
5585 ancestorRect
, &info
->mList
);
5586 info
->mBuilder
.LeavePresShell(ancestorFrame
, ancestorRect
);
5589 if (gDumpRangePaintList
) {
5590 fprintf(stderr
, "CreateRangePaintInfo --- before ClipListToRange:\n");
5591 nsFrame::PrintDisplayList(&(info
->mBuilder
), info
->mList
);
5595 nsRect rangeRect
= ClipListToRange(&info
->mBuilder
, &info
->mList
, range
);
5598 if (gDumpRangePaintList
) {
5599 fprintf(stderr
, "CreateRangePaintInfo --- after ClipListToRange:\n");
5600 nsFrame::PrintDisplayList(&(info
->mBuilder
), info
->mList
);
5604 // determine the offset of the reference frame for the display list
5605 // to the root frame. This will allow the coordinates used when painting
5606 // to all be offset from the same point
5607 info
->mRootOffset
= ancestorFrame
->GetOffsetTo(rootFrame
);
5608 rangeRect
.MoveBy(info
->mRootOffset
);
5609 aSurfaceRect
.UnionRect(aSurfaceRect
, rangeRect
);
5614 already_AddRefed
<gfxASurface
>
5615 PresShell::PaintRangePaintInfo(nsTArray
<nsAutoPtr
<RangePaintInfo
> >* aItems
,
5616 nsISelection
* aSelection
,
5617 nsIntRegion
* aRegion
,
5620 nsIntRect
* aScreenRect
)
5622 NS_TIME_FUNCTION_WITH_DOCURL
;
5624 nsPresContext
* pc
= GetPresContext();
5625 if (!pc
|| aArea
.width
== 0 || aArea
.height
== 0)
5628 nsIDeviceContext
* deviceContext
= pc
->DeviceContext();
5630 // use the rectangle to create the surface
5631 nsIntRect pixelArea
= aArea
.ToOutsidePixels(pc
->AppUnitsPerDevPixel());
5633 // if the area of the image is larger than the maximum area, scale it down
5635 nsIntRect rootScreenRect
=
5636 GetRootFrame()->GetScreenRectInAppUnits().ToNearestPixels(
5637 pc
->AppUnitsPerDevPixel());
5639 // if the image is larger in one or both directions than half the size of
5640 // the available screen area, scale the image down to that size.
5642 deviceContext
->GetClientRect(maxSize
);
5643 nscoord maxWidth
= pc
->AppUnitsToDevPixels(maxSize
.width
>> 1);
5644 nscoord maxHeight
= pc
->AppUnitsToDevPixels(maxSize
.height
>> 1);
5645 PRBool resize
= (pixelArea
.width
> maxWidth
|| pixelArea
.height
> maxHeight
);
5648 // divide the maximum size by the image size in both directions. Whichever
5649 // direction produces the smallest result determines how much should be
5651 if (pixelArea
.width
> maxWidth
)
5652 scale
= NS_MIN(scale
, float(maxWidth
) / pixelArea
.width
);
5653 if (pixelArea
.height
> maxHeight
)
5654 scale
= NS_MIN(scale
, float(maxHeight
) / pixelArea
.height
);
5656 pixelArea
.width
= NSToIntFloor(float(pixelArea
.width
) * scale
);
5657 pixelArea
.height
= NSToIntFloor(float(pixelArea
.height
) * scale
);
5659 // adjust the screen position based on the rescaled size
5660 nscoord left
= rootScreenRect
.x
+ pixelArea
.x
;
5661 nscoord top
= rootScreenRect
.y
+ pixelArea
.y
;
5662 aScreenRect
->x
= NSToIntFloor(aPoint
.x
- float(aPoint
.x
- left
) * scale
);
5663 aScreenRect
->y
= NSToIntFloor(aPoint
.y
- float(aPoint
.y
- top
) * scale
);
5666 // move aScreenRect to the position of the surface in screen coordinates
5667 aScreenRect
->MoveTo(rootScreenRect
.x
+ pixelArea
.x
, rootScreenRect
.y
+ pixelArea
.y
);
5669 aScreenRect
->width
= pixelArea
.width
;
5670 aScreenRect
->height
= pixelArea
.height
;
5672 gfxImageSurface
* surface
=
5673 new gfxImageSurface(gfxIntSize(pixelArea
.width
, pixelArea
.height
),
5674 gfxImageSurface::ImageFormatARGB32
);
5675 if (!surface
|| surface
->CairoStatus()) {
5681 gfxContext
context(surface
);
5682 context
.SetOperator(gfxContext::OPERATOR_CLEAR
);
5683 context
.Rectangle(gfxRect(0, 0, pixelArea
.width
, pixelArea
.height
));
5686 nsCOMPtr
<nsIRenderingContext
> rc
;
5687 deviceContext
->CreateRenderingContextInstance(*getter_AddRefs(rc
));
5688 rc
->Init(deviceContext
, surface
);
5691 // Convert aRegion from CSS pixels to dev pixels
5692 nsIntRegion region
=
5693 aRegion
->ToAppUnits(nsPresContext::AppUnitsPerCSSPixel())
5694 .ToOutsidePixels(pc
->AppUnitsPerDevPixel());
5695 rc
->SetClipRegion(region
, nsClipCombine_kReplace
);
5699 rc
->Scale(scale
, scale
);
5701 // translate so that points are relative to the surface area
5702 rc
->Translate(-aArea
.x
, -aArea
.y
);
5704 // temporarily hide the selection so that text is drawn normally. If a
5705 // selection is being rendered, use that, otherwise use the presshell's
5707 nsCOMPtr
<nsFrameSelection
> frameSelection
;
5709 nsCOMPtr
<nsISelectionPrivate
> selpriv
= do_QueryInterface(aSelection
);
5710 selpriv
->GetFrameSelection(getter_AddRefs(frameSelection
));
5713 frameSelection
= FrameSelection();
5715 PRInt16 oldDisplaySelection
= frameSelection
->GetDisplaySelection();
5716 frameSelection
->SetDisplaySelection(nsISelectionController::SELECTION_HIDDEN
);
5718 // next, paint each range in the selection
5719 PRInt32 count
= aItems
->Length();
5720 for (PRInt32 i
= 0; i
< count
; i
++) {
5721 RangePaintInfo
* rangeInfo
= (*aItems
)[i
];
5722 // the display lists paint relative to the offset from the reference
5723 // frame, so translate the rendering context
5724 nsIRenderingContext::AutoPushTranslation
5725 translate(rc
, rangeInfo
->mRootOffset
.x
, rangeInfo
->mRootOffset
.y
);
5727 aArea
.MoveBy(-rangeInfo
->mRootOffset
.x
, -rangeInfo
->mRootOffset
.y
);
5728 nsRegion
visible(aArea
);
5729 rangeInfo
->mList
.ComputeVisibilityForRoot(&rangeInfo
->mBuilder
, &visible
);
5730 rangeInfo
->mList
.PaintRoot(&rangeInfo
->mBuilder
, rc
, nsDisplayList::PAINT_DEFAULT
);
5731 aArea
.MoveBy(rangeInfo
->mRootOffset
.x
, rangeInfo
->mRootOffset
.y
);
5734 // restore the old selection display state
5735 frameSelection
->SetDisplaySelection(oldDisplaySelection
);
5741 already_AddRefed
<gfxASurface
>
5742 PresShell::RenderNode(nsIDOMNode
* aNode
,
5743 nsIntRegion
* aRegion
,
5745 nsIntRect
* aScreenRect
)
5747 // area will hold the size of the surface needed to draw the node, measured
5748 // from the root frame.
5750 nsTArray
<nsAutoPtr
<RangePaintInfo
> > rangeItems
;
5752 // nothing to draw if the node isn't in a document
5753 nsCOMPtr
<nsINode
> node
= do_QueryInterface(aNode
);
5754 if (!node
->IsInDoc())
5757 nsCOMPtr
<nsIDOMRange
> range
;
5758 NS_NewRange(getter_AddRefs(range
));
5759 if (NS_FAILED(range
->SelectNode(aNode
)))
5762 RangePaintInfo
* info
= CreateRangePaintInfo(range
, area
, PR_FALSE
);
5763 if (info
&& !rangeItems
.AppendElement(info
)) {
5769 // combine the area with the supplied region
5770 nsIntRect rrectPixels
= aRegion
->GetBounds();
5772 nsRect rrect
= rrectPixels
.ToAppUnits(nsPresContext::AppUnitsPerCSSPixel());
5773 area
.IntersectRect(area
, rrect
);
5775 nsPresContext
* pc
= GetPresContext();
5779 // move the region so that it is offset from the topleft corner of the surface
5780 aRegion
->MoveBy(-pc
->AppUnitsToDevPixels(area
.x
),
5781 -pc
->AppUnitsToDevPixels(area
.y
));
5784 return PaintRangePaintInfo(&rangeItems
, nsnull
, aRegion
, area
, aPoint
,
5788 already_AddRefed
<gfxASurface
>
5789 PresShell::RenderSelection(nsISelection
* aSelection
,
5791 nsIntRect
* aScreenRect
)
5793 // area will hold the size of the surface needed to draw the selection,
5794 // measured from the root frame.
5796 nsTArray
<nsAutoPtr
<RangePaintInfo
> > rangeItems
;
5798 // iterate over each range and collect them into the rangeItems array.
5799 // This is done so that the size of selection can be determined so as
5800 // to allocate a surface area
5802 aSelection
->GetRangeCount(&numRanges
);
5803 NS_ASSERTION(numRanges
> 0, "RenderSelection called with no selection");
5805 for (PRInt32 r
= 0; r
< numRanges
; r
++)
5807 nsCOMPtr
<nsIDOMRange
> range
;
5808 aSelection
->GetRangeAt(r
, getter_AddRefs(range
));
5810 RangePaintInfo
* info
= CreateRangePaintInfo(range
, area
, PR_TRUE
);
5811 if (info
&& !rangeItems
.AppendElement(info
)) {
5817 return PaintRangePaintInfo(&rangeItems
, aSelection
, nsnull
, area
, aPoint
,
5822 PresShell::AddPrintPreviewBackgroundItem(nsDisplayListBuilder
& aBuilder
,
5823 nsDisplayList
& aList
,
5825 const nsRect
& aBounds
)
5827 return aList
.AppendNewToBottom(new (&aBuilder
)
5828 nsDisplaySolidColor(&aBuilder
, aFrame
, aBounds
, NS_RGB(115, 115, 115)));
5832 AddCanvasBackgroundColor(const nsDisplayList
& aList
, nsIFrame
* aCanvasFrame
,
5835 for (nsDisplayItem
* i
= aList
.GetBottom(); i
; i
= i
->GetAbove()) {
5836 if (i
->GetUnderlyingFrame() == aCanvasFrame
&&
5837 i
->GetType() == nsDisplayItem::TYPE_CANVAS_BACKGROUND
) {
5838 nsDisplayCanvasBackground
* bg
= static_cast<nsDisplayCanvasBackground
*>(i
);
5839 bg
->SetExtraBackgroundColor(aColor
);
5842 nsDisplayList
* sublist
= i
->GetList();
5843 if (sublist
&& AddCanvasBackgroundColor(*sublist
, aCanvasFrame
, aColor
))
5849 nsresult
PresShell::AddCanvasBackgroundColorItem(nsDisplayListBuilder
& aBuilder
,
5850 nsDisplayList
& aList
,
5852 const nsRect
& aBounds
,
5853 nscolor aBackstopColor
,
5856 // We don't want to add an item for the canvas background color if the frame
5857 // (sub)tree we are painting doesn't include any canvas frames. There isn't
5858 // an easy way to check this directly, but if we check if the root of the
5859 // (sub)tree we are painting is a canvas frame that should cover us in all
5860 // cases (it will usually be a viewport frame when we have a canvas frame in
5862 if (!aForceDraw
&& !nsCSSRendering::IsCanvasFrame(aFrame
))
5865 nscolor bgcolor
= NS_ComposeColors(aBackstopColor
, mCanvasBackgroundColor
);
5867 // To make layers work better, we want to avoid having a big non-scrolled
5868 // color background behind a scrolled transparent background. Instead,
5869 // we'll try to move the color background into the scrolled content
5870 // by making nsDisplayCanvasBackground paint it.
5871 if (!aFrame
->GetParent()) {
5872 nsIScrollableFrame
* sf
=
5873 aFrame
->PresContext()->PresShell()->GetRootScrollFrameAsScrollable();
5875 nsCanvasFrame
* canvasFrame
= do_QueryFrame(sf
->GetScrolledFrame());
5876 if (canvasFrame
&& canvasFrame
->IsVisibleForPainting(&aBuilder
)) {
5877 if (AddCanvasBackgroundColor(aList
, canvasFrame
, bgcolor
))
5883 return aList
.AppendNewToBottom(
5884 new (&aBuilder
) nsDisplaySolidColor(&aBuilder
, aFrame
, aBounds
, bgcolor
));
5887 static PRBool
IsTransparentContainerElement(nsPresContext
* aPresContext
)
5889 nsCOMPtr
<nsISupports
> container
= aPresContext
->GetContainerInternal();
5890 nsCOMPtr
<nsIDocShellTreeItem
> docShellItem
= do_QueryInterface(container
);
5891 nsCOMPtr
<nsPIDOMWindow
> pwin(do_GetInterface(docShellItem
));
5894 nsCOMPtr
<nsIContent
> containerElement
=
5895 do_QueryInterface(pwin
->GetFrameElementInternal());
5896 return containerElement
&&
5897 containerElement
->HasAttr(kNameSpaceID_None
, nsGkAtoms::transparent
);
5900 void PresShell::UpdateCanvasBackground()
5902 // If we have a frame tree and it has style information that
5903 // specifies the background color of the canvas, update our local
5904 // cache of that color.
5905 nsIFrame
* rootStyleFrame
= FrameConstructor()->GetRootElementStyleFrame();
5906 if (rootStyleFrame
) {
5907 nsStyleContext
* bgStyle
=
5908 nsCSSRendering::FindRootFrameBackground(rootStyleFrame
);
5909 // XXX We should really be passing the canvasframe, not the root element
5910 // style frame but we don't have access to the canvasframe here. It isn't
5911 // a problem because only a few frames can return something other than true
5912 // and none of them would be a canvas frame or root element style frame.
5913 mCanvasBackgroundColor
=
5914 nsCSSRendering::DetermineBackgroundColor(mPresContext
, bgStyle
,
5916 if (GetPresContext()->IsRootContentDocument() &&
5917 !IsTransparentContainerElement(mPresContext
)) {
5918 mCanvasBackgroundColor
=
5919 NS_ComposeColors(mPresContext
->DefaultBackgroundColor(), mCanvasBackgroundColor
);
5923 // If the root element of the document (ie html) has style 'display: none'
5924 // then the document's background color does not get drawn; cache the
5925 // color we actually draw.
5926 if (!FrameConstructor()->GetRootElementFrame()) {
5927 mCanvasBackgroundColor
= mPresContext
->DefaultBackgroundColor();
5931 nscolor
PresShell::ComputeBackstopColor(nsIView
* aDisplayRoot
)
5933 nsIWidget
* widget
= aDisplayRoot
->GetWidget();
5934 if (widget
&& widget
->GetTransparencyMode() != eTransparencyOpaque
) {
5935 // Within a transparent widget, so the backstop color must be
5936 // totally transparent.
5937 return NS_RGBA(0,0,0,0);
5939 // Within an opaque widget (or no widget at all), so the backstop
5940 // color must be totally opaque. The user's default background
5941 // as reported by the prescontext is guaranteed to be opaque.
5942 return GetPresContext()->DefaultBackgroundColor();
5945 struct PaintParams
{
5947 nsPoint mOffsetToWidget
;
5948 const nsRegion
* mDirtyRegion
;
5949 nscolor mBackgroundColor
;
5952 LayerManager
* PresShell::GetLayerManager()
5954 NS_ASSERTION(mViewManager
, "Should have view manager");
5957 if (NS_SUCCEEDED(mViewManager
->GetRootView(rootView
)) && rootView
) {
5958 if (nsIWidget
* widget
= rootView
->GetWidget()) {
5959 return widget
->GetLayerManager();
5965 void PresShell::SetIgnoreViewportScrolling(PRBool aIgnore
)
5967 if (IgnoringViewportScrolling() == aIgnore
) {
5970 RenderingState
state(this);
5971 state
.mRenderFlags
= ChangeFlag(state
.mRenderFlags
, aIgnore
,
5972 STATE_IGNORING_VIEWPORT_SCROLLING
);
5973 SetRenderingState(state
);
5976 void PresShell::SetDisplayPort(const nsRect
& aDisplayPort
)
5978 if (UsingDisplayPort() && mDisplayPort
== aDisplayPort
) {
5981 RenderingState
state(this);
5982 state
.mRenderFlags
= ChangeFlag(mRenderFlags
, PR_TRUE
,
5983 STATE_USING_DISPLAYPORT
);
5984 state
.mDisplayPort
= aDisplayPort
;
5985 SetRenderingState(state
);
5988 nsresult
PresShell::SetResolution(float aXResolution
, float aYResolution
)
5990 if (!(aXResolution
> 0.0 && aXResolution
> 0.0)) {
5991 return NS_ERROR_ILLEGAL_VALUE
;
5993 if (aXResolution
== mXResolution
&& aYResolution
== mYResolution
) {
5996 RenderingState
state(this);
5997 state
.mXResolution
= aXResolution
;
5998 state
.mYResolution
= aYResolution
;
5999 SetRenderingState(state
);
6003 void PresShell::SetRenderingState(const RenderingState
& aState
)
6005 if (mRenderFlags
!= aState
.mRenderFlags
) {
6006 // Rendering state changed in a way that forces us to flush any
6007 // retained layers we might already have.
6008 LayerManager
* manager
= GetLayerManager();
6010 FrameLayerBuilder::InvalidateAllLayers(manager
);
6014 mRenderFlags
= aState
.mRenderFlags
;
6015 if (UsingDisplayPort()) {
6016 mDisplayPort
= aState
.mDisplayPort
;
6018 mDisplayPort
= nsRect();
6020 mXResolution
= aState
.mXResolution
;
6021 mYResolution
= aState
.mYResolution
;
6023 nsIFrame
* rootFrame
= FrameManager()->GetRootFrame();
6025 rootFrame
->InvalidateFrameSubtree();
6029 void PresShell::SynthesizeMouseMove(PRBool aFromScroll
)
6031 if (mViewManager
&& !mPaintingSuppressed
&& mIsActive
) {
6032 mViewManager
->SynthesizeMouseMove(aFromScroll
);
6036 static void DrawThebesLayer(ThebesLayer
* aLayer
,
6037 gfxContext
* aContext
,
6038 const nsIntRegion
& aRegionToDraw
,
6039 const nsIntRegion
& aRegionToInvalidate
,
6040 void* aCallbackData
)
6042 PaintParams
* params
= static_cast<PaintParams
*>(aCallbackData
);
6043 nsIFrame
* frame
= params
->mFrame
;
6045 // We're drawing into a child window.
6046 nsIDeviceContext
* devCtx
= frame
->PresContext()->DeviceContext();
6047 nsCOMPtr
<nsIRenderingContext
> rc
;
6048 nsresult rv
= devCtx
->CreateRenderingContextInstance(*getter_AddRefs(rc
));
6049 if (NS_SUCCEEDED(rv
)) {
6050 rc
->Init(devCtx
, aContext
);
6051 nsIRenderingContext::AutoPushTranslation
6052 push(rc
, params
->mOffsetToWidget
.x
, params
->mOffsetToWidget
.y
);
6053 nsLayoutUtils::PaintFrame(rc
, frame
, *params
->mDirtyRegion
,
6054 params
->mBackgroundColor
,
6055 nsLayoutUtils::PAINT_WIDGET_LAYERS
);
6058 aContext
->NewPath();
6059 aContext
->SetColor(gfxRGBA(params
->mBackgroundColor
));
6060 nsIntRect dirtyRect
= aRegionToDraw
.GetBounds();
6061 aContext
->Rectangle(
6062 gfxRect(dirtyRect
.x
, dirtyRect
.y
, dirtyRect
.width
, dirtyRect
.height
));
6068 PresShell::Paint(nsIView
* aDisplayRoot
,
6069 nsIView
* aViewToPaint
,
6070 nsIWidget
* aWidgetToPaint
,
6071 const nsRegion
& aDirtyRegion
,
6072 const nsIntRegion
& aIntDirtyRegion
,
6073 PRBool aPaintDefaultBackground
,
6074 PRBool aWillSendDidPaint
)
6076 #ifdef NS_FUNCTION_TIMER
6077 NS_TIME_FUNCTION_DECLARE_DOCURL
;
6078 const nsRect
& bounds__
= aDirtyRegion
.GetBounds();
6079 NS_TIME_FUNCTION_MIN_FMT(1.0, "%s (line %d) (document: %s, dirty rect: (<%f, %f>, <%f, %f>)",
6080 MOZ_FUNCTION_NAME
, __LINE__
, docURL__
.get(),
6081 NSCoordToFloat(bounds__
.x
),
6082 NSCoordToFloat(bounds__
.y
),
6083 NSCoordToFloat(bounds__
.XMost()),
6084 NSCoordToFloat(bounds__
.YMost()));
6087 nsPresContext
* presContext
= GetPresContext();
6088 AUTO_LAYOUT_PHASE_ENTRY_POINT(presContext
, Paint
);
6090 NS_ASSERTION(!mIsDestroying
, "painting a destroyed PresShell");
6091 NS_ASSERTION(aDisplayRoot
, "null view");
6092 NS_ASSERTION(aViewToPaint
, "null view");
6093 NS_ASSERTION(aWidgetToPaint
, "Can't paint without a widget");
6095 nscolor bgcolor
= ComputeBackstopColor(aDisplayRoot
);
6097 nsIFrame
* frame
= aPaintDefaultBackground
6098 ? nsnull
: static_cast<nsIFrame
*>(aDisplayRoot
->GetClientData());
6100 if (frame
&& aViewToPaint
== aDisplayRoot
) {
6101 // Defer invalidates that are triggered during painting, and discard
6102 // invalidates of areas that are already being repainted.
6103 // The layer system can trigger invalidates during painting
6104 // (see FrameLayerBuilder).
6105 frame
->BeginDeferringInvalidatesForDisplayRoot(aDirtyRegion
);
6107 // We can paint directly into the widget using its layer manager.
6108 // When we get rid of child widgets, this will be the only path we
6109 // need. (aPaintDefaultBackground will never be needed since the
6110 // chrome can always paint a default background.)
6111 nsLayoutUtils::PaintFrame(nsnull
, frame
, aDirtyRegion
, bgcolor
,
6112 nsLayoutUtils::PAINT_WIDGET_LAYERS
);
6114 frame
->EndDeferringInvalidatesForDisplayRoot();
6119 // Defer invalidates that are triggered during painting, and discard
6120 // invalidates of areas that are already being repainted.
6121 frame
->BeginDeferringInvalidatesForDisplayRoot(aDirtyRegion
);
6124 LayerManager
* layerManager
= aWidgetToPaint
->GetLayerManager();
6125 NS_ASSERTION(layerManager
, "Must be in paint event");
6127 layerManager
->BeginTransaction();
6128 nsRefPtr
<ThebesLayer
> root
= layerManager
->CreateThebesLayer();
6130 root
->SetVisibleRegion(aIntDirtyRegion
);
6131 layerManager
->SetRoot(root
);
6134 bgcolor
= NS_ComposeColors(bgcolor
, mCanvasBackgroundColor
);
6136 PaintParams params
=
6138 aDisplayRoot
->GetOffsetToWidget(aWidgetToPaint
),
6141 layerManager
->EndTransaction(DrawThebesLayer
, ¶ms
);
6144 frame
->EndDeferringInvalidatesForDisplayRoot();
6151 nsIPresShell::SetCapturingContent(nsIContent
* aContent
, PRUint8 aFlags
)
6153 NS_IF_RELEASE(gCaptureInfo
.mContent
);
6155 // only set capturing content if allowed or the CAPTURE_IGNOREALLOWED flag
6157 if ((aFlags
& CAPTURE_IGNOREALLOWED
) || gCaptureInfo
.mAllowed
) {
6159 NS_ADDREF(gCaptureInfo
.mContent
= aContent
);
6161 gCaptureInfo
.mRetargetToElement
= (aFlags
& CAPTURE_RETARGETTOELEMENT
) != 0;
6162 gCaptureInfo
.mPreventDrag
= (aFlags
& CAPTURE_PREVENTDRAG
) != 0;
6167 PresShell::GetCurrentEventFrame()
6169 if (NS_UNLIKELY(mIsDestroying
)) {
6173 if (!mCurrentEventFrame
&& mCurrentEventContent
) {
6174 // Make sure the content still has a document reference. If not,
6175 // then we assume it is no longer in the content tree and the
6176 // frame shouldn't get an event, nor should we even assume its
6177 // safe to try and find the frame.
6178 if (mCurrentEventContent
->GetDocument()) {
6179 mCurrentEventFrame
= mCurrentEventContent
->GetPrimaryFrame();
6183 return mCurrentEventFrame
;
6187 PresShell::GetEventTargetFrame()
6189 return GetCurrentEventFrame();
6192 already_AddRefed
<nsIContent
>
6193 PresShell::GetEventTargetContent(nsEvent
* aEvent
)
6195 nsIContent
* content
= nsnull
;
6197 if (mCurrentEventContent
) {
6198 content
= mCurrentEventContent
;
6199 NS_IF_ADDREF(content
);
6201 nsIFrame
* currentEventFrame
= GetCurrentEventFrame();
6202 if (currentEventFrame
) {
6203 currentEventFrame
->GetContentForEvent(mPresContext
, aEvent
, &content
);
6212 PresShell::PushCurrentEventInfo(nsIFrame
* aFrame
, nsIContent
* aContent
)
6214 if (mCurrentEventFrame
|| mCurrentEventContent
) {
6215 mCurrentEventFrameStack
.InsertElementAt(0, mCurrentEventFrame
);
6216 mCurrentEventContentStack
.InsertObjectAt(mCurrentEventContent
, 0);
6218 mCurrentEventFrame
= aFrame
;
6219 mCurrentEventContent
= aContent
;
6223 PresShell::PopCurrentEventInfo()
6225 mCurrentEventFrame
= nsnull
;
6226 mCurrentEventContent
= nsnull
;
6228 if (0 != mCurrentEventFrameStack
.Length()) {
6229 mCurrentEventFrame
= mCurrentEventFrameStack
.ElementAt(0);
6230 mCurrentEventFrameStack
.RemoveElementAt(0);
6231 mCurrentEventContent
= mCurrentEventContentStack
.ObjectAt(0);
6232 mCurrentEventContentStack
.RemoveObjectAt(0);
6236 PRBool
PresShell::InZombieDocument(nsIContent
*aContent
)
6238 // If a content node points to a null document, or the document is not
6239 // attached to a window, then it is possibly in a zombie document,
6240 // about to be replaced by a newly loading document.
6241 // Such documents cannot handle DOM events.
6242 // It might actually be in a node not attached to any document,
6243 // in which case there is not parent presshell to retarget it to.
6244 nsIDocument
*doc
= aContent
->GetDocument();
6245 return !doc
|| !doc
->GetWindow();
6248 already_AddRefed
<nsPIDOMWindow
>
6249 PresShell::GetRootWindow()
6251 nsCOMPtr
<nsPIDOMWindow
> window
=
6252 do_QueryInterface(mDocument
->GetWindow());
6254 nsCOMPtr
<nsPIDOMWindow
> rootWindow
= window
->GetPrivateRoot();
6255 NS_ASSERTION(rootWindow
, "nsPIDOMWindow::GetPrivateRoot() returns NULL");
6256 return rootWindow
.forget();
6259 // If we don't have DOM window, we're zombie, we should find the root window
6260 // with our parent shell.
6261 nsCOMPtr
<nsIPresShell
> parent
= GetParentPresShell();
6262 NS_ENSURE_TRUE(parent
, nsnull
);
6263 return parent
->GetRootWindow();
6266 already_AddRefed
<nsIPresShell
>
6267 PresShell::GetParentPresShell()
6269 NS_ENSURE_TRUE(mPresContext
, nsnull
);
6270 nsCOMPtr
<nsISupports
> container
= mPresContext
->GetContainer();
6272 container
= do_QueryReferent(mForwardingContainer
);
6275 // Now, find the parent pres shell and send the event there
6276 nsCOMPtr
<nsIDocShellTreeItem
> treeItem
= do_QueryInterface(container
);
6277 // Might have gone away, or never been around to start with
6278 NS_ENSURE_TRUE(treeItem
, nsnull
);
6280 nsCOMPtr
<nsIDocShellTreeItem
> parentTreeItem
;
6281 treeItem
->GetParent(getter_AddRefs(parentTreeItem
));
6282 nsCOMPtr
<nsIDocShell
> parentDocShell
= do_QueryInterface(parentTreeItem
);
6283 NS_ENSURE_TRUE(parentDocShell
&& treeItem
!= parentTreeItem
, nsnull
);
6285 nsIPresShell
* parentPresShell
= nsnull
;
6286 parentDocShell
->GetPresShell(&parentPresShell
);
6287 return parentPresShell
;
6291 PresShell::RetargetEventToParent(nsGUIEvent
* aEvent
,
6292 nsEventStatus
* aEventStatus
)
6294 // Send this events straight up to the parent pres shell.
6295 // We do this for keystroke events in zombie documents or if either a frame
6296 // or a root content is not present.
6297 // That way at least the UI key bindings can work.
6299 nsCOMPtr
<nsIPresShell
> kungFuDeathGrip(this);
6300 nsCOMPtr
<nsIPresShell
> parentPresShell
= GetParentPresShell();
6301 NS_ENSURE_TRUE(parentPresShell
, NS_ERROR_FAILURE
);
6302 nsCOMPtr
<nsIViewObserver
> parentViewObserver
=
6303 do_QueryInterface(parentPresShell
);
6304 if (!parentViewObserver
) {
6305 return NS_ERROR_FAILURE
;
6308 // Fake the event as though it'ss from the parent pres shell's root view.
6309 nsIView
*parentRootView
;
6310 parentPresShell
->GetViewManager()->GetRootView(parentRootView
);
6312 sDontRetargetEvents
= PR_TRUE
;
6313 nsresult rv
= parentViewObserver
->HandleEvent(parentRootView
, aEvent
, aEventStatus
);
6314 sDontRetargetEvents
= PR_FALSE
;
6319 PresShell::DisableNonTestMouseEvents(PRBool aDisable
)
6321 sDisableNonTestMouseEvents
= aDisable
;
6324 already_AddRefed
<nsPIDOMWindow
>
6325 PresShell::GetFocusedDOMWindowInOurWindow()
6327 nsCOMPtr
<nsPIDOMWindow
> rootWindow
= GetRootWindow();
6328 NS_ENSURE_TRUE(rootWindow
, nsnull
);
6329 nsPIDOMWindow
* focusedWindow
;
6330 nsFocusManager::GetFocusedDescendant(rootWindow
, PR_TRUE
, &focusedWindow
);
6331 return focusedWindow
;
6335 PresShell::HandleEvent(nsIView
*aView
,
6337 nsEventStatus
* aEventStatus
)
6339 NS_ASSERTION(aView
, "null view");
6341 if (mIsDestroying
||
6342 (sDisableNonTestMouseEvents
&& NS_IS_MOUSE_EVENT(aEvent
) &&
6343 !(aEvent
->flags
& NS_EVENT_FLAG_SYNTHETIC_TEST_EVENT
))) {
6347 #ifdef ACCESSIBILITY
6348 if (aEvent
->eventStructType
== NS_ACCESSIBLE_EVENT
) {
6349 NS_TIME_FUNCTION_MIN(1.0);
6351 // Accessibility events come through OS requests and not from scripts,
6352 // so it is safe to handle here
6353 return HandleEventInternal(aEvent
, aView
, aEventStatus
);
6357 if (!nsContentUtils::IsSafeToRunScript())
6360 NS_TIME_FUNCTION_MIN(1.0);
6362 nsIContent
* capturingContent
=
6363 NS_IS_MOUSE_EVENT(aEvent
) ? GetCapturingContent() : nsnull
;
6365 nsCOMPtr
<nsIDocument
> retargetEventDoc
;
6366 if (!sDontRetargetEvents
) {
6367 // key and IME related events should not cross top level window boundary.
6368 // Basically, such input events should be fired only on focused widget.
6369 // However, some IMEs might need to clean up composition after focused
6370 // window is deactivated. And also some tests on MozMill want to test key
6371 // handling on deactivated window because MozMill window can be activated
6372 // during tests. So, there is no merit the events should be redirected to
6373 // active window. So, the events should be handled on the last focused
6374 // content in the last focused DOM window in same top level window.
6375 // Note, if no DOM window has been focused yet, we can discard the events.
6376 if (NS_IsEventTargetedAtFocusedWindow(aEvent
)) {
6377 nsCOMPtr
<nsPIDOMWindow
> window
= GetFocusedDOMWindowInOurWindow();
6378 // No DOM window in same top level window has not been focused yet,
6379 // discard the events.
6384 retargetEventDoc
= do_QueryInterface(window
->GetExtantDocument());
6385 if (!retargetEventDoc
)
6387 } else if (capturingContent
) {
6388 // if the mouse is being captured then retarget the mouse event at the
6389 // document that is being captured.
6390 retargetEventDoc
= capturingContent
->GetCurrentDoc();
6393 if (retargetEventDoc
) {
6394 nsIPresShell
* presShell
= retargetEventDoc
->GetShell();
6398 if (presShell
!= this) {
6399 nsCOMPtr
<nsIViewObserver
> viewObserver
= do_QueryInterface(presShell
);
6401 return NS_ERROR_FAILURE
;
6404 presShell
->GetViewManager()->GetRootView(view
);
6405 sDontRetargetEvents
= PR_TRUE
;
6406 nsresult rv
= viewObserver
->HandleEvent(view
, aEvent
, aEventStatus
);
6407 sDontRetargetEvents
= PR_FALSE
;
6413 // Check for a theme change up front, since the frame type is irrelevant
6414 if (aEvent
->message
== NS_THEMECHANGED
&& mPresContext
) {
6415 mPresContext
->ThemeChanged();
6419 if (aEvent
->message
== NS_UISTATECHANGED
&& mDocument
) {
6420 nsPIDOMWindow
* win
= mDocument
->GetWindow();
6422 nsUIStateChangeEvent
* event
= (nsUIStateChangeEvent
*)aEvent
;
6423 win
->SetKeyboardIndicators(event
->showAccelerators
, event
->showFocusRings
);
6428 // Check for a system color change up front, since the frame type is
6430 if ((aEvent
->message
== NS_SYSCOLORCHANGED
) && mPresContext
) {
6431 nsIViewManager
* vm
= GetViewManager();
6433 // Only dispatch system color change when the message originates from
6434 // from the root views widget. This is necessary to prevent us from
6435 // dispatching the SysColorChanged notification for each child window
6436 // which may be redundant.
6438 vm
->GetRootView(view
);
6439 if (view
== aView
) {
6440 *aEventStatus
= nsEventStatus_eConsumeDoDefault
;
6441 mPresContext
->SysColorChanged();
6448 if (aEvent
->eventStructType
== NS_KEY_EVENT
&&
6449 mDocument
&& mDocument
->EventHandlingSuppressed()) {
6450 if (aEvent
->message
== NS_KEY_DOWN
) {
6451 mNoDelayedKeyEvents
= PR_TRUE
;
6452 } else if (!mNoDelayedKeyEvents
) {
6453 nsDelayedEvent
* event
=
6454 new nsDelayedKeyEvent(static_cast<nsKeyEvent
*>(aEvent
));
6455 if (event
&& !mDelayedEvents
.AppendElement(event
)) {
6462 nsIFrame
* frame
= static_cast<nsIFrame
*>(aView
->GetClientData());
6463 PRBool dispatchUsingCoordinates
= NS_IsEventUsingCoordinates(aEvent
);
6465 // if this event has no frame, we need to retarget it at a parent
6466 // view that has a frame.
6468 (dispatchUsingCoordinates
|| NS_IS_KEY_EVENT(aEvent
) ||
6469 NS_IS_IME_RELATED_EVENT(aEvent
) || NS_IS_NON_RETARGETED_PLUGIN_EVENT(aEvent
) ||
6470 aEvent
->message
== NS_PLUGIN_ACTIVATE
|| aEvent
->message
== NS_PLUGIN_FOCUS
)) {
6471 nsIView
* targetView
= aView
;
6472 while (targetView
&& !targetView
->GetClientData()) {
6473 targetView
= targetView
->GetParent();
6478 frame
= static_cast<nsIFrame
*>(aView
->GetClientData());
6482 if (dispatchUsingCoordinates
) {
6483 NS_WARN_IF_FALSE(frame
, "Nothing to handle this event!");
6487 nsPresContext
* framePresContext
= frame
->PresContext();
6488 nsPresContext
* rootPresContext
= framePresContext
->GetRootPresContext();
6489 NS_ASSERTION(rootPresContext
== mPresContext
->GetRootPresContext(),
6490 "How did we end up outside the connected prescontext/viewmanager hierarchy?");
6491 // If we aren't starting our event dispatch from the root frame of the root prescontext,
6492 // then someone must be capturing the mouse. In that case we don't want to search the popup
6494 if (framePresContext
== rootPresContext
&&
6495 frame
== FrameManager()->GetRootFrame()) {
6496 nsIFrame
* popupFrame
=
6497 nsLayoutUtils::GetPopupFrameForEventCoordinates(rootPresContext
, aEvent
);
6498 // If the popupFrame is an ancestor of the 'frame', the frame should
6499 // handle the event, otherwise, the popup should handle it.
6501 !nsContentUtils::ContentIsCrossDocDescendantOf(
6502 framePresContext
->GetPresShell()->GetDocument(),
6503 popupFrame
->GetContent())) {
6508 PRBool captureRetarget
= PR_FALSE
;
6509 if (capturingContent
) {
6510 // If a capture is active, determine if the docshell is visible. If not,
6511 // clear the capture and target the mouse event normally instead. This
6512 // would occur if the mouse button is held down while a tab change occurs.
6513 // If the docshell is visible, look for a scrolling container.
6515 nsCOMPtr
<nsISupports
> supports
= mPresContext
->GetContainer();
6516 nsCOMPtr
<nsIBaseWindow
> baseWin(do_QueryInterface(supports
));
6517 if (baseWin
&& NS_SUCCEEDED(baseWin
->GetVisibility(&vis
)) && vis
) {
6518 captureRetarget
= gCaptureInfo
.mRetargetToElement
;
6519 if (!captureRetarget
) {
6520 // A check was already done above to ensure that capturingContent is
6521 // in this presshell.
6522 NS_ASSERTION(capturingContent
->GetCurrentDoc() == GetDocument(),
6523 "Unexpected document");
6524 nsIFrame
* captureFrame
= capturingContent
->GetPrimaryFrame();
6526 if (capturingContent
->Tag() == nsGkAtoms::select
&&
6527 capturingContent
->IsHTML()) {
6528 // a dropdown <select> has a child in its selectPopupList and we should
6529 // capture on that instead.
6530 nsIFrame
* childFrame
= captureFrame
->GetChildList(nsGkAtoms::selectPopupList
).FirstChild();
6532 captureFrame
= childFrame
;
6536 // scrollable frames should use the scrolling container as
6537 // the root instead of the document
6538 nsIScrollableFrame
* scrollFrame
= do_QueryFrame(captureFrame
);
6540 frame
= scrollFrame
->GetScrolledFrame();
6546 ClearMouseCapture(nsnull
);
6547 capturingContent
= nsnull
;
6551 // Get the frame at the event point. However, don't do this if we're
6552 // capturing and retargeting the event because the captured frame will
6553 // be used instead below.
6554 if (!captureRetarget
) {
6556 = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent
, frame
);
6558 PRBool ignoreRootScrollFrame
= PR_FALSE
;
6559 if (aEvent
->eventStructType
== NS_MOUSE_EVENT
) {
6560 ignoreRootScrollFrame
= static_cast<nsMouseEvent
*>(aEvent
)->ignoreRootScrollFrame
;
6562 nsIFrame
* target
= nsLayoutUtils::GetFrameForPoint(frame
, eventPoint
,
6563 PR_FALSE
, ignoreRootScrollFrame
);
6570 // if a node is capturing the mouse, check if the event needs to be
6571 // retargeted at the capturing content instead. This will be the case when
6572 // capture retargeting is being used, no frame was found or the frame's
6573 // content is not a descendant of the capturing content.
6574 if (capturingContent
&&
6575 (gCaptureInfo
.mRetargetToElement
|| !frame
->GetContent() ||
6576 !nsContentUtils::ContentIsCrossDocDescendantOf(frame
->GetContent(),
6577 capturingContent
))) {
6578 // A check was already done above to ensure that capturingContent is
6579 // in this presshell.
6580 NS_ASSERTION(capturingContent
->GetCurrentDoc() == GetDocument(),
6581 "Unexpected document");
6582 nsIFrame
* capturingFrame
= capturingContent
->GetPrimaryFrame();
6583 if (capturingFrame
) {
6584 frame
= capturingFrame
;
6585 aView
= frame
->GetClosestView();
6589 // Suppress mouse event if it's being targeted at an element inside
6590 // a document which needs events suppressed
6591 if (aEvent
->eventStructType
== NS_MOUSE_EVENT
&&
6592 frame
->PresContext()->Document()->EventHandlingSuppressed()) {
6593 if (aEvent
->message
== NS_MOUSE_BUTTON_DOWN
) {
6594 mNoDelayedMouseEvents
= PR_TRUE
;
6595 } else if (!mNoDelayedMouseEvents
&& aEvent
->message
== NS_MOUSE_BUTTON_UP
) {
6596 nsDelayedEvent
* event
=
6597 new nsDelayedMouseEvent(static_cast<nsMouseEvent
*>(aEvent
));
6598 if (!mDelayedEvents
.AppendElement(event
)) {
6607 static_cast<PresShell
*>(frame
->PresContext()->PresShell());
6609 // Check if we have an active EventStateManager which isn't the
6610 // EventStateManager of the current PresContext.
6611 // If that is the case, and mouse is over some ancestor document,
6612 // forward event handling to the active document.
6613 // This way content can get mouse events even when
6614 // mouse is over the chrome or outside the window.
6616 // Note, currently for backwards compatibility we don't forward mouse events
6617 // to the active document when mouse is over some subdocument.
6618 nsIEventStateManager
* activeESM
=
6619 nsEventStateManager::GetActiveEventStateManager();
6620 if (activeESM
&& NS_IS_MOUSE_EVENT(aEvent
) &&
6621 activeESM
!= shell
->GetPresContext()->EventStateManager() &&
6622 static_cast<nsEventStateManager
*>(activeESM
)->GetPresContext()) {
6623 nsIPresShell
* activeShell
=
6624 static_cast<nsEventStateManager
*>(activeESM
)->GetPresContext()->GetPresShell();
6626 nsContentUtils::ContentIsCrossDocDescendantOf(activeShell
->GetDocument(),
6627 shell
->GetDocument())) {
6628 shell
= static_cast<PresShell
*>(activeShell
);
6629 nsIView
* activeShellRootView
;
6630 shell
->GetViewManager()->GetRootView(activeShellRootView
);
6631 frame
= static_cast<nsIFrame
*>(activeShellRootView
->GetClientData());
6635 if (shell
!= this) {
6636 // Handle the event in the correct shell.
6637 // Prevent deletion until we're done with event handling (bug 336582).
6638 nsCOMPtr
<nsIPresShell
> kungFuDeathGrip(shell
);
6639 nsIView
* subshellRootView
;
6640 shell
->GetViewManager()->GetRootView(subshellRootView
);
6641 // We pass the subshell's root view as the view to start from. This is
6642 // the only correct alternative; if the event was captured then it
6643 // must have been captured by us or some ancestor shell and we
6644 // now ask the subshell to dispatch it normally.
6645 return shell
->HandlePositionedEvent(subshellRootView
, frame
,
6646 aEvent
, aEventStatus
);
6649 return HandlePositionedEvent(aView
, frame
, aEvent
, aEventStatus
);
6652 nsresult rv
= NS_OK
;
6655 PushCurrentEventInfo(nsnull
, nsnull
);
6657 // key and IME related events go to the focused frame in this DOM window.
6658 if (NS_IsEventTargetedAtFocusedContent(aEvent
)) {
6659 NS_ASSERTION(mDocument
, "mDocument is null");
6660 nsCOMPtr
<nsPIDOMWindow
> window
=
6661 do_QueryInterface(mDocument
->GetWindow());
6662 nsCOMPtr
<nsPIDOMWindow
> focusedWindow
;
6663 mCurrentEventContent
=
6664 nsFocusManager::GetFocusedDescendant(window
, PR_FALSE
,
6665 getter_AddRefs(focusedWindow
));
6667 // otherwise, if there is no focused content or the focused content has
6668 // no frame, just use the root content. This ensures that key events
6669 // still get sent to the window properly if nothing is focused or if a
6670 // frame goes away while it is focused.
6671 if (!mCurrentEventContent
|| !GetCurrentEventFrame())
6672 mCurrentEventContent
= mDocument
->GetRootElement();
6674 if (aEvent
->message
== NS_KEY_DOWN
) {
6675 NS_IF_RELEASE(gKeyDownTarget
);
6676 NS_IF_ADDREF(gKeyDownTarget
= mCurrentEventContent
);
6678 else if ((aEvent
->message
== NS_KEY_PRESS
|| aEvent
->message
== NS_KEY_UP
) &&
6680 // If a different element is now focused for the keypress/keyup event
6681 // than what was focused during the keydown event, check if the new
6682 // focused element is not in a chrome document any more, and if so,
6683 // retarget the event back at the keydown target. This prevents a
6684 // content area from grabbing the focus from chrome in-between key
6686 if (mCurrentEventContent
&&
6687 nsContentUtils::IsChromeDoc(gKeyDownTarget
->GetCurrentDoc()) &&
6688 !nsContentUtils::IsChromeDoc(mCurrentEventContent
->GetCurrentDoc())) {
6689 mCurrentEventContent
= gKeyDownTarget
;
6692 if (aEvent
->message
== NS_KEY_UP
) {
6693 NS_RELEASE(gKeyDownTarget
);
6697 mCurrentEventFrame
= nsnull
;
6699 if (!mCurrentEventContent
|| !GetCurrentEventFrame() ||
6700 InZombieDocument(mCurrentEventContent
)) {
6701 rv
= RetargetEventToParent(aEvent
, aEventStatus
);
6702 PopCurrentEventInfo();
6706 mCurrentEventFrame
= frame
;
6708 if (GetCurrentEventFrame()) {
6709 rv
= HandleEventInternal(aEvent
, aView
, aEventStatus
);
6713 ShowEventTargetDebug();
6715 PopCurrentEventInfo();
6717 // Activation events need to be dispatched even if no frame was found, since
6718 // we don't want the focus to be out of sync.
6720 if (!NS_EVENT_NEEDS_FRAME(aEvent
)) {
6721 mCurrentEventFrame
= nsnull
;
6722 return HandleEventInternal(aEvent
, aView
, aEventStatus
);
6724 else if (NS_IS_KEY_EVENT(aEvent
)) {
6725 // Keypress events in new blank tabs should not be completely thrown away.
6726 // Retarget them -- the parent chrome shell might make use of them.
6727 return RetargetEventToParent(aEvent
, aEventStatus
);
6736 PresShell::ShowEventTargetDebug()
6738 if (nsFrame::GetShowEventTargetFrameBorder() &&
6739 GetCurrentEventFrame()) {
6740 if (mDrawEventTargetFrame
) {
6741 mDrawEventTargetFrame
->Invalidate(
6742 nsRect(nsPoint(0, 0), mDrawEventTargetFrame
->GetSize()));
6745 mDrawEventTargetFrame
= mCurrentEventFrame
;
6746 mDrawEventTargetFrame
->Invalidate(
6747 nsRect(nsPoint(0, 0), mDrawEventTargetFrame
->GetSize()));
6753 PresShell::HandlePositionedEvent(nsIView
* aView
,
6754 nsIFrame
* aTargetFrame
,
6756 nsEventStatus
* aEventStatus
)
6758 nsresult rv
= NS_OK
;
6760 PushCurrentEventInfo(nsnull
, nsnull
);
6762 mCurrentEventFrame
= aTargetFrame
;
6764 if (mCurrentEventFrame
) {
6765 nsCOMPtr
<nsIContent
> targetElement
;
6766 mCurrentEventFrame
->GetContentForEvent(mPresContext
, aEvent
,
6767 getter_AddRefs(targetElement
));
6769 // If there is no content for this frame, target it anyway. Some
6770 // frames can be targeted but do not have content, particularly
6771 // windows with scrolling off.
6772 if (targetElement
) {
6773 // Bug 103055, bug 185889: mouse events apply to *elements*, not all
6774 // nodes. Thus we get the nearest element parent here.
6775 // XXX we leave the frame the same even if we find an element
6776 // parent, so that the text frame will receive the event (selection
6777 // and friends are the ones who care about that anyway)
6779 // We use weak pointers because during this tight loop, the node
6780 // will *not* go away. And this happens on every mousemove.
6781 while (targetElement
&& !targetElement
->IsElement()) {
6782 targetElement
= targetElement
->GetParent();
6785 // If we found an element, target it. Otherwise, target *nothing*.
6786 if (!targetElement
) {
6787 mCurrentEventContent
= nsnull
;
6788 mCurrentEventFrame
= nsnull
;
6789 } else if (targetElement
!= mCurrentEventContent
) {
6790 mCurrentEventContent
= targetElement
;
6795 if (GetCurrentEventFrame()) {
6796 rv
= HandleEventInternal(aEvent
, aView
, aEventStatus
);
6800 ShowEventTargetDebug();
6802 PopCurrentEventInfo();
6807 PresShell::HandleEventWithTarget(nsEvent
* aEvent
, nsIFrame
* aFrame
,
6808 nsIContent
* aContent
, nsEventStatus
* aStatus
)
6810 PushCurrentEventInfo(aFrame
, aContent
);
6811 nsresult rv
= HandleEventInternal(aEvent
, nsnull
, aStatus
);
6812 PopCurrentEventInfo();
6816 static inline PRBool
6817 IsSynthesizedMouseEvent(nsEvent
* aEvent
)
6819 return aEvent
->eventStructType
== NS_MOUSE_EVENT
&&
6820 static_cast<nsMouseEvent
*>(aEvent
)->reason
!= nsMouseEvent::eReal
;
6823 static PRBool
CanHandleContextMenuEvent(nsMouseEvent
* aMouseEvent
,
6826 #if defined(XP_MACOSX) && defined(MOZ_XUL)
6827 nsXULPopupManager
* pm
= nsXULPopupManager::GetInstance();
6829 nsIFrame
* popupFrame
= pm
->GetTopPopup(ePopupTypeMenu
);
6831 // context menus should not be opened while another menu is open on Mac,
6832 // so return false so that the event is not fired.
6833 if (aMouseEvent
->context
== nsMouseEvent::eContextMenuKey
) {
6835 } else if (aMouseEvent
->widget
) {
6836 nsWindowType windowType
;
6837 aMouseEvent
->widget
->GetWindowType(windowType
);
6838 if (windowType
== eWindowType_popup
) {
6839 for (nsIFrame
* current
= aFrame
; current
;
6840 current
= nsLayoutUtils::GetCrossDocParentFrame(current
)) {
6841 if (current
->GetType() == nsGkAtoms::menuPopupFrame
) {
6854 PresShell::HandleEventInternal(nsEvent
* aEvent
, nsIView
*aView
,
6855 nsEventStatus
* aStatus
)
6857 NS_TIME_FUNCTION_MIN(1.0);
6859 #ifdef ACCESSIBILITY
6860 if (aEvent
->eventStructType
== NS_ACCESSIBLE_EVENT
)
6862 nsAccessibleEvent
*accEvent
= static_cast<nsAccessibleEvent
*>(aEvent
);
6863 accEvent
->mAccessible
= nsnull
;
6865 nsCOMPtr
<nsIAccessibilityService
> accService
=
6866 do_GetService("@mozilla.org/accessibilityService;1");
6868 nsCOMPtr
<nsISupports
> container
= mPresContext
->GetContainer();
6870 // This presshell is not active. This often happens when a
6871 // preshell is being held onto for fastback.
6875 // Accessible creation might be not safe so we make sure it's not created
6877 accEvent
->mAccessible
=
6878 accService
->GetRootDocumentAccessible(this, nsContentUtils::IsSafeToRunScript());
6880 // Ensure this is set in case a11y was activated before any
6881 // nsPresShells existed to observe "a11y-init-or-shutdown" topic
6882 gIsAccessibilityActive
= PR_TRUE
;
6888 nsCOMPtr
<nsIEventStateManager
> manager
= mPresContext
->EventStateManager();
6889 nsresult rv
= NS_OK
;
6891 if (!NS_EVENT_NEEDS_FRAME(aEvent
) || GetCurrentEventFrame()) {
6892 PRBool isHandlingUserInput
= PR_FALSE
;
6894 if (NS_IS_TRUSTED_EVENT(aEvent
)) {
6895 switch (aEvent
->message
) {
6896 case NS_MOUSE_BUTTON_DOWN
:
6897 case NS_MOUSE_BUTTON_UP
:
6901 isHandlingUserInput
= PR_TRUE
;
6903 case NS_DRAGDROP_DROP
:
6904 nsCOMPtr
<nsIDragSession
> session
= nsContentUtils::GetDragSession();
6906 PRBool onlyChromeDrop
= PR_FALSE
;
6907 session
->GetOnlyChromeDrop(&onlyChromeDrop
);
6908 if (onlyChromeDrop
) {
6909 aEvent
->flags
|= NS_EVENT_FLAG_ONLY_CHROME_DISPATCH
;
6916 if (aEvent
->message
== NS_CONTEXTMENU
) {
6917 nsMouseEvent
* me
= static_cast<nsMouseEvent
*>(aEvent
);
6918 if (!CanHandleContextMenuEvent(me
, GetCurrentEventFrame())) {
6921 if (me
->context
== nsMouseEvent::eContextMenuKey
&&
6922 !AdjustContextMenuKeyEvent(me
)) {
6927 nsAutoHandlingUserInputStatePusher
userInpStatePusher(isHandlingUserInput
,
6930 if (NS_IS_TRUSTED_EVENT(aEvent
) && aEvent
->message
== NS_MOUSE_MOVE
) {
6931 nsIPresShell::AllowMouseCapture(
6932 nsEventStateManager::GetActiveEventStateManager() == manager
);
6935 nsAutoPopupStatePusher
popupStatePusher(nsDOMEvent::GetEventPopupControlState(aEvent
));
6937 // FIXME. If the event was reused, we need to clear the old target,
6939 aEvent
->target
= nsnull
;
6941 nsWeakView
weakView(aView
);
6942 // 1. Give event to event manager for pre event state changes and
6943 // generation of synthetic events.
6944 rv
= manager
->PreHandleEvent(mPresContext
, aEvent
, mCurrentEventFrame
,
6947 // 2. Give event to the DOM for third party and JS use.
6948 if (GetCurrentEventFrame() && NS_SUCCEEDED(rv
)) {
6949 PRBool wasHandlingKeyBoardEvent
=
6950 nsContentUtils::IsHandlingKeyBoardEvent();
6951 if (aEvent
->eventStructType
== NS_KEY_EVENT
) {
6952 nsContentUtils::SetIsHandlingKeyBoardEvent(PR_TRUE
);
6954 // We want synthesized mouse moves to cause mouseover and mouseout
6955 // DOM events (PreHandleEvent above), but not mousemove DOM events.
6956 // Synthesized button up events also do not cause DOM events
6957 // because they do not have a reliable refPoint.
6958 if (!IsSynthesizedMouseEvent(aEvent
)) {
6959 nsPresShellEventCB
eventCB(this);
6960 if (mCurrentEventContent
) {
6961 nsEventDispatcher::Dispatch(mCurrentEventContent
, mPresContext
,
6962 aEvent
, nsnull
, aStatus
, &eventCB
);
6965 nsCOMPtr
<nsIContent
> targetContent
;
6966 rv
= mCurrentEventFrame
->GetContentForEvent(mPresContext
, aEvent
,
6967 getter_AddRefs(targetContent
));
6968 if (NS_SUCCEEDED(rv
) && targetContent
) {
6969 nsEventDispatcher::Dispatch(targetContent
, mPresContext
, aEvent
,
6970 nsnull
, aStatus
, &eventCB
);
6971 } else if (mDocument
) {
6972 nsEventDispatcher::Dispatch(mDocument
, mPresContext
, aEvent
,
6973 nsnull
, aStatus
, nsnull
);
6978 nsContentUtils::SetIsHandlingKeyBoardEvent(wasHandlingKeyBoardEvent
);
6980 // 3. Give event to event manager for post event state changes and
6981 // generation of synthetic events.
6982 if (!mIsDestroying
&& NS_SUCCEEDED(rv
)) {
6983 rv
= manager
->PostHandleEvent(mPresContext
, aEvent
,
6984 GetCurrentEventFrame(), aStatus
,
6985 weakView
.GetView());
6989 if (aEvent
->message
== NS_MOUSE_BUTTON_UP
) {
6990 // reset the capturing content now that the mouse button is up
6991 SetCapturingContent(nsnull
, 0);
6992 } else if (aEvent
->message
== NS_MOUSE_MOVE
) {
6993 nsIPresShell::AllowMouseCapture(PR_FALSE
);
6999 // Dispatch event to content only (NOT full processing)
7000 // See also HandleEventWithTarget which does full event processing.
7002 PresShell::HandleDOMEventWithTarget(nsIContent
* aTargetContent
, nsEvent
* aEvent
,
7003 nsEventStatus
* aStatus
)
7005 nsresult rv
= NS_OK
;
7007 PushCurrentEventInfo(nsnull
, aTargetContent
);
7009 // Bug 41013: Check if the event should be dispatched to content.
7010 // It's possible that we are in the middle of destroying the window
7011 // and the js context is out of date. This check detects the case
7012 // that caused a crash in bug 41013, but there may be a better way
7013 // to handle this situation!
7014 nsCOMPtr
<nsISupports
> container
= mPresContext
->GetContainer();
7017 // Dispatch event to content
7018 rv
= nsEventDispatcher::Dispatch(aTargetContent
, mPresContext
, aEvent
, nsnull
,
7022 PopCurrentEventInfo();
7026 // See the method above.
7028 PresShell::HandleDOMEventWithTarget(nsIContent
* aTargetContent
,
7029 nsIDOMEvent
* aEvent
,
7030 nsEventStatus
* aStatus
)
7032 nsresult rv
= NS_OK
;
7034 PushCurrentEventInfo(nsnull
, aTargetContent
);
7035 nsCOMPtr
<nsISupports
> container
= mPresContext
->GetContainer();
7037 rv
= nsEventDispatcher::DispatchDOMEvent(aTargetContent
, nsnull
, aEvent
,
7038 mPresContext
, aStatus
);
7041 PopCurrentEventInfo();
7046 PresShell::AdjustContextMenuKeyEvent(nsMouseEvent
* aEvent
)
7049 // if a menu is open, open the context menu relative to the active item on the menu.
7050 nsXULPopupManager
* pm
= nsXULPopupManager::GetInstance();
7052 nsIFrame
* popupFrame
= pm
->GetTopPopup(ePopupTypeMenu
);
7054 nsIFrame
* itemFrame
=
7055 (static_cast<nsMenuPopupFrame
*>(popupFrame
))->GetCurrentMenuItem();
7057 itemFrame
= popupFrame
;
7059 nsCOMPtr
<nsIWidget
> widget
= popupFrame
->GetNearestWidget();
7060 aEvent
->widget
= widget
;
7061 nsIntPoint widgetPoint
= widget
->WidgetToScreenOffset();
7062 aEvent
->refPoint
= itemFrame
->GetScreenRect().BottomLeft() - widgetPoint
;
7064 mCurrentEventContent
= itemFrame
->GetContent();
7065 mCurrentEventFrame
= itemFrame
;
7072 // If we're here because of the key-equiv for showing context menus, we
7073 // have to twiddle with the NS event to make sure the context menu comes
7074 // up in the upper left of the relevant content area before we create
7075 // the DOM event. Since we never call InitMouseEvent() on the event,
7076 // the client X/Y will be 0,0. We can make use of that if the widget is null.
7077 // Use the root view manager's widget since it's most likely to have one,
7078 // and the coordinates returned by GetCurrentItemAndPositionForElement
7079 // are relative to the widget of the root of the root view manager.
7080 nsRootPresContext
* rootPC
= mPresContext
->GetRootPresContext();
7081 aEvent
->refPoint
.x
= 0;
7082 aEvent
->refPoint
.y
= 0;
7084 rootPC
->PresShell()->GetViewManager()->
7085 GetRootWidget(getter_AddRefs(aEvent
->widget
));
7087 if (aEvent
->widget
) {
7088 // default the refpoint to the topleft of our document
7089 nsPoint
offset(0, 0);
7090 nsIFrame
* rootFrame
= FrameManager()->GetRootFrame();
7092 nsIView
* view
= rootFrame
->GetClosestView(&offset
);
7093 offset
+= view
->GetOffsetToWidget(aEvent
->widget
);
7095 offset
.ToNearestPixels(mPresContext
->AppUnitsPerDevPixel());
7099 aEvent
->widget
= nsnull
;
7102 // see if we should use the caret position for the popup
7103 nsIntPoint caretPoint
;
7104 // Beware! This may flush notifications via synchronous
7105 // ScrollSelectionIntoView.
7106 if (PrepareToUseCaretPosition(aEvent
->widget
, caretPoint
)) {
7107 // caret position is good
7108 aEvent
->refPoint
= caretPoint
;
7112 // If we're here because of the key-equiv for showing context menus, we
7113 // have to reset the event target to the currently focused element. Get it
7114 // from the focus controller.
7115 nsCOMPtr
<nsIDOMElement
> currentFocus
;
7116 nsIFocusManager
* fm
= nsFocusManager::GetFocusManager();
7118 fm
->GetFocusedElement(getter_AddRefs(currentFocus
));
7120 // Reset event coordinates relative to focused frame in view
7122 nsCOMPtr
<nsIContent
> currentPointElement
;
7123 GetCurrentItemAndPositionForElement(currentFocus
,
7124 getter_AddRefs(currentPointElement
),
7127 if (currentPointElement
) {
7128 mCurrentEventContent
= currentPointElement
;
7129 mCurrentEventFrame
= nsnull
;
7130 GetCurrentEventFrame();
7137 // PresShell::PrepareToUseCaretPosition
7139 // This checks to see if we should use the caret position for popup context
7140 // menus. Returns true if the caret position should be used, and the
7141 // coordinates of that position is returned in aTargetPt. This function
7142 // will also scroll the window as needed to make the caret visible.
7144 // The event widget should be the widget that generated the event, and
7145 // whose coordinate system the resulting event's refPoint should be
7146 // relative to. The returned point is in device pixels realtive to the
7147 // widget passed in.
7149 PresShell::PrepareToUseCaretPosition(nsIWidget
* aEventWidget
, nsIntPoint
& aTargetPt
)
7153 // check caret visibility
7154 nsRefPtr
<nsCaret
> caret
= GetCaret();
7155 NS_ENSURE_TRUE(caret
, PR_FALSE
);
7157 PRBool caretVisible
= PR_FALSE
;
7158 rv
= caret
->GetCaretVisible(&caretVisible
);
7159 if (NS_FAILED(rv
) || ! caretVisible
)
7162 // caret selection, this is a temporary weak reference, so no refcounting is
7164 nsISelection
* domSelection
= caret
->GetCaretDOMSelection();
7165 NS_ENSURE_TRUE(domSelection
, PR_FALSE
);
7167 // since the match could be an anonymous textnode inside a
7168 // <textarea> or text <input>, we need to get the outer frame
7169 // note: frames are not refcounted
7170 nsIFrame
* frame
= nsnull
; // may be NULL
7171 nsCOMPtr
<nsIDOMNode
> node
;
7172 rv
= domSelection
->GetFocusNode(getter_AddRefs(node
));
7173 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
7174 NS_ENSURE_TRUE(node
, PR_FALSE
);
7175 nsCOMPtr
<nsIContent
> content(do_QueryInterface(node
));
7177 nsIContent
* nonNative
= content
->FindFirstNonNativeAnonymous();
7178 content
= nonNative
;
7182 // It seems like ScrollSelectionIntoView should be enough, but it's
7183 // not. The problem is that scrolling the selection into view when it is
7184 // below the current viewport will align the top line of the frame exactly
7185 // with the bottom of the window. This is fine, BUT, the popup event causes
7186 // the control to be re-focused which does this exact call to
7187 // ScrollContentIntoView, which has a one-pixel disagreement of whether the
7188 // frame is actually in view. The result is that the frame is aligned with
7189 // the top of the window, but the menu is still at the bottom.
7191 // Doing this call first forces the frame to be in view, eliminating the
7192 // problem. The only difference in the result is that if your cursor is in
7193 // an edit box below the current view, you'll get the edit box aligned with
7194 // the top of the window. This is arguably better behavior anyway.
7195 rv
= ScrollContentIntoView(content
, NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE
,
7196 NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE
,
7197 SCROLL_OVERFLOW_HIDDEN
);
7198 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
7199 frame
= content
->GetPrimaryFrame();
7200 NS_WARN_IF_FALSE(frame
, "No frame for focused content?");
7203 // Actually scroll the selection (ie caret) into view. Note that this must
7204 // be synchronous since we will be checking the caret position on the screen.
7206 // Be easy about errors, and just don't scroll in those cases. Better to have
7207 // the correct menu at a weird place than the wrong menu.
7208 // After ScrollSelectionIntoView(), the pending notifications might be
7209 // flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
7210 nsCOMPtr
<nsISelectionController
> selCon
;
7212 frame
->GetSelectionController(GetPresContext(), getter_AddRefs(selCon
));
7214 selCon
= static_cast<nsISelectionController
*>(this);
7216 rv
= selCon
->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL
,
7217 nsISelectionController::SELECTION_FOCUS_REGION
,
7218 nsISelectionController::SCROLL_SYNCHRONOUS
);
7219 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
7222 nsPresContext
* presContext
= GetPresContext();
7224 // get caret position relative to the closest view
7226 nsIFrame
* caretFrame
= caret
->GetGeometry(domSelection
, &caretCoords
);
7230 nsIView
* view
= caretFrame
->GetClosestView(&viewOffset
);
7233 // and then get the caret coords relative to the event widget
7235 viewOffset
+= view
->GetOffsetToWidget(aEventWidget
);
7237 caretCoords
.MoveBy(viewOffset
);
7239 // caret coordinates are in app units, convert to pixels
7241 presContext
->AppUnitsToDevPixels(caretCoords
.x
+ caretCoords
.width
);
7243 presContext
->AppUnitsToDevPixels(caretCoords
.y
+ caretCoords
.height
);
7245 // make sure rounding doesn't return a pixel which is outside the caret
7246 // (e.g. one line lower)
7253 PresShell::GetCurrentItemAndPositionForElement(nsIDOMElement
*aCurrentEl
,
7254 nsIContent
** aTargetToUse
,
7255 nsIntPoint
& aTargetPt
,
7256 nsIWidget
*aRootWidget
)
7258 nsCOMPtr
<nsIContent
> focusedContent(do_QueryInterface(aCurrentEl
));
7259 ScrollContentIntoView(focusedContent
, NS_PRESSHELL_SCROLL_ANYWHERE
,
7260 NS_PRESSHELL_SCROLL_ANYWHERE
,
7261 SCROLL_OVERFLOW_HIDDEN
);
7263 nsPresContext
* presContext
= GetPresContext();
7265 PRBool istree
= PR_FALSE
, checkLineHeight
= PR_TRUE
;
7266 nscoord extraTreeY
= 0;
7269 // Set the position to just underneath the current item for multi-select
7270 // lists or just underneath the selected item for single-select lists. If
7271 // the element is not a list, or there is no selection, leave the position
7273 nsCOMPtr
<nsIDOMXULSelectControlItemElement
> item
;
7274 nsCOMPtr
<nsIDOMXULMultiSelectControlElement
> multiSelect
=
7275 do_QueryInterface(aCurrentEl
);
7277 checkLineHeight
= PR_FALSE
;
7279 PRInt32 currentIndex
;
7280 multiSelect
->GetCurrentIndex(¤tIndex
);
7281 if (currentIndex
>= 0) {
7282 nsCOMPtr
<nsIDOMXULElement
> xulElement(do_QueryInterface(aCurrentEl
));
7284 nsCOMPtr
<nsIBoxObject
> box
;
7285 xulElement
->GetBoxObject(getter_AddRefs(box
));
7286 nsCOMPtr
<nsITreeBoxObject
> treeBox(do_QueryInterface(box
));
7287 // Tree view special case (tree items have no frames)
7288 // Get the focused row and add its coordinates, which are already in pixels
7289 // XXX Boris, should we create a new interface so that this doesn't
7290 // need to know about trees? Something like nsINodelessChildCreator which
7291 // could provide the current focus coordinates?
7293 treeBox
->EnsureRowIsVisible(currentIndex
);
7294 PRInt32 firstVisibleRow
, rowHeight
;
7295 treeBox
->GetFirstVisibleRow(&firstVisibleRow
);
7296 treeBox
->GetRowHeight(&rowHeight
);
7298 extraTreeY
+= presContext
->CSSPixelsToAppUnits(
7299 (currentIndex
- firstVisibleRow
+ 1) * rowHeight
);
7302 nsCOMPtr
<nsITreeColumns
> cols
;
7303 treeBox
->GetColumns(getter_AddRefs(cols
));
7305 nsCOMPtr
<nsITreeColumn
> col
;
7306 cols
->GetFirstColumn(getter_AddRefs(col
));
7308 nsCOMPtr
<nsIDOMElement
> colElement
;
7309 col
->GetElement(getter_AddRefs(colElement
));
7310 nsCOMPtr
<nsIContent
> colContent(do_QueryInterface(colElement
));
7312 nsIFrame
* frame
= colContent
->GetPrimaryFrame();
7314 extraTreeY
+= frame
->GetSize().height
;
7321 multiSelect
->GetCurrentItem(getter_AddRefs(item
));
7327 // don't check menulists as the selected item will be inside a popup.
7328 nsCOMPtr
<nsIDOMXULMenuListElement
> menulist
= do_QueryInterface(aCurrentEl
);
7330 nsCOMPtr
<nsIDOMXULSelectControlElement
> select
=
7331 do_QueryInterface(aCurrentEl
);
7333 checkLineHeight
= PR_FALSE
;
7334 select
->GetSelectedItem(getter_AddRefs(item
));
7340 focusedContent
= do_QueryInterface(item
);
7343 nsIFrame
*frame
= focusedContent
->GetPrimaryFrame();
7345 NS_ASSERTION(frame
->PresContext() == GetPresContext(),
7346 "handling event for focused content that is not in our document?");
7348 nsPoint
frameOrigin(0, 0);
7350 // Get the frame's origin within its view
7351 nsIView
*view
= frame
->GetClosestView(&frameOrigin
);
7352 NS_ASSERTION(view
, "No view for frame");
7354 // View's origin relative the widget
7356 frameOrigin
+= view
->GetOffsetToWidget(aRootWidget
);
7359 // Start context menu down and to the right from top left of frame
7360 // use the lineheight. This is a good distance to move the context
7361 // menu away from the top left corner of the frame. If we always
7362 // used the frame height, the context menu could end up far away,
7363 // for example when we're focused on linked images.
7364 // On the other hand, we want to use the frame height if it's less
7365 // than the current line height, so that the context menu appears
7366 // associated with the correct frame.
7369 extra
= frame
->GetSize().height
;
7370 if (checkLineHeight
) {
7371 nsIScrollableFrame
*scrollFrame
=
7372 nsLayoutUtils::GetNearestScrollableFrame(frame
);
7374 nsSize scrollAmount
= scrollFrame
->GetLineScrollAmount();
7375 nsIFrame
* f
= do_QueryFrame(scrollFrame
);
7376 PRInt32 APD
= presContext
->AppUnitsPerDevPixel();
7377 PRInt32 scrollAPD
= f
->PresContext()->AppUnitsPerDevPixel();
7378 scrollAmount
= scrollAmount
.ConvertAppUnits(scrollAPD
, APD
);
7379 if (extra
> scrollAmount
.height
) {
7380 extra
= scrollAmount
.height
;
7386 aTargetPt
.x
= presContext
->AppUnitsToDevPixels(frameOrigin
.x
);
7387 aTargetPt
.y
= presContext
->AppUnitsToDevPixels(
7388 frameOrigin
.y
+ extra
+ extraTreeY
);
7391 NS_IF_ADDREF(*aTargetToUse
= focusedContent
);
7395 PresShell::ResizeReflow(nsIView
*aView
, nscoord aWidth
, nscoord aHeight
)
7397 return ResizeReflow(aWidth
, aHeight
);
7400 NS_IMETHODIMP_(PRBool
)
7401 PresShell::ShouldIgnoreInvalidation()
7403 return mPaintingSuppressed
|| !mIsActive
;
7406 NS_IMETHODIMP_(void)
7407 PresShell::WillPaint(PRBool aWillSendDidPaint
)
7409 // Don't bother doing anything if some viewmanager in our tree is painting
7410 // while we still have painting suppressed or we are not active.
7411 if (mPaintingSuppressed
|| !mIsActive
) {
7415 if (!aWillSendDidPaint
) {
7416 nsRootPresContext
* rootPresContext
= mPresContext
->GetRootPresContext();
7417 if (!rootPresContext
) {
7420 if (rootPresContext
== mPresContext
) {
7421 rootPresContext
->UpdatePluginGeometry();
7425 // Process reflows, if we have them, to reduce flicker due to invalidates and
7426 // reflow being interspersed. Note that we _do_ allow this to be
7427 // interruptible; if we can't do all the reflows it's better to flicker a bit
7428 // than to freeze up.
7429 FlushPendingNotifications(Flush_InterruptibleLayout
);
7432 NS_IMETHODIMP_(void)
7433 PresShell::DidPaint()
7435 nsRootPresContext
* rootPresContext
= mPresContext
->GetRootPresContext();
7436 if (!rootPresContext
) {
7439 if (rootPresContext
== mPresContext
) {
7440 rootPresContext
->UpdatePluginGeometry();
7445 PresShell::GetAgentStyleSheets(nsCOMArray
<nsIStyleSheet
>& aSheets
)
7448 PRInt32 sheetCount
= mStyleSet
->SheetCount(nsStyleSet::eAgentSheet
);
7450 for (PRInt32 i
= 0; i
< sheetCount
; ++i
) {
7451 nsIStyleSheet
*sheet
= mStyleSet
->StyleSheetAt(nsStyleSet::eAgentSheet
, i
);
7452 if (!aSheets
.AppendObject(sheet
))
7453 return NS_ERROR_OUT_OF_MEMORY
;
7460 PresShell::SetAgentStyleSheets(const nsCOMArray
<nsIStyleSheet
>& aSheets
)
7462 return mStyleSet
->ReplaceSheets(nsStyleSet::eAgentSheet
, aSheets
);
7466 PresShell::AddOverrideStyleSheet(nsIStyleSheet
*aSheet
)
7468 return mStyleSet
->PrependStyleSheet(nsStyleSet::eOverrideSheet
, aSheet
);
7472 PresShell::RemoveOverrideStyleSheet(nsIStyleSheet
*aSheet
)
7474 return mStyleSet
->RemoveStyleSheet(nsStyleSet::eOverrideSheet
, aSheet
);
7478 FreezeElement(nsIContent
*aContent
, void * /* unused */)
7480 nsIFrame
*frame
= aContent
->GetPrimaryFrame();
7481 nsIObjectFrame
*objectFrame
= do_QueryFrame(frame
);
7483 objectFrame
->StopPlugin();
7488 FreezeSubDocument(nsIDocument
*aDocument
, void *aData
)
7490 nsIPresShell
*shell
= aDocument
->GetShell();
7500 MaybeReleaseCapturingContent();
7502 mDocument
->EnumerateFreezableElements(FreezeElement
, nsnull
);
7505 mCaret
->SetCaretVisible(PR_FALSE
);
7507 mPaintingSuppressed
= PR_TRUE
;
7510 mDocument
->EnumerateSubDocuments(FreezeSubDocument
, nsnull
);
7512 nsPresContext
* presContext
= GetPresContext();
7514 presContext
->RefreshDriver()->PresContext() == presContext
) {
7515 presContext
->RefreshDriver()->Freeze();
7519 UpdateImageLockingState();
7523 PresShell::FireOrClearDelayedEvents(PRBool aFireEvents
)
7525 mNoDelayedMouseEvents
= PR_FALSE
;
7526 mNoDelayedKeyEvents
= PR_FALSE
;
7528 mDelayedEvents
.Clear();
7533 nsCOMPtr
<nsIDocument
> doc
= mDocument
;
7534 while (!mIsDestroying
&& mDelayedEvents
.Length() &&
7535 !doc
->EventHandlingSuppressed()) {
7536 nsAutoPtr
<nsDelayedEvent
> ev(mDelayedEvents
[0].forget());
7537 mDelayedEvents
.RemoveElementAt(0);
7540 if (!doc
->EventHandlingSuppressed()) {
7541 mDelayedEvents
.Clear();
7547 ThawElement(nsIContent
*aContent
, void *aShell
)
7549 nsCOMPtr
<nsIObjectLoadingContent
> objlc(do_QueryInterface(aContent
));
7551 nsCOMPtr
<nsIPluginInstance
> inst
;
7552 objlc
->EnsureInstantiation(getter_AddRefs(inst
));
7557 ThawSubDocument(nsIDocument
*aDocument
, void *aData
)
7559 nsIPresShell
*shell
= aDocument
->GetShell();
7569 nsPresContext
* presContext
= GetPresContext();
7571 presContext
->RefreshDriver()->PresContext() == presContext
) {
7572 presContext
->RefreshDriver()->Thaw();
7575 mDocument
->EnumerateFreezableElements(ThawElement
, this);
7578 mDocument
->EnumerateSubDocuments(ThawSubDocument
, nsnull
);
7580 // Get the activeness of our presshell, as this might have changed
7581 // while we were in the bfcache
7584 // We're now unfrozen
7586 UpdateImageLockingState();
7588 UnsuppressPainting();
7591 //--------------------------------------------------------
7592 // Start of protected and private methods on the PresShell
7593 //--------------------------------------------------------
7596 PresShell::MaybeScheduleReflow()
7598 ASSERT_REFLOW_SCHEDULED_STATE();
7599 if (mReflowScheduled
|| mIsDestroying
|| mIsReflowing
||
7600 mDirtyRoots
.Length() == 0)
7603 if (!mPresContext
->HasPendingInterrupt() || !ScheduleReflowOffTimer()) {
7607 ASSERT_REFLOW_SCHEDULED_STATE();
7611 PresShell::ScheduleReflow()
7613 NS_PRECONDITION(!mReflowScheduled
, "Why are we trying to schedule a reflow?");
7614 ASSERT_REFLOW_SCHEDULED_STATE();
7616 if (GetPresContext()->RefreshDriver()->AddLayoutFlushObserver(this)) {
7617 mReflowScheduled
= PR_TRUE
;
7620 ASSERT_REFLOW_SCHEDULED_STATE();
7624 PresShell::DidCauseReflow()
7626 NS_ASSERTION(mChangeNestCount
!= 0, "Unexpected call to DidCauseReflow()");
7628 nsContentUtils::RemoveScriptBlocker();
7634 PresShell::WillDoReflow()
7636 // We just reflowed, tell the caret that its frame might have moved.
7637 // XXXbz that comment makes no sense
7639 mCaret
->InvalidateOutsideCaret();
7642 mPresContext
->FlushUserFontSet();
7644 mFrameConstructor
->BeginUpdate();
7648 PresShell::DidDoReflow(PRBool aInterruptible
)
7650 mFrameConstructor
->EndUpdate();
7652 HandlePostedReflowCallbacks(aInterruptible
);
7653 SynthesizeMouseMove(PR_FALSE
);
7655 // Update the caret's position now to account for any changes created by
7657 mCaret
->InvalidateOutsideCaret();
7658 mCaret
->UpdateCaretPosition();
7662 static PLDHashOperator
7663 MarkFramesDirtyToRoot(nsPtrHashKey
<nsIFrame
>* p
, void* closure
)
7665 nsIFrame
* target
= static_cast<nsIFrame
*>(closure
);
7666 for (nsIFrame
* f
= p
->GetKey(); f
&& !NS_SUBTREE_DIRTY(f
);
7667 f
= f
->GetParent()) {
7668 f
->AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN
);
7675 return PL_DHASH_NEXT
;
7679 PresShell::sReflowContinueCallback(nsITimer
* aTimer
, void* aPresShell
)
7681 nsRefPtr
<PresShell
> self
= static_cast<PresShell
*>(aPresShell
);
7683 NS_PRECONDITION(aTimer
== self
->mReflowContinueTimer
, "Unexpected timer");
7684 self
->mReflowContinueTimer
= nsnull
;
7685 self
->ScheduleReflow();
7689 PresShell::ScheduleReflowOffTimer()
7691 NS_PRECONDITION(!mReflowScheduled
, "Shouldn't get here");
7692 ASSERT_REFLOW_SCHEDULED_STATE();
7694 if (!mReflowContinueTimer
) {
7695 mReflowContinueTimer
= do_CreateInstance("@mozilla.org/timer;1");
7696 if (!mReflowContinueTimer
||
7697 NS_FAILED(mReflowContinueTimer
->
7698 InitWithFuncCallback(sReflowContinueCallback
, this, 30,
7699 nsITimer::TYPE_ONE_SHOT
))) {
7707 PresShell::DoReflow(nsIFrame
* target
, PRBool aInterruptible
)
7709 NS_TIME_FUNCTION_WITH_DOCURL
;
7711 if (mReflowContinueTimer
) {
7712 mReflowContinueTimer
->Cancel();
7713 mReflowContinueTimer
= nsnull
;
7716 nsIFrame
* rootFrame
= FrameManager()->GetRootFrame();
7718 nsCOMPtr
<nsIRenderingContext
> rcx
= GetReferenceRenderingContext();
7720 NS_NOTREACHED("CreateRenderingContext failure");
7725 mCurrentReflowRoot
= target
;
7728 target
->WillReflow(mPresContext
);
7730 // If the target frame is the root of the frame hierarchy, then
7731 // use all the available space. If it's simply a `reflow root',
7732 // then use the target frame's size as the available space.
7734 if (target
== rootFrame
) {
7735 size
= mPresContext
->GetVisibleArea().Size();
7737 // target->GetRect() has the old size of the frame,
7738 // mPresContext->GetVisibleArea() has the new size.
7739 target
->InvalidateRectDifference(mPresContext
->GetVisibleArea(),
7742 size
= target
->GetSize();
7745 NS_ASSERTION(!target
->GetNextInFlow() && !target
->GetPrevInFlow(),
7746 "reflow roots should never split");
7748 // Don't pass size directly to the reflow state, since a
7749 // constrained height implies page/column breaking.
7750 nsSize
reflowSize(size
.width
, NS_UNCONSTRAINEDSIZE
);
7751 nsHTMLReflowState
reflowState(mPresContext
, target
, rcx
, reflowSize
);
7753 if (rootFrame
== target
) {
7754 // When the root frame is being reflowed with unconstrained height
7755 // (which happens when we're called from
7756 // DocumentViewerImpl::SizeToContent), we're effectively doing a
7757 // vertical resize, since it changes the meaning of percentage
7758 // heights even if no heights actually changed. The same applies
7759 // when we reflow again after that computation. This is an unusual
7760 // case, and isn't caught by nsHTMLReflowState::InitResizeFlags.
7761 PRBool hasUnconstrainedHeight
= size
.height
== NS_UNCONSTRAINEDSIZE
;
7763 if (hasUnconstrainedHeight
|| mLastRootReflowHadUnconstrainedHeight
) {
7764 reflowState
.mFlags
.mVResize
= PR_TRUE
;
7767 mLastRootReflowHadUnconstrainedHeight
= hasUnconstrainedHeight
;
7770 // fix the computed height
7771 NS_ASSERTION(reflowState
.mComputedMargin
== nsMargin(0, 0, 0, 0),
7772 "reflow state should not set margin for reflow roots");
7773 if (size
.height
!= NS_UNCONSTRAINEDSIZE
) {
7774 nscoord computedHeight
=
7775 size
.height
- reflowState
.mComputedBorderPadding
.TopBottom();
7776 computedHeight
= NS_MAX(computedHeight
, 0);
7777 reflowState
.SetComputedHeight(computedHeight
);
7779 NS_ASSERTION(reflowState
.ComputedWidth() ==
7781 reflowState
.mComputedBorderPadding
.LeftRight(),
7782 "reflow state computed incorrect width");
7784 mPresContext
->ReflowStarted(aInterruptible
);
7785 mIsReflowing
= PR_TRUE
;
7787 nsReflowStatus status
;
7788 nsHTMLReflowMetrics desiredSize
;
7789 target
->Reflow(mPresContext
, desiredSize
, reflowState
, status
);
7791 // If an incremental reflow is initiated at a frame other than the
7792 // root frame, then its desired size had better not change! If it's
7793 // initiated at the root, then the size better not change unless its
7794 // height was unconstrained to start with.
7795 NS_ASSERTION((target
== rootFrame
&& size
.height
== NS_UNCONSTRAINEDSIZE
) ||
7796 (desiredSize
.width
== size
.width
&&
7797 desiredSize
.height
== size
.height
),
7798 "non-root frame's desired size changed during an "
7799 "incremental reflow");
7800 NS_ASSERTION(desiredSize
.VisualOverflow() ==
7801 nsRect(nsPoint(0, 0),
7802 nsSize(desiredSize
.width
, desiredSize
.height
)),
7803 "reflow roots must not have visible overflow");
7804 NS_ASSERTION(desiredSize
.ScrollableOverflow() ==
7805 nsRect(nsPoint(0, 0),
7806 nsSize(desiredSize
.width
, desiredSize
.height
)),
7807 "reflow roots must not have scrollable overflow");
7808 NS_ASSERTION(status
== NS_FRAME_COMPLETE
,
7809 "reflow roots should never split");
7811 target
->SetSize(nsSize(desiredSize
.width
, desiredSize
.height
));
7813 nsContainerFrame::SyncFrameViewAfterReflow(mPresContext
, target
,
7815 desiredSize
.VisualOverflow());
7816 nsContainerFrame::SyncWindowProperties(mPresContext
, target
,
7819 target
->DidReflow(mPresContext
, nsnull
, NS_FRAME_REFLOW_FINISHED
);
7820 if (target
== rootFrame
&& size
.height
== NS_UNCONSTRAINEDSIZE
) {
7821 mPresContext
->SetVisibleArea(nsRect(0, 0, desiredSize
.width
,
7822 desiredSize
.height
));
7826 mCurrentReflowRoot
= nsnull
;
7829 NS_ASSERTION(mPresContext
->HasPendingInterrupt() ||
7830 mFramesToDirty
.Count() == 0,
7831 "Why do we need to dirty anything if not interrupted?");
7833 mIsReflowing
= PR_FALSE
;
7834 PRBool interrupted
= mPresContext
->HasPendingInterrupt();
7836 // Make sure target gets reflowed again.
7837 mFramesToDirty
.EnumerateEntries(&MarkFramesDirtyToRoot
, target
);
7838 NS_ASSERTION(NS_SUBTREE_DIRTY(target
), "Why is the target not dirty?");
7839 mDirtyRoots
.AppendElement(target
);
7841 // Clear mFramesToDirty after we've done the NS_SUBTREE_DIRTY(target)
7842 // assertion so that if it fails it's easier to see what's going on.
7843 #ifdef NOISY_INTERRUPTIBLE_REFLOW
7844 printf("mFramesToDirty.Count() == %u\n", mFramesToDirty
.Count());
7845 #endif /* NOISY_INTERRUPTIBLE_REFLOW */
7846 mFramesToDirty
.Clear();
7848 // Any FlushPendingNotifications with interruptible reflows
7849 // should be suppressed now. We don't want to do extra reflow work
7850 // before our reflow event happens.
7851 mSuppressInterruptibleReflows
= PR_TRUE
;
7852 MaybeScheduleReflow();
7855 nsRootPresContext
* rootPC
= mPresContext
->GetRootPresContext();
7857 rootPC
->RequestUpdatePluginGeometry(target
);
7860 return !interrupted
;
7865 PresShell::DoVerifyReflow()
7867 if (GetVerifyReflowEnable()) {
7868 // First synchronously render what we have so far so that we can
7871 mViewManager
->GetRootView(rootView
);
7872 mViewManager
->UpdateView(rootView
, NS_VMREFRESH_IMMEDIATE
);
7874 FlushPendingNotifications(Flush_Layout
);
7875 mInVerifyReflow
= PR_TRUE
;
7876 PRBool ok
= VerifyIncrementalReflow();
7877 mInVerifyReflow
= PR_FALSE
;
7878 if (VERIFY_REFLOW_ALL
& gVerifyReflowFlags
) {
7879 printf("ProcessReflowCommands: finished (%s)\n",
7880 ok
? "ok" : "failed");
7883 if (0 != mDirtyRoots
.Length()) {
7884 printf("XXX yikes! reflow commands queued during verify-reflow\n");
7891 PresShell::ProcessReflowCommands(PRBool aInterruptible
)
7893 NS_TIME_FUNCTION_WITH_DOCURL
;
7895 PRBool interrupted
= PR_FALSE
;
7896 if (0 != mDirtyRoots
.Length()) {
7899 if (VERIFY_REFLOW_DUMP_COMMANDS
& gVerifyReflowFlags
) {
7900 printf("ProcessReflowCommands: begin incremental reflow\n");
7904 // If reflow is interruptible, then make a note of our deadline.
7905 const PRIntervalTime deadline
= aInterruptible
7906 ? PR_IntervalNow() + PR_MicrosecondsToInterval(gMaxRCProcessingTime
)
7907 : (PRIntervalTime
)0;
7909 // Scope for the reflow entry point
7911 nsAutoScriptBlocker scriptBlocker
;
7913 AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Reflow
);
7916 // Send an incremental reflow notification to the target frame.
7917 PRInt32 idx
= mDirtyRoots
.Length() - 1;
7918 nsIFrame
*target
= mDirtyRoots
[idx
];
7919 mDirtyRoots
.RemoveElementAt(idx
);
7921 if (!NS_SUBTREE_DIRTY(target
)) {
7922 // It's not dirty anymore, which probably means the notification
7923 // was posted in the middle of a reflow (perhaps with a reflow
7924 // root in the middle). Don't do anything.
7928 interrupted
= !DoReflow(target
, aInterruptible
);
7930 // Keep going until we're out of reflow commands, or we've run
7931 // past our deadline, or we're interrupted.
7932 } while (!interrupted
&& mDirtyRoots
.Length() &&
7933 (!aInterruptible
|| PR_IntervalNow() < deadline
));
7935 interrupted
= mDirtyRoots
.Length() != 0;
7938 // Exiting the scriptblocker might have killed us
7939 if (!mIsDestroying
) {
7940 DidDoReflow(aInterruptible
);
7943 // DidDoReflow might have killed us
7944 if (!mIsDestroying
) {
7946 if (VERIFY_REFLOW_DUMP_COMMANDS
& gVerifyReflowFlags
) {
7947 printf("\nPresShell::ProcessReflowCommands() finished: this=%p\n",
7953 // If any new reflow commands were enqueued during the reflow, schedule
7954 // another reflow event to process them. Note that we want to do this
7955 // after DidDoReflow(), since that method can change whether there are
7956 // dirty roots around by flushing, and there's no point in posting a
7957 // reflow event just to have the flush revoke it.
7958 if (mDirtyRoots
.Length())
7959 MaybeScheduleReflow();
7963 if (!mIsDestroying
&& mShouldUnsuppressPainting
&&
7964 mDirtyRoots
.Length() == 0) {
7965 // We only unlock if we're out of reflows. It's pointless
7966 // to unlock if reflows are still pending, since reflows
7967 // are just going to thrash the frames around some more. By
7968 // waiting we avoid an overeager "jitter" effect.
7969 mShouldUnsuppressPainting
= PR_FALSE
;
7970 UnsuppressAndInvalidate();
7973 return !interrupted
;
7978 * It's better to add stuff to the |DidSetStyleContext| method of the
7979 * relevant frames than adding it here. These methods should (ideally,
7983 // Return value says whether to walk children.
7984 typedef PRBool (* frameWalkerFn
)(nsIFrame
*aFrame
, void *aClosure
);
7987 ReResolveMenusAndTrees(nsIFrame
*aFrame
, void *aClosure
)
7989 // Trees have a special style cache that needs to be flushed when
7990 // the theme changes.
7991 nsTreeBodyFrame
*treeBody
= do_QueryFrame(aFrame
);
7993 treeBody
->ClearStyleAndImageCaches();
7995 // We deliberately don't re-resolve style on a menu's popup
7996 // sub-content, since doing so slows menus to a crawl. That means we
7997 // have to special-case them on a skin switch, and ensure that the
7998 // popup frames just get destroyed completely.
7999 if (aFrame
&& aFrame
->GetType() == nsGkAtoms::menuFrame
)
8000 (static_cast<nsMenuFrame
*>(aFrame
))->CloseMenu(PR_TRUE
);
8005 ReframeImageBoxes(nsIFrame
*aFrame
, void *aClosure
)
8007 nsStyleChangeList
*list
= static_cast<nsStyleChangeList
*>(aClosure
);
8008 if (aFrame
->GetType() == nsGkAtoms::imageBoxFrame
) {
8009 list
->AppendChange(aFrame
, aFrame
->GetContent(),
8010 NS_STYLE_HINT_FRAMECHANGE
);
8011 return PR_FALSE
; // don't walk descendants
8013 return PR_TRUE
; // walk descendants
8017 WalkFramesThroughPlaceholders(nsPresContext
*aPresContext
, nsIFrame
*aFrame
,
8018 frameWalkerFn aFunc
, void *aClosure
)
8020 PRBool walkChildren
= (*aFunc
)(aFrame
, aClosure
);
8024 PRInt32 listIndex
= 0;
8025 nsIAtom
* childList
= nsnull
;
8028 nsIFrame
*child
= aFrame
->GetFirstChild(childList
);
8030 if (!(child
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
)) {
8031 // only do frames that are in flow, and recur through the
8032 // out-of-flows of placeholders.
8033 WalkFramesThroughPlaceholders(aPresContext
,
8034 nsPlaceholderFrame::GetRealFrameFor(child
),
8037 child
= child
->GetNextSibling();
8040 childList
= aFrame
->GetAdditionalChildListName(listIndex
++);
8041 } while (childList
);
8046 PresShell::Observe(nsISupports
* aSubject
,
8048 const PRUnichar
* aData
)
8051 if (!nsCRT::strcmp(aTopic
, "chrome-flush-skin-caches")) {
8052 nsIFrame
*rootFrame
= FrameManager()->GetRootFrame();
8053 // Need to null-check because "chrome-flush-skin-caches" can happen
8054 // at interesting times during startup.
8056 NS_ASSERTION(mViewManager
, "View manager must exist");
8057 nsIViewManager::UpdateViewBatch
batch(mViewManager
);
8059 nsWeakFrame
weakRoot(rootFrame
);
8060 // Have to make sure that the content notifications are flushed before we
8061 // start messing with the frame model; otherwise we can get content doubling.
8062 mDocument
->FlushPendingNotifications(Flush_ContentAndNotify
);
8064 if (weakRoot
.IsAlive()) {
8065 WalkFramesThroughPlaceholders(mPresContext
, rootFrame
,
8066 &ReResolveMenusAndTrees
, nsnull
);
8068 // Because "chrome:" URL equality is messy, reframe image box
8070 nsStyleChangeList changeList
;
8071 WalkFramesThroughPlaceholders(mPresContext
, rootFrame
,
8072 ReframeImageBoxes
, &changeList
);
8073 // Mark ourselves as not safe to flush while we're doing frame
8076 nsAutoScriptBlocker scriptBlocker
;
8078 mFrameConstructor
->ProcessRestyledFrames(changeList
);
8082 batch
.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC
);
8088 if (!nsCRT::strcmp(aTopic
, "agent-sheet-added") && mStyleSet
) {
8089 AddAgentSheet(aSubject
);
8093 if (!nsCRT::strcmp(aTopic
, "user-sheet-added") && mStyleSet
) {
8094 AddUserSheet(aSubject
);
8098 if (!nsCRT::strcmp(aTopic
, "agent-sheet-removed") && mStyleSet
) {
8099 RemoveSheet(nsStyleSet::eAgentSheet
, aSubject
);
8103 if (!nsCRT::strcmp(aTopic
, "user-sheet-removed") && mStyleSet
) {
8104 RemoveSheet(nsStyleSet::eUserSheet
, aSubject
);
8108 #ifdef ACCESSIBILITY
8109 if (!nsCRT::strcmp(aTopic
, "a11y-init-or-shutdown")) {
8110 gIsAccessibilityActive
= aData
&& *aData
== '1';
8113 NS_WARNING("unrecognized topic in PresShell::Observe");
8114 return NS_ERROR_FAILURE
;
8118 nsIPresShell::AddRefreshObserverInternal(nsARefreshObserver
* aObserver
,
8119 mozFlushType aFlushType
)
8121 return GetPresContext()->RefreshDriver()->
8122 AddRefreshObserver(aObserver
, aFlushType
);
8125 /* virtual */ PRBool
8126 nsIPresShell::AddRefreshObserverExternal(nsARefreshObserver
* aObserver
,
8127 mozFlushType aFlushType
)
8129 return AddRefreshObserverInternal(aObserver
, aFlushType
);
8133 nsIPresShell::RemoveRefreshObserverInternal(nsARefreshObserver
* aObserver
,
8134 mozFlushType aFlushType
)
8136 return GetPresContext()->RefreshDriver()->
8137 RemoveRefreshObserver(aObserver
, aFlushType
);
8140 /* virtual */ PRBool
8141 nsIPresShell::RemoveRefreshObserverExternal(nsARefreshObserver
* aObserver
,
8142 mozFlushType aFlushType
)
8144 return RemoveRefreshObserverInternal(aObserver
, aFlushType
);
8147 //------------------------------------------------------
8148 // End of protected and private methods on the PresShell
8149 //------------------------------------------------------
8151 // Start of DEBUG only code
8154 #include "nsViewsCID.h"
8155 #include "nsWidgetsCID.h"
8156 #include "nsIDeviceContext.h"
8158 #include "nsILinkHandler.h"
8160 static NS_DEFINE_CID(kViewManagerCID
, NS_VIEW_MANAGER_CID
);
8163 LogVerifyMessage(nsIFrame
* k1
, nsIFrame
* k2
, const char* aMsg
)
8165 nsAutoString n1
, n2
;
8167 k1
->GetFrameName(n1
);
8169 n1
.Assign(NS_LITERAL_STRING("(null)"));
8173 k2
->GetFrameName(n2
);
8175 n2
.Assign(NS_LITERAL_STRING("(null)"));
8178 printf("verifyreflow: %s %p != %s %p %s\n",
8179 NS_LossyConvertUTF16toASCII(n1
).get(), (void*)k1
,
8180 NS_LossyConvertUTF16toASCII(n2
).get(), (void*)k2
, aMsg
);
8184 LogVerifyMessage(nsIFrame
* k1
, nsIFrame
* k2
, const char* aMsg
,
8185 const nsRect
& r1
, const nsRect
& r2
)
8187 printf("VerifyReflow Error:\n");
8191 k1
->GetFrameName(name
);
8192 printf(" %s %p ", NS_LossyConvertUTF16toASCII(name
).get(), (void*)k1
);
8194 printf("{%d, %d, %d, %d} != \n", r1
.x
, r1
.y
, r1
.width
, r1
.height
);
8197 k2
->GetFrameName(name
);
8198 printf(" %s %p ", NS_LossyConvertUTF16toASCII(name
).get(), (void*)k2
);
8200 printf("{%d, %d, %d, %d}\n %s\n",
8201 r2
.x
, r2
.y
, r2
.width
, r2
.height
, aMsg
);
8205 LogVerifyMessage(nsIFrame
* k1
, nsIFrame
* k2
, const char* aMsg
,
8206 const nsIntRect
& r1
, const nsIntRect
& r2
)
8208 printf("VerifyReflow Error:\n");
8212 k1
->GetFrameName(name
);
8213 printf(" %s %p ", NS_LossyConvertUTF16toASCII(name
).get(), (void*)k1
);
8215 printf("{%d, %d, %d, %d} != \n", r1
.x
, r1
.y
, r1
.width
, r1
.height
);
8218 k2
->GetFrameName(name
);
8219 printf(" %s %p ", NS_LossyConvertUTF16toASCII(name
).get(), (void*)k2
);
8221 printf("{%d, %d, %d, %d}\n %s\n",
8222 r2
.x
, r2
.y
, r2
.width
, r2
.height
, aMsg
);
8226 CompareTrees(nsPresContext
* aFirstPresContext
, nsIFrame
* aFirstFrame
,
8227 nsPresContext
* aSecondPresContext
, nsIFrame
* aSecondFrame
)
8229 if (!aFirstPresContext
|| !aFirstFrame
|| !aSecondPresContext
|| !aSecondFrame
)
8231 // XXX Evil hack to reduce false positives; I can't seem to figure
8232 // out how to flush scrollbar changes correctly
8233 //if (aFirstFrame->GetType() == nsGkAtoms::scrollbarFrame)
8235 PRBool ok
= PR_TRUE
;
8236 nsIAtom
* listName
= nsnull
;
8237 PRInt32 listIndex
= 0;
8239 const nsFrameList
& kids1
= aFirstFrame
->GetChildList(listName
);
8240 const nsFrameList
& kids2
= aSecondFrame
->GetChildList(listName
);
8241 PRInt32 l1
= kids1
.GetLength();
8242 PRInt32 l2
= kids2
.GetLength();;
8245 LogVerifyMessage(kids1
.FirstChild(), kids2
.FirstChild(),
8246 "child counts don't match: ");
8247 printf("%d != %d\n", l1
, l2
);
8248 if (0 == (VERIFY_REFLOW_ALL
& gVerifyReflowFlags
)) {
8255 for (nsFrameList::Enumerator
e1(kids1
), e2(kids2
);
8257 e1
.Next(), e2
.Next()) {
8258 nsIFrame
* k1
= e1
.get();
8259 nsIFrame
* k2
= e2
.get();
8260 if (((nsnull
== k1
) && (nsnull
!= k2
)) ||
8261 ((nsnull
!= k1
) && (nsnull
== k2
))) {
8263 LogVerifyMessage(k1
, k2
, "child lists are different\n");
8266 else if (nsnull
!= k1
) {
8267 // Verify that the frames are the same size
8268 if (k1
->GetRect() != k2
->GetRect()) {
8270 LogVerifyMessage(k1
, k2
, "(frame rects)", k1
->GetRect(), k2
->GetRect());
8273 // Make sure either both have views or neither have views; if they
8274 // do have views, make sure the views are the same size. If the
8275 // views have widgets, make sure they both do or neither does. If
8276 // they do, make sure the widgets are the same size.
8279 if (((nsnull
== v1
) && (nsnull
!= v2
)) ||
8280 ((nsnull
!= v1
) && (nsnull
== v2
))) {
8282 LogVerifyMessage(k1
, k2
, "child views are not matched\n");
8284 else if (nsnull
!= v1
) {
8285 if (v1
->GetBounds() != v2
->GetBounds()) {
8286 LogVerifyMessage(k1
, k2
, "(view rects)", v1
->GetBounds(), v2
->GetBounds());
8289 nsIWidget
* w1
= v1
->GetWidget();
8290 nsIWidget
* w2
= v2
->GetWidget();
8291 if (((nsnull
== w1
) && (nsnull
!= w2
)) ||
8292 ((nsnull
!= w1
) && (nsnull
== w2
))) {
8294 LogVerifyMessage(k1
, k2
, "child widgets are not matched\n");
8296 else if (nsnull
!= w1
) {
8300 LogVerifyMessage(k1
, k2
, "(widget rects)", r1
, r2
);
8304 if (!ok
&& (0 == (VERIFY_REFLOW_ALL
& gVerifyReflowFlags
))) {
8308 // XXX Should perhaps compare their float managers.
8310 // Compare the sub-trees too
8311 if (!CompareTrees(aFirstPresContext
, k1
, aSecondPresContext
, k2
)) {
8313 if (0 == (VERIFY_REFLOW_ALL
& gVerifyReflowFlags
)) {
8322 if (!ok
&& (0 == (VERIFY_REFLOW_ALL
& gVerifyReflowFlags
))) {
8326 nsIAtom
* listName1
= aFirstFrame
->GetAdditionalChildListName(listIndex
);
8327 nsIAtom
* listName2
= aSecondFrame
->GetAdditionalChildListName(listIndex
);
8329 if (listName1
!= listName2
) {
8330 if (0 == (VERIFY_REFLOW_ALL
& gVerifyReflowFlags
)) {
8333 LogVerifyMessage(kids1
.FirstChild(), kids2
.FirstChild(),
8334 "child list names are not matched: ");
8336 if (nsnull
!= listName1
) {
8337 listName1
->ToString(tmp
);
8338 fputs(NS_LossyConvertUTF16toASCII(tmp
).get(), stdout
);
8341 fputs("(null)", stdout
);
8343 if (nsnull
!= listName2
) {
8344 listName2
->ToString(tmp
);
8345 fputs(NS_LossyConvertUTF16toASCII(tmp
).get(), stdout
);
8348 fputs("(null)", stdout
);
8352 listName
= listName1
;
8353 } while (ok
&& (listName
!= nsnull
));
8361 FindTopFrame(nsIFrame
* aRoot
)
8364 nsIContent
* content
= aRoot
->GetContent();
8367 content
->GetTag(tag
);
8368 if (nsnull
!= tag
) {
8374 // Try one of the children
8375 nsIFrame
* kid
= aRoot
->GetFirstChild(nsnull
);
8376 while (nsnull
!= kid
) {
8377 nsIFrame
* result
= FindTopFrame(kid
);
8378 if (nsnull
!= result
) {
8381 kid
= kid
->GetNextSibling();
8392 PresShell::CloneStyleSet(nsStyleSet
* aSet
, nsStyleSet
** aResult
)
8394 nsStyleSet
*clone
= new nsStyleSet();
8396 return NS_ERROR_OUT_OF_MEMORY
;
8399 PRInt32 i
, n
= aSet
->SheetCount(nsStyleSet::eOverrideSheet
);
8400 for (i
= 0; i
< n
; i
++) {
8401 nsIStyleSheet
* ss
= aSet
->StyleSheetAt(nsStyleSet::eOverrideSheet
, i
);
8403 clone
->AppendStyleSheet(nsStyleSet::eOverrideSheet
, ss
);
8406 // The document expects to insert document stylesheets itself
8408 n
= aSet
->SheetCount(nsStyleSet::eDocSheet
);
8409 for (i
= 0; i
< n
; i
++) {
8410 nsIStyleSheet
* ss
= aSet
->StyleSheetAt(nsStyleSet::eDocSheet
, i
);
8412 clone
->AddDocStyleSheet(ss
, mDocument
);
8416 n
= aSet
->SheetCount(nsStyleSet::eUserSheet
);
8417 for (i
= 0; i
< n
; i
++) {
8418 nsIStyleSheet
* ss
= aSet
->StyleSheetAt(nsStyleSet::eUserSheet
, i
);
8420 clone
->AppendStyleSheet(nsStyleSet::eUserSheet
, ss
);
8423 n
= aSet
->SheetCount(nsStyleSet::eAgentSheet
);
8424 for (i
= 0; i
< n
; i
++) {
8425 nsIStyleSheet
* ss
= aSet
->StyleSheetAt(nsStyleSet::eAgentSheet
, i
);
8427 clone
->AppendStyleSheet(nsStyleSet::eAgentSheet
, ss
);
8435 DumpToPNG(nsIPresShell
* shell
, nsAString
& name
) {
8436 PRInt32 width
=1000, height
=1000;
8437 nsRect
r(0, 0, shell
->GetPresContext()->DevPixelsToAppUnits(width
),
8438 shell
->GetPresContext()->DevPixelsToAppUnits(height
));
8440 nsRefPtr
<gfxImageSurface
> imgSurface
=
8441 new gfxImageSurface(gfxIntSize(width
, height
),
8442 gfxImageSurface::ImageFormatARGB32
);
8443 NS_ENSURE_TRUE(imgSurface
, NS_ERROR_OUT_OF_MEMORY
);
8445 nsRefPtr
<gfxContext
> imgContext
= new gfxContext(imgSurface
);
8447 nsRefPtr
<gfxASurface
> surface
=
8448 gfxPlatform::GetPlatform()->
8449 CreateOffscreenSurface(gfxIntSize(width
, height
),
8450 gfxASurface::ContentFromFormat(gfxASurface::ImageFormatARGB32
));
8451 NS_ENSURE_TRUE(surface
, NS_ERROR_OUT_OF_MEMORY
);
8453 nsRefPtr
<gfxContext
> context
= new gfxContext(surface
);
8454 NS_ENSURE_TRUE(context
, NS_ERROR_OUT_OF_MEMORY
);
8456 shell
->RenderDocument(r
, 0, NS_RGB(255, 255, 0), context
);
8458 imgContext
->DrawSurface(surface
, gfxSize(width
, height
));
8460 nsCOMPtr
<imgIEncoder
> encoder
= do_CreateInstance("@mozilla.org/image/encoder;2?type=image/png");
8461 NS_ENSURE_TRUE(encoder
, NS_ERROR_FAILURE
);
8462 encoder
->InitFromData(imgSurface
->Data(), imgSurface
->Stride() * height
,
8463 width
, height
, imgSurface
->Stride(),
8464 imgIEncoder::INPUT_FORMAT_HOSTARGB
, EmptyString());
8466 // XXX not sure if this is the right way to write to a file
8467 nsCOMPtr
<nsILocalFile
> file
= do_CreateInstance("@mozilla.org/file/local;1");
8468 NS_ENSURE_TRUE(file
, NS_ERROR_FAILURE
);
8469 rv
= file
->InitWithPath(name
);
8470 NS_ENSURE_SUCCESS(rv
, rv
);
8473 encoder
->Available(&length
);
8475 nsCOMPtr
<nsIOutputStream
> outputStream
;
8476 rv
= NS_NewLocalFileOutputStream(getter_AddRefs(outputStream
), file
);
8477 NS_ENSURE_SUCCESS(rv
, rv
);
8479 nsCOMPtr
<nsIOutputStream
> bufferedOutputStream
;
8480 rv
= NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream
),
8481 outputStream
, length
);
8483 PRUint32 numWritten
;
8484 rv
= bufferedOutputStream
->WriteFrom(encoder
, length
, &numWritten
);
8485 NS_ENSURE_SUCCESS(rv
, rv
);
8491 // After an incremental reflow, we verify the correctness by doing a
8492 // full reflow into a fresh frame tree.
8494 PresShell::VerifyIncrementalReflow()
8496 if (VERIFY_REFLOW_NOISY
& gVerifyReflowFlags
) {
8497 printf("Building Verification Tree...\n");
8500 // Create a presentation context to view the new frame tree
8501 nsRefPtr
<nsPresContext
> cx
=
8502 new nsRootPresContext(mDocument
, mPresContext
->IsPaginated() ?
8503 nsPresContext::eContext_PrintPreview
:
8504 nsPresContext::eContext_Galley
);
8505 NS_ENSURE_TRUE(cx
, PR_FALSE
);
8507 nsIDeviceContext
*dc
= mPresContext
->DeviceContext();
8508 nsresult rv
= cx
->Init(dc
);
8509 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
8511 // Get our scrolling preference
8513 mViewManager
->GetRootView(rootView
);
8514 NS_ENSURE_TRUE(rootView
->HasWidget(), PR_FALSE
);
8515 nsIWidget
* parentWidget
= rootView
->GetWidget();
8517 // Create a new view manager.
8518 nsCOMPtr
<nsIViewManager
> vm
= do_CreateInstance(kViewManagerCID
);
8519 NS_ENSURE_TRUE(vm
, PR_FALSE
);
8521 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
8523 // Create a child window of the parent that is our "root view/window"
8525 nsRect tbounds
= mPresContext
->GetVisibleArea();
8526 nsIView
* view
= vm
->CreateView(tbounds
, nsnull
);
8527 NS_ENSURE_TRUE(view
, PR_FALSE
);
8529 //now create the widget for the view
8530 rv
= view
->CreateWidgetForParent(parentWidget
, nsnull
, PR_TRUE
);
8531 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
8533 // Setup hierarchical relationship in view manager
8534 vm
->SetRootView(view
);
8536 // Make the new presentation context the same size as our
8537 // presentation context.
8538 nsRect r
= mPresContext
->GetVisibleArea();
8539 cx
->SetVisibleArea(r
);
8541 // Create a new presentation shell to view the document. Use the
8542 // exact same style information that this document has.
8543 nsAutoPtr
<nsStyleSet
> newSet
;
8544 rv
= CloneStyleSet(mStyleSet
, getter_Transfers(newSet
));
8545 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
8546 nsCOMPtr
<nsIPresShell
> sh
;
8547 rv
= mDocument
->CreateShell(cx
, vm
, newSet
, getter_AddRefs(sh
));
8548 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
8550 // Note that after we create the shell, we must make sure to destroy it
8551 sh
->SetVerifyReflowEnable(PR_FALSE
); // turn off verify reflow while we're reflowing the test frame tree
8552 vm
->SetViewObserver((nsIViewObserver
*)((PresShell
*)sh
.get()));
8554 nsAutoCauseReflowNotifier
crNotifier(this);
8555 sh
->InitialReflow(r
.width
, r
.height
);
8557 mDocument
->BindingManager()->ProcessAttachedQueue();
8558 sh
->FlushPendingNotifications(Flush_Layout
);
8559 sh
->SetVerifyReflowEnable(PR_TRUE
); // turn on verify reflow again now that we're done reflowing the test frame tree
8560 // Force the non-primary presshell to unsuppress; it doesn't want to normally
8561 // because it thinks it's hidden
8562 ((PresShell
*)sh
.get())->mPaintingSuppressed
= PR_FALSE
;
8563 if (VERIFY_REFLOW_NOISY
& gVerifyReflowFlags
) {
8564 printf("Verification Tree built, comparing...\n");
8567 // Now that the document has been reflowed, use its frame tree to
8568 // compare against our frame tree.
8569 nsIFrame
* root1
= FrameManager()->GetRootFrame();
8570 nsIFrame
* root2
= sh
->FrameManager()->GetRootFrame();
8571 PRBool ok
= CompareTrees(mPresContext
, root1
, cx
, root2
);
8572 if (!ok
&& (VERIFY_REFLOW_NOISY
& gVerifyReflowFlags
)) {
8573 printf("Verify reflow failed, primary tree:\n");
8574 root1
->List(stdout
, 0);
8575 printf("Verification tree:\n");
8576 root2
->List(stdout
, 0);
8580 // Sample code for dumping page to png
8581 // XXX Needs to be made more flexible
8585 stra
.AppendLiteral("C:\\mozilla\\mozilla\\debug\\filea");
8586 stra
.AppendInt(num
);
8587 stra
.AppendLiteral(".png");
8588 DumpToPNG(sh
, stra
);
8590 strb
.AppendLiteral("C:\\mozilla\\mozilla\\debug\\fileb");
8591 strb
.AppendInt(num
);
8592 strb
.AppendLiteral(".png");
8593 DumpToPNG(this, strb
);
8598 sh
->EndObservingDocument();
8600 if (VERIFY_REFLOW_NOISY
& gVerifyReflowFlags
) {
8601 printf("Finished Verifying Reflow...\n");
8607 // Layout debugging hooks
8609 PresShell::ListStyleContexts(nsIFrame
*aRootFrame
, FILE *out
, PRInt32 aIndent
)
8611 nsStyleContext
*sc
= aRootFrame
->GetStyleContext();
8613 sc
->List(out
, aIndent
);
8617 PresShell::ListStyleSheets(FILE *out
, PRInt32 aIndent
)
8619 PRInt32 sheetCount
= mStyleSet
->SheetCount(nsStyleSet::eDocSheet
);
8620 for (PRInt32 i
= 0; i
< sheetCount
; ++i
) {
8621 mStyleSet
->StyleSheetAt(nsStyleSet::eDocSheet
, i
)->List(out
, aIndent
);
8627 PresShell::VerifyStyleTree()
8633 //=============================================================
8634 //=============================================================
8635 //-- Debug Reflow Counts
8636 //=============================================================
8637 //=============================================================
8638 #ifdef MOZ_REFLOW_PERF
8639 //-------------------------------------------------------------
8641 PresShell::DumpReflows()
8643 if (mReflowCountMgr
) {
8644 nsCAutoString uriStr
;
8646 nsIURI
*uri
= mDocument
->GetDocumentURI();
8648 uri
->GetPath(uriStr
);
8651 mReflowCountMgr
->DisplayTotals(uriStr
.get());
8652 mReflowCountMgr
->DisplayHTMLTotals(uriStr
.get());
8653 mReflowCountMgr
->DisplayDiffsInTotals("Differences");
8657 //-------------------------------------------------------------
8659 PresShell::CountReflows(const char * aName
, nsIFrame
* aFrame
)
8661 if (mReflowCountMgr
) {
8662 mReflowCountMgr
->Add(aName
, aFrame
);
8666 //-------------------------------------------------------------
8668 PresShell::PaintCount(const char * aName
,
8669 nsIRenderingContext
* aRenderingContext
,
8670 nsPresContext
* aPresContext
,
8674 if (mReflowCountMgr
) {
8675 mReflowCountMgr
->PaintCount(aName
, aRenderingContext
, aPresContext
, aFrame
, aColor
);
8679 //-------------------------------------------------------------
8681 PresShell::SetPaintFrameCount(PRBool aPaintFrameCounts
)
8683 if (mReflowCountMgr
) {
8684 mReflowCountMgr
->SetPaintFrameCounts(aPaintFrameCounts
);
8689 PresShell::IsPaintingFrameCounts()
8691 if (mReflowCountMgr
)
8692 return mReflowCountMgr
->IsPaintingFrameCounts();
8696 //------------------------------------------------------------------
8697 //-- Reflow Counter Classes Impls
8698 //------------------------------------------------------------------
8700 //------------------------------------------------------------------
8701 ReflowCounter::ReflowCounter(ReflowCountMgr
* aMgr
) :
8708 //------------------------------------------------------------------
8709 ReflowCounter::~ReflowCounter()
8714 //------------------------------------------------------------------
8715 void ReflowCounter::ClearTotals()
8720 //------------------------------------------------------------------
8721 void ReflowCounter::SetTotalsCache()
8723 mCacheTotal
= mTotal
;
8726 //------------------------------------------------------------------
8727 void ReflowCounter::CalcDiffInTotals()
8729 mCacheTotal
= mTotal
- mCacheTotal
;
8732 //------------------------------------------------------------------
8733 void ReflowCounter::DisplayTotals(const char * aStr
)
8735 DisplayTotals(mTotal
, aStr
?aStr
:"Totals");
8738 //------------------------------------------------------------------
8739 void ReflowCounter::DisplayDiffTotals(const char * aStr
)
8741 DisplayTotals(mCacheTotal
, aStr
?aStr
:"Diff Totals");
8744 //------------------------------------------------------------------
8745 void ReflowCounter::DisplayHTMLTotals(const char * aStr
)
8747 DisplayHTMLTotals(mTotal
, aStr
?aStr
:"Totals");
8750 //------------------------------------------------------------------
8751 void ReflowCounter::DisplayTotals(PRUint32 aTotal
, const char * aTitle
)
8757 ReflowCounter
* gTots
= (ReflowCounter
*)mMgr
->LookUp(kGrandTotalsStr
);
8759 printf("%25s\t", aTitle
);
8760 printf("%d\t", aTotal
);
8761 if (gTots
!= this && aTotal
> 0) {
8766 //------------------------------------------------------------------
8767 void ReflowCounter::DisplayHTMLTotals(PRUint32 aTotal
, const char * aTitle
)
8773 ReflowCounter
* gTots
= (ReflowCounter
*)mMgr
->LookUp(kGrandTotalsStr
);
8774 FILE * fd
= mMgr
->GetOutFile();
8779 fprintf(fd
, "<tr><td><center>%s</center></td>", aTitle
);
8780 fprintf(fd
, "<td><center>%d</center></td></tr>\n", aTotal
);
8782 if (gTots
!= this && aTotal
> 0) {
8787 //------------------------------------------------------------------
8789 //------------------------------------------------------------------
8790 ReflowCountMgr::ReflowCountMgr()
8792 mCounts
= PL_NewHashTable(10, PL_HashString
, PL_CompareStrings
,
8793 PL_CompareValues
, nsnull
, nsnull
);
8794 mIndiFrameCounts
= PL_NewHashTable(10, PL_HashString
, PL_CompareStrings
,
8795 PL_CompareValues
, nsnull
, nsnull
);
8796 mCycledOnce
= PR_FALSE
;
8797 mDumpFrameCounts
= PR_FALSE
;
8798 mDumpFrameByFrameCounts
= PR_FALSE
;
8799 mPaintFrameByFrameCounts
= PR_FALSE
;
8802 //------------------------------------------------------------------
8803 ReflowCountMgr::~ReflowCountMgr()
8808 //------------------------------------------------------------------
8809 ReflowCounter
* ReflowCountMgr::LookUp(const char * aName
)
8811 if (nsnull
!= mCounts
) {
8812 ReflowCounter
* counter
= (ReflowCounter
*)PL_HashTableLookup(mCounts
, aName
);
8819 //------------------------------------------------------------------
8820 void ReflowCountMgr::Add(const char * aName
, nsIFrame
* aFrame
)
8822 NS_ASSERTION(aName
!= nsnull
, "Name shouldn't be null!");
8824 if (mDumpFrameCounts
&& nsnull
!= mCounts
) {
8825 ReflowCounter
* counter
= (ReflowCounter
*)PL_HashTableLookup(mCounts
, aName
);
8826 if (counter
== nsnull
) {
8827 counter
= new ReflowCounter(this);
8828 NS_ASSERTION(counter
!= nsnull
, "null ptr");
8829 char * name
= NS_strdup(aName
);
8830 NS_ASSERTION(name
!= nsnull
, "null ptr");
8831 PL_HashTableAdd(mCounts
, name
, counter
);
8836 if ((mDumpFrameByFrameCounts
|| mPaintFrameByFrameCounts
) &&
8837 nsnull
!= mIndiFrameCounts
&&
8839 char * key
= new char[16];
8840 sprintf(key
, "%p", (void*)aFrame
);
8841 IndiReflowCounter
* counter
= (IndiReflowCounter
*)PL_HashTableLookup(mIndiFrameCounts
, key
);
8842 if (counter
== nsnull
) {
8843 counter
= new IndiReflowCounter(this);
8844 NS_ASSERTION(counter
!= nsnull
, "null ptr");
8845 counter
->mFrame
= aFrame
;
8846 counter
->mName
.AssignASCII(aName
);
8847 PL_HashTableAdd(mIndiFrameCounts
, key
, counter
);
8849 // this eliminates extra counts from super classes
8850 if (counter
!= nsnull
&& counter
->mName
.EqualsASCII(aName
)) {
8852 counter
->mCounter
.Add(1);
8857 //------------------------------------------------------------------
8858 void ReflowCountMgr::PaintCount(const char * aName
,
8859 nsIRenderingContext
* aRenderingContext
,
8860 nsPresContext
* aPresContext
,
8864 if (mPaintFrameByFrameCounts
&&
8865 nsnull
!= mIndiFrameCounts
&&
8867 char * key
= new char[16];
8868 sprintf(key
, "%p", (void*)aFrame
);
8869 IndiReflowCounter
* counter
= (IndiReflowCounter
*)PL_HashTableLookup(mIndiFrameCounts
, key
);
8870 if (counter
!= nsnull
&& counter
->mName
.EqualsASCII(aName
)) {
8871 aRenderingContext
->PushState();
8872 nsFont
font("Times", NS_FONT_STYLE_NORMAL
, NS_FONT_VARIANT_NORMAL
,
8873 NS_FONT_WEIGHT_NORMAL
, NS_FONT_STRETCH_NORMAL
, 0,
8874 nsPresContext::CSSPixelsToAppUnits(11));
8876 nsCOMPtr
<nsIFontMetrics
> fm
= aPresContext
->GetMetricsFor(font
);
8877 aRenderingContext
->SetFont(fm
);
8879 sprintf(buf
, "%d", counter
->mCount
);
8881 nscoord width
, height
;
8882 aRenderingContext
->SetTextRunRTL(PR_FALSE
);
8883 aRenderingContext
->GetWidth((char*)buf
, width
);
8884 fm
->GetHeight(height
);
8885 fm
->GetMaxAscent(y
);
8891 color2
= NS_RGB(0,0,0);
8893 PRUint8 rc
= 0, gc
= 0, bc
= 0;
8894 if (counter
->mCount
< 5) {
8897 } else if ( counter
->mCount
< 11) {
8902 color
= NS_RGB(rc
,gc
,bc
);
8903 color2
= NS_RGB(rc
/2,gc
/2,bc
/2);
8906 nsRect
rect(0,0, width
+15, height
+15);
8907 aRenderingContext
->SetColor(NS_RGB(0,0,0));
8908 aRenderingContext
->FillRect(rect
);
8909 aRenderingContext
->SetColor(color2
);
8910 aRenderingContext
->DrawString(buf
, strlen(buf
), x
+15,y
+15);
8911 aRenderingContext
->SetColor(color
);
8912 aRenderingContext
->DrawString(buf
, strlen(buf
), x
,y
);
8914 aRenderingContext
->PopState();
8919 //------------------------------------------------------------------
8920 PRIntn
ReflowCountMgr::RemoveItems(PLHashEntry
*he
, PRIntn i
, void *arg
)
8922 char *str
= (char *)he
->key
;
8923 ReflowCounter
* counter
= (ReflowCounter
*)he
->value
;
8927 return HT_ENUMERATE_REMOVE
;
8930 //------------------------------------------------------------------
8931 PRIntn
ReflowCountMgr::RemoveIndiItems(PLHashEntry
*he
, PRIntn i
, void *arg
)
8933 char *str
= (char *)he
->key
;
8934 IndiReflowCounter
* counter
= (IndiReflowCounter
*)he
->value
;
8938 return HT_ENUMERATE_REMOVE
;
8941 //------------------------------------------------------------------
8942 void ReflowCountMgr::CleanUp()
8944 if (nsnull
!= mCounts
) {
8945 PL_HashTableEnumerateEntries(mCounts
, RemoveItems
, nsnull
);
8946 PL_HashTableDestroy(mCounts
);
8950 if (nsnull
!= mIndiFrameCounts
) {
8951 PL_HashTableEnumerateEntries(mIndiFrameCounts
, RemoveIndiItems
, nsnull
);
8952 PL_HashTableDestroy(mIndiFrameCounts
);
8953 mIndiFrameCounts
= nsnull
;
8957 //------------------------------------------------------------------
8958 PRIntn
ReflowCountMgr::DoSingleTotal(PLHashEntry
*he
, PRIntn i
, void *arg
)
8960 char *str
= (char *)he
->key
;
8961 ReflowCounter
* counter
= (ReflowCounter
*)he
->value
;
8963 counter
->DisplayTotals(str
);
8965 return HT_ENUMERATE_NEXT
;
8968 //------------------------------------------------------------------
8969 void ReflowCountMgr::DoGrandTotals()
8971 if (nsnull
!= mCounts
) {
8972 ReflowCounter
* gTots
= (ReflowCounter
*)PL_HashTableLookup(mCounts
, kGrandTotalsStr
);
8973 if (gTots
== nsnull
) {
8974 gTots
= new ReflowCounter(this);
8975 PL_HashTableAdd(mCounts
, NS_strdup(kGrandTotalsStr
), gTots
);
8977 gTots
->ClearTotals();
8980 printf("\t\t\t\tTotal\n");
8981 for (PRUint32 i
=0;i
<78;i
++) {
8985 PL_HashTableEnumerateEntries(mCounts
, DoSingleTotal
, this);
8989 static void RecurseIndiTotals(nsPresContext
* aPresContext
,
8991 nsIFrame
* aParentFrame
,
8994 if (aParentFrame
== nsnull
) {
8999 sprintf(key
, "%p", (void*)aParentFrame
);
9000 IndiReflowCounter
* counter
= (IndiReflowCounter
*)PL_HashTableLookup(aHT
, key
);
9002 counter
->mHasBeenOutput
= PR_TRUE
;
9003 char * name
= ToNewCString(counter
->mName
);
9004 for (PRInt32 i
=0;i
<aLevel
;i
++) printf(" ");
9005 printf("%s - %p [%d][", name
, (void*)aParentFrame
, counter
->mCount
);
9006 printf("%d", counter
->mCounter
.GetTotal());
9008 nsMemory::Free(name
);
9011 nsIFrame
* child
= aParentFrame
->GetFirstChild(nsnull
);
9013 RecurseIndiTotals(aPresContext
, aHT
, child
, aLevel
+1);
9014 child
= child
->GetNextSibling();
9019 //------------------------------------------------------------------
9020 PRIntn
ReflowCountMgr::DoSingleIndi(PLHashEntry
*he
, PRIntn i
, void *arg
)
9022 IndiReflowCounter
* counter
= (IndiReflowCounter
*)he
->value
;
9023 if (counter
&& !counter
->mHasBeenOutput
) {
9024 char * name
= ToNewCString(counter
->mName
);
9025 printf("%s - %p [%d][", name
, (void*)counter
->mFrame
, counter
->mCount
);
9026 printf("%d", counter
->mCounter
.GetTotal());
9028 nsMemory::Free(name
);
9030 return HT_ENUMERATE_NEXT
;
9033 //------------------------------------------------------------------
9034 void ReflowCountMgr::DoIndiTotalsTree()
9036 if (nsnull
!= mCounts
) {
9037 printf("\n------------------------------------------------\n");
9038 printf("-- Individual Frame Counts\n");
9039 printf("------------------------------------------------\n");
9042 nsIFrame
* rootFrame
= mPresShell
->FrameManager()->GetRootFrame();
9043 RecurseIndiTotals(mPresContext
, mIndiFrameCounts
, rootFrame
, 0);
9044 printf("------------------------------------------------\n");
9045 printf("-- Individual Counts of Frames not in Root Tree\n");
9046 printf("------------------------------------------------\n");
9047 PL_HashTableEnumerateEntries(mIndiFrameCounts
, DoSingleIndi
, this);
9052 //------------------------------------------------------------------
9053 PRIntn
ReflowCountMgr::DoSingleHTMLTotal(PLHashEntry
*he
, PRIntn i
, void *arg
)
9055 char *str
= (char *)he
->key
;
9056 ReflowCounter
* counter
= (ReflowCounter
*)he
->value
;
9058 counter
->DisplayHTMLTotals(str
);
9060 return HT_ENUMERATE_NEXT
;
9063 //------------------------------------------------------------------
9064 void ReflowCountMgr::DoGrandHTMLTotals()
9066 if (nsnull
!= mCounts
) {
9067 ReflowCounter
* gTots
= (ReflowCounter
*)PL_HashTableLookup(mCounts
, kGrandTotalsStr
);
9068 if (gTots
== nsnull
) {
9069 gTots
= new ReflowCounter(this);
9070 PL_HashTableAdd(mCounts
, NS_strdup(kGrandTotalsStr
), gTots
);
9072 gTots
->ClearTotals();
9075 static const char * title
[] = {"Class", "Reflows"};
9076 fprintf(mFD
, "<tr>");
9077 for (PRUint32 i
=0; i
< NS_ARRAY_LENGTH(title
); i
++) {
9078 fprintf(mFD
, "<td><center><b>%s<b></center></td>", title
[i
]);
9080 fprintf(mFD
, "</tr>\n");
9081 PL_HashTableEnumerateEntries(mCounts
, DoSingleHTMLTotal
, this);
9085 //------------------------------------
9086 void ReflowCountMgr::DisplayTotals(const char * aStr
)
9089 printf("%s\n", aStr
?aStr
:"No name");
9091 if (mDumpFrameCounts
) {
9094 if (mDumpFrameByFrameCounts
) {
9099 //------------------------------------
9100 void ReflowCountMgr::DisplayHTMLTotals(const char * aStr
)
9102 #ifdef WIN32x // XXX NOT XP!
9105 char * sptr
= strrchr(aStr
, '/');
9109 char * eptr
= strrchr(name
, '.');
9113 strcat(name
, "_stats.html");
9115 mFD
= fopen(name
, "w");
9117 fprintf(mFD
, "<html><head><title>Reflow Stats</title></head><body>\n");
9118 const char * title
= aStr
?aStr
:"No name";
9119 fprintf(mFD
, "<center><b>%s</b><br><table border=1 style=\"background-color:#e0e0e0\">", title
);
9120 DoGrandHTMLTotals();
9121 fprintf(mFD
, "</center></table>\n");
9122 fprintf(mFD
, "</body></html>\n");
9129 //------------------------------------------------------------------
9130 PRIntn
ReflowCountMgr::DoClearTotals(PLHashEntry
*he
, PRIntn i
, void *arg
)
9132 ReflowCounter
* counter
= (ReflowCounter
*)he
->value
;
9133 counter
->ClearTotals();
9135 return HT_ENUMERATE_NEXT
;
9138 //------------------------------------------------------------------
9139 void ReflowCountMgr::ClearTotals()
9141 PL_HashTableEnumerateEntries(mCounts
, DoClearTotals
, this);
9144 //------------------------------------------------------------------
9145 void ReflowCountMgr::ClearGrandTotals()
9147 if (nsnull
!= mCounts
) {
9148 ReflowCounter
* gTots
= (ReflowCounter
*)PL_HashTableLookup(mCounts
, kGrandTotalsStr
);
9149 if (gTots
== nsnull
) {
9150 gTots
= new ReflowCounter(this);
9151 PL_HashTableAdd(mCounts
, NS_strdup(kGrandTotalsStr
), gTots
);
9153 gTots
->ClearTotals();
9154 gTots
->SetTotalsCache();
9159 //------------------------------------------------------------------
9160 PRIntn
ReflowCountMgr::DoDisplayDiffTotals(PLHashEntry
*he
, PRIntn i
, void *arg
)
9162 PRBool cycledOnce
= (arg
!= 0);
9164 char *str
= (char *)he
->key
;
9165 ReflowCounter
* counter
= (ReflowCounter
*)he
->value
;
9168 counter
->CalcDiffInTotals();
9169 counter
->DisplayDiffTotals(str
);
9171 counter
->SetTotalsCache();
9173 return HT_ENUMERATE_NEXT
;
9176 //------------------------------------------------------------------
9177 void ReflowCountMgr::DisplayDiffsInTotals(const char * aStr
)
9180 printf("Differences\n");
9181 for (PRInt32 i
=0;i
<78;i
++) {
9187 PL_HashTableEnumerateEntries(mCounts
, DoDisplayDiffTotals
, (void *)mCycledOnce
);
9189 mCycledOnce
= PR_TRUE
;
9192 #endif // MOZ_REFLOW_PERF
9194 // make a color string like #RRGGBB
9195 void ColorToString(nscolor aColor
, nsAutoString
&aString
)
9199 PR_snprintf(buf
, sizeof(buf
), "#%02x%02x%02x",
9200 NS_GET_R(aColor
), NS_GET_G(aColor
), NS_GET_B(aColor
));
9201 CopyASCIItoUTF16(buf
, aString
);
9204 nsIFrame
* nsIPresShell::GetAbsoluteContainingBlock(nsIFrame
*aFrame
)
9206 return FrameConstructor()->GetAbsoluteContainingBlock(aFrame
);
9209 void nsIPresShell::InitializeStatics()
9211 NS_ASSERTION(sLiveShells
== nsnull
, "InitializeStatics called multiple times!");
9212 sLiveShells
= new nsTHashtable
<PresShellPtrKey
>();
9213 sLiveShells
->Init();
9216 void nsIPresShell::ReleaseStatics()
9218 NS_ASSERTION(sLiveShells
, "ReleaseStatics called without Initialize!");
9220 sLiveShells
= nsnull
;
9223 // Asks our docshell whether we're active.
9224 void PresShell::QueryIsActive()
9226 nsCOMPtr
<nsISupports
> container
= mPresContext
->GetContainer();
9228 nsIDocument
* displayDoc
= mDocument
->GetDisplayDocument();
9230 // Ok, we're an external resource document -- we need to use our display
9231 // document's docshell to determine "IsActive" status, since we lack
9233 NS_ABORT_IF_FALSE(!container
,
9234 "external resource doc shouldn't have "
9235 "its own container");
9237 nsIPresShell
* displayPresShell
= displayDoc
->GetShell();
9238 if (displayPresShell
) {
9239 container
= displayPresShell
->GetPresContext()->GetContainer();
9244 nsCOMPtr
<nsIDocShell
> docshell(do_QueryInterface(container
));
9247 nsresult rv
= docshell
->GetIsActive(&isActive
);
9248 if (NS_SUCCEEDED(rv
))
9249 SetIsActive(isActive
);
9253 // Helper for propagating mIsActive changes to external resources
9255 SetExternalResourceIsActive(nsIDocument
* aDocument
, void* aClosure
)
9257 nsIPresShell
* shell
= aDocument
->GetShell();
9259 shell
->SetIsActive(*static_cast<PRBool
*>(aClosure
));
9265 PresShell::SetIsActive(PRBool aIsActive
)
9267 mIsActive
= aIsActive
;
9268 nsPresContext
* presContext
= GetPresContext();
9270 presContext
->RefreshDriver()->PresContext() == presContext
) {
9271 presContext
->RefreshDriver()->SetThrottled(!mIsActive
);
9274 // Propagate state-change to my resource documents' PresShells
9276 mDocument
->EnumerateExternalResources(SetExternalResourceIsActive
,
9279 return UpdateImageLockingState();
9283 * Determines the current image locking state. Called when one of the
9284 * dependent factors changes.
9287 PresShell::UpdateImageLockingState()
9289 // We're locked if we're both thawed and active.
9290 return mDocument
->SetImageLockingState(!mFrozen
&& mIsActive
);