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>
30 * Alternatively, the contents of this file may be used under the terms of
31 * either of the GNU General Public License Version 2 or later (the "GPL"),
32 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
33 * in which case the provisions of the GPL or the LGPL are applicable instead
34 * of those above. If you wish to allow use of your version of this file only
35 * under the terms of either the GPL or the LGPL, and not to allow others to
36 * use your version of this file under the terms of the MPL, indicate your
37 * decision by deleting the provisions above and replace them with the notice
38 * and other provisions required by the GPL or the LGPL. If you do not delete
39 * the provisions above, a recipient may use your version of this file under
40 * the terms of any one of the MPL, the GPL or the LGPL.
42 * ***** END LICENSE BLOCK *****
44 * This Original Code has been modified by IBM Corporation.
45 * Modifications made by IBM described herein are
46 * Copyright (c) International Business Machines
49 * Modifications to Mozilla code or documentation
50 * identified per MPL Section 3.3
52 * Date Modified by Description of modification
53 * 05/03/2000 IBM Corp. Observer events for reflow states
56 /* a presentation of a document, part 2 */
58 #include "nsIPresShell.h"
59 #include "nsPresContext.h"
60 #include "nsIContent.h"
61 #include "mozilla/dom/Element.h"
62 #include "nsIDocument.h"
63 #include "nsIDOMXULDocument.h"
64 #include "nsStubDocumentObserver.h"
65 #include "nsStyleSet.h"
66 #include "nsCSSStyleSheet.h" // XXX for UA sheet loading hack, can this go away please?
67 #include "nsIDOMCSSStyleSheet.h" // for Pref-related rule management (bugs 22963,20760,31816)
68 #include "nsINameSpaceManager.h" // for Pref-related rule management (bugs 22963,20760,31816)
69 #include "nsIServiceManager.h"
71 #include "nsIViewManager.h"
73 #include "nsCRTGlue.h"
79 #include "nsCOMArray.h"
80 #include "nsHashtable.h"
81 #include "nsIViewObserver.h"
82 #include "nsContainerFrame.h"
83 #include "nsIDeviceContext.h"
84 #include "nsEventStateManager.h"
85 #include "nsDOMEvent.h"
86 #include "nsGUIEvent.h"
87 #include "nsHTMLParts.h"
88 #include "nsContentUtils.h"
89 #include "nsISelection.h"
90 #include "nsISelectionController.h"
91 #include "nsISelectionPrivate.h"
92 #include "nsLayoutCID.h"
93 #include "nsGkAtoms.h"
94 #include "nsIDOMRange.h"
95 #include "nsIDOMDocument.h"
96 #include "nsIDOMNode.h"
97 #include "nsIDOM3Node.h"
98 #include "nsIDOMNodeList.h"
99 #include "nsIDOMElement.h"
101 #include "nsCSSPseudoElements.h"
102 #include "nsCOMPtr.h"
103 #include "nsAutoPtr.h"
104 #include "nsReadableUtils.h"
105 #include "nsUnicharUtils.h"
106 #include "nsWeakReference.h"
107 #include "nsIPageSequenceFrame.h"
109 #include "nsIDOMHTMLDocument.h"
110 #include "nsIXPointer.h"
111 #include "nsIDOMXMLDocument.h"
112 #include "nsIParser.h"
113 #include "nsParserCIID.h"
114 #include "nsFrameSelection.h"
115 #include "nsIDOMNSHTMLTextAreaElement.h"
116 #include "nsViewsCID.h"
117 #include "nsPresArena.h"
118 #include "nsFrameManager.h"
120 #include "nsISupportsPrimitives.h"
121 #include "nsILayoutHistoryState.h"
122 #include "nsILineIterator.h" // for ScrollContentIntoView
123 #include "nsWeakPtr.h"
125 #include "nsIObserverService.h"
126 #include "nsIObserver.h"
127 #include "nsIDocShell.h" // for reflow observation
128 #include "nsIBaseWindow.h"
129 #include "nsLayoutErrors.h"
130 #include "nsLayoutUtils.h"
131 #include "nsCSSRendering.h"
132 // for |#ifdef DEBUG| code
134 #include "nsIAttribute.h"
135 #include "nsIGlobalHistory2.h"
136 #include "nsDisplayList.h"
137 #include "nsIRegion.h"
138 #include "nsRegion.h"
140 #ifdef MOZ_REFLOW_PERF
141 #include "nsIRenderingContext.h"
142 #include "nsIFontMetrics.h"
145 #include "nsIReflowCallback.h"
147 #include "nsPIDOMWindow.h"
148 #include "nsFocusManager.h"
149 #include "nsIPluginInstance.h"
150 #include "nsIObjectFrame.h"
151 #include "nsIObjectLoadingContent.h"
152 #include "nsNetUtil.h"
153 #include "nsEventDispatcher.h"
154 #include "nsThreadUtils.h"
155 #include "nsStyleSheetService.h"
156 #include "gfxImageSurface.h"
157 #include "gfxContext.h"
159 #include "nsHTMLMediaElement.h"
162 #include "nsSMILAnimationController.h"
165 #include "nsRefreshDriver.h"
167 // Drag & Drop, Clipboard
168 #include "nsWidgetsCID.h"
169 #include "nsIClipboard.h"
170 #include "nsIClipboardHelper.h"
171 #include "nsIDocShellTreeItem.h"
173 #include "nsIScrollableFrame.h"
176 #include "nsIDragService.h"
177 #include "nsCopySupport.h"
178 #include "nsIDOMHTMLAnchorElement.h"
179 #include "nsIDOMHTMLAreaElement.h"
180 #include "nsIDOMHTMLLinkElement.h"
181 #include "nsITimer.h"
183 #include "nsIAccessibilityService.h"
184 #include "nsAccessible.h"
187 // For style data reconstruction
188 #include "nsStyleChangeList.h"
189 #include "nsCSSFrameConstructor.h"
191 #include "nsMenuFrame.h"
192 #include "nsTreeBodyFrame.h"
193 #include "nsIBoxObject.h"
194 #include "nsITreeBoxObject.h"
195 #include "nsMenuPopupFrame.h"
196 #include "nsITreeColumns.h"
197 #include "nsIDOMXULMultSelectCntrlEl.h"
198 #include "nsIDOMXULSelectCntrlItemEl.h"
199 #include "nsIDOMXULMenuListElement.h"
202 #include "nsPlaceholderFrame.h"
203 #include "nsCanvasFrame.h"
205 // Content viewer interfaces
206 #include "nsIContentViewer.h"
207 #include "imgIEncoder.h"
208 #include "gfxPlatform.h"
210 #include "mozilla/FunctionTimer.h"
214 #ifdef NS_FUNCTION_TIMER
215 #define NS_TIME_FUNCTION_DECLARE_DOCURL \
216 nsCAutoString docURL__("N/A"); \
217 nsIURI *uri__ = mDocument->GetDocumentURI(); \
218 if (uri__) uri__->GetSpec(docURL__);
219 #define NS_TIME_FUNCTION_WITH_DOCURL \
220 NS_TIME_FUNCTION_DECLARE_DOCURL \
221 NS_TIME_FUNCTION_MIN_FMT(1.0, \
222 "%s (line %d) (document: %s)", MOZ_FUNCTION_NAME, \
223 __LINE__, docURL__.get())
225 #define NS_TIME_FUNCTION_WITH_DOCURL do{} while(0)
228 #include "nsContentCID.h"
229 static NS_DEFINE_IID(kRangeCID
, NS_RANGE_CID
);
231 /* for NS_MEMORY_REPORTER_IMPLEMENT */
232 #include "nsIMemoryReporter.h"
234 using namespace mozilla
;
235 using namespace mozilla::dom
;
236 using namespace mozilla::layers
;
238 PRBool
nsIPresShell::gIsAccessibilityActive
= PR_FALSE
;
239 CapturingContentInfo
nsIPresShell::gCaptureInfo
;
240 nsIContent
* nsIPresShell::gKeyDownTarget
;
242 // convert a color value to a string, in the CSS format #RRGGBB
243 // * - initially created for bugs 31816, 20760, 22963
244 static void ColorToString(nscolor aColor
, nsAutoString
&aString
);
247 static NS_DEFINE_CID(kFrameSelectionCID
, NS_FRAMESELECTION_CID
);
249 // RangePaintInfo is used to paint ranges to offscreen buffers
250 struct RangePaintInfo
{
251 nsCOMPtr
<nsIRange
> mRange
;
252 nsDisplayListBuilder mBuilder
;
255 // offset of builder's reference frame to the root frame
258 RangePaintInfo(nsIRange
* aRange
, nsIFrame
* aFrame
)
259 : mRange(aRange
), mBuilder(aFrame
, PR_FALSE
, PR_FALSE
)
261 MOZ_COUNT_CTOR(RangePaintInfo
);
267 MOZ_COUNT_DTOR(RangePaintInfo
);
273 // ----------------------------------------------------------------------
276 // Set the environment variable GECKO_VERIFY_REFLOW_FLAGS to one or
277 // more of the following flags (comma separated) for handy debug
279 static PRUint32 gVerifyReflowFlags
;
281 struct VerifyReflowFlags
{
286 static const VerifyReflowFlags gFlags
[] = {
287 { "verify", VERIFY_REFLOW_ON
},
288 { "reflow", VERIFY_REFLOW_NOISY
},
289 { "all", VERIFY_REFLOW_ALL
},
290 { "list-commands", VERIFY_REFLOW_DUMP_COMMANDS
},
291 { "noisy-commands", VERIFY_REFLOW_NOISY_RC
},
292 { "really-noisy-commands", VERIFY_REFLOW_REALLY_NOISY_RC
},
293 { "resize", VERIFY_REFLOW_DURING_RESIZE_REFLOW
},
296 #define NUM_VERIFY_REFLOW_FLAGS (sizeof(gFlags) / sizeof(gFlags[0]))
299 ShowVerifyReflowFlags()
301 printf("Here are the available GECKO_VERIFY_REFLOW_FLAGS:\n");
302 const VerifyReflowFlags
* flag
= gFlags
;
303 const VerifyReflowFlags
* limit
= gFlags
+ NUM_VERIFY_REFLOW_FLAGS
;
304 while (flag
< limit
) {
305 printf(" %s\n", flag
->name
);
308 printf("Note: GECKO_VERIFY_REFLOW_FLAGS is a comma separated list of flag\n");
309 printf("names (no whitespace)\n");
313 //========================================================================
314 //========================================================================
315 //========================================================================
316 #ifdef MOZ_REFLOW_PERF
317 class ReflowCountMgr
;
319 static const char kGrandTotalsStr
[] = "Grand Totals";
322 class ReflowCounter
{
324 ReflowCounter(ReflowCountMgr
* aMgr
= nsnull
);
328 void DisplayTotals(const char * aStr
);
329 void DisplayDiffTotals(const char * aStr
);
330 void DisplayHTMLTotals(const char * aStr
);
332 void Add() { mTotal
++; }
333 void Add(PRUint32 aTotal
) { mTotal
+= aTotal
; }
335 void CalcDiffInTotals();
336 void SetTotalsCache();
338 void SetMgr(ReflowCountMgr
* aMgr
) { mMgr
= aMgr
; }
340 PRUint32
GetTotal() { return mTotal
; }
343 void DisplayTotals(PRUint32 aTotal
, const char * aTitle
);
344 void DisplayHTMLTotals(PRUint32 aTotal
, const char * aTitle
);
347 PRUint32 mCacheTotal
;
349 ReflowCountMgr
* mMgr
; // weak reference (don't delete)
353 class IndiReflowCounter
{
355 IndiReflowCounter(ReflowCountMgr
* aMgr
= nsnull
)
360 mHasBeenOutput(PR_FALSE
)
362 virtual ~IndiReflowCounter() {}
365 nsIFrame
* mFrame
; // weak reference (don't delete)
368 ReflowCountMgr
* mMgr
; // weak reference (don't delete)
370 ReflowCounter mCounter
;
371 PRBool mHasBeenOutput
;
375 //--------------------
377 //--------------------
378 class ReflowCountMgr
{
381 virtual ~ReflowCountMgr();
384 void ClearGrandTotals();
385 void DisplayTotals(const char * aStr
);
386 void DisplayHTMLTotals(const char * aStr
);
387 void DisplayDiffsInTotals(const char * aStr
);
389 void Add(const char * aName
, nsIFrame
* aFrame
);
390 ReflowCounter
* LookUp(const char * aName
);
392 void PaintCount(const char * aName
, nsIRenderingContext
* aRenderingContext
, nsPresContext
* aPresContext
, nsIFrame
* aFrame
, PRUint32 aColor
);
394 FILE * GetOutFile() { return mFD
; }
396 PLHashTable
* GetIndiFrameHT() { return mIndiFrameCounts
; }
398 void SetPresContext(nsPresContext
* aPresContext
) { mPresContext
= aPresContext
; } // weak reference
399 void SetPresShell(nsIPresShell
* aPresShell
) { mPresShell
= aPresShell
; } // weak reference
401 void SetDumpFrameCounts(PRBool aVal
) { mDumpFrameCounts
= aVal
; }
402 void SetDumpFrameByFrameCounts(PRBool aVal
) { mDumpFrameByFrameCounts
= aVal
; }
403 void SetPaintFrameCounts(PRBool aVal
) { mPaintFrameByFrameCounts
= aVal
; }
405 PRBool
IsPaintingFrameCounts() { return mPaintFrameByFrameCounts
; }
408 void DisplayTotals(PRUint32 aTotal
, PRUint32
* aDupArray
, char * aTitle
);
409 void DisplayHTMLTotals(PRUint32 aTotal
, PRUint32
* aDupArray
, char * aTitle
);
411 static PRIntn
RemoveItems(PLHashEntry
*he
, PRIntn i
, void *arg
);
412 static PRIntn
RemoveIndiItems(PLHashEntry
*he
, PRIntn i
, void *arg
);
415 // stdout Output Methods
416 static PRIntn
DoSingleTotal(PLHashEntry
*he
, PRIntn i
, void *arg
);
417 static PRIntn
DoSingleIndi(PLHashEntry
*he
, PRIntn i
, void *arg
);
419 void DoGrandTotals();
420 void DoIndiTotalsTree();
422 // HTML Output Methods
423 static PRIntn
DoSingleHTMLTotal(PLHashEntry
*he
, PRIntn i
, void *arg
);
424 void DoGrandHTMLTotals();
426 // Zero Out the Totals
427 static PRIntn
DoClearTotals(PLHashEntry
*he
, PRIntn i
, void *arg
);
429 // Displays the Diff Totals
430 static PRIntn
DoDisplayDiffTotals(PLHashEntry
*he
, PRIntn i
, void *arg
);
432 PLHashTable
* mCounts
;
433 PLHashTable
* mIndiFrameCounts
;
436 PRBool mDumpFrameCounts
;
437 PRBool mDumpFrameByFrameCounts
;
438 PRBool mPaintFrameByFrameCounts
;
442 // Root Frame for Individual Tracking
443 nsPresContext
* mPresContext
;
444 nsIPresShell
* mPresShell
;
446 // ReflowCountMgr gReflowCountMgr;
449 //========================================================================
451 // comment out to hide caret
454 // The upper bound on the amount of time to spend reflowing, in
455 // microseconds. When this bound is exceeded and reflow commands are
456 // still queued up, a reflow event is posted. The idea is for reflow
457 // to not hog the processor beyond the time specifed in
458 // gMaxRCProcessingTime. This data member is initialized from the
459 // layout.reflow.timeslice pref.
460 #define NS_MAX_REFLOW_TIME 1000000
461 static PRInt32 gMaxRCProcessingTime
= -1;
463 #define MARK_INCREMENT 50
464 #define BLOCK_INCREMENT 4044 /* a bit under 4096, for malloc overhead */
466 /**A block of memory that the stack will
467 * chop up and hand out
471 // a block of memory. Note that this must be first so that it will
473 char mBlock
[BLOCK_INCREMENT
];
475 // another block of memory that would only be created
476 // if our stack overflowed. Yes we have the ability
477 // to grow on a stack overflow
480 StackBlock() : mNext(nsnull
) { }
484 /* we hold an array of marks. A push pushes a mark on the stack
488 // the block of memory we are currently handing out chunks of
491 // our current position in the memory
496 /* A stack arena allows a stack based interface to a block of memory.
497 * It should be used when you need to allocate some temporary memory that
498 * you will immediately return.
505 nsresult
Init() { return mBlocks
? NS_OK
: NS_ERROR_OUT_OF_MEMORY
; }
507 // Memory management functions
508 void* Allocate(size_t aSize
);
514 StackBlock
*block
= mBlocks
;
516 result
+= sizeof(StackBlock
);
517 block
= block
->mNext
;
523 // our current position in memory
526 // a list of memory block. Usually there is only one
527 // but if we overrun our stack size we can get more memory.
530 // the current block of memory we are passing our chucks of
531 StackBlock
* mCurBlock
;
533 // our stack of mark where push has been called
536 // the current top of the mark list
539 // the size of the mark array
540 PRUint32 mMarkLength
;
545 StackArena::StackArena()
550 // allocate our stack memory
551 mBlocks
= new StackBlock();
558 StackArena::~StackArena()
564 StackBlock
* toDelete
= mBlocks
;
565 mBlocks
= mBlocks
->mNext
;
573 // Resize the mark array if we overrun it. Failure to allocate the
574 // mark array is not fatal; we just won't free to that mark. This
575 // allows callers not to worry about error checking.
576 if (mStackTop
>= mMarkLength
)
578 PRUint32 newLength
= mStackTop
+ MARK_INCREMENT
;
579 StackMark
* newMarks
= new StackMark
[newLength
];
582 memcpy(newMarks
, mMarks
, sizeof(StackMark
)*mMarkLength
);
583 // Fill in any marks that we couldn't allocate during a prior call
585 for (; mMarkLength
< mStackTop
; ++mMarkLength
) {
586 NS_NOTREACHED("should only hit this on out-of-memory");
587 newMarks
[mMarkLength
].mBlock
= mCurBlock
;
588 newMarks
[mMarkLength
].mPos
= mPos
;
592 mMarkLength
= newLength
;
596 // set a mark at the top (if we can)
597 NS_ASSERTION(mStackTop
< mMarkLength
, "out of memory");
598 if (mStackTop
< mMarkLength
) {
599 mMarks
[mStackTop
].mBlock
= mCurBlock
;
600 mMarks
[mStackTop
].mPos
= mPos
;
607 StackArena::Allocate(size_t aSize
)
609 NS_ASSERTION(mStackTop
> 0, "Allocate called without Push");
611 // make sure we are aligned. Beard said 8 was safer then 4.
612 // Round size to multiple of 8
613 aSize
= PR_ROUNDUP(aSize
, 8);
615 // if the size makes the stack overflow. Grab another block for the stack
616 if (mPos
+ aSize
>= BLOCK_INCREMENT
)
618 NS_ASSERTION(aSize
<= BLOCK_INCREMENT
,"Requested memory is greater that our block size!!");
619 if (mCurBlock
->mNext
== nsnull
)
620 mCurBlock
->mNext
= new StackBlock();
622 mCurBlock
= mCurBlock
->mNext
;
626 // return the chunk they need.
627 void *result
= mCurBlock
->mBlock
+ mPos
;
637 NS_ASSERTION(mStackTop
> 0, "unmatched pop");
640 if (mStackTop
>= mMarkLength
) {
641 // We couldn't allocate the marks array at the time of the push, so
642 // we don't know where we're freeing to.
643 NS_NOTREACHED("out of memory");
644 if (mStackTop
== 0) {
645 // But we do know if we've completely pushed the stack.
653 // Mark the "freed" memory with 0xdd to help with debugging of memory
654 // allocation problems.
656 StackBlock
*block
= mMarks
[mStackTop
].mBlock
, *block_end
= mCurBlock
;
657 size_t pos
= mMarks
[mStackTop
].mPos
;
658 for (; block
!= block_end
; block
= block
->mNext
, pos
= 0) {
659 memset(block
->mBlock
+ pos
, 0xdd, sizeof(block
->mBlock
) - pos
);
661 memset(block
->mBlock
+ pos
, 0xdd, mPos
- pos
);
665 mCurBlock
= mMarks
[mStackTop
].mBlock
;
666 mPos
= mMarks
[mStackTop
].mPos
;
669 struct nsCallbackEventRequest
671 nsIReflowCallback
* callback
;
672 nsCallbackEventRequest
* next
;
675 // ----------------------------------------------------------------------------
676 #define ASSERT_REFLOW_SCHEDULED_STATE() \
677 NS_ASSERTION(mReflowScheduled == \
678 GetPresContext()->RefreshDriver()-> \
679 IsLayoutFlushObserver(this), "Unexpected state")
681 class nsPresShellEventCB
;
682 class nsAutoCauseReflowNotifier
;
684 class PresShell
: public nsIPresShell
, public nsIViewObserver
,
685 public nsStubDocumentObserver
,
686 public nsISelectionController
, public nsIObserver
,
687 public nsSupportsWeakReference
692 NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
698 virtual NS_HIDDEN_(nsresult
) Init(nsIDocument
* aDocument
,
699 nsPresContext
* aPresContext
,
700 nsIViewManager
* aViewManager
,
701 nsStyleSet
* aStyleSet
,
702 nsCompatibility aCompatMode
);
703 virtual NS_HIDDEN_(void) Destroy();
705 virtual NS_HIDDEN_(void*) AllocateFrame(nsQueryFrame::FrameIID aCode
,
707 virtual NS_HIDDEN_(void) FreeFrame(nsQueryFrame::FrameIID aCode
,
710 virtual NS_HIDDEN_(void*) AllocateMisc(size_t aSize
);
711 virtual NS_HIDDEN_(void) FreeMisc(size_t aSize
, void* aChunk
);
713 // Dynamic stack memory allocation
714 virtual NS_HIDDEN_(void) PushStackMemory();
715 virtual NS_HIDDEN_(void) PopStackMemory();
716 virtual NS_HIDDEN_(void*) AllocateStackMemory(size_t aSize
);
718 virtual NS_HIDDEN_(nsresult
) SetPreferenceStyleRules(PRBool aForceReflow
);
720 NS_IMETHOD
GetSelection(SelectionType aType
, nsISelection
** aSelection
);
721 virtual nsISelection
* GetCurrentSelection(SelectionType aType
);
723 NS_IMETHOD
SetDisplaySelection(PRInt16 aToggle
);
724 NS_IMETHOD
GetDisplaySelection(PRInt16
*aToggle
);
725 NS_IMETHOD
ScrollSelectionIntoView(SelectionType aType
, SelectionRegion aRegion
, PRBool aIsSynchronous
);
726 NS_IMETHOD
RepaintSelection(SelectionType aType
);
728 virtual NS_HIDDEN_(void) BeginObservingDocument();
729 virtual NS_HIDDEN_(void) EndObservingDocument();
730 virtual NS_HIDDEN_(nsresult
) InitialReflow(nscoord aWidth
, nscoord aHeight
);
731 virtual NS_HIDDEN_(nsresult
) ResizeReflow(nscoord aWidth
, nscoord aHeight
);
732 virtual NS_HIDDEN_(void) StyleChangeReflow();
733 virtual NS_HIDDEN_(nsIPageSequenceFrame
*) GetPageSequenceFrame() const;
734 virtual NS_HIDDEN_(nsIFrame
*) GetRealPrimaryFrameFor(nsIContent
* aContent
) const;
736 virtual NS_HIDDEN_(nsIFrame
*) GetPlaceholderFrameFor(nsIFrame
* aFrame
) const;
737 virtual NS_HIDDEN_(void) FrameNeedsReflow(nsIFrame
*aFrame
, IntrinsicDirty aIntrinsicDirty
,
738 nsFrameState aBitToAdd
);
739 virtual NS_HIDDEN_(void) FrameNeedsToContinueReflow(nsIFrame
*aFrame
);
740 virtual NS_HIDDEN_(void) CancelAllPendingReflows();
741 virtual NS_HIDDEN_(PRBool
) IsSafeToFlush() const;
742 virtual NS_HIDDEN_(void) FlushPendingNotifications(mozFlushType aType
);
745 * Recreates the frames for a node
747 virtual NS_HIDDEN_(nsresult
) RecreateFramesFor(nsIContent
* aContent
);
750 * Post a callback that should be handled after reflow has finished.
752 virtual NS_HIDDEN_(nsresult
) PostReflowCallback(nsIReflowCallback
* aCallback
);
753 virtual NS_HIDDEN_(void) CancelReflowCallback(nsIReflowCallback
* aCallback
);
755 virtual NS_HIDDEN_(void) ClearFrameRefs(nsIFrame
* aFrame
);
756 virtual NS_HIDDEN_(already_AddRefed
<nsIRenderingContext
>) GetReferenceRenderingContext();
757 virtual NS_HIDDEN_(nsresult
) GoToAnchor(const nsAString
& aAnchorName
, PRBool aScroll
);
758 virtual NS_HIDDEN_(nsresult
) ScrollToAnchor();
760 virtual NS_HIDDEN_(nsresult
) ScrollContentIntoView(nsIContent
* aContent
,
763 virtual PRBool
ScrollFrameRectIntoView(nsIFrame
* aFrame
,
768 virtual nsRectVisibility
GetRectVisibility(nsIFrame
*aFrame
,
770 nscoord aMinTwips
) const;
772 virtual NS_HIDDEN_(void) SetIgnoreFrameDestruction(PRBool aIgnore
);
773 virtual NS_HIDDEN_(void) NotifyDestroyingFrame(nsIFrame
* aFrame
);
775 virtual NS_HIDDEN_(nsresult
) GetLinkLocation(nsIDOMNode
* aNode
, nsAString
& aLocationString
) const;
777 virtual NS_HIDDEN_(nsresult
) CaptureHistoryState(nsILayoutHistoryState
** aLayoutHistoryState
, PRBool aLeavingPage
);
779 virtual NS_HIDDEN_(void) UnsuppressPainting();
781 virtual nsresult
GetAgentStyleSheets(nsCOMArray
<nsIStyleSheet
>& aSheets
);
782 virtual nsresult
SetAgentStyleSheets(const nsCOMArray
<nsIStyleSheet
>& aSheets
);
784 virtual nsresult
AddOverrideStyleSheet(nsIStyleSheet
*aSheet
);
785 virtual nsresult
RemoveOverrideStyleSheet(nsIStyleSheet
*aSheet
);
787 virtual NS_HIDDEN_(nsresult
) HandleEventWithTarget(nsEvent
* aEvent
, nsIFrame
* aFrame
,
788 nsIContent
* aContent
,
789 nsEventStatus
* aStatus
);
790 virtual NS_HIDDEN_(nsIFrame
*) GetEventTargetFrame();
791 virtual NS_HIDDEN_(already_AddRefed
<nsIContent
>) GetEventTargetContent(nsEvent
* aEvent
);
794 virtual nsresult
ReconstructFrames(void);
795 virtual void Freeze();
797 virtual void FireOrClearDelayedEvents(PRBool aFireEvents
);
799 virtual nsIFrame
* GetFrameForPoint(nsIFrame
* aFrame
, nsPoint aPt
);
801 virtual NS_HIDDEN_(nsresult
) RenderDocument(const nsRect
& aRect
, PRUint32 aFlags
,
802 nscolor aBackgroundColor
,
803 gfxContext
* aThebesContext
);
805 virtual already_AddRefed
<gfxASurface
> RenderNode(nsIDOMNode
* aNode
,
806 nsIntRegion
* aRegion
,
808 nsIntRect
* aScreenRect
);
810 virtual already_AddRefed
<gfxASurface
> RenderSelection(nsISelection
* aSelection
,
812 nsIntRect
* aScreenRect
);
814 virtual already_AddRefed
<nsPIDOMWindow
> GetRootWindow();
816 virtual LayerManager
* GetLayerManager();
818 //nsIViewObserver interface
820 NS_IMETHOD
Paint(nsIView
* aDisplayRoot
,
821 nsIView
* aViewToPaint
,
823 const nsRegion
& aDirtyRegion
,
824 const nsIntRegion
& aIntDirtyRegion
,
825 PRBool aPaintDefaultBackground
,
826 PRBool aWillSendDidPaint
);
827 NS_IMETHOD
HandleEvent(nsIView
* aView
,
829 nsEventStatus
* aEventStatus
);
830 virtual NS_HIDDEN_(nsresult
) HandleDOMEventWithTarget(nsIContent
* aTargetContent
,
832 nsEventStatus
* aStatus
);
833 virtual NS_HIDDEN_(nsresult
) HandleDOMEventWithTarget(nsIContent
* aTargetContent
,
835 nsEventStatus
* aStatus
);
836 NS_IMETHOD
ResizeReflow(nsIView
*aView
, nscoord aWidth
, nscoord aHeight
);
837 NS_IMETHOD_(PRBool
) IsVisible();
838 NS_IMETHOD_(PRBool
) ShouldIgnoreInvalidation();
839 NS_IMETHOD_(void) WillPaint(PRBool aWillSendDidPaint
);
840 NS_IMETHOD_(void) DidPaint();
841 NS_IMETHOD_(void) DispatchSynthMouseMove(nsGUIEvent
*aEvent
,
842 PRBool aFlushOnHoverChange
);
843 NS_IMETHOD_(void) ClearMouseCapture(nsIView
* aView
);
846 virtual NS_HIDDEN_(already_AddRefed
<nsCaret
>) GetCaret() const;
847 virtual NS_HIDDEN_(void) MaybeInvalidateCaretPosition();
848 NS_IMETHOD
SetCaretEnabled(PRBool aInEnable
);
849 NS_IMETHOD
SetCaretReadOnly(PRBool aReadOnly
);
850 NS_IMETHOD
GetCaretEnabled(PRBool
*aOutEnabled
);
851 NS_IMETHOD
SetCaretVisibilityDuringSelection(PRBool aVisibility
);
852 NS_IMETHOD
GetCaretVisible(PRBool
*_retval
);
853 virtual void SetCaret(nsCaret
*aNewCaret
);
854 virtual void RestoreCaret();
856 NS_IMETHOD
SetSelectionFlags(PRInt16 aInEnable
);
857 NS_IMETHOD
GetSelectionFlags(PRInt16
*aOutEnable
);
859 // nsISelectionController
861 NS_IMETHOD
CharacterMove(PRBool aForward
, PRBool aExtend
);
862 NS_IMETHOD
CharacterExtendForDelete();
863 NS_IMETHOD
CharacterExtendForBackspace();
864 NS_IMETHOD
WordMove(PRBool aForward
, PRBool aExtend
);
865 NS_IMETHOD
WordExtendForDelete(PRBool aForward
);
866 NS_IMETHOD
LineMove(PRBool aForward
, PRBool aExtend
);
867 NS_IMETHOD
IntraLineMove(PRBool aForward
, PRBool aExtend
);
868 NS_IMETHOD
PageMove(PRBool aForward
, PRBool aExtend
);
869 NS_IMETHOD
ScrollPage(PRBool aForward
);
870 NS_IMETHOD
ScrollLine(PRBool aForward
);
871 NS_IMETHOD
ScrollHorizontal(PRBool aLeft
);
872 NS_IMETHOD
CompleteScroll(PRBool aForward
);
873 NS_IMETHOD
CompleteMove(PRBool aForward
, PRBool aExtend
);
874 NS_IMETHOD
SelectAll();
875 NS_IMETHOD
CheckVisibility(nsIDOMNode
*node
, PRInt16 startOffset
, PRInt16 EndOffset
, PRBool
*_retval
);
877 // nsIDocumentObserver
878 virtual void BeginUpdate(nsIDocument
* aDocument
, nsUpdateType aUpdateType
);
879 virtual void EndUpdate(nsIDocument
* aDocument
, nsUpdateType aUpdateType
);
880 virtual void BeginLoad(nsIDocument
* aDocument
);
881 virtual void EndLoad(nsIDocument
* aDocument
);
882 virtual void ContentStatesChanged(nsIDocument
* aDocument
,
883 nsIContent
* aContent1
,
884 nsIContent
* aContent2
,
886 virtual void DocumentStatesChanged(nsIDocument
* aDocument
,
888 virtual void StyleSheetAdded(nsIDocument
* aDocument
,
889 nsIStyleSheet
* aStyleSheet
,
890 PRBool aDocumentSheet
);
891 virtual void StyleSheetRemoved(nsIDocument
* aDocument
,
892 nsIStyleSheet
* aStyleSheet
,
893 PRBool aDocumentSheet
);
894 virtual void StyleSheetApplicableStateChanged(nsIDocument
* aDocument
,
895 nsIStyleSheet
* aStyleSheet
,
897 virtual void StyleRuleChanged(nsIDocument
* aDocument
,
898 nsIStyleSheet
* aStyleSheet
,
899 nsIStyleRule
* aOldStyleRule
,
900 nsIStyleRule
* aNewStyleRule
);
901 virtual void StyleRuleAdded(nsIDocument
* aDocument
,
902 nsIStyleSheet
* aStyleSheet
,
903 nsIStyleRule
* aStyleRule
);
904 virtual void StyleRuleRemoved(nsIDocument
* aDocument
,
905 nsIStyleSheet
* aStyleSheet
,
906 nsIStyleRule
* aStyleRule
);
908 // nsIMutationObserver
909 NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
910 NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTEWILLCHANGE
911 NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
912 NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
913 NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
914 NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
918 #ifdef MOZ_REFLOW_PERF
919 virtual NS_HIDDEN_(void) DumpReflows();
920 virtual NS_HIDDEN_(void) CountReflows(const char * aName
, nsIFrame
* aFrame
);
921 virtual NS_HIDDEN_(void) PaintCount(const char * aName
,
922 nsIRenderingContext
* aRenderingContext
,
923 nsPresContext
* aPresContext
,
926 virtual NS_HIDDEN_(void) SetPaintFrameCount(PRBool aOn
);
927 virtual PRBool
IsPaintingFrameCounts();
931 virtual void ListStyleContexts(nsIFrame
*aRootFrame
, FILE *out
,
932 PRInt32 aIndent
= 0);
934 virtual void ListStyleSheets(FILE *out
, PRInt32 aIndent
= 0);
935 virtual void VerifyStyleTree();
939 static PRLogModuleInfo
* gLog
;
942 virtual NS_HIDDEN_(void) DisableNonTestMouseEvents(PRBool aDisable
);
944 virtual void UpdateCanvasBackground();
946 virtual nsresult
AddCanvasBackgroundColorItem(nsDisplayListBuilder
& aBuilder
,
947 nsDisplayList
& aList
,
949 const nsRect
& aBounds
,
950 nscolor aBackstopColor
,
953 virtual nsresult
AddPrintPreviewBackgroundItem(nsDisplayListBuilder
& aBuilder
,
954 nsDisplayList
& aList
,
956 const nsRect
& aBounds
);
958 virtual nscolor
ComputeBackstopColor(nsIView
* aDisplayRoot
);
960 virtual NS_HIDDEN_(nsresult
) SetIsActive(PRBool aIsActive
);
963 virtual ~PresShell();
965 void HandlePostedReflowCallbacks(PRBool aInterruptible
);
966 void CancelPostedReflowCallbacks();
968 void UnsuppressAndInvalidate();
970 void WillCauseReflow() {
971 nsContentUtils::AddScriptBlocker();
974 nsresult
DidCauseReflow();
975 friend class nsAutoCauseReflowNotifier
;
978 void DidDoReflow(PRBool aInterruptible
);
979 // ProcessReflowCommands returns whether we processed all our dirty roots
980 // without interruptions.
981 PRBool
ProcessReflowCommands(PRBool aInterruptible
);
982 // MaybeScheduleReflow checks if posting a reflow is needed, then checks if
983 // the last reflow was interrupted. In the interrupted case ScheduleReflow is
984 // called off a timer, otherwise it is called directly.
985 void MaybeScheduleReflow();
986 // Actually schedules a reflow. This should only be called by
987 // MaybeScheduleReflow and the reflow timer ScheduleReflowOffTimer
989 void ScheduleReflow();
991 // DoReflow returns whether the reflow finished without interruption
992 PRBool
DoReflow(nsIFrame
* aFrame
, PRBool aInterruptible
);
994 void DoVerifyReflow();
995 void VerifyHasDirtyRootAncestor(nsIFrame
* aFrame
);
998 // Helper for ScrollContentIntoView
999 void DoScrollContentIntoView(nsIContent
* aContent
,
1003 friend class nsPresShellEventCB
;
1005 PRBool mCaretEnabled
;
1007 nsresult
CloneStyleSet(nsStyleSet
* aSet
, nsStyleSet
** aResult
);
1008 PRBool
VerifyIncrementalReflow();
1009 PRBool mInVerifyReflow
;
1010 void ShowEventTargetDebug();
1014 * methods that manage rules that are used to implement the associated preferences
1015 * - initially created for bugs 31816, 20760, 22963
1017 nsresult
ClearPreferenceStyleRules(void);
1018 nsresult
CreatePreferenceStyleSheet(void);
1019 nsresult
SetPrefLinkRules(void);
1020 nsresult
SetPrefFocusRules(void);
1021 nsresult
SetPrefNoScriptRule();
1022 nsresult
SetPrefNoFramesRule(void);
1024 // methods for painting a range to an offscreen buffer
1026 // given a display list, clip the items within the list to
1028 nsRect
ClipListToRange(nsDisplayListBuilder
*aBuilder
,
1029 nsDisplayList
* aList
,
1032 // create a RangePaintInfo for the range aRange containing the
1033 // display list needed to paint the range to a surface
1034 RangePaintInfo
* CreateRangePaintInfo(nsIDOMRange
* aRange
,
1035 nsRect
& aSurfaceRect
,
1036 PRBool aForPrimarySelection
);
1039 * Paint the items to a new surface and return it.
1041 * aSelection - selection being painted, if any
1042 * aRegion - clip region, if any
1043 * aArea - area that the surface occupies, relative to the root frame
1044 * aPoint - reference point, typically the mouse position
1045 * aScreenRect - [out] set to the area of the screen the painted area should
1048 already_AddRefed
<gfxASurface
>
1049 PaintRangePaintInfo(nsTArray
<nsAutoPtr
<RangePaintInfo
> >* aItems
,
1050 nsISelection
* aSelection
,
1051 nsIntRegion
* aRegion
,
1054 nsIntRect
* aScreenRect
);
1057 * Methods to handle changes to user and UA sheet lists that we get
1060 void AddUserSheet(nsISupports
* aSheet
);
1061 void AddAgentSheet(nsISupports
* aSheet
);
1062 void RemoveSheet(nsStyleSet::sheetType aType
, nsISupports
* aSheet
);
1064 // Hide a view if it is a popup
1065 void HideViewIfPopup(nsIView
* aView
);
1067 // Utility method to restore the root scrollframe state
1068 void RestoreRootScrollPosition();
1070 void MaybeReleaseCapturingContent()
1072 nsCOMPtr
<nsFrameSelection
> frameSelection
= FrameSelection();
1073 if (frameSelection
) {
1074 frameSelection
->SetMouseDownState(PR_FALSE
);
1076 if (gCaptureInfo
.mContent
&&
1077 gCaptureInfo
.mContent
->GetOwnerDoc() == mDocument
) {
1078 SetCapturingContent(nsnull
, 0);
1082 nsRefPtr
<nsCSSStyleSheet
> mPrefStyleSheet
; // mStyleSet owns it but we
1083 // maintain a ref, may be null
1085 PRUint32 mUpdateCount
;
1087 // reflow roots that need to be reflowed, as both a queue and a hashtable
1088 nsTArray
<nsIFrame
*> mDirtyRoots
;
1090 PRPackedBool mDocumentLoading
;
1092 PRPackedBool mIgnoreFrameDestruction
;
1093 PRPackedBool mHaveShutDown
;
1095 // This is used to protect ourselves from triggering reflow while in the
1096 // middle of frame construction and the like... it really shouldn't be
1097 // needed, one hopes, but it is for now.
1098 PRUint32 mChangeNestCount
;
1100 nsIFrame
* mCurrentEventFrame
;
1101 nsCOMPtr
<nsIContent
> mCurrentEventContent
;
1102 nsTArray
<nsIFrame
*> mCurrentEventFrameStack
;
1103 nsCOMArray
<nsIContent
> mCurrentEventContentStack
;
1105 nsCOMPtr
<nsIContent
> mLastAnchorScrolledTo
;
1106 nscoord mLastAnchorScrollPositionY
;
1107 nsRefPtr
<nsCaret
> mCaret
;
1108 nsRefPtr
<nsCaret
> mOriginalCaret
;
1109 nsPresArena mFrameArena
;
1110 StackArena mStackArena
;
1111 nsCOMPtr
<nsIDragService
> mDragService
;
1114 // The reflow root under which we're currently reflowing. Null when
1116 nsIFrame
* mCurrentReflowRoot
;
1119 // Set of frames that we should mark with NS_FRAME_HAS_DIRTY_CHILDREN after
1120 // we finish reflowing mCurrentReflowRoot.
1121 nsTHashtable
< nsPtrHashKey
<nsIFrame
> > mFramesToDirty
;
1123 // Information needed to properly handle scrolling content into view if the
1124 // pre-scroll reflow flush can be interrupted. mContentToScrollTo is
1125 // non-null between the initial scroll attempt and the first time we finish
1126 // processing all our dirty roots. mContentScrollVPosition and
1127 // mContentScrollHPosition are only used when it's non-null.
1128 nsCOMPtr
<nsIContent
> mContentToScrollTo
;
1129 PRIntn mContentScrollVPosition
;
1130 PRIntn mContentScrollHPosition
;
1132 class nsDelayedEvent
1135 virtual ~nsDelayedEvent() {};
1136 virtual void Dispatch(PresShell
* aShell
) {}
1139 class nsDelayedInputEvent
: public nsDelayedEvent
1142 virtual void Dispatch(PresShell
* aShell
)
1144 if (mEvent
&& mEvent
->widget
) {
1145 nsCOMPtr
<nsIWidget
> w
= mEvent
->widget
;
1146 nsEventStatus status
;
1147 w
->DispatchEvent(mEvent
, status
);
1152 void Init(nsInputEvent
* aEvent
)
1154 mEvent
->time
= aEvent
->time
;
1155 mEvent
->refPoint
= aEvent
->refPoint
;
1156 mEvent
->isShift
= aEvent
->isShift
;
1157 mEvent
->isControl
= aEvent
->isControl
;
1158 mEvent
->isAlt
= aEvent
->isAlt
;
1159 mEvent
->isMeta
= aEvent
->isMeta
;
1162 nsDelayedInputEvent()
1163 : nsDelayedEvent(), mEvent(nsnull
) {}
1165 nsInputEvent
* mEvent
;
1168 class nsDelayedMouseEvent
: public nsDelayedInputEvent
1171 nsDelayedMouseEvent(nsMouseEvent
* aEvent
) : nsDelayedInputEvent()
1173 mEvent
= new nsMouseEvent(NS_IS_TRUSTED_EVENT(aEvent
),
1180 static_cast<nsMouseEvent
*>(mEvent
)->clickCount
= aEvent
->clickCount
;
1184 virtual ~nsDelayedMouseEvent()
1186 delete static_cast<nsMouseEvent
*>(mEvent
);
1190 class nsDelayedKeyEvent
: public nsDelayedInputEvent
1193 nsDelayedKeyEvent(nsKeyEvent
* aEvent
) : nsDelayedInputEvent()
1195 mEvent
= new nsKeyEvent(NS_IS_TRUSTED_EVENT(aEvent
),
1200 static_cast<nsKeyEvent
*>(mEvent
)->keyCode
= aEvent
->keyCode
;
1201 static_cast<nsKeyEvent
*>(mEvent
)->charCode
= aEvent
->charCode
;
1202 static_cast<nsKeyEvent
*>(mEvent
)->alternativeCharCodes
=
1203 aEvent
->alternativeCharCodes
;
1204 static_cast<nsKeyEvent
*>(mEvent
)->isChar
= aEvent
->isChar
;
1208 virtual ~nsDelayedKeyEvent()
1210 delete static_cast<nsKeyEvent
*>(mEvent
);
1214 PRPackedBool mNoDelayedMouseEvents
;
1215 PRPackedBool mNoDelayedKeyEvents
;
1216 nsTArray
<nsAutoPtr
<nsDelayedEvent
> > mDelayedEvents
;
1218 nsCallbackEventRequest
* mFirstCallbackEventRequest
;
1219 nsCallbackEventRequest
* mLastCallbackEventRequest
;
1221 PRPackedBool mIsDocumentGone
; // We've been disconnected from the document.
1222 // We will refuse to paint the document until either
1223 // (a) our timer fires or (b) all frames are constructed.
1224 PRPackedBool mShouldUnsuppressPainting
; // Indicates that it is safe to unlock painting once all pending
1225 // reflows have been processed.
1226 nsCOMPtr
<nsITimer
> mPaintSuppressionTimer
; // This timer controls painting suppression. Until it fires
1227 // or all frames are constructed, we won't paint anything but
1228 // our <body> background and scrollbars.
1229 #define PAINTLOCK_EVENT_DELAY 250 // 250ms. This is actually
1230 // pref-controlled, but we use this
1231 // value if we fail to get the pref
1234 static void sPaintSuppressionCallback(nsITimer
* aTimer
, void* aPresShell
); // A callback for the timer.
1236 // At least on Win32 and Mac after interupting a reflow we need to post
1237 // the resume reflow event off a timer to avoid event starvation because
1238 // posted messages are processed before other messages when the modal
1239 // moving/sizing loop is running, see bug 491700 for details.
1240 nsCOMPtr
<nsITimer
> mReflowContinueTimer
;
1241 static void sReflowContinueCallback(nsITimer
* aTimer
, void* aPresShell
);
1242 PRBool
ScheduleReflowOffTimer();
1244 #ifdef MOZ_REFLOW_PERF
1245 ReflowCountMgr
* mReflowCountMgr
;
1248 static PRBool sDisableNonTestMouseEvents
;
1250 // false if a check should be done for key/ime events that should be
1251 // retargeted to the currently focused presshell
1252 static PRBool sDontRetargetEvents
;
1256 PRBool
InZombieDocument(nsIContent
*aContent
);
1257 already_AddRefed
<nsIPresShell
> GetParentPresShell();
1258 nsresult
RetargetEventToParent(nsGUIEvent
* aEvent
,
1259 nsEventStatus
* aEventStatus
);
1261 //helper funcs for event handling
1263 //protected because nsPresShellEventCB needs this.
1264 nsIFrame
* GetCurrentEventFrame();
1266 void PushCurrentEventInfo(nsIFrame
* aFrame
, nsIContent
* aContent
);
1267 void PopCurrentEventInfo();
1268 nsresult
HandleEventInternal(nsEvent
* aEvent
, nsIView
* aView
,
1269 nsEventStatus
*aStatus
);
1270 nsresult
HandlePositionedEvent(nsIView
* aView
,
1271 nsIFrame
* aTargetFrame
,
1273 nsEventStatus
* aEventStatus
);
1274 // This returns the focused DOM window under our top level window.
1275 // I.e., when we are deactive, this returns the *last* focused DOM window.
1276 already_AddRefed
<nsPIDOMWindow
> GetFocusedDOMWindowInOurWindow();
1279 * This and the next two helper methods are used to target and position the
1280 * context menu when the keyboard shortcut is used to open it.
1282 * If another menu is open, the context menu is opened relative to the
1283 * active menuitem within the menu, or the menu itself if no item is active.
1284 * Otherwise, if the caret is visible, the menu is opened near the caret.
1285 * Otherwise, if a selectable list such as a listbox is focused, the
1286 * current item within the menu is opened relative to this item.
1287 * Otherwise, the context menu is opened at the topleft corner of the
1290 * Returns true if the context menu event should fire and false if it should
1293 PRBool
AdjustContextMenuKeyEvent(nsMouseEvent
* aEvent
);
1296 PRBool
PrepareToUseCaretPosition(nsIWidget
* aEventWidget
, nsIntPoint
& aTargetPt
);
1298 // Get the selected item and coordinates in device pixels relative to root
1299 // document's root view for element, first ensuring the element is onscreen
1300 void GetCurrentItemAndPositionForElement(nsIDOMElement
*aCurrentEl
,
1301 nsIContent
**aTargetToUse
,
1302 nsIntPoint
& aTargetPt
,
1303 nsIWidget
*aRootWidget
);
1305 void FireResizeEvent();
1306 static void AsyncResizeEventCallback(nsITimer
* aTimer
, void* aPresShell
);
1307 nsRevocableEventPtr
<nsRunnableMethod
<PresShell
> > mResizeEvent
;
1308 nsCOMPtr
<nsITimer
> mAsyncResizeEventTimer
;
1309 PRPackedBool mAsyncResizeTimerIsActive
;
1310 PRPackedBool mInResize
;
1314 // Ensure that every allocation from the PresArena is eventually freed.
1315 PRUint32 mPresArenaAllocCount
;
1320 PRUint32
EstimateMemoryUsed() {
1321 PRUint32 result
= 0;
1323 result
+= sizeof(PresShell
);
1324 result
+= mStackArena
.Size();
1325 result
+= mFrameArena
.Size();
1330 static PLDHashOperator
LiveShellSizeEnumerator(PresShellPtrKey
*aEntry
,
1333 PresShell
*aShell
= static_cast<PresShell
*>(aEntry
->GetKey());
1334 PRUint32
*val
= (PRUint32
*)userArg
;
1335 *val
+= aShell
->EstimateMemoryUsed();
1336 *val
+= aShell
->mPresContext
->EstimateMemoryUsed();
1337 return PL_DHASH_NEXT
;
1340 static PLDHashOperator
LiveShellBidiSizeEnumerator(PresShellPtrKey
*aEntry
,
1343 PresShell
*aShell
= static_cast<PresShell
*>(aEntry
->GetKey());
1344 PRUint32
*val
= (PRUint32
*)userArg
;
1345 *val
+= aShell
->mPresContext
->GetBidiMemoryUsed();
1346 return PL_DHASH_NEXT
;
1350 EstimateShellsMemory(nsTHashtable
<PresShellPtrKey
>::Enumerator aEnumerator
)
1352 PRUint32 result
= 0;
1353 sLiveShells
->EnumerateEntries(aEnumerator
, &result
);
1358 static PRInt64
SizeOfLayoutMemoryReporter(void *) {
1359 return EstimateShellsMemory(LiveShellSizeEnumerator
);
1362 static PRInt64
SizeOfBidiMemoryReporter(void *) {
1363 return EstimateShellsMemory(LiveShellBidiSizeEnumerator
);
1367 void QueryIsActive();
1368 nsresult
UpdateImageLockingState();
1371 class nsAutoCauseReflowNotifier
1374 nsAutoCauseReflowNotifier(PresShell
* aShell
)
1377 mShell
->WillCauseReflow();
1379 ~nsAutoCauseReflowNotifier()
1381 // This check should not be needed. Currently the only place that seem
1382 // to need it is the code that deals with bug 337586.
1383 if (!mShell
->mHaveShutDown
) {
1384 mShell
->DidCauseReflow();
1387 nsContentUtils::RemoveScriptBlocker();
1394 class NS_STACK_CLASS nsPresShellEventCB
: public nsDispatchingCallback
1397 nsPresShellEventCB(PresShell
* aPresShell
) : mPresShell(aPresShell
) {}
1399 virtual void HandleEvent(nsEventChainPostVisitor
& aVisitor
)
1401 if (aVisitor
.mPresContext
&& aVisitor
.mEvent
->eventStructType
!= NS_EVENT
) {
1402 nsIFrame
* frame
= mPresShell
->GetCurrentEventFrame();
1404 frame
->HandleEvent(aVisitor
.mPresContext
,
1405 (nsGUIEvent
*) aVisitor
.mEvent
,
1406 &aVisitor
.mEventStatus
);
1411 nsRefPtr
<PresShell
> mPresShell
;
1414 PRBool
PresShell::sDisableNonTestMouseEvents
= PR_FALSE
;
1415 PRBool
PresShell::sDontRetargetEvents
= PR_FALSE
;
1418 PRLogModuleInfo
* PresShell::gLog
;
1423 VerifyStyleTree(nsPresContext
* aPresContext
, nsFrameManager
* aFrameManager
)
1425 if (nsFrame::GetVerifyStyleTreeEnable()) {
1426 nsIFrame
* rootFrame
= aFrameManager
->GetRootFrame();
1427 aFrameManager
->DebugVerifyStyleTree(rootFrame
);
1430 #define VERIFY_STYLE_TREE ::VerifyStyleTree(mPresContext, FrameManager())
1432 #define VERIFY_STYLE_TREE
1435 static PRBool gVerifyReflowEnabled
;
1438 nsIPresShell::GetVerifyReflowEnable()
1441 static PRBool firstTime
= PR_TRUE
;
1443 firstTime
= PR_FALSE
;
1444 char* flags
= PR_GetEnv("GECKO_VERIFY_REFLOW_FLAGS");
1446 PRBool error
= PR_FALSE
;
1449 char* comma
= PL_strchr(flags
, ',');
1453 PRBool found
= PR_FALSE
;
1454 const VerifyReflowFlags
* flag
= gFlags
;
1455 const VerifyReflowFlags
* limit
= gFlags
+ NUM_VERIFY_REFLOW_FLAGS
;
1456 while (flag
< limit
) {
1457 if (PL_strcasecmp(flag
->name
, flags
) == 0) {
1458 gVerifyReflowFlags
|= flag
->bit
;
1476 ShowVerifyReflowFlags();
1479 if (VERIFY_REFLOW_ON
& gVerifyReflowFlags
) {
1480 gVerifyReflowEnabled
= PR_TRUE
;
1482 printf("Note: verifyreflow is enabled");
1483 if (VERIFY_REFLOW_NOISY
& gVerifyReflowFlags
) {
1486 if (VERIFY_REFLOW_ALL
& gVerifyReflowFlags
) {
1489 if (VERIFY_REFLOW_DUMP_COMMANDS
& gVerifyReflowFlags
) {
1490 printf(" (show reflow commands)");
1492 if (VERIFY_REFLOW_NOISY_RC
& gVerifyReflowFlags
) {
1493 printf(" (noisy reflow commands)");
1494 if (VERIFY_REFLOW_REALLY_NOISY_RC
& gVerifyReflowFlags
) {
1495 printf(" (REALLY noisy reflow commands)");
1502 return gVerifyReflowEnabled
;
1506 nsIPresShell::SetVerifyReflowEnable(PRBool aEnabled
)
1508 gVerifyReflowEnabled
= aEnabled
;
1512 nsIPresShell::AddWeakFrameExternal(nsWeakFrame
* aWeakFrame
)
1514 AddWeakFrameInternal(aWeakFrame
);
1518 nsIPresShell::AddWeakFrameInternal(nsWeakFrame
* aWeakFrame
)
1520 if (aWeakFrame
->GetFrame()) {
1521 aWeakFrame
->GetFrame()->AddStateBits(NS_FRAME_EXTERNAL_REFERENCE
);
1523 aWeakFrame
->SetPreviousWeakFrame(mWeakFrames
);
1524 mWeakFrames
= aWeakFrame
;
1528 nsIPresShell::RemoveWeakFrameExternal(nsWeakFrame
* aWeakFrame
)
1530 RemoveWeakFrameInternal(aWeakFrame
);
1534 nsIPresShell::RemoveWeakFrameInternal(nsWeakFrame
* aWeakFrame
)
1536 if (mWeakFrames
== aWeakFrame
) {
1537 mWeakFrames
= aWeakFrame
->GetPreviousWeakFrame();
1540 nsWeakFrame
* nextWeak
= mWeakFrames
;
1541 while (nextWeak
&& nextWeak
->GetPreviousWeakFrame() != aWeakFrame
) {
1542 nextWeak
= nextWeak
->GetPreviousWeakFrame();
1545 nextWeak
->SetPreviousWeakFrame(aWeakFrame
->GetPreviousWeakFrame());
1549 already_AddRefed
<nsFrameSelection
>
1550 nsIPresShell::FrameSelection()
1552 NS_IF_ADDREF(mSelection
);
1556 //----------------------------------------------------------------------
1559 NS_NewPresShell(nsIPresShell
** aInstancePtrResult
)
1561 NS_PRECONDITION(nsnull
!= aInstancePtrResult
, "null ptr");
1563 if (!aInstancePtrResult
)
1564 return NS_ERROR_NULL_POINTER
;
1566 *aInstancePtrResult
= new PresShell();
1567 if (!*aInstancePtrResult
)
1568 return NS_ERROR_OUT_OF_MEMORY
;
1570 NS_ADDREF(*aInstancePtrResult
);
1574 nsTHashtable
<PresShell::PresShellPtrKey
> *nsIPresShell::sLiveShells
= 0;
1576 NS_MEMORY_REPORTER_IMPLEMENT(LayoutPresShell
,
1578 "Memory in use by layout PresShell, PresContext, and other related areas.",
1579 PresShell::SizeOfLayoutMemoryReporter
,
1582 NS_MEMORY_REPORTER_IMPLEMENT(LayoutBidi
,
1584 "Memory in use by layout Bidi processor.",
1585 PresShell::SizeOfBidiMemoryReporter
,
1588 PresShell::PresShell()
1590 mSelection
= nsnull
;
1591 #ifdef MOZ_REFLOW_PERF
1592 mReflowCountMgr
= new ReflowCountMgr();
1593 mReflowCountMgr
->SetPresContext(mPresContext
);
1594 mReflowCountMgr
->SetPresShell(this);
1598 gLog
= PR_NewLogModule("PresShell");
1600 mSelectionFlags
= nsISelectionDisplay::DISPLAY_TEXT
| nsISelectionDisplay::DISPLAY_IMAGES
;
1601 mIsThemeSupportDisabled
= PR_FALSE
;
1602 mIsActive
= PR_TRUE
;
1605 mPresArenaAllocCount
= 0;
1608 static bool registeredReporter
= false;
1609 if (!registeredReporter
) {
1610 NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(LayoutPresShell
));
1611 NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(LayoutBidi
));
1612 registeredReporter
= true;
1615 new (this) nsFrameManager();
1617 sLiveShells
->PutEntry(this);
1620 NS_IMPL_ISUPPORTS8(PresShell
, nsIPresShell
, nsIDocumentObserver
,
1621 nsIViewObserver
, nsISelectionController
,
1622 nsISelectionDisplay
, nsIObserver
, nsISupportsWeakReference
,
1623 nsIMutationObserver
)
1625 PresShell::~PresShell()
1627 sLiveShells
->RemoveEntry(this);
1629 if (!mHaveShutDown
) {
1630 NS_NOTREACHED("Someone did not call nsIPresShell::destroy");
1634 NS_ASSERTION(mCurrentEventContentStack
.Count() == 0,
1635 "Huh, event content left on the stack in pres shell dtor!");
1636 NS_ASSERTION(mFirstCallbackEventRequest
== nsnull
&&
1637 mLastCallbackEventRequest
== nsnull
,
1638 "post-reflow queues not empty. This means we're leaking");
1641 NS_ASSERTION(mPresArenaAllocCount
== 0,
1642 "Some pres arena objects were not freed");
1646 delete mFrameConstructor
;
1648 mCurrentEventContent
= nsnull
;
1650 NS_IF_RELEASE(mPresContext
);
1651 NS_IF_RELEASE(mDocument
);
1652 NS_IF_RELEASE(mSelection
);
1656 * Initialize the presentation shell. Create view manager and style
1660 PresShell::Init(nsIDocument
* aDocument
,
1661 nsPresContext
* aPresContext
,
1662 nsIViewManager
* aViewManager
,
1663 nsStyleSet
* aStyleSet
,
1664 nsCompatibility aCompatMode
)
1666 NS_TIME_FUNCTION_MIN(1.0);
1668 NS_PRECONDITION(nsnull
!= aDocument
, "null ptr");
1669 NS_PRECONDITION(nsnull
!= aPresContext
, "null ptr");
1670 NS_PRECONDITION(nsnull
!= aViewManager
, "null ptr");
1673 if ((nsnull
== aDocument
) || (nsnull
== aPresContext
) ||
1674 (nsnull
== aViewManager
)) {
1675 return NS_ERROR_NULL_POINTER
;
1678 NS_WARNING("PresShell double init'ed");
1679 return NS_ERROR_ALREADY_INITIALIZED
;
1681 result
= mStackArena
.Init();
1682 NS_ENSURE_SUCCESS(result
, result
);
1684 if (!mFramesToDirty
.Init()) {
1685 return NS_ERROR_OUT_OF_MEMORY
;
1688 mDocument
= aDocument
;
1689 NS_ADDREF(mDocument
);
1690 mViewManager
= aViewManager
;
1692 // Create our frame constructor.
1693 mFrameConstructor
= new nsCSSFrameConstructor(mDocument
, this);
1694 NS_ENSURE_TRUE(mFrameConstructor
, NS_ERROR_OUT_OF_MEMORY
);
1696 // The document viewer owns both view manager and pres shell.
1697 mViewManager
->SetViewObserver(this);
1699 // Bind the context to the presentation shell.
1700 mPresContext
= aPresContext
;
1701 NS_ADDREF(mPresContext
);
1702 aPresContext
->SetShell(this);
1704 // Now we can initialize the style set.
1705 result
= aStyleSet
->Init(aPresContext
);
1706 NS_ENSURE_SUCCESS(result
, result
);
1708 // From this point on, any time we return an error we need to make
1709 // sure to null out mStyleSet first, since an error return from this
1710 // method will cause the caller to delete the style set, so we don't
1711 // want to delete it in our destructor.
1712 mStyleSet
= aStyleSet
;
1714 // Notify our prescontext that it now has a compatibility mode. Note that
1715 // this MUST happen after we set up our style set but before we create any
1717 mPresContext
->CompatibilityModeChanged();
1719 // setup the preference style rules (no forced reflow), and do it
1720 // before creating any frames.
1721 SetPreferenceStyleRules(PR_FALSE
);
1723 result
= CallCreateInstance(kFrameSelectionCID
, &mSelection
);
1724 if (NS_FAILED(result
)) {
1729 // Create and initialize the frame manager
1730 result
= FrameManager()->Init(this, mStyleSet
);
1731 if (NS_FAILED(result
)) {
1732 NS_WARNING("Frame manager initialization failed");
1737 mSelection
->Init(this, nsnull
);
1739 // Important: this has to happen after the selection has been set up
1742 nsresult err
= NS_NewCaret(getter_AddRefs(mCaret
));
1743 if (NS_SUCCEEDED(err
))
1746 mOriginalCaret
= mCaret
;
1749 //SetCaretEnabled(PR_TRUE); // make it show in browser windows
1751 //set up selection to be displayed in document
1752 // Don't enable selection for print media
1753 nsPresContext::nsPresContextType type
= aPresContext
->Type();
1754 if (type
!= nsPresContext::eContext_PrintPreview
&&
1755 type
!= nsPresContext::eContext_Print
)
1756 SetDisplaySelection(nsISelectionController::SELECTION_DISABLED
);
1758 if (gMaxRCProcessingTime
== -1) {
1759 gMaxRCProcessingTime
=
1760 nsContentUtils::GetIntPref("layout.reflow.timeslice",
1761 NS_MAX_REFLOW_TIME
);
1765 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
1767 os
->AddObserver(this, "agent-sheet-added", PR_FALSE
);
1768 os
->AddObserver(this, "user-sheet-added", PR_FALSE
);
1769 os
->AddObserver(this, "agent-sheet-removed", PR_FALSE
);
1770 os
->AddObserver(this, "user-sheet-removed", PR_FALSE
);
1772 os
->AddObserver(this, "chrome-flush-skin-caches", PR_FALSE
);
1774 #ifdef ACCESSIBILITY
1775 os
->AddObserver(this, "a11y-init-or-shutdown", PR_FALSE
);
1780 // cache the drag service so we can check it during reflows
1781 mDragService
= do_GetService("@mozilla.org/widget/dragservice;1");
1783 #ifdef MOZ_REFLOW_PERF
1784 if (mReflowCountMgr
) {
1785 PRBool paintFrameCounts
=
1786 nsContentUtils::GetBoolPref("layout.reflow.showframecounts");
1788 PRBool dumpFrameCounts
=
1789 nsContentUtils::GetBoolPref("layout.reflow.dumpframecounts");
1791 PRBool dumpFrameByFrameCounts
=
1792 nsContentUtils::GetBoolPref("layout.reflow.dumpframebyframecounts");
1794 mReflowCountMgr
->SetDumpFrameCounts(dumpFrameCounts
);
1795 mReflowCountMgr
->SetDumpFrameByFrameCounts(dumpFrameByFrameCounts
);
1796 mReflowCountMgr
->SetPaintFrameCounts(paintFrameCounts
);
1801 if (mDocument
->HasAnimationController()) {
1802 nsSMILAnimationController
* animCtrl
= mDocument
->GetAnimationController();
1803 if (!animCtrl
->IsPaused()) {
1804 animCtrl
->StartSampling(GetPresContext()->RefreshDriver());
1809 // Get our activeness from the docShell.
1816 PresShell::Destroy()
1818 NS_TIME_FUNCTION_MIN(1.0);
1820 NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
1821 "destroy called on presshell while scripts not blocked");
1823 #ifdef MOZ_REFLOW_PERF
1825 if (mReflowCountMgr
) {
1826 delete mReflowCountMgr
;
1827 mReflowCountMgr
= nsnull
;
1834 #ifdef ACCESSIBILITY
1835 if (gIsAccessibilityActive
) {
1836 nsCOMPtr
<nsIAccessibilityService
> accService
=
1837 do_GetService("@mozilla.org/accessibilityService;1");
1839 accService
->PresShellDestroyed(this);
1842 #endif // ACCESSIBILITY
1844 MaybeReleaseCapturingContent();
1846 if (gKeyDownTarget
&& gKeyDownTarget
->GetOwnerDoc() == mDocument
) {
1847 NS_RELEASE(gKeyDownTarget
);
1850 mContentToScrollTo
= nsnull
;
1853 // We need to notify the destroying the nsPresContext to ESM for
1854 // suppressing to use from ESM.
1855 mPresContext
->EventStateManager()->NotifyDestroyPresContext(mPresContext
);
1859 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
1861 os
->RemoveObserver(this, "agent-sheet-added");
1862 os
->RemoveObserver(this, "user-sheet-added");
1863 os
->RemoveObserver(this, "agent-sheet-removed");
1864 os
->RemoveObserver(this, "user-sheet-removed");
1866 os
->RemoveObserver(this, "chrome-flush-skin-caches");
1868 #ifdef ACCESSIBILITY
1869 os
->RemoveObserver(this, "a11y-init-or-shutdown");
1874 // If our paint suppression timer is still active, kill it.
1875 if (mPaintSuppressionTimer
) {
1876 mPaintSuppressionTimer
->Cancel();
1877 mPaintSuppressionTimer
= nsnull
;
1880 // Same for our reflow continuation timer
1881 if (mReflowContinueTimer
) {
1882 mReflowContinueTimer
->Cancel();
1883 mReflowContinueTimer
= nsnull
;
1887 mCaret
->Terminate();
1892 mSelection
->DisconnectFromPresShell();
1895 // release our pref style sheet, if we have one still
1896 ClearPreferenceStyleRules();
1898 mIsDestroying
= PR_TRUE
;
1900 // We can't release all the event content in
1901 // mCurrentEventContentStack here since there might be code on the
1902 // stack that will release the event content too. Double release
1905 // The frames will be torn down, so remove them from the current
1906 // event frame stack (since they'd be dangling references if we'd
1907 // leave them in) and null out the mCurrentEventFrame pointer as
1910 mCurrentEventFrame
= nsnull
;
1912 PRInt32 i
, count
= mCurrentEventFrameStack
.Length();
1913 for (i
= 0; i
< count
; i
++) {
1914 mCurrentEventFrameStack
[i
] = nsnull
;
1917 mFramesToDirty
.Clear();
1920 // Clear the view manager's weak pointer back to |this| in case it
1922 mViewManager
->SetViewObserver(nsnull
);
1923 mViewManager
= nsnull
;
1926 mStyleSet
->BeginShutdown(mPresContext
);
1927 nsRefreshDriver
* rd
= GetPresContext()->RefreshDriver();
1929 // This shell must be removed from the document before the frame
1930 // hierarchy is torn down to avoid finding deleted frames through
1931 // this presshell while the frames are being torn down
1933 NS_ASSERTION(mDocument
->GetShell() == this, "Wrong shell?");
1934 mDocument
->DeleteShell();
1937 if (mDocument
->HasAnimationController()) {
1938 mDocument
->GetAnimationController()->StopSampling(rd
);
1943 // Revoke any pending events. We need to do this and cancel pending reflows
1944 // before we destroy the frame manager, since apparently frame destruction
1945 // sometimes spins the event queue when plug-ins are involved(!).
1946 rd
->RemoveLayoutFlushObserver(this);
1947 mResizeEvent
.Revoke();
1948 if (mAsyncResizeTimerIsActive
) {
1949 mAsyncResizeEventTimer
->Cancel();
1950 mAsyncResizeTimerIsActive
= PR_FALSE
;
1953 CancelAllPendingReflows();
1954 CancelPostedReflowCallbacks();
1956 // Destroy the frame manager. This will destroy the frame hierarchy
1957 mFrameConstructor
->WillDestroyFrameTree();
1958 FrameManager()->Destroy();
1960 // Destroy all frame properties (whose destruction was suppressed
1961 // while destroying the frame tree, but which might contain more
1962 // frames within the properties.
1964 // Clear out the prescontext's property table -- since our frame tree is
1965 // now dead, we shouldn't be looking up any more properties in that table.
1966 // We want to do this before we call SetShell() on the prescontext, so
1967 // property destructors can usefully call GetPresShell() on the
1969 mPresContext
->PropertyTable()->DeleteAll();
1973 NS_WARN_IF_FALSE(!mWeakFrames
, "Weak frames alive after destroying FrameManager");
1974 while (mWeakFrames
) {
1975 mWeakFrames
->Clear(this);
1978 // Let the style set do its cleanup.
1979 mStyleSet
->Shutdown(mPresContext
);
1982 // We hold a reference to the pres context, and it holds a weak link back
1983 // to us. To avoid the pres context having a dangling reference, set its
1984 // pres shell to NULL
1985 mPresContext
->SetShell(nsnull
);
1987 // Clear the link handler (weak reference) as well
1988 mPresContext
->SetLinkHandler(nsnull
);
1991 mHaveShutDown
= PR_TRUE
;
1994 // Dynamic stack memory allocation
1996 PresShell::PushStackMemory()
2002 PresShell::PopStackMemory()
2008 PresShell::AllocateStackMemory(size_t aSize
)
2010 return mStackArena
.Allocate(aSize
);
2014 PresShell::FreeFrame(nsQueryFrame::FrameIID aCode
, void* aPtr
)
2017 mPresArenaAllocCount
--;
2019 if (PRESARENA_MUST_FREE_DURING_DESTROY
|| !mIsDestroying
)
2020 mFrameArena
.FreeByCode(aCode
, aPtr
);
2024 PresShell::AllocateFrame(nsQueryFrame::FrameIID aCode
, size_t aSize
)
2027 mPresArenaAllocCount
++;
2029 void* result
= mFrameArena
.AllocateByCode(aCode
, aSize
);
2032 memset(result
, 0, aSize
);
2038 PresShell::FreeMisc(size_t aSize
, void* aPtr
)
2041 mPresArenaAllocCount
--;
2043 if (PRESARENA_MUST_FREE_DURING_DESTROY
|| !mIsDestroying
)
2044 mFrameArena
.FreeBySize(aSize
, aPtr
);
2048 PresShell::AllocateMisc(size_t aSize
)
2051 mPresArenaAllocCount
++;
2053 return mFrameArena
.AllocateBySize(aSize
);
2057 nsIPresShell::SetAuthorStyleDisabled(PRBool aStyleDisabled
)
2059 if (aStyleDisabled
!= mStyleSet
->GetAuthorStyleDisabled()) {
2060 mStyleSet
->SetAuthorStyleDisabled(aStyleDisabled
);
2061 ReconstructStyleData();
2066 nsIPresShell::GetAuthorStyleDisabled() const
2068 return mStyleSet
->GetAuthorStyleDisabled();
2072 PresShell::SetPreferenceStyleRules(PRBool aForceReflow
)
2074 NS_TIME_FUNCTION_MIN(1.0);
2077 return NS_ERROR_NULL_POINTER
;
2080 nsPIDOMWindow
*window
= mDocument
->GetWindow();
2082 // If the document doesn't have a window there's no need to notify
2083 // its presshell about changes to preferences since the document is
2084 // in a state where it doesn't matter any more (see
2085 // DocumentViewerImpl::Close()).
2088 return NS_ERROR_NULL_POINTER
;
2091 NS_PRECONDITION(mPresContext
, "presContext cannot be null");
2093 // first, make sure this is not a chrome shell
2094 if (nsContentUtils::IsInChromeDocshell(mDocument
)) {
2098 #ifdef DEBUG_attinasi
2099 printf("Setting Preference Style Rules:\n");
2101 // if here, we need to create rules for the prefs
2102 // - this includes the background-color, the text-color,
2103 // the link color, the visited link color and the link-underlining
2105 // first clear any exising rules
2106 nsresult result
= ClearPreferenceStyleRules();
2108 // now the link rules (must come after the color rules, or links will not be correct color!)
2109 // XXX - when there is both an override and agent pref stylesheet this won't matter,
2110 // as the color rules will be overrides and the links rules will be agent
2111 if (NS_SUCCEEDED(result
)) {
2112 result
= SetPrefLinkRules();
2114 if (NS_SUCCEEDED(result
)) {
2115 result
= SetPrefFocusRules();
2117 if (NS_SUCCEEDED(result
)) {
2118 result
= SetPrefNoScriptRule();
2120 if (NS_SUCCEEDED(result
)) {
2121 result
= SetPrefNoFramesRule();
2123 #ifdef DEBUG_attinasi
2124 printf( "Preference Style Rules set: error=%ld\n", (long)result
);
2127 // Note that this method never needs to force any calculation; the caller
2128 // will recalculate style if needed
2133 return NS_ERROR_NULL_POINTER
;
2136 nsresult
PresShell::ClearPreferenceStyleRules(void)
2138 nsresult result
= NS_OK
;
2139 if (mPrefStyleSheet
) {
2140 NS_ASSERTION(mStyleSet
, "null styleset entirely unexpected!");
2142 // remove the sheet from the styleset:
2143 // - note that we have to check for success by comparing the count before and after...
2145 PRInt32 numBefore
= mStyleSet
->SheetCount(nsStyleSet::eUserSheet
);
2146 NS_ASSERTION(numBefore
> 0, "no user stylesheets in styleset, but we have one!");
2148 mStyleSet
->RemoveStyleSheet(nsStyleSet::eUserSheet
, mPrefStyleSheet
);
2150 #ifdef DEBUG_attinasi
2151 NS_ASSERTION((numBefore
- 1) == mStyleSet
->GetNumberOfUserStyleSheets(),
2152 "Pref stylesheet was not removed");
2153 printf("PrefStyleSheet removed\n");
2155 // clear the sheet pointer: it is strictly historical now
2156 mPrefStyleSheet
= nsnull
;
2162 nsresult
PresShell::CreatePreferenceStyleSheet(void)
2164 NS_TIME_FUNCTION_MIN(1.0);
2166 NS_ASSERTION(!mPrefStyleSheet
, "prefStyleSheet already exists");
2167 nsresult result
= NS_NewCSSStyleSheet(getter_AddRefs(mPrefStyleSheet
));
2168 if (NS_SUCCEEDED(result
)) {
2169 NS_ASSERTION(mPrefStyleSheet
, "null but no error");
2170 nsCOMPtr
<nsIURI
> uri
;
2171 result
= NS_NewURI(getter_AddRefs(uri
), "about:PreferenceStyleSheet", nsnull
);
2172 if (NS_SUCCEEDED(result
)) {
2173 NS_ASSERTION(uri
, "null but no error");
2174 mPrefStyleSheet
->SetURIs(uri
, uri
, uri
);
2175 mPrefStyleSheet
->SetComplete();
2178 mPrefStyleSheet
->InsertRuleInternal(NS_LITERAL_STRING("@namespace url(http://www.w3.org/1999/xhtml);"),
2180 if (NS_SUCCEEDED(result
)) {
2181 mStyleSet
->AppendStyleSheet(nsStyleSet::eUserSheet
, mPrefStyleSheet
);
2186 #ifdef DEBUG_attinasi
2187 printf("CreatePrefStyleSheet completed: error=%ld\n",(long)result
);
2190 if (NS_FAILED(result
)) {
2191 mPrefStyleSheet
= nsnull
;
2197 // XXX We want these after the @namespace rule. Does order matter
2198 // for these rules, or can we call nsICSSStyleRule::StyleRuleCount()
2199 // and just "append"?
2200 static PRUint32 sInsertPrefSheetRulesAt
= 1;
2203 PresShell::SetPrefNoScriptRule()
2205 NS_TIME_FUNCTION_MIN(1.0);
2207 nsresult rv
= NS_OK
;
2209 // also handle the case where print is done from print preview
2210 // see bug #342439 for more details
2211 nsIDocument
* doc
= mDocument
;
2212 if (mPresContext
->Type() == nsPresContext::eContext_PrintPreview
||
2213 mPresContext
->Type() == nsPresContext::eContext_Print
) {
2214 while (doc
->GetOriginalDocument()) {
2215 doc
= doc
->GetOriginalDocument();
2219 PRBool scriptEnabled
= doc
->IsScriptEnabled();
2220 if (scriptEnabled
) {
2221 if (!mPrefStyleSheet
) {
2222 rv
= CreatePreferenceStyleSheet();
2223 NS_ENSURE_SUCCESS(rv
, rv
);
2228 InsertRuleInternal(NS_LITERAL_STRING("noscript{display:none!important}"),
2229 sInsertPrefSheetRulesAt
, &index
);
2235 nsresult
PresShell::SetPrefNoFramesRule(void)
2237 NS_TIME_FUNCTION_MIN(1.0);
2239 NS_ASSERTION(mPresContext
,"null prescontext not allowed");
2240 if (!mPresContext
) {
2241 return NS_ERROR_FAILURE
;
2244 nsresult rv
= NS_OK
;
2246 if (!mPrefStyleSheet
) {
2247 rv
= CreatePreferenceStyleSheet();
2248 NS_ENSURE_SUCCESS(rv
, rv
);
2251 NS_ASSERTION(mPrefStyleSheet
, "prefstylesheet should not be null");
2253 PRBool allowSubframes
= PR_TRUE
;
2254 nsCOMPtr
<nsISupports
> container
= mPresContext
->GetContainer();
2255 nsCOMPtr
<nsIDocShell
> docShell(do_QueryInterface(container
));
2257 docShell
->GetAllowSubframes(&allowSubframes
);
2259 if (!allowSubframes
) {
2261 rv
= mPrefStyleSheet
->
2262 InsertRuleInternal(NS_LITERAL_STRING("noframes{display:block}"),
2263 sInsertPrefSheetRulesAt
, &index
);
2264 NS_ENSURE_SUCCESS(rv
, rv
);
2265 rv
= mPrefStyleSheet
->
2266 InsertRuleInternal(NS_LITERAL_STRING("frame, frameset, iframe {display:none!important}"),
2267 sInsertPrefSheetRulesAt
, &index
);
2272 nsresult
PresShell::SetPrefLinkRules(void)
2274 NS_TIME_FUNCTION_MIN(1.0);
2276 NS_ASSERTION(mPresContext
,"null prescontext not allowed");
2277 if (!mPresContext
) {
2278 return NS_ERROR_FAILURE
;
2281 nsresult rv
= NS_OK
;
2283 if (!mPrefStyleSheet
) {
2284 rv
= CreatePreferenceStyleSheet();
2285 NS_ENSURE_SUCCESS(rv
, rv
);
2288 NS_ASSERTION(mPrefStyleSheet
, "prefstylesheet should not be null");
2290 // support default link colors:
2291 // this means the link colors need to be overridable,
2292 // which they are if we put them in the agent stylesheet,
2293 // though if using an override sheet this will cause authors grief still
2294 // In the agent stylesheet, they are !important when we are ignoring document colors
2296 nscolor
linkColor(mPresContext
->DefaultLinkColor());
2297 nscolor
activeColor(mPresContext
->DefaultActiveLinkColor());
2298 nscolor
visitedColor(mPresContext
->DefaultVisitedLinkColor());
2300 NS_NAMED_LITERAL_STRING(ruleClose
, "}");
2302 nsAutoString strColor
;
2304 // insert a rule to color links: '*|*:link {color: #RRGGBB [!important];}'
2305 ColorToString(linkColor
, strColor
);
2306 rv
= mPrefStyleSheet
->
2307 InsertRuleInternal(NS_LITERAL_STRING("*|*:link{color:") +
2308 strColor
+ ruleClose
,
2309 sInsertPrefSheetRulesAt
, &index
);
2310 NS_ENSURE_SUCCESS(rv
, rv
);
2312 // - visited links: '*|*:visited {color: #RRGGBB [!important];}'
2313 ColorToString(visitedColor
, strColor
);
2314 rv
= mPrefStyleSheet
->
2315 InsertRuleInternal(NS_LITERAL_STRING("*|*:visited{color:") +
2316 strColor
+ ruleClose
,
2317 sInsertPrefSheetRulesAt
, &index
);
2318 NS_ENSURE_SUCCESS(rv
, rv
);
2320 // - active links: '*|*:-moz-any-link:active {color: #RRGGBB [!important];}'
2321 ColorToString(activeColor
, strColor
);
2322 rv
= mPrefStyleSheet
->
2323 InsertRuleInternal(NS_LITERAL_STRING("*|*:-moz-any-link:active{color:") +
2324 strColor
+ ruleClose
,
2325 sInsertPrefSheetRulesAt
, &index
);
2326 NS_ENSURE_SUCCESS(rv
, rv
);
2328 PRBool underlineLinks
=
2329 mPresContext
->GetCachedBoolPref(kPresContext_UnderlineLinks
);
2331 if (underlineLinks
) {
2332 // create a rule to make underlining happen
2333 // '*|*:-moz-any-link {text-decoration:[underline|none];}'
2334 // no need for important, we want these to be overridable
2335 // NOTE: these must go in the agent stylesheet or they cannot be
2336 // overridden by authors
2337 rv
= mPrefStyleSheet
->
2338 InsertRuleInternal(NS_LITERAL_STRING("*|*:-moz-any-link{text-decoration:underline}"),
2339 sInsertPrefSheetRulesAt
, &index
);
2341 rv
= mPrefStyleSheet
->
2342 InsertRuleInternal(NS_LITERAL_STRING("*|*:-moz-any-link{text-decoration:none}"),
2343 sInsertPrefSheetRulesAt
, &index
);
2349 nsresult
PresShell::SetPrefFocusRules(void)
2351 NS_TIME_FUNCTION_MIN(1.0);
2353 NS_ASSERTION(mPresContext
,"null prescontext not allowed");
2354 nsresult result
= NS_OK
;
2357 result
= NS_ERROR_FAILURE
;
2359 if (NS_SUCCEEDED(result
) && !mPrefStyleSheet
)
2360 result
= CreatePreferenceStyleSheet();
2362 if (NS_SUCCEEDED(result
)) {
2363 NS_ASSERTION(mPrefStyleSheet
, "prefstylesheet should not be null");
2365 if (mPresContext
->GetUseFocusColors()) {
2366 nscolor
focusBackground(mPresContext
->FocusBackgroundColor());
2367 nscolor
focusText(mPresContext
->FocusTextColor());
2369 // insert a rule to make focus the preferred color
2371 nsAutoString strRule
, strColor
;
2373 ///////////////////////////////////////////////////////////////
2374 // - focus: '*:focus
2375 ColorToString(focusText
,strColor
);
2376 strRule
.AppendLiteral("*:focus,*:focus>font {color: ");
2377 strRule
.Append(strColor
);
2378 strRule
.AppendLiteral(" !important; background-color: ");
2379 ColorToString(focusBackground
,strColor
);
2380 strRule
.Append(strColor
);
2381 strRule
.AppendLiteral(" !important; } ");
2383 result
= mPrefStyleSheet
->
2384 InsertRuleInternal(strRule
, sInsertPrefSheetRulesAt
, &index
);
2386 PRUint8 focusRingWidth
= mPresContext
->FocusRingWidth();
2387 PRBool focusRingOnAnything
= mPresContext
->GetFocusRingOnAnything();
2388 PRUint8 focusRingStyle
= mPresContext
->GetFocusRingStyle();
2390 if ((NS_SUCCEEDED(result
) && focusRingWidth
!= 1 && focusRingWidth
<= 4 ) || focusRingOnAnything
) {
2392 nsAutoString strRule
;
2393 if (!focusRingOnAnything
)
2394 strRule
.AppendLiteral("*|*:link:focus, *|*:visited"); // If we only want focus rings on the normal things like links
2395 strRule
.AppendLiteral(":focus {outline: "); // For example 3px dotted WindowText (maximum 4)
2396 strRule
.AppendInt(focusRingWidth
);
2397 if (focusRingStyle
== 0) // solid
2398 strRule
.AppendLiteral("px solid -moz-mac-focusring !important; -moz-outline-radius: 3px; outline-offset: 1px; } ");
2400 strRule
.AppendLiteral("px dotted WindowText !important; } ");
2402 result
= mPrefStyleSheet
->
2403 InsertRuleInternal(strRule
, sInsertPrefSheetRulesAt
, &index
);
2404 NS_ENSURE_SUCCESS(result
, result
);
2405 if (focusRingWidth
!= 1) {
2406 // If the focus ring width is different from the default, fix buttons with rings
2407 strRule
.AssignLiteral("button::-moz-focus-inner, input[type=\"reset\"]::-moz-focus-inner,");
2408 strRule
.AppendLiteral("input[type=\"button\"]::-moz-focus-inner, ");
2409 strRule
.AppendLiteral("input[type=\"submit\"]::-moz-focus-inner { padding: 1px 2px 1px 2px; border: ");
2410 strRule
.AppendInt(focusRingWidth
);
2411 if (focusRingStyle
== 0) // solid
2412 strRule
.AppendLiteral("px solid transparent !important; } ");
2414 strRule
.AppendLiteral("px dotted transparent !important; } ");
2415 result
= mPrefStyleSheet
->
2416 InsertRuleInternal(strRule
, sInsertPrefSheetRulesAt
, &index
);
2417 NS_ENSURE_SUCCESS(result
, result
);
2419 strRule
.AssignLiteral("button:focus::-moz-focus-inner, input[type=\"reset\"]:focus::-moz-focus-inner,");
2420 strRule
.AppendLiteral("input[type=\"button\"]:focus::-moz-focus-inner, input[type=\"submit\"]:focus::-moz-focus-inner {");
2421 strRule
.AppendLiteral("border-color: ButtonText !important; }");
2422 result
= mPrefStyleSheet
->
2423 InsertRuleInternal(strRule
, sInsertPrefSheetRulesAt
, &index
);
2431 PresShell::AddUserSheet(nsISupports
* aSheet
)
2433 // Make sure this does what DocumentViewerImpl::CreateStyleSet does wrt
2434 // ordering. We want this new sheet to come after all the existing stylesheet
2435 // service sheets, but before other user sheets; see nsIStyleSheetService.idl
2436 // for the ordering. Just remove and readd all the nsStyleSheetService
2438 nsCOMPtr
<nsIStyleSheetService
> dummy
=
2439 do_GetService(NS_STYLESHEETSERVICE_CONTRACTID
);
2441 mStyleSet
->BeginUpdate();
2443 nsStyleSheetService
*sheetService
= nsStyleSheetService::gInstance
;
2444 nsCOMArray
<nsIStyleSheet
> & userSheets
= *sheetService
->UserStyleSheets();
2446 // Iterate forwards when removing so the searches for RemoveStyleSheet are as
2447 // short as possible.
2448 for (i
= 0; i
< userSheets
.Count(); ++i
) {
2449 mStyleSet
->RemoveStyleSheet(nsStyleSet::eUserSheet
, userSheets
[i
]);
2452 // Now iterate backwards, so that the order of userSheets will be the same as
2453 // the order of sheets from it in the style set.
2454 for (i
= userSheets
.Count() - 1; i
>= 0; --i
) {
2455 mStyleSet
->PrependStyleSheet(nsStyleSet::eUserSheet
, userSheets
[i
]);
2458 mStyleSet
->EndUpdate();
2460 ReconstructStyleData();
2464 PresShell::AddAgentSheet(nsISupports
* aSheet
)
2466 // Make sure this does what DocumentViewerImpl::CreateStyleSet does
2468 nsCOMPtr
<nsIStyleSheet
> sheet
= do_QueryInterface(aSheet
);
2473 mStyleSet
->AppendStyleSheet(nsStyleSet::eAgentSheet
, sheet
);
2474 ReconstructStyleData();
2478 PresShell::RemoveSheet(nsStyleSet::sheetType aType
, nsISupports
* aSheet
)
2480 nsCOMPtr
<nsIStyleSheet
> sheet
= do_QueryInterface(aSheet
);
2485 mStyleSet
->RemoveStyleSheet(aType
, sheet
);
2486 ReconstructStyleData();
2490 PresShell::SetDisplaySelection(PRInt16 aToggle
)
2492 mSelection
->SetDisplaySelection(aToggle
);
2497 PresShell::GetDisplaySelection(PRInt16
*aToggle
)
2499 *aToggle
= mSelection
->GetDisplaySelection();
2504 PresShell::GetSelection(SelectionType aType
, nsISelection
**aSelection
)
2506 if (!aSelection
|| !mSelection
)
2507 return NS_ERROR_NULL_POINTER
;
2509 *aSelection
= mSelection
->GetSelection(aType
);
2512 return NS_ERROR_INVALID_ARG
;
2514 NS_ADDREF(*aSelection
);
2520 PresShell::GetCurrentSelection(SelectionType aType
)
2525 return mSelection
->GetSelection(aType
);
2529 PresShell::ScrollSelectionIntoView(SelectionType aType
, SelectionRegion aRegion
, PRBool aIsSynchronous
)
2532 return NS_ERROR_NULL_POINTER
;
2534 return mSelection
->ScrollSelectionIntoView(aType
, aRegion
, aIsSynchronous
);
2538 PresShell::RepaintSelection(SelectionType aType
)
2541 return NS_ERROR_NULL_POINTER
;
2543 return mSelection
->RepaintSelection(aType
);
2546 // Make shell be a document observer
2548 PresShell::BeginObservingDocument()
2550 if (mDocument
&& !mIsDestroying
) {
2551 mDocument
->AddObserver(this);
2552 if (mIsDocumentGone
) {
2553 NS_WARNING("Adding a presshell that was disconnected from the document "
2554 "as a document observer? Sounds wrong...");
2555 mIsDocumentGone
= PR_FALSE
;
2560 // Make shell stop being a document observer
2562 PresShell::EndObservingDocument()
2564 // XXXbz do we need to tell the frame constructor that the document
2565 // is gone, perhaps? Except for printing it's NOT gone, sometimes.
2566 mIsDocumentGone
= PR_TRUE
;
2568 mDocument
->RemoveObserver(this);
2573 char* nsPresShell_ReflowStackPointerTop
;
2577 PresShell::InitialReflow(nscoord aWidth
, nscoord aHeight
)
2579 if (mIsDestroying
) {
2588 NS_TIME_FUNCTION_WITH_DOCURL
;
2590 NS_ASSERTION(!mDidInitialReflow
, "Why are we being called?");
2592 nsCOMPtr
<nsIPresShell
> kungFuDeathGrip(this);
2593 mDidInitialReflow
= PR_TRUE
;
2596 if (VERIFY_REFLOW_NOISY_RC
& gVerifyReflowFlags
) {
2598 nsIURI
*uri
= mDocument
->GetDocumentURI();
2602 printf("*** PresShell::InitialReflow (this=%p, url='%s')\n", (void*)this, url
.get());
2609 mCaret
->EraseCaret();
2611 // XXX Do a full invalidate at the beginning so that invalidates along
2612 // the way don't have region accumulation issues?
2614 mPresContext
->SetVisibleArea(nsRect(0, 0, aWidth
, aHeight
));
2616 // Get the root frame from the frame manager
2617 // XXXbz it would be nice to move this somewhere else... like frame manager
2618 // Init(), say. But we need to make sure our views are all set up by the
2620 nsIFrame
* rootFrame
= FrameManager()->GetRootFrame();
2621 NS_ASSERTION(!rootFrame
, "How did that happen, exactly?");
2623 nsAutoScriptBlocker scriptBlocker
;
2624 mFrameConstructor
->BeginUpdate();
2625 mFrameConstructor
->ConstructRootFrame(&rootFrame
);
2626 FrameManager()->SetRootFrame(rootFrame
);
2627 mFrameConstructor
->EndUpdate();
2630 NS_ENSURE_STATE(!mHaveShutDown
);
2633 return NS_ERROR_OUT_OF_MEMORY
;
2636 Element
*root
= mDocument
->GetRootElement();
2640 nsAutoCauseReflowNotifier
reflowNotifier(this);
2641 mFrameConstructor
->BeginUpdate();
2643 // Have the style sheet processor construct frame for the root
2644 // content object down
2645 mFrameConstructor
->ContentInserted(nsnull
, root
, nsnull
, PR_FALSE
);
2648 // Something in mFrameConstructor->ContentInserted may have caused
2649 // Destroy() to get called, bug 337586.
2650 NS_ENSURE_STATE(!mHaveShutDown
);
2652 mFrameConstructor
->EndUpdate();
2655 // nsAutoScriptBlocker going out of scope may have killed us too
2656 NS_ENSURE_STATE(!mHaveShutDown
);
2658 // Run the XBL binding constructors for any new frames we've constructed
2659 mDocument
->BindingManager()->ProcessAttachedQueue();
2661 NS_TIME_FUNCTION_MARK("XBL binding constructors fired");
2663 // Constructors may have killed us too
2664 NS_ENSURE_STATE(!mHaveShutDown
);
2666 // Now flush out pending restyles before we actually reflow, in
2667 // case XBL constructors changed styles somewhere.
2669 nsAutoScriptBlocker scriptBlocker
;
2670 mFrameConstructor
->CreateNeededFrames();
2671 mFrameConstructor
->ProcessPendingRestyles();
2674 // And that might have run _more_ XBL constructors
2675 NS_ENSURE_STATE(!mHaveShutDown
);
2678 NS_ASSERTION(rootFrame
, "How did that happen?");
2680 // Note: Because the frame just got created, it has the NS_FRAME_IS_DIRTY
2681 // bit set. Unset it so that FrameNeedsReflow() will work right.
2682 NS_ASSERTION(!mDirtyRoots
.Contains(rootFrame
),
2683 "Why is the root in mDirtyRoots already?");
2685 rootFrame
->RemoveStateBits(NS_FRAME_IS_DIRTY
|
2686 NS_FRAME_HAS_DIRTY_CHILDREN
);
2687 FrameNeedsReflow(rootFrame
, eResize
, NS_FRAME_IS_DIRTY
);
2689 NS_ASSERTION(mDirtyRoots
.Contains(rootFrame
),
2690 "Should be in mDirtyRoots now");
2691 NS_ASSERTION(mReflowScheduled
, "Why no reflow scheduled?");
2693 // Restore our root scroll position now if we're getting here after EndLoad
2694 // got called, since this is our one chance to do it. Note that we need not
2695 // have reflowed for this to work; when the scrollframe is finally reflowed
2696 // it'll puick up the position we store in it here.
2697 if (!mDocumentLoading
) {
2698 RestoreRootScrollPosition();
2701 // For printing, we just immediately unsuppress.
2702 if (!mPresContext
->IsPaginated()) {
2703 // Kick off a one-shot timer based off our pref value. When this timer
2704 // fires, if painting is still locked down, then we will go ahead and
2705 // trigger a full invalidate and allow painting to proceed normally.
2706 mPaintingSuppressed
= PR_TRUE
;
2707 mPaintSuppressionTimer
= do_CreateInstance("@mozilla.org/timer;1");
2708 if (!mPaintSuppressionTimer
)
2709 // Uh-oh. We must be out of memory. No point in keeping painting locked down.
2710 mPaintingSuppressed
= PR_FALSE
;
2712 // Initialize the timer.
2714 // Default to PAINTLOCK_EVENT_DELAY if we can't get the pref value.
2716 nsContentUtils::GetIntPref("nglayout.initialpaint.delay",
2717 PAINTLOCK_EVENT_DELAY
);
2719 mPaintSuppressionTimer
->InitWithFuncCallback(sPaintSuppressionCallback
,
2721 nsITimer::TYPE_ONE_SHOT
);
2725 return NS_OK
; //XXX this needs to be real. MMP
2729 PresShell::sPaintSuppressionCallback(nsITimer
*aTimer
, void* aPresShell
)
2731 nsRefPtr
<PresShell
> self
= static_cast<PresShell
*>(aPresShell
);
2733 self
->UnsuppressPainting();
2737 PresShell::AsyncResizeEventCallback(nsITimer
* aTimer
, void* aPresShell
)
2739 static_cast<PresShell
*>(aPresShell
)->FireResizeEvent();
2743 PresShell::ResizeReflow(nscoord aWidth
, nscoord aHeight
)
2745 NS_PRECONDITION(!mIsReflowing
, "Shouldn't be in reflow here!");
2746 NS_PRECONDITION(aWidth
!= NS_UNCONSTRAINEDSIZE
,
2747 "shouldn't use unconstrained widths anymore");
2749 // If we don't have a root frame yet, that means we haven't had our initial
2750 // reflow... If that's the case, and aWidth or aHeight is unconstrained,
2751 // ignore them altogether.
2752 nsIFrame
* rootFrame
= FrameManager()->GetRootFrame();
2754 if (!rootFrame
&& aHeight
== NS_UNCONSTRAINEDSIZE
) {
2755 // We can't do the work needed for SizeToContent without a root
2756 // frame, and we want to return before setting the visible area.
2757 return NS_ERROR_NOT_AVAILABLE
;
2760 mPresContext
->SetVisibleArea(nsRect(0, 0, aWidth
, aHeight
));
2762 // There isn't anything useful we can do if the initial reflow hasn't happened
2766 NS_ASSERTION(mViewManager
, "Must have view manager");
2767 nsCOMPtr
<nsIViewManager
> viewManagerDeathGrip
= mViewManager
;
2768 // Take this ref after viewManager so it'll make sure to go away first
2769 nsCOMPtr
<nsIPresShell
> kungFuDeathGrip(this);
2770 if (!GetPresContext()->SupressingResizeReflow())
2772 nsIViewManager::UpdateViewBatch
batch(mViewManager
);
2774 // Have to make sure that the content notifications are flushed before we
2775 // start messing with the frame model; otherwise we can get content doubling.
2776 mDocument
->FlushPendingNotifications(Flush_ContentAndNotify
);
2778 // Make sure style is up to date
2780 nsAutoScriptBlocker scriptBlocker
;
2781 mFrameConstructor
->CreateNeededFrames();
2782 mFrameConstructor
->ProcessPendingRestyles();
2785 if (!mIsDestroying
) {
2786 // XXX Do a full invalidate at the beginning so that invalidates along
2787 // the way don't have region accumulation issues?
2790 nsAutoCauseReflowNotifier
crNotifier(this);
2793 // Kick off a top-down reflow
2794 AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Reflow
);
2796 mDirtyRoots
.RemoveElement(rootFrame
);
2797 DoReflow(rootFrame
, PR_TRUE
);
2800 DidDoReflow(PR_TRUE
);
2803 batch
.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC
);
2806 if (aHeight
== NS_UNCONSTRAINEDSIZE
) {
2807 mPresContext
->SetVisibleArea(
2808 nsRect(0, 0, aWidth
, rootFrame
->GetRect().height
));
2811 if (!mIsDestroying
&& !mResizeEvent
.IsPending() &&
2812 !mAsyncResizeTimerIsActive
) {
2814 if (!mAsyncResizeEventTimer
) {
2815 mAsyncResizeEventTimer
= do_CreateInstance("@mozilla.org/timer;1");
2817 if (mAsyncResizeEventTimer
) {
2818 mAsyncResizeTimerIsActive
= PR_TRUE
;
2819 mAsyncResizeEventTimer
->InitWithFuncCallback(AsyncResizeEventCallback
,
2821 nsITimer::TYPE_ONE_SHOT
);
2824 nsRefPtr
<nsRunnableMethod
<PresShell
> > resizeEvent
=
2825 NS_NewRunnableMethod(this, &PresShell::FireResizeEvent
);
2826 if (NS_SUCCEEDED(NS_DispatchToCurrentThread(resizeEvent
))) {
2827 mResizeEvent
= resizeEvent
;
2832 return NS_OK
; //XXX this needs to be real. MMP
2836 PresShell::FireResizeEvent()
2838 if (mAsyncResizeTimerIsActive
) {
2839 mAsyncResizeTimerIsActive
= PR_FALSE
;
2840 mAsyncResizeEventTimer
->Cancel();
2842 mResizeEvent
.Revoke();
2844 if (mIsDocumentGone
)
2847 //Send resize event from here.
2848 nsEvent
event(PR_TRUE
, NS_RESIZE_EVENT
);
2849 nsEventStatus status
= nsEventStatus_eIgnore
;
2851 nsPIDOMWindow
*window
= mDocument
->GetWindow();
2853 nsCOMPtr
<nsIPresShell
> kungFuDeathGrip(this);
2854 mInResize
= PR_TRUE
;
2855 nsEventDispatcher::Dispatch(window
, mPresContext
, &event
, nsnull
, &status
);
2856 mInResize
= PR_FALSE
;
2861 PresShell::SetIgnoreFrameDestruction(PRBool aIgnore
)
2863 mIgnoreFrameDestruction
= aIgnore
;
2867 PresShell::NotifyDestroyingFrame(nsIFrame
* aFrame
)
2869 NS_TIME_FUNCTION_MIN(1.0);
2871 mPresContext
->ForgetUpdatePluginGeometryFrame(aFrame
);
2873 if (!mIgnoreFrameDestruction
) {
2874 mPresContext
->StopImagesFor(aFrame
);
2876 mFrameConstructor
->NotifyDestroyingFrame(aFrame
);
2878 for (PRInt32 idx
= mDirtyRoots
.Length(); idx
; ) {
2880 if (mDirtyRoots
[idx
] == aFrame
) {
2881 mDirtyRoots
.RemoveElementAt(idx
);
2885 // Notify the frame manager
2886 FrameManager()->NotifyDestroyingFrame(aFrame
);
2888 // Remove frame properties
2889 mPresContext
->NotifyDestroyingFrame(aFrame
);
2891 if (aFrame
== mCurrentEventFrame
) {
2892 mCurrentEventContent
= aFrame
->GetContent();
2893 mCurrentEventFrame
= nsnull
;
2897 if (aFrame
== mDrawEventTargetFrame
) {
2898 mDrawEventTargetFrame
= nsnull
;
2902 for (unsigned int i
=0; i
< mCurrentEventFrameStack
.Length(); i
++) {
2903 if (aFrame
== mCurrentEventFrameStack
.ElementAt(i
)) {
2904 //One of our stack frames was deleted. Get its content so that when we
2905 //pop it we can still get its new frame from its content
2906 nsIContent
*currentEventContent
= aFrame
->GetContent();
2907 mCurrentEventContentStack
.ReplaceObjectAt(currentEventContent
, i
);
2908 mCurrentEventFrameStack
[i
] = nsnull
;
2912 mFramesToDirty
.RemoveEntry(aFrame
);
2916 already_AddRefed
<nsCaret
> PresShell::GetCaret() const
2918 nsCaret
* caret
= mCaret
;
2919 NS_IF_ADDREF(caret
);
2923 void PresShell::MaybeInvalidateCaretPosition()
2926 mCaret
->InvalidateOutsideCaret();
2930 void PresShell::SetCaret(nsCaret
*aNewCaret
)
2935 void PresShell::RestoreCaret()
2937 mCaret
= mOriginalCaret
;
2940 NS_IMETHODIMP
PresShell::SetCaretEnabled(PRBool aInEnable
)
2942 PRBool oldEnabled
= mCaretEnabled
;
2944 mCaretEnabled
= aInEnable
;
2946 if (mCaret
&& (mCaretEnabled
!= oldEnabled
))
2948 /* Don't change the caret's selection here! This was an evil side-effect of SetCaretEnabled()
2949 nsCOMPtr<nsIDOMSelection> domSel;
2950 if (NS_SUCCEEDED(GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(domSel))) && domSel)
2951 mCaret->SetCaretDOMSelection(domSel);
2953 mCaret
->SetCaretVisible(mCaretEnabled
);
2959 NS_IMETHODIMP
PresShell::SetCaretReadOnly(PRBool aReadOnly
)
2962 mCaret
->SetCaretReadOnly(aReadOnly
);
2966 NS_IMETHODIMP
PresShell::GetCaretEnabled(PRBool
*aOutEnabled
)
2968 NS_ENSURE_ARG_POINTER(aOutEnabled
);
2969 *aOutEnabled
= mCaretEnabled
;
2973 NS_IMETHODIMP
PresShell::SetCaretVisibilityDuringSelection(PRBool aVisibility
)
2976 mCaret
->SetVisibilityDuringSelection(aVisibility
);
2980 NS_IMETHODIMP
PresShell::GetCaretVisible(PRBool
*aOutIsVisible
)
2982 *aOutIsVisible
= PR_FALSE
;
2984 nsresult rv
= mCaret
->GetCaretVisible(aOutIsVisible
);
2985 NS_ENSURE_SUCCESS(rv
,rv
);
2990 NS_IMETHODIMP
PresShell::SetSelectionFlags(PRInt16 aInEnable
)
2992 mSelectionFlags
= aInEnable
;
2996 NS_IMETHODIMP
PresShell::GetSelectionFlags(PRInt16
*aOutEnable
)
2999 return NS_ERROR_INVALID_ARG
;
3000 *aOutEnable
= mSelectionFlags
;
3004 //implementation of nsISelectionController
3007 PresShell::CharacterMove(PRBool aForward
, PRBool aExtend
)
3009 return mSelection
->CharacterMove(aForward
, aExtend
);
3013 PresShell::CharacterExtendForDelete()
3015 return mSelection
->CharacterExtendForDelete();
3019 PresShell::CharacterExtendForBackspace()
3021 return mSelection
->CharacterExtendForBackspace();
3025 PresShell::WordMove(PRBool aForward
, PRBool aExtend
)
3027 return mSelection
->WordMove(aForward
, aExtend
);
3031 PresShell::WordExtendForDelete(PRBool aForward
)
3033 return mSelection
->WordExtendForDelete(aForward
);
3037 PresShell::LineMove(PRBool aForward
, PRBool aExtend
)
3039 nsresult result
= mSelection
->LineMove(aForward
, aExtend
);
3040 // if we can't go down/up any more we must then move caret completely to
3041 // end/beginning respectively.
3042 if (NS_FAILED(result
))
3043 result
= CompleteMove(aForward
,aExtend
);
3048 PresShell::IntraLineMove(PRBool aForward
, PRBool aExtend
)
3050 return mSelection
->IntraLineMove(aForward
, aExtend
);
3056 PresShell::PageMove(PRBool aForward
, PRBool aExtend
)
3058 nsIScrollableFrame
*scrollableFrame
=
3059 GetFrameToScrollAsScrollable(nsIPresShell::eVertical
);
3060 if (!scrollableFrame
)
3063 mSelection
->CommonPageMove(aForward
, aExtend
, scrollableFrame
);
3064 // After ScrollSelectionIntoView(), the pending notifications might be
3065 // flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
3066 return ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL
, nsISelectionController::SELECTION_FOCUS_REGION
, PR_TRUE
);
3072 PresShell::ScrollPage(PRBool aForward
)
3074 nsIScrollableFrame
* scrollFrame
=
3075 GetFrameToScrollAsScrollable(nsIPresShell::eVertical
);
3077 scrollFrame
->ScrollBy(nsIntPoint(0, aForward
? 1 : -1),
3078 nsIScrollableFrame::PAGES
,
3079 nsIScrollableFrame::SMOOTH
);
3085 PresShell::ScrollLine(PRBool aForward
)
3087 nsIScrollableFrame
* scrollFrame
=
3088 GetFrameToScrollAsScrollable(nsIPresShell::eVertical
);
3090 PRInt32 lineCount
= 1;
3091 #ifdef MOZ_WIDGET_COCOA
3092 // Emulate the Mac IE behavior of scrolling a minimum of 2 lines
3093 // rather than 1. This vastly improves scrolling speed.
3096 scrollFrame
->ScrollBy(nsIntPoint(0, aForward
? lineCount
: -lineCount
),
3097 nsIScrollableFrame::LINES
,
3098 nsIScrollableFrame::SMOOTH
);
3101 // force the update to happen now, otherwise multiple scrolls can
3102 // occur before the update is processed. (bug #7354)
3104 // I'd use Composite here, but it doesn't always work.
3106 nsIViewManager
* viewManager
= GetViewManager();
3108 viewManager
->ForceUpdate();
3115 PresShell::ScrollHorizontal(PRBool aLeft
)
3117 nsIScrollableFrame
* scrollFrame
=
3118 GetFrameToScrollAsScrollable(nsIPresShell::eHorizontal
);
3120 scrollFrame
->ScrollBy(nsIntPoint(aLeft
? -1 : 1, 0),
3121 nsIScrollableFrame::LINES
,
3122 nsIScrollableFrame::SMOOTH
);
3124 // force the update to happen now, otherwise multiple scrolls can
3125 // occur before the update is processed. (bug #7354)
3127 // I'd use Composite here, but it doesn't always work.
3129 nsIViewManager
* viewManager
= GetViewManager();
3131 viewManager
->ForceUpdate();
3138 PresShell::CompleteScroll(PRBool aForward
)
3140 nsIScrollableFrame
* scrollFrame
=
3141 GetFrameToScrollAsScrollable(nsIPresShell::eVertical
);
3143 scrollFrame
->ScrollBy(nsIntPoint(0, aForward
? 1 : -1),
3144 nsIScrollableFrame::WHOLE
,
3145 nsIScrollableFrame::INSTANT
);
3151 PresShell::CompleteMove(PRBool aForward
, PRBool aExtend
)
3153 // Beware! This may flush notifications via synchronous
3154 // ScrollSelectionIntoView.
3155 nsIContent
* limiter
= mSelection
->GetAncestorLimiter();
3156 nsIFrame
* frame
= limiter
? limiter
->GetPrimaryFrame()
3157 : FrameConstructor()->GetRootElementFrame();
3159 return NS_ERROR_FAILURE
;
3160 nsPeekOffsetStruct pos
= frame
->GetExtremeCaretPosition(!aForward
);
3161 mSelection
->HandleClick(pos
.mResultContent
, pos
.mContentOffset
,
3162 pos
.mContentOffset
, aExtend
, PR_FALSE
, aForward
);
3164 // HandleClick resets ancestorLimiter, so set it again.
3165 mSelection
->SetAncestorLimiter(limiter
);
3168 // After ScrollSelectionIntoView(), the pending notifications might be
3169 // flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
3170 return ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL
,
3171 nsISelectionController::SELECTION_FOCUS_REGION
,
3176 PresShell::SelectAll()
3178 return mSelection
->SelectAll();
3182 PresShell::CheckVisibility(nsIDOMNode
*node
, PRInt16 startOffset
, PRInt16 EndOffset
, PRBool
*_retval
)
3184 if (!node
|| startOffset
>EndOffset
|| !_retval
|| startOffset
<0 || EndOffset
<0)
3185 return NS_ERROR_INVALID_ARG
;
3186 *_retval
= PR_FALSE
; //initialize return parameter
3187 nsCOMPtr
<nsIContent
> content(do_QueryInterface(node
));
3189 return NS_ERROR_FAILURE
;
3190 nsIFrame
*frame
= content
->GetPrimaryFrame();
3191 if (!frame
) //no frame to look at so it must not be visible
3193 //start process now to go through all frames to find startOffset. then check chars after that to see
3194 //if anything until EndOffset is visible.
3195 PRBool finished
= PR_FALSE
;
3196 frame
->CheckVisibility(mPresContext
,startOffset
,EndOffset
,PR_TRUE
,&finished
, _retval
);
3197 return NS_OK
;//dont worry about other return val
3200 //end implementations nsISelectionController
3204 PresShell::StyleChangeReflow()
3206 nsIFrame
* rootFrame
= FrameManager()->GetRootFrame();
3207 // At the moment at least, we don't have a root frame before the initial
3208 // reflow; it's safe to just ignore the request in that case
3212 FrameNeedsReflow(rootFrame
, eStyleChange
, NS_FRAME_IS_DIRTY
);
3216 nsIPresShell::GetRootFrameExternal() const
3218 return FrameManager()->GetRootFrame();
3222 nsIPresShell::GetRootScrollFrame() const
3224 nsIFrame
* rootFrame
= FrameManager()->GetRootFrame();
3225 // Ensure root frame is a viewport frame
3226 if (!rootFrame
|| nsGkAtoms::viewportFrame
!= rootFrame
->GetType())
3228 nsIFrame
* theFrame
= rootFrame
->GetFirstChild(nsnull
);
3229 if (!theFrame
|| nsGkAtoms::scrollFrame
!= theFrame
->GetType())
3235 nsIPresShell::GetRootScrollFrameAsScrollable() const
3237 nsIFrame
* frame
= GetRootScrollFrame();
3240 nsIScrollableFrame
* scrollableFrame
= do_QueryFrame(frame
);
3241 NS_ASSERTION(scrollableFrame
,
3242 "All scroll frames must implement nsIScrollableFrame");
3243 return scrollableFrame
;
3247 nsIPresShell::GetRootScrollFrameAsScrollableExternal() const
3249 return GetRootScrollFrameAsScrollable();
3252 nsIPageSequenceFrame
*
3253 PresShell::GetPageSequenceFrame() const
3255 nsIFrame
* frame
= mFrameConstructor
->GetPageSequenceFrame();
3256 return do_QueryFrame(frame
);
3260 PresShell::GetFrameForPoint(nsIFrame
* aFrame
, nsPoint aPt
)
3262 return nsLayoutUtils::GetFrameForPoint(aFrame
, aPt
);
3266 PresShell::BeginUpdate(nsIDocument
*aDocument
, nsUpdateType aUpdateType
)
3271 mFrameConstructor
->BeginUpdate();
3273 if (aUpdateType
& UPDATE_STYLE
)
3274 mStyleSet
->BeginUpdate();
3278 PresShell::EndUpdate(nsIDocument
*aDocument
, nsUpdateType aUpdateType
)
3281 NS_PRECONDITION(0 != mUpdateCount
, "too many EndUpdate's");
3285 if (aUpdateType
& UPDATE_STYLE
) {
3286 mStyleSet
->EndUpdate();
3287 if (mStylesHaveChanged
)
3288 ReconstructStyleData();
3291 mFrameConstructor
->EndUpdate();
3295 PresShell::RestoreRootScrollPosition()
3297 // Restore frame state for the root scroll frame
3298 nsCOMPtr
<nsILayoutHistoryState
> historyState
=
3299 mDocument
->GetLayoutHistoryState();
3300 // Make sure we don't reenter reflow via the sync paint that happens while
3301 // we're scrolling to our restored position. Entering reflow for the
3302 // scrollable frame will cause it to reenter ScrollToRestoredPosition(), and
3303 // it'll get all confused.
3304 nsAutoScriptBlocker scriptBlocker
;
3308 nsIFrame
* scrollFrame
= GetRootScrollFrame();
3310 nsIScrollableFrame
* scrollableFrame
= do_QueryFrame(scrollFrame
);
3311 if (scrollableFrame
) {
3312 FrameManager()->RestoreFrameStateFor(scrollFrame
, historyState
,
3313 nsIStatefulFrame::eDocumentScrollState
);
3314 scrollableFrame
->ScrollToRestoredPosition();
3323 PresShell::BeginLoad(nsIDocument
*aDocument
)
3325 mDocumentLoading
= PR_TRUE
;
3329 PresShell::EndLoad(nsIDocument
*aDocument
)
3331 NS_PRECONDITION(aDocument
== mDocument
, "Wrong document");
3333 RestoreRootScrollPosition();
3335 mDocumentLoading
= PR_FALSE
;
3340 PresShell::VerifyHasDirtyRootAncestor(nsIFrame
* aFrame
)
3342 // XXXbz due to bug 372769, can't actually assert anything here...
3345 // XXXbz shouldn't need this part; remove it once FrameNeedsReflow
3346 // handles the root frame correctly.
3347 if (!aFrame
->GetParent()) {
3351 // Make sure that there is a reflow root ancestor of |aFrame| that's
3352 // in mDirtyRoots already.
3353 while (aFrame
&& (aFrame
->GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN
)) {
3354 if (((aFrame
->GetStateBits() & NS_FRAME_REFLOW_ROOT
) ||
3355 !aFrame
->GetParent()) &&
3356 mDirtyRoots
.Contains(aFrame
)) {
3360 aFrame
= aFrame
->GetParent();
3362 NS_NOTREACHED("Frame has dirty bits set but isn't scheduled to be "
3368 PresShell::FrameNeedsReflow(nsIFrame
*aFrame
, IntrinsicDirty aIntrinsicDirty
,
3369 nsFrameState aBitToAdd
)
3371 #ifdef NS_FUNCTION_TIMER
3372 NS_TIME_FUNCTION_DECLARE_DOCURL
;
3373 nsCAutoString
frameType__("N/A");
3374 nsIAtom
*atomType__
= aFrame
? aFrame
->GetType() : nsnull
;
3375 if (atomType__
) atomType__
->ToUTF8String(frameType__
);
3376 NS_TIME_FUNCTION_MIN_FMT(1.0, "%s (line %d) (document: %s, frame type: %s)", MOZ_FUNCTION_NAME
,
3377 __LINE__
, docURL__
.get(), frameType__
.get());
3380 NS_PRECONDITION(aBitToAdd
== NS_FRAME_IS_DIRTY
||
3381 aBitToAdd
== NS_FRAME_HAS_DIRTY_CHILDREN
,
3382 "Unexpected bits being added");
3383 NS_PRECONDITION(aIntrinsicDirty
!= eStyleChange
||
3384 aBitToAdd
== NS_FRAME_IS_DIRTY
,
3385 "bits don't correspond to style change reason");
3387 NS_ASSERTION(!mIsReflowing
, "can't mark frame dirty during reflow");
3389 // If we've not yet done the initial reflow, then don't bother
3390 // enqueuing a reflow command yet.
3391 if (! mDidInitialReflow
)
3394 // If we're already destroying, don't bother with this either.
3399 //printf("gShellCounter: %d\n", gShellCounter++);
3400 if (mInVerifyReflow
)
3403 if (VERIFY_REFLOW_NOISY_RC
& gVerifyReflowFlags
) {
3404 printf("\nPresShell@%p: frame %p needs reflow\n", (void*)this, (void*)aFrame
);
3405 if (VERIFY_REFLOW_REALLY_NOISY_RC
& gVerifyReflowFlags
) {
3406 printf("Current content model:\n");
3407 Element
*rootElement
= mDocument
->GetRootElement();
3409 rootElement
->List(stdout
, 0);
3415 nsAutoTArray
<nsIFrame
*, 4> subtrees
;
3416 subtrees
.AppendElement(aFrame
);
3419 nsIFrame
*subtreeRoot
= subtrees
.ElementAt(subtrees
.Length() - 1);
3420 subtrees
.RemoveElementAt(subtrees
.Length() - 1);
3422 // Grab |wasDirty| now so we can go ahead and update the bits on
3424 PRBool wasDirty
= NS_SUBTREE_DIRTY(subtreeRoot
);
3425 subtreeRoot
->AddStateBits(aBitToAdd
);
3427 // Now if subtreeRoot is a reflow root we can cut off this reflow at it if
3428 // the bit being added is NS_FRAME_HAS_DIRTY_CHILDREN.
3429 PRBool targetFrameDirty
= (aBitToAdd
== NS_FRAME_IS_DIRTY
);
3431 #define FRAME_IS_REFLOW_ROOT(_f) \
3432 ((_f->GetStateBits() & NS_FRAME_REFLOW_ROOT) && \
3433 (_f != subtreeRoot || !targetFrameDirty))
3436 // Mark the intrinsic widths as dirty on the frame, all of its ancestors,
3437 // and all of its descendants, if needed:
3439 if (aIntrinsicDirty
!= eResize
) {
3440 // Mark argument and all ancestors dirty. (Unless we hit a reflow
3441 // root that should contain the reflow. That root could be
3442 // subtreeRoot itself if it's not dirty, or it could be some
3443 // ancestor of subtreeRoot.)
3444 for (nsIFrame
*a
= subtreeRoot
;
3445 a
&& !FRAME_IS_REFLOW_ROOT(a
);
3447 a
->MarkIntrinsicWidthsDirty();
3450 if (aIntrinsicDirty
== eStyleChange
) {
3451 // Mark all descendants dirty (using an nsTArray stack rather than
3453 nsAutoTArray
<nsIFrame
*, 32> stack
;
3454 stack
.AppendElement(subtreeRoot
);
3457 nsIFrame
*f
= stack
.ElementAt(stack
.Length() - 1);
3458 stack
.RemoveElementAt(stack
.Length() - 1);
3460 if (f
->GetType() == nsGkAtoms::placeholderFrame
) {
3461 nsIFrame
*oof
= nsPlaceholderFrame::GetRealFrameForPlaceholder(f
);
3462 if (!nsLayoutUtils::IsProperAncestorFrame(subtreeRoot
, oof
)) {
3463 // We have another distinct subtree we need to mark.
3464 subtrees
.AppendElement(oof
);
3468 PRInt32 childListIndex
= 0;
3469 nsIAtom
*childListName
;
3471 childListName
= f
->GetAdditionalChildListName(childListIndex
++);
3472 for (nsIFrame
*kid
= f
->GetFirstChild(childListName
); kid
;
3473 kid
= kid
->GetNextSibling()) {
3474 kid
->MarkIntrinsicWidthsDirty();
3475 stack
.AppendElement(kid
);
3477 } while (childListName
);
3478 } while (stack
.Length() != 0);
3481 // Set NS_FRAME_HAS_DIRTY_CHILDREN bits (via nsIFrame::ChildIsDirty)
3482 // up the tree until we reach either a frame that's already dirty or
3484 nsIFrame
*f
= subtreeRoot
;
3486 if (FRAME_IS_REFLOW_ROOT(f
) || !f
->GetParent()) {
3487 // we've hit a reflow root or the root frame
3489 mDirtyRoots
.AppendElement(f
);
3493 VerifyHasDirtyRootAncestor(f
);
3500 nsIFrame
*child
= f
;
3502 wasDirty
= NS_SUBTREE_DIRTY(f
);
3503 f
->ChildIsDirty(child
);
3504 NS_ASSERTION(f
->GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN
,
3505 "ChildIsDirty didn't do its job");
3507 // This frame was already marked dirty.
3509 VerifyHasDirtyRootAncestor(f
);
3514 } while (subtrees
.Length() != 0);
3516 MaybeScheduleReflow();
3520 PresShell::FrameNeedsToContinueReflow(nsIFrame
*aFrame
)
3522 NS_ASSERTION(mIsReflowing
, "Must be in reflow when marking path dirty.");
3523 NS_PRECONDITION(mCurrentReflowRoot
, "Must have a current reflow root here");
3524 NS_ASSERTION(aFrame
== mCurrentReflowRoot
||
3525 nsLayoutUtils::IsProperAncestorFrame(mCurrentReflowRoot
, aFrame
),
3526 "Frame passed in is not the descendant of mCurrentReflowRoot");
3527 NS_ASSERTION(aFrame
->GetStateBits() & NS_FRAME_IN_REFLOW
,
3528 "Frame passed in not in reflow?");
3530 mFramesToDirty
.PutEntry(aFrame
);
3534 nsIPresShell::GetFrameToScrollAsScrollable(
3535 nsIPresShell::ScrollDirection aDirection
)
3537 nsIScrollableFrame
* scrollFrame
= nsnull
;
3539 nsCOMPtr
<nsIContent
> focusedContent
;
3540 nsIFocusManager
* fm
= nsFocusManager::GetFocusManager();
3541 if (fm
&& mDocument
) {
3542 nsCOMPtr
<nsIDOMWindow
> window
= do_QueryInterface(mDocument
->GetWindow());
3544 nsCOMPtr
<nsIDOMElement
> focusedElement
;
3545 fm
->GetFocusedElementForWindow(window
, PR_FALSE
, nsnull
, getter_AddRefs(focusedElement
));
3546 focusedContent
= do_QueryInterface(focusedElement
);
3548 if (!focusedContent
&& mSelection
) {
3549 nsISelection
* domSelection
= mSelection
->
3550 GetSelection(nsISelectionController::SELECTION_NORMAL
);
3552 nsCOMPtr
<nsIDOMNode
> focusedNode
;
3553 domSelection
->GetFocusNode(getter_AddRefs(focusedNode
));
3554 focusedContent
= do_QueryInterface(focusedNode
);
3557 if (focusedContent
) {
3558 nsIFrame
* startFrame
= focusedContent
->GetPrimaryFrame();
3560 scrollFrame
= startFrame
->GetScrollTargetFrame();
3562 startFrame
= scrollFrame
->GetScrolledFrame();
3564 if (aDirection
== nsIPresShell::eEither
) {
3566 nsLayoutUtils::GetNearestScrollableFrame(startFrame
);
3569 nsLayoutUtils::GetNearestScrollableFrameForDirection(startFrame
,
3570 aDirection
== eVertical
? nsLayoutUtils::eVertical
:
3571 nsLayoutUtils::eHorizontal
);
3576 scrollFrame
= GetRootScrollFrameAsScrollable();
3582 PresShell::CancelAllPendingReflows()
3584 mDirtyRoots
.Clear();
3586 if (mReflowScheduled
) {
3587 GetPresContext()->RefreshDriver()->RemoveLayoutFlushObserver(this);
3588 mReflowScheduled
= PR_FALSE
;
3591 ASSERT_REFLOW_SCHEDULED_STATE();
3594 #ifdef ACCESSIBILITY
3595 void nsIPresShell::InvalidateAccessibleSubtree(nsIContent
*aContent
)
3597 if (gIsAccessibilityActive
) {
3598 nsCOMPtr
<nsIAccessibilityService
> accService
=
3599 do_GetService("@mozilla.org/accessibilityService;1");
3601 accService
->InvalidateSubtreeFor(this, aContent
,
3602 nsIAccessibilityService::FRAME_SIGNIFICANT_CHANGE
);
3609 PresShell::RecreateFramesFor(nsIContent
* aContent
)
3611 NS_TIME_FUNCTION_MIN(1.0);
3613 NS_ENSURE_TRUE(mPresContext
, NS_ERROR_FAILURE
);
3614 if (!mDidInitialReflow
) {
3615 // Nothing to do here. In fact, if we proceed and aContent is the
3616 // root we will crash.
3620 // Don't call RecreateFramesForContent since that is not exported and we want
3621 // to keep the number of entrypoints down.
3623 NS_ASSERTION(mViewManager
, "Should have view manager");
3624 nsIViewManager::UpdateViewBatch
batch(mViewManager
);
3626 // Have to make sure that the content notifications are flushed before we
3627 // start messing with the frame model; otherwise we can get content doubling.
3628 mDocument
->FlushPendingNotifications(Flush_ContentAndNotify
);
3630 nsAutoScriptBlocker scriptBlocker
;
3632 nsStyleChangeList changeList
;
3633 changeList
.AppendChange(nsnull
, aContent
, nsChangeHint_ReconstructFrame
);
3635 // Mark ourselves as not safe to flush while we're doing frame construction.
3637 nsresult rv
= mFrameConstructor
->ProcessRestyledFrames(changeList
);
3640 batch
.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC
);
3641 #ifdef ACCESSIBILITY
3642 InvalidateAccessibleSubtree(aContent
);
3648 nsIPresShell::PostRecreateFramesFor(Element
* aElement
)
3650 FrameConstructor()->PostRestyleEvent(aElement
, nsRestyleHint(0),
3651 nsChangeHint_ReconstructFrame
);
3655 nsIPresShell::RestyleForAnimation(Element
* aElement
, nsRestyleHint aHint
)
3657 FrameConstructor()->PostAnimationRestyleEvent(aElement
, aHint
,
3658 NS_STYLE_HINT_NONE
);
3662 PresShell::ClearFrameRefs(nsIFrame
* aFrame
)
3664 mPresContext
->EventStateManager()->ClearFrameRefs(aFrame
);
3666 nsWeakFrame
* weakFrame
= mWeakFrames
;
3668 nsWeakFrame
* prev
= weakFrame
->GetPreviousWeakFrame();
3669 if (weakFrame
->GetFrame() == aFrame
) {
3670 // This removes weakFrame from mWeakFrames.
3671 weakFrame
->Clear(this);
3677 already_AddRefed
<nsIRenderingContext
>
3678 PresShell::GetReferenceRenderingContext()
3680 NS_TIME_FUNCTION_MIN(1.0);
3682 nsIDeviceContext
* devCtx
= mPresContext
->DeviceContext();
3683 nsRefPtr
<nsIRenderingContext
> rc
;
3684 if (mPresContext
->IsScreen()) {
3685 devCtx
->CreateRenderingContextInstance(*getter_AddRefs(rc
));
3687 rc
->Init(devCtx
, gfxPlatform::GetPlatform()->ScreenReferenceSurface());
3690 devCtx
->CreateRenderingContext(*getter_AddRefs(rc
));
3696 PresShell::GoToAnchor(const nsAString
& aAnchorName
, PRBool aScroll
)
3699 return NS_ERROR_FAILURE
;
3702 // Hold a reference to the ESM in case event dispatch tears us down.
3703 nsCOMPtr
<nsIEventStateManager
> esm
= mPresContext
->EventStateManager();
3705 if (aAnchorName
.IsEmpty()) {
3706 NS_ASSERTION(!aScroll
, "can't scroll to empty anchor name");
3707 esm
->SetContentState(nsnull
, NS_EVENT_STATE_URLTARGET
);
3711 nsCOMPtr
<nsIDOMHTMLDocument
> htmlDoc
= do_QueryInterface(mDocument
);
3712 nsresult rv
= NS_OK
;
3713 nsCOMPtr
<nsIContent
> content
;
3715 // Search for an element with a matching "id" attribute
3717 content
= mDocument
->GetElementById(aAnchorName
);
3720 // Search for an anchor element with a matching "name" attribute
3721 if (!content
&& htmlDoc
) {
3722 nsCOMPtr
<nsIDOMNodeList
> list
;
3723 // Find a matching list of named nodes
3724 rv
= htmlDoc
->GetElementsByName(aAnchorName
, getter_AddRefs(list
));
3725 if (NS_SUCCEEDED(rv
) && list
) {
3727 // Loop through the named nodes looking for the first anchor
3728 for (i
= 0; PR_TRUE
; i
++) {
3729 nsCOMPtr
<nsIDOMNode
> node
;
3730 rv
= list
->Item(i
, getter_AddRefs(node
));
3731 if (!node
) { // End of list
3734 // Ensure it's an anchor element
3735 content
= do_QueryInterface(node
);
3737 if (content
->Tag() == nsGkAtoms::a
&& content
->IsHTML()) {
3746 // Search for anchor in the HTML namespace with a matching name
3747 if (!content
&& !htmlDoc
)
3749 nsCOMPtr
<nsIDOMDocument
> doc
= do_QueryInterface(mDocument
);
3750 nsCOMPtr
<nsIDOMNodeList
> list
;
3751 NS_NAMED_LITERAL_STRING(nameSpace
, "http://www.w3.org/1999/xhtml");
3752 // Get the list of anchor elements
3753 rv
= doc
->GetElementsByTagNameNS(nameSpace
, NS_LITERAL_STRING("a"), getter_AddRefs(list
));
3754 if (NS_SUCCEEDED(rv
) && list
) {
3756 // Loop through the named nodes looking for the first anchor
3757 for (i
= 0; PR_TRUE
; i
++) {
3758 nsCOMPtr
<nsIDOMNode
> node
;
3759 rv
= list
->Item(i
, getter_AddRefs(node
));
3760 if (!node
) { // End of list
3763 // Compare the name attribute
3764 nsCOMPtr
<nsIDOMElement
> element
= do_QueryInterface(node
);
3766 if (element
&& NS_SUCCEEDED(element
->GetAttribute(NS_LITERAL_STRING("name"), value
))) {
3767 if (value
.Equals(aAnchorName
)) {
3768 content
= do_QueryInterface(element
);
3776 nsCOMPtr
<nsIDOMRange
> jumpToRange
;
3777 nsCOMPtr
<nsIXPointerResult
> xpointerResult
;
3779 nsCOMPtr
<nsIDOMXMLDocument
> xmldoc
= do_QueryInterface(mDocument
);
3782 xmldoc
->EvaluateXPointer(aAnchorName
, getter_AddRefs(xpointerResult
));
3783 if (xpointerResult
) {
3784 xpointerResult
->Item(0, getter_AddRefs(jumpToRange
));
3786 // We know it was an XPointer, so there is no point in
3787 // trying any other pointer types, let's just return
3789 return NS_ERROR_FAILURE
;
3793 // Finally try FIXptr
3795 xmldoc
->EvaluateFIXptr(aAnchorName
,getter_AddRefs(jumpToRange
));
3799 nsCOMPtr
<nsIDOMNode
> node
;
3800 jumpToRange
->GetStartContainer(getter_AddRefs(node
));
3803 node
->GetNodeType(&nodeType
);
3804 PRInt32 offset
= -1;
3805 jumpToRange
->GetStartOffset(&offset
);
3807 case nsIDOMNode::ATTRIBUTE_NODE
:
3809 // XXX Assuming jumping to the ownerElement is the sanest action.
3810 nsCOMPtr
<nsIAttribute
> attr
= do_QueryInterface(node
);
3811 content
= attr
->GetContent();
3814 case nsIDOMNode::DOCUMENT_NODE
:
3817 nsCOMPtr
<nsIDocument
> document
= do_QueryInterface(node
);
3818 content
= document
->GetChildAt(offset
);
3822 case nsIDOMNode::DOCUMENT_FRAGMENT_NODE
:
3823 case nsIDOMNode::ELEMENT_NODE
:
3824 case nsIDOMNode::ENTITY_REFERENCE_NODE
:
3827 nsCOMPtr
<nsIContent
> parent
= do_QueryInterface(node
);
3828 content
= parent
->GetChildAt(offset
);
3832 case nsIDOMNode::CDATA_SECTION_NODE
:
3833 case nsIDOMNode::COMMENT_NODE
:
3834 case nsIDOMNode::TEXT_NODE
:
3835 case nsIDOMNode::PROCESSING_INSTRUCTION_NODE
:
3837 // XXX This should scroll to a specific position in the text.
3838 content
= do_QueryInterface(node
);
3847 esm
->SetContentState(content
, NS_EVENT_STATE_URLTARGET
);
3849 #ifdef ACCESSIBILITY
3850 nsIContent
*anchorTarget
= content
;
3855 rv
= ScrollContentIntoView(content
, NS_PRESSHELL_SCROLL_TOP
,
3856 NS_PRESSHELL_SCROLL_ANYWHERE
);
3857 NS_ENSURE_SUCCESS(rv
, rv
);
3859 nsIScrollableFrame
* rootScroll
= GetRootScrollFrameAsScrollable();
3861 mLastAnchorScrolledTo
= content
;
3862 mLastAnchorScrollPositionY
= rootScroll
->GetScrollPosition().y
;
3866 // Should we select the target? This action is controlled by a
3867 // preference: the default is to not select.
3868 PRBool selectAnchor
= nsContentUtils::GetBoolPref("layout.selectanchor");
3870 // Even if select anchor pref is false, we must still move the
3871 // caret there. That way tabbing will start from the new
3874 jumpToRange
= do_CreateInstance(kRangeCID
);
3876 while (content
&& content
->GetChildCount() > 0) {
3877 content
= content
->GetChildAt(0);
3879 nsCOMPtr
<nsIDOMNode
> node(do_QueryInterface(content
));
3880 NS_ASSERTION(node
, "No nsIDOMNode for descendant of anchor");
3881 jumpToRange
->SelectNodeContents(node
);
3885 // Select the anchor
3886 nsISelection
* sel
= mSelection
->
3887 GetSelection(nsISelectionController::SELECTION_NORMAL
);
3889 sel
->RemoveAllRanges();
3890 sel
->AddRange(jumpToRange
);
3891 if (!selectAnchor
) {
3892 // Use a caret (collapsed selection) at the start of the anchor
3893 sel
->CollapseToStart();
3897 if (selectAnchor
&& xpointerResult
) {
3898 // Select the rest (if any) of the ranges in XPointerResult
3900 xpointerResult
->GetLength(&count
);
3901 for (i
= 1; i
< count
; i
++) { // jumpToRange is i = 0
3902 nsCOMPtr
<nsIDOMRange
> range
;
3903 xpointerResult
->Item(i
, getter_AddRefs(range
));
3904 sel
->AddRange(range
);
3907 // Selection is at anchor.
3908 // Now focus the document itself if focus is on an element within it.
3909 nsPIDOMWindow
*win
= mDocument
->GetWindow();
3911 nsIFocusManager
* fm
= nsFocusManager::GetFocusManager();
3913 nsCOMPtr
<nsIDOMWindow
> focusedWindow
;
3914 fm
->GetFocusedWindow(getter_AddRefs(focusedWindow
));
3915 if (SameCOMIdentity(win
, focusedWindow
))
3916 fm
->ClearFocus(focusedWindow
);
3920 rv
= NS_ERROR_FAILURE
; //changed to NS_OK in quirks mode if ScrollTo is called
3922 // Scroll to the top/left if the anchor can not be
3923 // found and it is labelled top (quirks mode only). @see bug 80784
3924 if ((NS_LossyConvertUTF16toASCII(aAnchorName
).LowerCaseEqualsLiteral("top")) &&
3925 (mPresContext
->CompatibilityMode() == eCompatibility_NavQuirks
)) {
3927 nsIScrollableFrame
* sf
= GetRootScrollFrameAsScrollable();
3928 // Check |aScroll| after setting |rv| so we set |rv| to the same
3929 // thing whether or not |aScroll| is true.
3930 if (aScroll
&& sf
) {
3931 // Scroll to the top of the page
3932 sf
->ScrollTo(nsPoint(0, 0), nsIScrollableFrame::INSTANT
);
3937 #ifdef ACCESSIBILITY
3938 if (anchorTarget
&& gIsAccessibilityActive
) {
3939 nsCOMPtr
<nsIAccessibilityService
> accService
=
3940 do_GetService("@mozilla.org/accessibilityService;1");
3942 accService
->NotifyOfAnchorJumpTo(anchorTarget
);
3950 PresShell::ScrollToAnchor()
3952 if (!mLastAnchorScrolledTo
)
3955 NS_ASSERTION(mDidInitialReflow
, "should have done initial reflow by now");
3957 nsIScrollableFrame
* rootScroll
= GetRootScrollFrameAsScrollable();
3959 mLastAnchorScrollPositionY
!= rootScroll
->GetScrollPosition().y
)
3962 nsresult rv
= ScrollContentIntoView(mLastAnchorScrolledTo
, NS_PRESSHELL_SCROLL_TOP
,
3963 NS_PRESSHELL_SCROLL_ANYWHERE
);
3964 mLastAnchorScrolledTo
= nsnull
;
3969 * Helper (per-continuation) for ScrollContentIntoView.
3971 * @param aContainerFrame [in] the frame which aRect is relative to
3972 * @param aFrame [in] Frame whose bounds should be unioned
3973 * @param aUseWholeLineHeightForInlines [in] if true, then for inline frames
3974 * we should include the top of the line in the added rectangle
3975 * @param aRect [inout] rect into which its bounds should be unioned
3976 * @param aHaveRect [inout] whether aRect contains data yet
3979 AccumulateFrameBounds(nsIFrame
* aContainerFrame
,
3981 PRBool aUseWholeLineHeightForInlines
,
3985 nsRect frameBounds
= aFrame
->GetRect() +
3986 aFrame
->GetParent()->GetOffsetTo(aContainerFrame
);
3988 // If this is an inline frame and either the bounds height is 0 (quirks
3989 // layout model) or aUseWholeLineHeightForInlines is set, we need to
3990 // change the top of the bounds to include the whole line.
3991 if (frameBounds
.height
== 0 || aUseWholeLineHeightForInlines
) {
3992 nsIAtom
* frameType
= NULL
;
3993 nsIFrame
*prevFrame
= aFrame
;
3994 nsIFrame
*f
= aFrame
;
3997 (frameType
= f
->GetType()) == nsGkAtoms::inlineFrame
) {
3999 f
= prevFrame
->GetParent();
4004 frameType
== nsGkAtoms::blockFrame
) {
4005 // find the line containing aFrame and increase the top of |offset|.
4006 nsAutoLineIterator lines
= f
->GetLineIterator();
4008 PRInt32 index
= lines
->FindLineContaining(prevFrame
);
4015 if (NS_SUCCEEDED(lines
->GetLine(index
, &trash1
, &trash2
,
4016 lineBounds
, &trash3
))) {
4017 lineBounds
+= f
->GetOffsetTo(aContainerFrame
);
4018 if (lineBounds
.y
< frameBounds
.y
) {
4019 frameBounds
.height
= frameBounds
.YMost() - lineBounds
.y
;
4020 frameBounds
.y
= lineBounds
.y
;
4029 // We can't use nsRect::UnionRect since it drops empty rects on
4030 // the floor, and we need to include them. (Thus we need
4031 // aHaveRect to know when to drop the initial value on the floor.)
4032 aRect
.UnionRectIncludeEmpty(aRect
, frameBounds
);
4034 aHaveRect
= PR_TRUE
;
4035 aRect
= frameBounds
;
4040 * This function takes a scrollable frame, a rect in the coordinate system
4041 * of the scrolled frame, and a desired percentage-based scroll
4042 * position and attempts to scroll the rect to that position in the
4045 * This needs to work even if aRect has a width or height of zero.
4047 static void ScrollToShowRect(nsIScrollableFrame
* aScrollFrame
,
4048 const nsRect
& aRect
,
4053 nsPoint scrollPt
= aScrollFrame
->GetScrollPosition();
4054 nsRect
visibleRect(scrollPt
, aScrollFrame
->GetScrollPortRect().Size());
4055 nsSize lineSize
= aScrollFrame
->GetLineScrollAmount();
4056 nsPresContext::ScrollbarStyles ss
= aScrollFrame
->GetScrollbarStyles();
4058 if ((aFlags
& nsIPresShell::SCROLL_OVERFLOW_HIDDEN
) ||
4059 ss
.mVertical
!= NS_STYLE_OVERFLOW_HIDDEN
) {
4060 // See how the rect should be positioned vertically
4061 if (NS_PRESSHELL_SCROLL_ANYWHERE
== aVPercent
||
4062 (NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE
== aVPercent
&&
4063 aRect
.height
< lineSize
.height
)) {
4064 // The caller doesn't care where the frame is positioned vertically,
4065 // so long as it's fully visible
4066 if (aRect
.y
< visibleRect
.y
) {
4067 // Scroll up so the frame's top edge is visible
4068 scrollPt
.y
= aRect
.y
;
4069 } else if (aRect
.YMost() > visibleRect
.YMost()) {
4070 // Scroll down so the frame's bottom edge is visible. Make sure the
4071 // frame's top edge is still visible
4072 scrollPt
.y
+= aRect
.YMost() - visibleRect
.YMost();
4073 if (scrollPt
.y
> aRect
.y
) {
4074 scrollPt
.y
= aRect
.y
;
4077 } else if (NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE
== aVPercent
) {
4078 // Scroll only if no part of the frame is visible in this view
4079 if (aRect
.YMost() - lineSize
.height
< visibleRect
.y
) {
4080 // Scroll up so the frame's top edge is visible
4081 scrollPt
.y
= aRect
.y
;
4082 } else if (aRect
.y
+ lineSize
.height
> visibleRect
.YMost()) {
4083 // Scroll down so the frame's bottom edge is visible. Make sure the
4084 // frame's top edge is still visible
4085 scrollPt
.y
+= aRect
.YMost() - visibleRect
.YMost();
4086 if (scrollPt
.y
> aRect
.y
) {
4087 scrollPt
.y
= aRect
.y
;
4091 // Align the frame edge according to the specified percentage
4092 nscoord frameAlignY
=
4093 NSToCoordRound(aRect
.y
+ aRect
.height
* (aVPercent
/ 100.0f
));
4095 NSToCoordRound(frameAlignY
- visibleRect
.height
* (aVPercent
/ 100.0f
));
4099 if ((aFlags
& nsIPresShell::SCROLL_OVERFLOW_HIDDEN
) ||
4100 ss
.mHorizontal
!= NS_STYLE_OVERFLOW_HIDDEN
) {
4101 // See how the frame should be positioned horizontally
4102 if (NS_PRESSHELL_SCROLL_ANYWHERE
== aHPercent
||
4103 (NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE
== aHPercent
&&
4104 aRect
.width
< lineSize
.width
)) {
4105 // The caller doesn't care where the frame is positioned horizontally,
4106 // so long as it's fully visible
4107 if (aRect
.x
< visibleRect
.x
) {
4108 // Scroll left so the frame's left edge is visible
4109 scrollPt
.x
= aRect
.x
;
4110 } else if (aRect
.XMost() > visibleRect
.XMost()) {
4111 // Scroll right so the frame's right edge is visible. Make sure the
4112 // frame's left edge is still visible
4113 scrollPt
.x
+= aRect
.XMost() - visibleRect
.XMost();
4114 if (scrollPt
.x
> aRect
.x
) {
4115 scrollPt
.x
= aRect
.x
;
4118 } else if (NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE
== aHPercent
) {
4119 // Scroll only if no part of the frame is visible in this view
4120 if (aRect
.XMost() - lineSize
.width
< visibleRect
.x
) {
4121 // Scroll left so the frame's left edge is visible
4122 scrollPt
.x
= aRect
.x
;
4123 } else if (aRect
.x
+ lineSize
.width
> visibleRect
.XMost()) {
4124 // Scroll right so the frame's right edge is visible. Make sure the
4125 // frame's left edge is still visible
4126 scrollPt
.x
+= aRect
.XMost() - visibleRect
.XMost();
4127 if (scrollPt
.x
> aRect
.x
) {
4128 scrollPt
.x
= aRect
.x
;
4132 // Align the frame edge according to the specified percentage
4133 nscoord frameAlignX
=
4134 NSToCoordRound(aRect
.x
+ (aRect
.width
) * (aHPercent
/ 100.0f
));
4136 NSToCoordRound(frameAlignX
- visibleRect
.width
* (aHPercent
/ 100.0f
));
4140 aScrollFrame
->ScrollTo(scrollPt
, nsIScrollableFrame::INSTANT
);
4144 PresShell::ScrollContentIntoView(nsIContent
* aContent
,
4148 nsCOMPtr
<nsIContent
> content
= aContent
; // Keep content alive while flushing.
4149 NS_ENSURE_TRUE(content
, NS_ERROR_NULL_POINTER
);
4150 nsCOMPtr
<nsIDocument
> currentDoc
= content
->GetCurrentDoc();
4151 NS_ENSURE_STATE(currentDoc
);
4153 NS_ASSERTION(mDidInitialReflow
, "should have done initial reflow by now");
4155 mContentToScrollTo
= aContent
;
4156 mContentScrollVPosition
= aVPercent
;
4157 mContentScrollHPosition
= aHPercent
;
4159 // Flush layout and attempt to scroll in the process.
4160 currentDoc
->FlushPendingNotifications(Flush_InterruptibleLayout
);
4162 // If mContentToScrollTo is non-null, that means we interrupted the reflow
4163 // (or suppressed it altogether because we're suppressing interruptible
4164 // flushes right now) and won't necessarily get the position correct, but do
4165 // a best-effort scroll here. The other option would be to do this inside
4166 // FlushPendingNotifications, but I'm not sure the repeated scrolling that
4167 // could trigger if reflows keep getting interrupted would be more desirable
4168 // than a single best-effort scroll followed by one final scroll on the first
4169 // completed reflow.
4170 if (mContentToScrollTo
) {
4171 DoScrollContentIntoView(content
, aVPercent
, aHPercent
);
4177 PresShell::DoScrollContentIntoView(nsIContent
* aContent
,
4181 NS_ASSERTION(mDidInitialReflow
, "should have done initial reflow by now");
4183 nsIFrame
* frame
= aContent
->GetPrimaryFrame();
4185 mContentToScrollTo
= nsnull
;
4189 if (frame
->GetStateBits() & NS_FRAME_FIRST_REFLOW
) {
4190 // The reflow flush before this scroll got interrupted, and this frame's
4191 // coords and size are all zero, and it has no content showing anyway.
4192 // Don't bother scrolling to it. We'll try again when we finish up layout.
4196 nsIFrame
* container
=
4197 nsLayoutUtils::GetClosestFrameOfType(frame
, nsGkAtoms::scrollFrame
);
4199 // nothing can be scrolled
4203 // This is a two-step process.
4204 // Step 1: Find the bounds of the rect we want to scroll into view. For
4205 // example, for an inline frame we may want to scroll in the whole
4206 // line, or we may want to scroll multiple lines into view.
4207 // Step 2: Walk container frame and its ancestors and scroll them
4209 // frameBounds is relative to container. We're assuming
4210 // that scrollframes don't split so every continuation of frame will
4211 // be a descendant of container. (Things would still mostly work
4212 // even if that assumption was false.)
4214 PRBool haveRect
= PR_FALSE
;
4215 PRBool useWholeLineHeightForInlines
= aVPercent
!= NS_PRESSHELL_SCROLL_ANYWHERE
;
4217 AccumulateFrameBounds(container
, frame
, useWholeLineHeightForInlines
,
4218 frameBounds
, haveRect
);
4219 } while ((frame
= frame
->GetNextContinuation()));
4221 ScrollFrameRectIntoView(container
, frameBounds
, aVPercent
, aHPercent
,
4222 SCROLL_OVERFLOW_HIDDEN
);
4226 PresShell::ScrollFrameRectIntoView(nsIFrame
* aFrame
,
4227 const nsRect
& aRect
,
4232 PRBool didScroll
= PR_FALSE
;
4233 // This function needs to work even if rect has a width or height of 0.
4234 nsRect rect
= aRect
;
4235 nsIFrame
* container
= aFrame
;
4236 // Walk up the frame hierarchy scrolling the rect into view and
4237 // keeping rect relative to container
4239 nsIScrollableFrame
* sf
= do_QueryFrame(container
);
4241 nsPoint oldPosition
= sf
->GetScrollPosition();
4242 ScrollToShowRect(sf
, rect
- sf
->GetScrolledFrame()->GetPosition(),
4243 aVPercent
, aHPercent
, aFlags
);
4244 nsPoint newPosition
= sf
->GetScrollPosition();
4245 // If the scroll position increased, that means our content moved up,
4246 // so our rect's offset should decrease
4247 rect
+= oldPosition
- newPosition
;
4249 if (oldPosition
!= newPosition
) {
4250 didScroll
= PR_TRUE
;
4253 // only scroll one container when this flag is set
4254 if (aFlags
& SCROLL_FIRST_ANCESTOR_ONLY
) {
4258 nsRect scrollPort
= sf
->GetScrollPortRect();
4259 if (rect
.XMost() < scrollPort
.x
||
4260 rect
.x
> scrollPort
.XMost() ||
4261 rect
.YMost() < scrollPort
.y
||
4262 rect
.y
> scrollPort
.YMost()) {
4263 // We tried to show the rectangle, but none of it is visible,
4264 // not even an edge.
4265 // Stop trying to scroll ancestors into view.
4269 // Restrict rect to the area that is actually visible through
4270 // the scrollport. We don't want to try to scroll some clipped-out
4271 // part of 'rect' into view in some ancestor.
4272 rect
.IntersectRect(rect
, sf
->GetScrollPortRect());
4274 rect
+= container
->GetPosition();
4275 nsIFrame
* parent
= container
->GetParent();
4277 nsPoint
extraOffset(0,0);
4278 parent
= nsLayoutUtils::GetCrossDocParentFrame(container
, &extraOffset
);
4280 PRInt32 APD
= container
->PresContext()->AppUnitsPerDevPixel();
4281 PRInt32 parentAPD
= parent
->PresContext()->AppUnitsPerDevPixel();
4282 rect
= rect
.ConvertAppUnitsRoundOut(APD
, parentAPD
);
4283 rect
+= extraOffset
;
4287 } while (container
);
4293 PresShell::GetRectVisibility(nsIFrame
* aFrame
,
4294 const nsRect
&aRect
,
4295 nscoord aMinTwips
) const
4297 NS_ASSERTION(aFrame
->PresContext() == GetPresContext(),
4298 "prescontext mismatch?");
4299 nsIFrame
* rootFrame
= FrameManager()->GetRootFrame();
4300 NS_ASSERTION(rootFrame
,
4301 "How can someone have a frame for this presshell when there's no root?");
4302 nsIScrollableFrame
* sf
= GetRootScrollFrameAsScrollable();
4303 nsRect scrollPortRect
;
4305 scrollPortRect
= sf
->GetScrollPortRect();
4306 nsIFrame
* f
= do_QueryFrame(sf
);
4307 scrollPortRect
+= f
->GetOffsetTo(rootFrame
);
4309 scrollPortRect
= nsRect(nsPoint(0,0), rootFrame
->GetSize());
4312 nsRect r
= aRect
+ aFrame
->GetOffsetTo(rootFrame
);
4313 // If aRect is entirely visible then we don't need to ensure that
4314 // at least aMinTwips of it is visible
4315 if (scrollPortRect
.Contains(r
))
4316 return nsRectVisibility_kVisible
;
4318 nsRect insetRect
= scrollPortRect
;
4319 insetRect
.Deflate(aMinTwips
, aMinTwips
);
4320 if (r
.YMost() <= insetRect
.y
)
4321 return nsRectVisibility_kAboveViewport
;
4322 if (r
.y
>= insetRect
.YMost())
4323 return nsRectVisibility_kBelowViewport
;
4324 if (r
.XMost() <= insetRect
.x
)
4325 return nsRectVisibility_kLeftOfViewport
;
4326 if (r
.x
>= insetRect
.XMost())
4327 return nsRectVisibility_kRightOfViewport
;
4329 return nsRectVisibility_kVisible
;
4332 // GetLinkLocation: copy link location to clipboard
4333 nsresult
PresShell::GetLinkLocation(nsIDOMNode
* aNode
, nsAString
& aLocationString
) const
4336 printf("dr :: PresShell::GetLinkLocation\n");
4339 NS_ENSURE_ARG_POINTER(aNode
);
4341 nsAutoString anchorText
;
4342 static char strippedChars
[] = {'\t','\r','\n'};
4344 // are we an anchor?
4345 nsCOMPtr
<nsIDOMHTMLAnchorElement
> anchor(do_QueryInterface(aNode
));
4346 nsCOMPtr
<nsIDOMHTMLAreaElement
> area
;
4347 nsCOMPtr
<nsIDOMHTMLLinkElement
> link
;
4348 nsAutoString xlinkType
;
4350 rv
= anchor
->GetHref(anchorText
);
4351 NS_ENSURE_SUCCESS(rv
, rv
);
4354 area
= do_QueryInterface(aNode
);
4356 rv
= area
->GetHref(anchorText
);
4357 NS_ENSURE_SUCCESS(rv
, rv
);
4360 link
= do_QueryInterface(aNode
);
4362 rv
= link
->GetHref(anchorText
);
4363 NS_ENSURE_SUCCESS(rv
, rv
);
4366 nsCOMPtr
<nsIDOMElement
> element(do_QueryInterface(aNode
));
4368 NS_NAMED_LITERAL_STRING(xlinkNS
,"http://www.w3.org/1999/xlink");
4369 element
->GetAttributeNS(xlinkNS
,NS_LITERAL_STRING("type"),xlinkType
);
4370 if (xlinkType
.EqualsLiteral("simple")) {
4371 element
->GetAttributeNS(xlinkNS
,NS_LITERAL_STRING("href"),anchorText
);
4372 if (!anchorText
.IsEmpty()) {
4373 // Resolve the full URI using baseURI property
4376 nsCOMPtr
<nsIDOM3Node
> node(do_QueryInterface(aNode
,&rv
));
4377 NS_ENSURE_SUCCESS(rv
, rv
);
4378 node
->GetBaseURI(base
);
4380 nsCOMPtr
<nsIIOService
>
4381 ios(do_GetService("@mozilla.org/network/io-service;1", &rv
));
4382 NS_ENSURE_SUCCESS(rv
, rv
);
4384 nsCOMPtr
<nsIURI
> baseURI
;
4385 rv
= ios
->NewURI(NS_ConvertUTF16toUTF8(base
),nsnull
,nsnull
,getter_AddRefs(baseURI
));
4386 NS_ENSURE_SUCCESS(rv
, rv
);
4389 rv
= baseURI
->Resolve(NS_ConvertUTF16toUTF8(anchorText
),spec
);
4390 NS_ENSURE_SUCCESS(rv
, rv
);
4392 CopyUTF8toUTF16(spec
, anchorText
);
4400 if (anchor
|| area
|| link
|| xlinkType
.EqualsLiteral("simple")) {
4401 //Remove all the '\t', '\r' and '\n' from 'anchorText'
4402 anchorText
.StripChars(strippedChars
);
4404 aLocationString
= anchorText
;
4409 // if no link, fail.
4410 return NS_ERROR_FAILURE
;
4413 NS_IMETHODIMP_(void)
4414 PresShell::DispatchSynthMouseMove(nsGUIEvent
*aEvent
,
4415 PRBool aFlushOnHoverChange
)
4417 PRUint32 hoverGenerationBefore
= mFrameConstructor
->GetHoverGeneration();
4418 nsEventStatus status
;
4419 nsIView
* targetView
= nsIView::GetViewFor(aEvent
->widget
);
4420 targetView
->GetViewManager()->DispatchEvent(aEvent
, targetView
, &status
);
4421 if (aFlushOnHoverChange
&&
4422 hoverGenerationBefore
!= mFrameConstructor
->GetHoverGeneration()) {
4423 // Flush so that the resulting reflow happens now so that our caller
4424 // can suppress any synthesized mouse moves caused by that reflow.
4425 FlushPendingNotifications(Flush_Layout
);
4429 NS_IMETHODIMP_(void)
4430 PresShell::ClearMouseCapture(nsIView
* aView
)
4432 if (gCaptureInfo
.mContent
) {
4434 // if a view was specified, ensure that the captured content is within
4436 nsIFrame
* frame
= gCaptureInfo
.mContent
->GetPrimaryFrame();
4438 nsIView
* view
= frame
->GetClosestView();
4439 // if there is no view, capturing won't be handled any more, so
4440 // just release the capture.
4443 if (view
== aView
) {
4444 NS_RELEASE(gCaptureInfo
.mContent
);
4445 // the view containing the captured content likely disappeared so
4446 // disable capture for now.
4447 gCaptureInfo
.mAllowed
= PR_FALSE
;
4451 view
= view
->GetParent();
4453 // return if the view wasn't found
4459 NS_RELEASE(gCaptureInfo
.mContent
);
4462 // disable mouse capture until the next mousedown as a dialog has opened
4463 // or a drag has started. Otherwise, someone could start capture during
4464 // the modal dialog or drag.
4465 gCaptureInfo
.mAllowed
= PR_FALSE
;
4469 PresShell::CaptureHistoryState(nsILayoutHistoryState
** aState
, PRBool aLeavingPage
)
4471 NS_TIME_FUNCTION_MIN(1.0);
4473 nsresult rv
= NS_OK
;
4475 NS_PRECONDITION(nsnull
!= aState
, "null state pointer");
4477 // We actually have to mess with the docshell here, since we want to
4478 // store the state back in it.
4479 // XXXbz this isn't really right, since this is being called in the
4480 // content viewer's Hide() method... by that point the docshell's
4481 // state could be wrong. We should sort out a better ownership
4482 // model for the layout history state.
4483 nsCOMPtr
<nsISupports
> container
= mPresContext
->GetContainer();
4485 return NS_ERROR_FAILURE
;
4487 nsCOMPtr
<nsIDocShell
> docShell(do_QueryInterface(container
));
4489 return NS_ERROR_FAILURE
;
4491 nsCOMPtr
<nsILayoutHistoryState
> historyState
;
4492 docShell
->GetLayoutHistoryState(getter_AddRefs(historyState
));
4493 if (!historyState
) {
4494 // Create the document state object
4495 rv
= NS_NewLayoutHistoryState(getter_AddRefs(historyState
));
4497 if (NS_FAILED(rv
)) {
4502 docShell
->SetLayoutHistoryState(historyState
);
4505 *aState
= historyState
;
4506 NS_IF_ADDREF(*aState
);
4508 // Capture frame state for the entire frame hierarchy
4509 nsIFrame
* rootFrame
= FrameManager()->GetRootFrame();
4510 if (!rootFrame
) return NS_OK
;
4511 // Capture frame state for the root scroll frame
4512 // Don't capture state when first creating doc element hierarchy
4513 // As the scroll position is 0 and this will cause us to lose
4514 // our previously saved place!
4516 nsIFrame
* scrollFrame
= GetRootScrollFrame();
4518 FrameManager()->CaptureFrameStateFor(scrollFrame
, historyState
,
4519 nsIStatefulFrame::eDocumentScrollState
);
4523 FrameManager()->CaptureFrameState(rootFrame
, historyState
);
4529 PresShell::UnsuppressAndInvalidate()
4531 if (!mPresContext
->EnsureVisible() || mHaveShutDown
) {
4532 // No point; we're about to be torn down anyway.
4536 mPaintingSuppressed
= PR_FALSE
;
4537 nsIFrame
* rootFrame
= FrameManager()->GetRootFrame();
4539 // let's assume that outline on a root frame is not supported
4540 nsRect
rect(nsPoint(0, 0), rootFrame
->GetSize());
4541 rootFrame
->Invalidate(rect
);
4543 if (mCaretEnabled
&& mCaret
) {
4544 mCaret
->CheckCaretDrawingState();
4547 nsRootPresContext
* rootPC
= mPresContext
->GetRootPresContext();
4549 rootPC
->RequestUpdatePluginGeometry(rootFrame
);
4553 // now that painting is unsuppressed, focus may be set on the document
4554 nsPIDOMWindow
*win
= mDocument
->GetWindow();
4556 win
->SetReadyForFocus();
4558 if (!mHaveShutDown
&& mViewManager
)
4559 mViewManager
->SynthesizeMouseMove(PR_FALSE
);
4563 PresShell::UnsuppressPainting()
4565 if (mPaintSuppressionTimer
) {
4566 mPaintSuppressionTimer
->Cancel();
4567 mPaintSuppressionTimer
= nsnull
;
4570 if (mIsDocumentGone
|| !mPaintingSuppressed
)
4573 // If we have reflows pending, just wait until we process
4574 // the reflows and get all the frames where we want them
4575 // before actually unlocking the painting. Otherwise
4576 // go ahead and unlock now.
4577 if (mDirtyRoots
.Length() > 0)
4578 mShouldUnsuppressPainting
= PR_TRUE
;
4580 UnsuppressAndInvalidate();
4583 // Post a request to handle an arbitrary callback after reflow has finished.
4585 PresShell::PostReflowCallback(nsIReflowCallback
* aCallback
)
4587 void* result
= AllocateMisc(sizeof(nsCallbackEventRequest
));
4588 if (NS_UNLIKELY(!result
)) {
4589 return NS_ERROR_OUT_OF_MEMORY
;
4591 nsCallbackEventRequest
* request
= (nsCallbackEventRequest
*)result
;
4593 request
->callback
= aCallback
;
4594 request
->next
= nsnull
;
4596 if (mLastCallbackEventRequest
) {
4597 mLastCallbackEventRequest
= mLastCallbackEventRequest
->next
= request
;
4599 mFirstCallbackEventRequest
= request
;
4600 mLastCallbackEventRequest
= request
;
4607 PresShell::CancelReflowCallback(nsIReflowCallback
* aCallback
)
4609 nsCallbackEventRequest
* before
= nsnull
;
4610 nsCallbackEventRequest
* node
= mFirstCallbackEventRequest
;
4613 nsIReflowCallback
* callback
= node
->callback
;
4615 if (callback
== aCallback
)
4617 nsCallbackEventRequest
* toFree
= node
;
4618 if (node
== mFirstCallbackEventRequest
) {
4620 mFirstCallbackEventRequest
= node
;
4621 NS_ASSERTION(before
== nsnull
, "impossible");
4624 before
->next
= node
;
4627 if (toFree
== mLastCallbackEventRequest
) {
4628 mLastCallbackEventRequest
= before
;
4631 FreeMisc(sizeof(nsCallbackEventRequest
), toFree
);
4640 PresShell::CancelPostedReflowCallbacks()
4642 while (mFirstCallbackEventRequest
) {
4643 nsCallbackEventRequest
* node
= mFirstCallbackEventRequest
;
4644 mFirstCallbackEventRequest
= node
->next
;
4645 if (!mFirstCallbackEventRequest
) {
4646 mLastCallbackEventRequest
= nsnull
;
4648 nsIReflowCallback
* callback
= node
->callback
;
4649 FreeMisc(sizeof(nsCallbackEventRequest
), node
);
4651 callback
->ReflowCallbackCanceled();
4657 PresShell::HandlePostedReflowCallbacks(PRBool aInterruptible
)
4659 PRBool shouldFlush
= PR_FALSE
;
4661 while (mFirstCallbackEventRequest
) {
4662 nsCallbackEventRequest
* node
= mFirstCallbackEventRequest
;
4663 mFirstCallbackEventRequest
= node
->next
;
4664 if (!mFirstCallbackEventRequest
) {
4665 mLastCallbackEventRequest
= nsnull
;
4667 nsIReflowCallback
* callback
= node
->callback
;
4668 FreeMisc(sizeof(nsCallbackEventRequest
), node
);
4670 if (callback
->ReflowFinished()) {
4671 shouldFlush
= PR_TRUE
;
4676 mozFlushType flushType
=
4677 aInterruptible
? Flush_InterruptibleLayout
: Flush_Layout
;
4679 FlushPendingNotifications(flushType
);
4683 PresShell::IsSafeToFlush() const
4685 // Not safe if we are reflowing or in the middle of frame construction
4686 PRBool isSafeToFlush
= !mIsReflowing
&&
4689 if (isSafeToFlush
) {
4690 // Not safe if we are painting
4691 nsIViewManager
* viewManager
= GetViewManager();
4693 PRBool isPainting
= PR_FALSE
;
4694 viewManager
->IsPainting(isPainting
);
4696 isSafeToFlush
= PR_FALSE
;
4701 return isSafeToFlush
;
4706 PresShell::FlushPendingNotifications(mozFlushType aType
)
4708 #ifdef NS_FUNCTION_TIMER
4709 NS_TIME_FUNCTION_DECLARE_DOCURL
;
4710 static const char *flushTypeNames
[] = {
4712 "Flush_ContentAndNotify",
4714 "Flush_InterruptibleLayout",
4718 NS_TIME_FUNCTION_MIN_FMT(1.0, "%s (line %d) (document: %s, type: %s)", MOZ_FUNCTION_NAME
,
4719 __LINE__
, docURL__
.get(), flushTypeNames
[aType
- 1]);
4722 NS_ASSERTION(aType
>= Flush_Frames
, "Why did we get called?");
4724 PRBool isSafeToFlush
= IsSafeToFlush();
4725 isSafeToFlush
= isSafeToFlush
&& nsContentUtils::IsSafeToRunScript();
4727 NS_ASSERTION(!isSafeToFlush
|| mViewManager
, "Must have view manager");
4728 // Make sure the view manager stays alive while batching view updates.
4729 nsCOMPtr
<nsIViewManager
> viewManagerDeathGrip
= mViewManager
;
4730 if (isSafeToFlush
&& mViewManager
) {
4731 // Processing pending notifications can kill us, and some callers only
4732 // hold weak refs when calling FlushPendingNotifications(). :(
4733 nsCOMPtr
<nsIPresShell
> kungFuDeathGrip(this);
4735 if (mResizeEvent
.IsPending()) {
4737 if (mIsDestroying
) {
4742 // Style reresolves not in conjunction with reflows can't cause
4743 // painting or geometry changes, so don't bother with view update
4744 // batching if we only have style reresolve
4745 nsIViewManager::UpdateViewBatch
batch(mViewManager
);
4747 // We need to make sure external resource documents are flushed too (for
4748 // example, svg filters that reference a filter in an external document
4749 // need the frames in the external document to be constructed for the
4750 // filter to work). We only need external resources to be flushed when the
4751 // main document is flushing >= Flush_Frames, so we flush external
4752 // resources here instead of nsDocument::FlushPendingNotifications.
4753 mDocument
->FlushExternalResources(aType
);
4755 // Force flushing of any pending content notifications that might have
4756 // queued up while our event was pending. That will ensure that we don't
4757 // construct frames for content right now that's still waiting to be
4759 mDocument
->FlushPendingNotifications(Flush_ContentAndNotify
);
4761 // Process pending restyles, since any flush of the presshell wants
4762 // up-to-date style data.
4763 if (!mIsDestroying
) {
4764 mViewManager
->FlushDelayedResize(PR_FALSE
);
4765 mPresContext
->FlushPendingMediaFeatureValuesChanged();
4767 // Flush any pending update of the user font set, since that could
4768 // cause style changes (for updating ex/ch units, and to cause a
4770 mPresContext
->FlushUserFontSet();
4773 // Flush any requested SMIL samples.
4774 if (mDocument
->HasAnimationController()) {
4775 mDocument
->GetAnimationController()->FlushResampleRequests();
4779 nsAutoScriptBlocker scriptBlocker
;
4780 mFrameConstructor
->CreateNeededFrames();
4781 mFrameConstructor
->ProcessPendingRestyles();
4784 // Process whatever XBL constructors those restyles queued up. This
4785 // ensures that onload doesn't fire too early and that we won't do extra
4786 // reflows after those constructors run.
4787 if (!mIsDestroying
) {
4788 mDocument
->BindingManager()->ProcessAttachedQueue();
4791 // Now those constructors might have posted restyle events. At the same
4792 // time, we still need up-to-date style data. In particular, reflow
4793 // depends on style being completely up to date. If it's not, then style
4794 // context reparenting, which can happen during reflow, might suddenly pick
4795 // up the new rules and we'll end up with frames whose style doesn't match
4797 if (!mIsDestroying
) {
4798 nsAutoScriptBlocker scriptBlocker
;
4799 mFrameConstructor
->CreateNeededFrames();
4800 mFrameConstructor
->ProcessPendingRestyles();
4804 // There might be more pending constructors now, but we're not going to
4805 // worry about them. They can't be triggered during reflow, so we should
4808 if (aType
>= (mSuppressInterruptibleReflows
? Flush_Layout
: Flush_InterruptibleLayout
) &&
4810 mFrameConstructor
->RecalcQuotesAndCounters();
4811 mViewManager
->FlushDelayedResize(PR_TRUE
);
4812 if (ProcessReflowCommands(aType
< Flush_Layout
) && mContentToScrollTo
) {
4813 // We didn't get interrupted. Go ahead and scroll to our content
4814 DoScrollContentIntoView(mContentToScrollTo
, mContentScrollVPosition
,
4815 mContentScrollHPosition
);
4816 mContentToScrollTo
= nsnull
;
4820 if (aType
>= Flush_Layout
) {
4821 // Flush plugin geometry. Don't flush plugin geometry for
4822 // interruptible layouts, since WillPaint does an interruptible
4824 nsRootPresContext
* rootPresContext
= mPresContext
->GetRootPresContext();
4825 if (rootPresContext
) {
4826 rootPresContext
->UpdatePluginGeometry();
4830 PRUint32 updateFlags
= NS_VMREFRESH_NO_SYNC
;
4831 if (aType
>= Flush_Display
) {
4832 // Flushing paints, so perform the invalidates and drawing
4834 updateFlags
= NS_VMREFRESH_IMMEDIATE
;
4836 batch
.EndUpdateViewBatch(updateFlags
);
4841 PresShell::CharacterDataChanged(nsIDocument
*aDocument
,
4842 nsIContent
* aContent
,
4843 CharacterDataChangeInfo
* aInfo
)
4845 NS_PRECONDITION(!mIsDocumentGone
, "Unexpected CharacterDataChanged");
4846 NS_PRECONDITION(aDocument
== mDocument
, "Unexpected aDocument");
4848 nsAutoCauseReflowNotifier
crNotifier(this);
4851 // Invalidate the caret's current location before we call into the frame
4852 // constructor. It is important to do this now, and not wait until the
4853 // resulting reflow, because this call causes continuation frames of the
4854 // text frame the caret is in to forget what part of the content they
4855 // refer to, making it hard for them to return the correct continuation
4856 // frame to the caret.
4857 mCaret
->InvalidateOutsideCaret();
4860 // Call this here so it only happens for real content mutations and
4861 // not cases when the frame constructor calls its own methods to force
4862 // frame reconstruction.
4863 nsIContent
*container
= aContent
->GetParent();
4864 PRUint32 selectorFlags
=
4865 container
? (container
->GetFlags() & NODE_ALL_SELECTOR_FLAGS
) : 0;
4866 if (selectorFlags
!= 0 && !aContent
->IsRootOfAnonymousSubtree()) {
4867 Element
* element
= container
->AsElement();
4868 if (aInfo
->mAppend
&& !aContent
->GetNextSibling())
4869 mFrameConstructor
->RestyleForAppend(element
, aContent
);
4871 mFrameConstructor
->RestyleForInsertOrChange(element
, aContent
);
4874 mFrameConstructor
->CharacterDataChanged(aContent
, aInfo
);
4879 PresShell::ContentStatesChanged(nsIDocument
* aDocument
,
4880 nsIContent
* aContent1
,
4881 nsIContent
* aContent2
,
4884 NS_PRECONDITION(!mIsDocumentGone
, "Unexpected ContentStatesChanged");
4885 NS_PRECONDITION(aDocument
== mDocument
, "Unexpected aDocument");
4887 if (mDidInitialReflow
) {
4888 nsAutoCauseReflowNotifier
crNotifier(this);
4889 mFrameConstructor
->ContentStatesChanged(aContent1
, aContent2
, aStateMask
);
4895 PresShell::DocumentStatesChanged(nsIDocument
* aDocument
,
4898 NS_PRECONDITION(!mIsDocumentGone
, "Unexpected DocumentStatesChanged");
4899 NS_PRECONDITION(aDocument
== mDocument
, "Unexpected aDocument");
4901 if (mDidInitialReflow
&&
4902 mStyleSet
->HasDocumentStateDependentStyle(mPresContext
,
4903 mDocument
->GetRootElement(),
4905 mFrameConstructor
->PostRestyleEvent(mDocument
->GetRootElement(),
4906 eRestyle_Subtree
, NS_STYLE_HINT_NONE
);
4910 if (aStateMask
& NS_DOCUMENT_STATE_WINDOW_INACTIVE
) {
4911 nsIFrame
* root
= FrameManager()->GetRootFrame();
4913 // It's a display root. So, invalidate the layer contents of
4914 // everything we can find. We need to do this because the contents
4915 // of controls etc can depend on whether the window is active,
4916 // and when a window becomes (in)active it just gets repainted
4917 // and we don't specifically invalidate each affected control.
4918 nsIWidget
* widget
= root
->GetNearestWidget();
4920 LayerManager
* layerManager
= widget
->GetLayerManager();
4922 FrameLayerBuilder::InvalidateAllThebesLayerContents(layerManager
);
4930 PresShell::AttributeWillChange(nsIDocument
* aDocument
,
4932 PRInt32 aNameSpaceID
,
4933 nsIAtom
* aAttribute
,
4936 NS_PRECONDITION(!mIsDocumentGone
, "Unexpected AttributeWillChange");
4937 NS_PRECONDITION(aDocument
== mDocument
, "Unexpected aDocument");
4939 // XXXwaterson it might be more elegant to wait until after the
4940 // initial reflow to begin observing the document. That would
4941 // squelch any other inappropriate notifications as well.
4942 if (mDidInitialReflow
) {
4943 nsAutoCauseReflowNotifier
crNotifier(this);
4944 mFrameConstructor
->AttributeWillChange(aElement
, aNameSpaceID
,
4945 aAttribute
, aModType
);
4951 PresShell::AttributeChanged(nsIDocument
* aDocument
,
4953 PRInt32 aNameSpaceID
,
4954 nsIAtom
* aAttribute
,
4957 NS_PRECONDITION(!mIsDocumentGone
, "Unexpected AttributeChanged");
4958 NS_PRECONDITION(aDocument
== mDocument
, "Unexpected aDocument");
4960 // XXXwaterson it might be more elegant to wait until after the
4961 // initial reflow to begin observing the document. That would
4962 // squelch any other inappropriate notifications as well.
4963 if (mDidInitialReflow
) {
4964 nsAutoCauseReflowNotifier
crNotifier(this);
4965 mFrameConstructor
->AttributeChanged(aElement
, aNameSpaceID
,
4966 aAttribute
, aModType
);
4972 PresShell::ContentAppended(nsIDocument
*aDocument
,
4973 nsIContent
* aContainer
,
4974 nsIContent
* aFirstNewContent
,
4975 PRInt32 aNewIndexInContainer
)
4977 NS_PRECONDITION(!mIsDocumentGone
, "Unexpected ContentAppended");
4978 NS_PRECONDITION(aDocument
== mDocument
, "Unexpected aDocument");
4979 NS_PRECONDITION(aContainer
, "must have container");
4981 if (!mDidInitialReflow
) {
4985 nsAutoCauseReflowNotifier
crNotifier(this);
4987 // Call this here so it only happens for real content mutations and
4988 // not cases when the frame constructor calls its own methods to force
4989 // frame reconstruction.
4990 mFrameConstructor
->RestyleForAppend(aContainer
->AsElement(), aFirstNewContent
);
4992 mFrameConstructor
->ContentAppended(aContainer
, aFirstNewContent
, PR_TRUE
);
4997 PresShell::ContentInserted(nsIDocument
* aDocument
,
4998 nsIContent
* aContainer
,
5000 PRInt32 aIndexInContainer
)
5002 NS_PRECONDITION(!mIsDocumentGone
, "Unexpected ContentInserted");
5003 NS_PRECONDITION(aDocument
== mDocument
, "Unexpected aDocument");
5005 if (!mDidInitialReflow
) {
5009 nsAutoCauseReflowNotifier
crNotifier(this);
5011 // Call this here so it only happens for real content mutations and
5012 // not cases when the frame constructor calls its own methods to force
5013 // frame reconstruction.
5015 mFrameConstructor
->RestyleForInsertOrChange(aContainer
->AsElement(), aChild
);
5017 mFrameConstructor
->ContentInserted(aContainer
, aChild
, nsnull
, PR_TRUE
);
5022 PresShell::ContentRemoved(nsIDocument
*aDocument
,
5023 nsIContent
* aContainer
,
5025 PRInt32 aIndexInContainer
,
5026 nsIContent
* aPreviousSibling
)
5028 NS_PRECONDITION(!mIsDocumentGone
, "Unexpected ContentRemoved");
5029 NS_PRECONDITION(aDocument
== mDocument
, "Unexpected aDocument");
5031 // Make sure that the caret doesn't leave a turd where the child used to be.
5033 mCaret
->InvalidateOutsideCaret();
5036 // Notify the ESM that the content has been removed, so that
5037 // it can clean up any state related to the content.
5038 mPresContext
->EventStateManager()->ContentRemoved(aDocument
, aChild
);
5040 nsAutoCauseReflowNotifier
crNotifier(this);
5042 // Call this here so it only happens for real content mutations and
5043 // not cases when the frame constructor calls its own methods to force
5044 // frame reconstruction.
5045 nsIContent
* oldNextSibling
;
5047 oldNextSibling
= aContainer
->GetChildAt(aIndexInContainer
);
5049 oldNextSibling
= nsnull
;
5053 mFrameConstructor
->RestyleForRemove(aContainer
->AsElement(), aChild
,
5056 PRBool didReconstruct
;
5057 mFrameConstructor
->ContentRemoved(aContainer
, aChild
, oldNextSibling
,
5058 nsCSSFrameConstructor::REMOVE_CONTENT
,
5065 PresShell::ReconstructFrames(void)
5067 nsCOMPtr
<nsIPresShell
> kungFuDeathGrip(this);
5069 // Have to make sure that the content notifications are flushed before we
5070 // start messing with the frame model; otherwise we can get content doubling.
5071 mDocument
->FlushPendingNotifications(Flush_ContentAndNotify
);
5073 nsAutoCauseReflowNotifier
crNotifier(this);
5074 mFrameConstructor
->BeginUpdate();
5075 nsresult rv
= mFrameConstructor
->ReconstructDocElementHierarchy();
5077 mFrameConstructor
->EndUpdate();
5083 nsIPresShell::ReconstructStyleDataInternal()
5085 mStylesHaveChanged
= PR_FALSE
;
5087 if (mIsDestroying
) {
5088 // We don't want to mess with restyles at this point
5093 mPresContext
->RebuildUserFontSet();
5096 Element
* root
= mDocument
->GetRootElement();
5097 if (!mDidInitialReflow
) {
5098 // Nothing to do here, since we have no frames yet
5103 // No content to restyle
5107 mFrameConstructor
->PostRestyleEvent(root
, eRestyle_Subtree
, NS_STYLE_HINT_NONE
);
5109 #ifdef ACCESSIBILITY
5110 InvalidateAccessibleSubtree(nsnull
);
5115 nsIPresShell::ReconstructStyleDataExternal()
5117 ReconstructStyleDataInternal();
5121 PresShell::StyleSheetAdded(nsIDocument
*aDocument
,
5122 nsIStyleSheet
* aStyleSheet
,
5123 PRBool aDocumentSheet
)
5125 // We only care when enabled sheets are added
5126 NS_PRECONDITION(aStyleSheet
, "Must have a style sheet!");
5128 if (aStyleSheet
->IsApplicable() && aStyleSheet
->HasRules()) {
5129 mStylesHaveChanged
= PR_TRUE
;
5134 PresShell::StyleSheetRemoved(nsIDocument
*aDocument
,
5135 nsIStyleSheet
* aStyleSheet
,
5136 PRBool aDocumentSheet
)
5138 // We only care when enabled sheets are removed
5139 NS_PRECONDITION(aStyleSheet
, "Must have a style sheet!");
5141 if (aStyleSheet
->IsApplicable() && aStyleSheet
->HasRules()) {
5142 mStylesHaveChanged
= PR_TRUE
;
5147 PresShell::StyleSheetApplicableStateChanged(nsIDocument
*aDocument
,
5148 nsIStyleSheet
* aStyleSheet
,
5151 if (aStyleSheet
->HasRules()) {
5152 mStylesHaveChanged
= PR_TRUE
;
5157 PresShell::StyleRuleChanged(nsIDocument
*aDocument
,
5158 nsIStyleSheet
* aStyleSheet
,
5159 nsIStyleRule
* aOldStyleRule
,
5160 nsIStyleRule
* aNewStyleRule
)
5162 mStylesHaveChanged
= PR_TRUE
;
5166 PresShell::StyleRuleAdded(nsIDocument
*aDocument
,
5167 nsIStyleSheet
* aStyleSheet
,
5168 nsIStyleRule
* aStyleRule
)
5170 mStylesHaveChanged
= PR_TRUE
;
5174 PresShell::StyleRuleRemoved(nsIDocument
*aDocument
,
5175 nsIStyleSheet
* aStyleSheet
,
5176 nsIStyleRule
* aStyleRule
)
5178 mStylesHaveChanged
= PR_TRUE
;
5182 PresShell::GetRealPrimaryFrameFor(nsIContent
* aContent
) const
5184 if (aContent
->GetDocument() != GetDocument()) {
5187 nsIFrame
*primaryFrame
= aContent
->GetPrimaryFrame();
5190 return nsPlaceholderFrame::GetRealFrameFor(primaryFrame
);
5194 PresShell::GetPlaceholderFrameFor(nsIFrame
* aFrame
) const
5196 return FrameManager()->GetPlaceholderFrameFor(aFrame
);
5200 PresShell::RenderDocument(const nsRect
& aRect
, PRUint32 aFlags
,
5201 nscolor aBackgroundColor
,
5202 gfxContext
* aThebesContext
)
5204 NS_TIME_FUNCTION_WITH_DOCURL
;
5206 NS_ENSURE_TRUE(!(aFlags
& RENDER_IS_UNTRUSTED
), NS_ERROR_NOT_IMPLEMENTED
);
5208 // Set up the rectangle as the path in aThebesContext
5210 nsPresContext::AppUnitsToFloatCSSPixels(aRect
.width
),
5211 nsPresContext::AppUnitsToFloatCSSPixels(aRect
.height
));
5212 aThebesContext
->NewPath();
5213 #ifdef MOZ_GFX_OPTIMIZE_MOBILE
5214 aThebesContext
->Rectangle(r
, PR_TRUE
);
5216 aThebesContext
->Rectangle(r
);
5219 nsIFrame
* rootFrame
= FrameManager()->GetRootFrame();
5221 // Nothing to paint, just fill the rect
5222 aThebesContext
->SetColor(gfxRGBA(aBackgroundColor
));
5223 aThebesContext
->Fill();
5227 gfxContextAutoSaveRestore
save(aThebesContext
);
5229 gfxContext::GraphicsOperator oldOperator
= aThebesContext
->CurrentOperator();
5230 if (oldOperator
== gfxContext::OPERATOR_OVER
) {
5231 // Clip to the destination rectangle before we push the group,
5232 // to limit the size of the temporary surface
5233 aThebesContext
->Clip();
5236 // we want the window to be composited as a single image using
5237 // whatever operator was set; set OPERATOR_OVER here, which is
5238 // either already the case, or overrides the operator in a group.
5239 // the original operator will be present when we PopGroup.
5240 // we can avoid using a temporary surface if we're using OPERATOR_OVER
5241 // and our background color has no alpha (so we'll be compositing on top
5242 // of a fully opaque solid color region)
5243 PRBool needsGroup
= NS_GET_A(aBackgroundColor
) < 0xff ||
5244 oldOperator
!= gfxContext::OPERATOR_OVER
;
5247 aThebesContext
->PushGroup(NS_GET_A(aBackgroundColor
) == 0xff ?
5248 gfxASurface::CONTENT_COLOR
:
5249 gfxASurface::CONTENT_COLOR_ALPHA
);
5250 aThebesContext
->Save();
5252 if (oldOperator
!= gfxContext::OPERATOR_OVER
) {
5253 // Clip now while we paint to the temporary surface. For
5254 // non-source-bounded operators (e.g., SOURCE), we need to do clip
5255 // here after we've pushed the group, so that eventually popping
5256 // the group and painting it will be able to clear the entire
5257 // destination surface.
5258 aThebesContext
->Clip();
5259 aThebesContext
->SetOperator(gfxContext::OPERATOR_OVER
);
5263 aThebesContext
->Translate(gfxPoint(-nsPresContext::AppUnitsToFloatCSSPixels(aRect
.x
),
5264 -nsPresContext::AppUnitsToFloatCSSPixels(aRect
.y
)));
5266 nsIDeviceContext
* devCtx
= mPresContext
->DeviceContext();
5267 gfxFloat scale
= gfxFloat(devCtx
->AppUnitsPerDevPixel())/nsPresContext::AppUnitsPerCSSPixel();
5268 aThebesContext
->Scale(scale
, scale
);
5270 // Since canvas APIs use floats to set up their matrices, we may have
5271 // some slight inaccuracy here. Adjust matrix components that are
5272 // integers up to the accuracy of floats to be those integers.
5273 aThebesContext
->NudgeCurrentMatrixToIntegers();
5275 nsCOMPtr
<nsIRenderingContext
> rc
;
5276 devCtx
->CreateRenderingContextInstance(*getter_AddRefs(rc
));
5277 rc
->Init(devCtx
, aThebesContext
);
5279 PRUint32 flags
= nsLayoutUtils::PAINT_IGNORE_SUPPRESSION
;
5280 if (!(aFlags
& RENDER_ASYNC_DECODE_IMAGES
)) {
5281 flags
|= nsLayoutUtils::PAINT_SYNC_DECODE_IMAGES
;
5283 if (aFlags
& RENDER_USE_WIDGET_LAYERS
) {
5284 // We only support using widget layers on display root's with widgets.
5285 nsIView
* view
= rootFrame
->GetView();
5286 if (view
&& view
->GetWidget() &&
5287 nsLayoutUtils::GetDisplayRootFrame(rootFrame
) == rootFrame
) {
5288 flags
|= nsLayoutUtils::PAINT_WIDGET_LAYERS
;
5291 if (!(aFlags
& RENDER_CARET
)) {
5292 flags
|= nsLayoutUtils::PAINT_HIDE_CARET
;
5294 if (aFlags
& RENDER_IGNORE_VIEWPORT_SCROLLING
) {
5295 flags
|= nsLayoutUtils::PAINT_IGNORE_VIEWPORT_SCROLLING
;
5297 nsLayoutUtils::PaintFrame(rc
, rootFrame
, nsRegion(aRect
),
5298 aBackgroundColor
, flags
);
5300 // if we had to use a group, paint it to the destination now
5302 aThebesContext
->Restore();
5303 aThebesContext
->PopGroupToSource();
5304 aThebesContext
->Paint();
5311 * Clip the display list aList to a range. Returns the clipped
5312 * rectangle surrounding the range.
5315 PresShell::ClipListToRange(nsDisplayListBuilder
*aBuilder
,
5316 nsDisplayList
* aList
,
5319 NS_TIME_FUNCTION_WITH_DOCURL
;
5321 // iterate though the display items and add up the bounding boxes of each.
5322 // This will allow the total area of the frames within the range to be
5323 // determined. To do this, remove an item from the bottom of the list, check
5324 // whether it should be part of the range, and if so, append it to the top
5325 // of the temporary list tmpList. If the item is a text frame at the end of
5326 // the selection range, wrap it in an nsDisplayClip to clip the display to
5327 // the portion of the text frame that is part of the selection. Then, append
5328 // the wrapper to the top of the list. Otherwise, just delete the item and
5331 nsDisplayList tmpList
;
5334 while ((i
= aList
->RemoveBottom())) {
5335 // itemToInsert indiciates the item that should be inserted into the
5336 // temporary list. If null, no item should be inserted.
5337 nsDisplayItem
* itemToInsert
= nsnull
;
5338 nsIFrame
* frame
= i
->GetUnderlyingFrame();
5340 nsIContent
* content
= frame
->GetContent();
5342 PRBool atStart
= (content
== aRange
->GetStartParent());
5343 PRBool atEnd
= (content
== aRange
->GetEndParent());
5344 if ((atStart
|| atEnd
) && frame
->GetType() == nsGkAtoms::textFrame
) {
5345 PRInt32 frameStartOffset
, frameEndOffset
;
5346 frame
->GetOffsets(frameStartOffset
, frameEndOffset
);
5348 PRInt32 hilightStart
=
5349 atStart
? NS_MAX(aRange
->StartOffset(), frameStartOffset
) : frameStartOffset
;
5350 PRInt32 hilightEnd
=
5351 atEnd
? NS_MIN(aRange
->EndOffset(), frameEndOffset
) : frameEndOffset
;
5352 if (hilightStart
< hilightEnd
) {
5353 // determine the location of the start and end edges of the range.
5354 nsPoint startPoint
, endPoint
;
5355 frame
->GetPointFromOffset(hilightStart
, &startPoint
);
5356 frame
->GetPointFromOffset(hilightEnd
, &endPoint
);
5358 // the clip rectangle is determined by taking the the start and
5359 // end points of the range, offset from the reference frame.
5360 // Because of rtl, the end point may be to the left of the
5361 // start point, so x is set to the lowest value
5362 nsRect
textRect(aBuilder
->ToReferenceFrame(frame
), frame
->GetSize());
5363 nscoord x
= NS_MIN(startPoint
.x
, endPoint
.x
);
5365 textRect
.width
= NS_MAX(startPoint
.x
, endPoint
.x
) - x
;
5366 surfaceRect
.UnionRect(surfaceRect
, textRect
);
5368 // wrap the item in an nsDisplayClip so that it can be clipped to
5369 // the selection. If the allocation fails, fall through and delete
5371 itemToInsert
= new (aBuilder
)
5372 nsDisplayClip(aBuilder
, frame
, frame
, i
, textRect
);
5375 // Don't try to descend into subdocuments.
5376 // If this ever changes we'd need to add handling for subdocuments with
5377 // different zoom levels.
5378 else if (content
->GetCurrentDoc() ==
5379 aRange
->GetStartParent()->GetCurrentDoc()) {
5380 // if the node is within the range, append it to the temporary list
5381 PRBool before
, after
;
5383 nsRange::CompareNodeToRange(content
, aRange
, &before
, &after
);
5384 if (NS_SUCCEEDED(rv
) && !before
&& !after
) {
5386 surfaceRect
.UnionRect(surfaceRect
, i
->GetBounds(aBuilder
));
5392 // insert the item into the list if necessary. If the item has a child
5393 // list, insert that as well
5394 nsDisplayList
* sublist
= i
->GetList();
5395 if (itemToInsert
|| sublist
) {
5396 tmpList
.AppendToTop(itemToInsert
? itemToInsert
: i
);
5397 // if the item is a list, iterate over it as well
5399 surfaceRect
.UnionRect(surfaceRect
,
5400 ClipListToRange(aBuilder
, sublist
, aRange
));
5403 // otherwise, just delete the item and don't readd it to the list
5404 i
->~nsDisplayItem();
5408 // now add all the items back onto the original list again
5409 aList
->AppendToTop(&tmpList
);
5417 static PRBool gDumpRangePaintList
= PR_FALSE
;
5421 PresShell::CreateRangePaintInfo(nsIDOMRange
* aRange
,
5422 nsRect
& aSurfaceRect
,
5423 PRBool aForPrimarySelection
)
5425 NS_TIME_FUNCTION_WITH_DOCURL
;
5427 RangePaintInfo
* info
= nsnull
;
5429 nsCOMPtr
<nsIRange
> range
= do_QueryInterface(aRange
);
5433 nsIFrame
* ancestorFrame
;
5434 nsIFrame
* rootFrame
= GetRootFrame();
5436 // If the start or end of the range is the document, just use the root
5437 // frame, otherwise get the common ancestor of the two endpoints of the
5439 nsINode
* startParent
= range
->GetStartParent();
5440 nsINode
* endParent
= range
->GetEndParent();
5441 nsIDocument
* doc
= startParent
->GetCurrentDoc();
5442 if (startParent
== doc
|| endParent
== doc
) {
5443 ancestorFrame
= rootFrame
;
5446 nsINode
* ancestor
= nsContentUtils::GetCommonAncestor(startParent
, endParent
);
5447 NS_ASSERTION(!ancestor
|| ancestor
->IsNodeOfType(nsINode::eCONTENT
),
5448 "common ancestor is not content");
5449 if (!ancestor
|| !ancestor
->IsNodeOfType(nsINode::eCONTENT
))
5452 nsIContent
* ancestorContent
= static_cast<nsIContent
*>(ancestor
);
5453 ancestorFrame
= ancestorContent
->GetPrimaryFrame();
5455 // use the nearest ancestor frame that includes all continuations as the
5456 // root for building the display list
5457 while (ancestorFrame
&&
5458 nsLayoutUtils::GetNextContinuationOrSpecialSibling(ancestorFrame
))
5459 ancestorFrame
= ancestorFrame
->GetParent();
5465 info
= new RangePaintInfo(range
, ancestorFrame
);
5469 nsRect ancestorRect
= ancestorFrame
->GetOverflowRect();
5471 // get a display list containing the range
5472 if (aForPrimarySelection
) {
5473 info
->mBuilder
.SetSelectedFramesOnly();
5475 info
->mBuilder
.EnterPresShell(ancestorFrame
, ancestorRect
);
5476 ancestorFrame
->BuildDisplayListForStackingContext(&info
->mBuilder
,
5477 ancestorRect
, &info
->mList
);
5478 info
->mBuilder
.LeavePresShell(ancestorFrame
, ancestorRect
);
5481 if (gDumpRangePaintList
) {
5482 fprintf(stderr
, "CreateRangePaintInfo --- before ClipListToRange:\n");
5483 nsFrame::PrintDisplayList(&(info
->mBuilder
), info
->mList
);
5487 nsRect rangeRect
= ClipListToRange(&info
->mBuilder
, &info
->mList
, range
);
5490 if (gDumpRangePaintList
) {
5491 fprintf(stderr
, "CreateRangePaintInfo --- after ClipListToRange:\n");
5492 nsFrame::PrintDisplayList(&(info
->mBuilder
), info
->mList
);
5496 // determine the offset of the reference frame for the display list
5497 // to the root frame. This will allow the coordinates used when painting
5498 // to all be offset from the same point
5499 info
->mRootOffset
= ancestorFrame
->GetOffsetTo(rootFrame
);
5500 rangeRect
.MoveBy(info
->mRootOffset
);
5501 aSurfaceRect
.UnionRect(aSurfaceRect
, rangeRect
);
5506 already_AddRefed
<gfxASurface
>
5507 PresShell::PaintRangePaintInfo(nsTArray
<nsAutoPtr
<RangePaintInfo
> >* aItems
,
5508 nsISelection
* aSelection
,
5509 nsIntRegion
* aRegion
,
5512 nsIntRect
* aScreenRect
)
5514 NS_TIME_FUNCTION_WITH_DOCURL
;
5516 nsPresContext
* pc
= GetPresContext();
5517 if (!pc
|| aArea
.width
== 0 || aArea
.height
== 0)
5520 nsIDeviceContext
* deviceContext
= pc
->DeviceContext();
5522 // use the rectangle to create the surface
5523 nsIntRect pixelArea
= aArea
.ToOutsidePixels(pc
->AppUnitsPerDevPixel());
5525 // if the area of the image is larger than the maximum area, scale it down
5527 nsIntRect rootScreenRect
=
5528 GetRootFrame()->GetScreenRectInAppUnits().ToNearestPixels(
5529 pc
->AppUnitsPerDevPixel());
5531 // if the image is larger in one or both directions than half the size of
5532 // the available screen area, scale the image down to that size.
5534 deviceContext
->GetClientRect(maxSize
);
5535 nscoord maxWidth
= pc
->AppUnitsToDevPixels(maxSize
.width
>> 1);
5536 nscoord maxHeight
= pc
->AppUnitsToDevPixels(maxSize
.height
>> 1);
5537 PRBool resize
= (pixelArea
.width
> maxWidth
|| pixelArea
.height
> maxHeight
);
5540 // divide the maximum size by the image size in both directions. Whichever
5541 // direction produces the smallest result determines how much should be
5543 if (pixelArea
.width
> maxWidth
)
5544 scale
= NS_MIN(scale
, float(maxWidth
) / pixelArea
.width
);
5545 if (pixelArea
.height
> maxHeight
)
5546 scale
= NS_MIN(scale
, float(maxHeight
) / pixelArea
.height
);
5548 pixelArea
.width
= NSToIntFloor(float(pixelArea
.width
) * scale
);
5549 pixelArea
.height
= NSToIntFloor(float(pixelArea
.height
) * scale
);
5551 // adjust the screen position based on the rescaled size
5552 nscoord left
= rootScreenRect
.x
+ pixelArea
.x
;
5553 nscoord top
= rootScreenRect
.y
+ pixelArea
.y
;
5554 aScreenRect
->x
= NSToIntFloor(aPoint
.x
- float(aPoint
.x
- left
) * scale
);
5555 aScreenRect
->y
= NSToIntFloor(aPoint
.y
- float(aPoint
.y
- top
) * scale
);
5558 // move aScreenRect to the position of the surface in screen coordinates
5559 aScreenRect
->MoveTo(rootScreenRect
.x
+ pixelArea
.x
, rootScreenRect
.y
+ pixelArea
.y
);
5561 aScreenRect
->width
= pixelArea
.width
;
5562 aScreenRect
->height
= pixelArea
.height
;
5564 gfxImageSurface
* surface
=
5565 new gfxImageSurface(gfxIntSize(pixelArea
.width
, pixelArea
.height
),
5566 gfxImageSurface::ImageFormatARGB32
);
5567 if (!surface
|| surface
->CairoStatus()) {
5573 gfxContext
context(surface
);
5574 context
.SetOperator(gfxContext::OPERATOR_CLEAR
);
5575 context
.Rectangle(gfxRect(0, 0, pixelArea
.width
, pixelArea
.height
));
5578 nsCOMPtr
<nsIRenderingContext
> rc
;
5579 deviceContext
->CreateRenderingContextInstance(*getter_AddRefs(rc
));
5580 rc
->Init(deviceContext
, surface
);
5583 // Convert aRegion from CSS pixels to dev pixels
5584 nsIntRegion region
=
5585 aRegion
->ToAppUnits(nsPresContext::AppUnitsPerCSSPixel())
5586 .ToOutsidePixels(pc
->AppUnitsPerDevPixel());
5587 rc
->SetClipRegion(region
, nsClipCombine_kReplace
);
5591 rc
->Scale(scale
, scale
);
5593 // translate so that points are relative to the surface area
5594 rc
->Translate(-aArea
.x
, -aArea
.y
);
5596 // temporarily hide the selection so that text is drawn normally. If a
5597 // selection is being rendered, use that, otherwise use the presshell's
5599 nsCOMPtr
<nsFrameSelection
> frameSelection
;
5601 nsCOMPtr
<nsISelectionPrivate
> selpriv
= do_QueryInterface(aSelection
);
5602 selpriv
->GetFrameSelection(getter_AddRefs(frameSelection
));
5605 frameSelection
= FrameSelection();
5607 PRInt16 oldDisplaySelection
= frameSelection
->GetDisplaySelection();
5608 frameSelection
->SetDisplaySelection(nsISelectionController::SELECTION_HIDDEN
);
5610 // next, paint each range in the selection
5611 PRInt32 count
= aItems
->Length();
5612 for (PRInt32 i
= 0; i
< count
; i
++) {
5613 RangePaintInfo
* rangeInfo
= (*aItems
)[i
];
5614 // the display lists paint relative to the offset from the reference
5615 // frame, so translate the rendering context
5616 nsIRenderingContext::AutoPushTranslation
5617 translate(rc
, rangeInfo
->mRootOffset
.x
, rangeInfo
->mRootOffset
.y
);
5619 aArea
.MoveBy(-rangeInfo
->mRootOffset
.x
, -rangeInfo
->mRootOffset
.y
);
5620 nsRegion
visible(aArea
);
5621 rangeInfo
->mList
.ComputeVisibility(&rangeInfo
->mBuilder
, &visible
);
5622 rangeInfo
->mList
.PaintRoot(&rangeInfo
->mBuilder
, rc
, nsDisplayList::PAINT_DEFAULT
);
5623 aArea
.MoveBy(rangeInfo
->mRootOffset
.x
, rangeInfo
->mRootOffset
.y
);
5626 // restore the old selection display state
5627 frameSelection
->SetDisplaySelection(oldDisplaySelection
);
5633 already_AddRefed
<gfxASurface
>
5634 PresShell::RenderNode(nsIDOMNode
* aNode
,
5635 nsIntRegion
* aRegion
,
5637 nsIntRect
* aScreenRect
)
5639 // area will hold the size of the surface needed to draw the node, measured
5640 // from the root frame.
5642 nsTArray
<nsAutoPtr
<RangePaintInfo
> > rangeItems
;
5644 // nothing to draw if the node isn't in a document
5645 nsCOMPtr
<nsINode
> node
= do_QueryInterface(aNode
);
5646 if (!node
->IsInDoc())
5649 nsCOMPtr
<nsIDOMRange
> range
;
5650 NS_NewRange(getter_AddRefs(range
));
5651 if (NS_FAILED(range
->SelectNode(aNode
)))
5654 RangePaintInfo
* info
= CreateRangePaintInfo(range
, area
, PR_FALSE
);
5655 if (info
&& !rangeItems
.AppendElement(info
)) {
5661 // combine the area with the supplied region
5662 nsIntRect rrectPixels
= aRegion
->GetBounds();
5664 nsRect rrect
= rrectPixels
.ToAppUnits(nsPresContext::AppUnitsPerCSSPixel());
5665 area
.IntersectRect(area
, rrect
);
5667 nsPresContext
* pc
= GetPresContext();
5671 // move the region so that it is offset from the topleft corner of the surface
5672 aRegion
->MoveBy(-pc
->AppUnitsToDevPixels(area
.x
),
5673 -pc
->AppUnitsToDevPixels(area
.y
));
5676 return PaintRangePaintInfo(&rangeItems
, nsnull
, aRegion
, area
, aPoint
,
5680 already_AddRefed
<gfxASurface
>
5681 PresShell::RenderSelection(nsISelection
* aSelection
,
5683 nsIntRect
* aScreenRect
)
5685 // area will hold the size of the surface needed to draw the selection,
5686 // measured from the root frame.
5688 nsTArray
<nsAutoPtr
<RangePaintInfo
> > rangeItems
;
5690 // iterate over each range and collect them into the rangeItems array.
5691 // This is done so that the size of selection can be determined so as
5692 // to allocate a surface area
5694 aSelection
->GetRangeCount(&numRanges
);
5695 NS_ASSERTION(numRanges
> 0, "RenderSelection called with no selection");
5697 for (PRInt32 r
= 0; r
< numRanges
; r
++)
5699 nsCOMPtr
<nsIDOMRange
> range
;
5700 aSelection
->GetRangeAt(r
, getter_AddRefs(range
));
5702 RangePaintInfo
* info
= CreateRangePaintInfo(range
, area
, PR_TRUE
);
5703 if (info
&& !rangeItems
.AppendElement(info
)) {
5709 return PaintRangePaintInfo(&rangeItems
, aSelection
, nsnull
, area
, aPoint
,
5714 PresShell::AddPrintPreviewBackgroundItem(nsDisplayListBuilder
& aBuilder
,
5715 nsDisplayList
& aList
,
5717 const nsRect
& aBounds
)
5719 return aList
.AppendNewToBottom(new (&aBuilder
)
5720 nsDisplaySolidColor(&aBuilder
, aFrame
, aBounds
, NS_RGB(115, 115, 115)));
5724 AddCanvasBackgroundColor(const nsDisplayList
& aList
, nsIFrame
* aCanvasFrame
,
5727 for (nsDisplayItem
* i
= aList
.GetBottom(); i
; i
= i
->GetAbove()) {
5728 if (i
->GetUnderlyingFrame() == aCanvasFrame
&&
5729 i
->GetType() == nsDisplayItem::TYPE_CANVAS_BACKGROUND
) {
5730 nsDisplayCanvasBackground
* bg
= static_cast<nsDisplayCanvasBackground
*>(i
);
5731 bg
->SetExtraBackgroundColor(aColor
);
5734 nsDisplayList
* sublist
= i
->GetList();
5735 if (sublist
&& AddCanvasBackgroundColor(*sublist
, aCanvasFrame
, aColor
))
5741 nsresult
PresShell::AddCanvasBackgroundColorItem(nsDisplayListBuilder
& aBuilder
,
5742 nsDisplayList
& aList
,
5744 const nsRect
& aBounds
,
5745 nscolor aBackstopColor
,
5748 // We don't want to add an item for the canvas background color if the frame
5749 // (sub)tree we are painting doesn't include any canvas frames. There isn't
5750 // an easy way to check this directly, but if we check if the root of the
5751 // (sub)tree we are painting is a canvas frame that should cover us in all
5752 // cases (it will usually be a viewport frame when we have a canvas frame in
5754 if (!aForceDraw
&& !nsCSSRendering::IsCanvasFrame(aFrame
))
5757 nscolor bgcolor
= NS_ComposeColors(aBackstopColor
, mCanvasBackgroundColor
);
5759 // To make layers work better, we want to avoid having a big non-scrolled
5760 // color background behind a scrolled transparent background. Instead,
5761 // we'll try to move the color background into the scrolled content
5762 // by making nsDisplayCanvasBackground paint it.
5763 if (!aFrame
->GetParent()) {
5764 nsIScrollableFrame
* sf
=
5765 aFrame
->PresContext()->PresShell()->GetRootScrollFrameAsScrollable();
5767 nsCanvasFrame
* canvasFrame
= do_QueryFrame(sf
->GetScrolledFrame());
5768 if (canvasFrame
&& canvasFrame
->IsVisibleForPainting(&aBuilder
)) {
5769 if (AddCanvasBackgroundColor(aList
, canvasFrame
, bgcolor
))
5775 return aList
.AppendNewToBottom(
5776 new (&aBuilder
) nsDisplaySolidColor(&aBuilder
, aFrame
, aBounds
, bgcolor
));
5779 void PresShell::UpdateCanvasBackground()
5781 // If we have a frame tree and it has style information that
5782 // specifies the background color of the canvas, update our local
5783 // cache of that color.
5784 nsIFrame
* rootFrame
= FrameConstructor()->GetRootElementStyleFrame();
5786 nsStyleContext
* bgStyle
=
5787 nsCSSRendering::FindRootFrameBackground(rootFrame
);
5788 // XXX We should really be passing the canvasframe, not the root element
5789 // style frame but we don't have access to the canvasframe here. It isn't
5790 // a problem because only a few frames can return something other than true
5791 // and none of them would be a canvas frame or root element style frame.
5792 mCanvasBackgroundColor
=
5793 nsCSSRendering::DetermineBackgroundColor(GetPresContext(), bgStyle
,
5797 // If the root element of the document (ie html) has style 'display: none'
5798 // then the document's background color does not get drawn; cache the
5799 // color we actually draw.
5800 if (!FrameConstructor()->GetRootElementFrame()) {
5801 mCanvasBackgroundColor
= mPresContext
->DefaultBackgroundColor();
5805 nscolor
PresShell::ComputeBackstopColor(nsIView
* aDisplayRoot
)
5807 nsIWidget
* widget
= aDisplayRoot
->GetWidget();
5808 if (widget
&& widget
->GetTransparencyMode() != eTransparencyOpaque
) {
5809 // Within a transparent widget, so the backstop color must be
5810 // totally transparent.
5811 return NS_RGBA(0,0,0,0);
5813 // Within an opaque widget (or no widget at all), so the backstop
5814 // color must be totally opaque. The user's default background
5815 // as reported by the prescontext is guaranteed to be opaque.
5816 return GetPresContext()->DefaultBackgroundColor();
5819 struct PaintParams
{
5821 nsPoint mOffsetToWidget
;
5822 const nsRegion
* mDirtyRegion
;
5823 nscolor mBackgroundColor
;
5826 LayerManager
* PresShell::GetLayerManager()
5828 NS_ASSERTION(mViewManager
, "Should have view manager");
5831 if (NS_SUCCEEDED(mViewManager
->GetRootView(rootView
)) && rootView
) {
5832 if (nsIWidget
* widget
= rootView
->GetWidget()) {
5833 return widget
->GetLayerManager();
5839 static void DrawThebesLayer(ThebesLayer
* aLayer
,
5840 gfxContext
* aContext
,
5841 const nsIntRegion
& aRegionToDraw
,
5842 const nsIntRegion
& aRegionToInvalidate
,
5843 void* aCallbackData
)
5845 PaintParams
* params
= static_cast<PaintParams
*>(aCallbackData
);
5846 nsIFrame
* frame
= params
->mFrame
;
5848 // We're drawing into a child window.
5849 nsIDeviceContext
* devCtx
= frame
->PresContext()->DeviceContext();
5850 nsCOMPtr
<nsIRenderingContext
> rc
;
5851 nsresult rv
= devCtx
->CreateRenderingContextInstance(*getter_AddRefs(rc
));
5852 if (NS_SUCCEEDED(rv
)) {
5853 rc
->Init(devCtx
, aContext
);
5854 nsIRenderingContext::AutoPushTranslation
5855 push(rc
, params
->mOffsetToWidget
.x
, params
->mOffsetToWidget
.y
);
5856 nsLayoutUtils::PaintFrame(rc
, frame
, *params
->mDirtyRegion
,
5857 params
->mBackgroundColor
,
5858 nsLayoutUtils::PAINT_WIDGET_LAYERS
);
5861 aContext
->NewPath();
5862 aContext
->SetColor(gfxRGBA(params
->mBackgroundColor
));
5863 nsIntRect dirtyRect
= aRegionToDraw
.GetBounds();
5864 aContext
->Rectangle(
5865 gfxRect(dirtyRect
.x
, dirtyRect
.y
, dirtyRect
.width
, dirtyRect
.height
));
5871 PresShell::Paint(nsIView
* aDisplayRoot
,
5872 nsIView
* aViewToPaint
,
5873 nsIWidget
* aWidgetToPaint
,
5874 const nsRegion
& aDirtyRegion
,
5875 const nsIntRegion
& aIntDirtyRegion
,
5876 PRBool aPaintDefaultBackground
,
5877 PRBool aWillSendDidPaint
)
5879 #ifdef NS_FUNCTION_TIMER
5880 NS_TIME_FUNCTION_DECLARE_DOCURL
;
5881 const nsRect
& bounds__
= aDirtyRegion
.GetBounds();
5882 NS_TIME_FUNCTION_MIN_FMT(1.0, "%s (line %d) (document: %s, dirty rect: (<%f, %f>, <%f, %f>)",
5883 MOZ_FUNCTION_NAME
, __LINE__
, docURL__
.get(),
5884 NSCoordToFloat(bounds__
.x
),
5885 NSCoordToFloat(bounds__
.y
),
5886 NSCoordToFloat(bounds__
.XMost()),
5887 NSCoordToFloat(bounds__
.YMost()));
5890 nsPresContext
* presContext
= GetPresContext();
5891 AUTO_LAYOUT_PHASE_ENTRY_POINT(presContext
, Paint
);
5893 NS_ASSERTION(!mIsDestroying
, "painting a destroyed PresShell");
5894 NS_ASSERTION(aDisplayRoot
, "null view");
5895 NS_ASSERTION(aViewToPaint
, "null view");
5896 NS_ASSERTION(aWidgetToPaint
, "Can't paint without a widget");
5898 nscolor bgcolor
= ComputeBackstopColor(aDisplayRoot
);
5900 nsIFrame
* frame
= aPaintDefaultBackground
5901 ? nsnull
: static_cast<nsIFrame
*>(aDisplayRoot
->GetClientData());
5903 if (frame
&& aViewToPaint
== aDisplayRoot
) {
5904 // Defer invalidates that are triggered during painting, and discard
5905 // invalidates of areas that are already being repainted.
5906 // The layer system can trigger invalidates during painting
5907 // (see FrameLayerBuilder).
5908 frame
->BeginDeferringInvalidatesForDisplayRoot(aDirtyRegion
);
5910 // We can paint directly into the widget using its layer manager.
5911 // When we get rid of child widgets, this will be the only path we
5912 // need. (aPaintDefaultBackground will never be needed since the
5913 // chrome can always paint a default background.)
5914 nsLayoutUtils::PaintFrame(nsnull
, frame
, aDirtyRegion
, bgcolor
,
5915 nsLayoutUtils::PAINT_WIDGET_LAYERS
);
5917 frame
->EndDeferringInvalidatesForDisplayRoot();
5922 // Defer invalidates that are triggered during painting, and discard
5923 // invalidates of areas that are already being repainted.
5924 frame
->BeginDeferringInvalidatesForDisplayRoot(aDirtyRegion
);
5927 LayerManager
* layerManager
= aWidgetToPaint
->GetLayerManager();
5928 NS_ASSERTION(layerManager
, "Must be in paint event");
5930 layerManager
->BeginTransaction();
5931 nsRefPtr
<ThebesLayer
> root
= layerManager
->CreateThebesLayer();
5933 root
->SetVisibleRegion(aIntDirtyRegion
);
5934 layerManager
->SetRoot(root
);
5937 bgcolor
= NS_ComposeColors(bgcolor
, mCanvasBackgroundColor
);
5939 PaintParams params
=
5941 aDisplayRoot
->GetOffsetToWidget(aWidgetToPaint
),
5944 layerManager
->EndTransaction(DrawThebesLayer
, ¶ms
);
5947 frame
->EndDeferringInvalidatesForDisplayRoot();
5954 nsIPresShell::SetCapturingContent(nsIContent
* aContent
, PRUint8 aFlags
)
5956 NS_IF_RELEASE(gCaptureInfo
.mContent
);
5958 // only set capturing content if allowed or the CAPTURE_IGNOREALLOWED flag
5960 if ((aFlags
& CAPTURE_IGNOREALLOWED
) || gCaptureInfo
.mAllowed
) {
5962 NS_ADDREF(gCaptureInfo
.mContent
= aContent
);
5964 gCaptureInfo
.mRetargetToElement
= (aFlags
& CAPTURE_RETARGETTOELEMENT
) != 0;
5965 gCaptureInfo
.mPreventDrag
= (aFlags
& CAPTURE_PREVENTDRAG
) != 0;
5970 PresShell::GetCurrentEventFrame()
5972 if (NS_UNLIKELY(mIsDestroying
)) {
5976 if (!mCurrentEventFrame
&& mCurrentEventContent
) {
5977 // Make sure the content still has a document reference. If not,
5978 // then we assume it is no longer in the content tree and the
5979 // frame shouldn't get an event, nor should we even assume its
5980 // safe to try and find the frame.
5981 if (mCurrentEventContent
->GetDocument()) {
5982 mCurrentEventFrame
= mCurrentEventContent
->GetPrimaryFrame();
5986 return mCurrentEventFrame
;
5990 PresShell::GetEventTargetFrame()
5992 return GetCurrentEventFrame();
5995 already_AddRefed
<nsIContent
>
5996 PresShell::GetEventTargetContent(nsEvent
* aEvent
)
5998 nsIContent
* content
= nsnull
;
6000 if (mCurrentEventContent
) {
6001 content
= mCurrentEventContent
;
6002 NS_IF_ADDREF(content
);
6004 nsIFrame
* currentEventFrame
= GetCurrentEventFrame();
6005 if (currentEventFrame
) {
6006 currentEventFrame
->GetContentForEvent(mPresContext
, aEvent
, &content
);
6015 PresShell::PushCurrentEventInfo(nsIFrame
* aFrame
, nsIContent
* aContent
)
6017 if (mCurrentEventFrame
|| mCurrentEventContent
) {
6018 mCurrentEventFrameStack
.InsertElementAt(0, mCurrentEventFrame
);
6019 mCurrentEventContentStack
.InsertObjectAt(mCurrentEventContent
, 0);
6021 mCurrentEventFrame
= aFrame
;
6022 mCurrentEventContent
= aContent
;
6026 PresShell::PopCurrentEventInfo()
6028 mCurrentEventFrame
= nsnull
;
6029 mCurrentEventContent
= nsnull
;
6031 if (0 != mCurrentEventFrameStack
.Length()) {
6032 mCurrentEventFrame
= mCurrentEventFrameStack
.ElementAt(0);
6033 mCurrentEventFrameStack
.RemoveElementAt(0);
6034 mCurrentEventContent
= mCurrentEventContentStack
.ObjectAt(0);
6035 mCurrentEventContentStack
.RemoveObjectAt(0);
6039 PRBool
PresShell::InZombieDocument(nsIContent
*aContent
)
6041 // If a content node points to a null document, or the document is not
6042 // attached to a window, then it is possibly in a zombie document,
6043 // about to be replaced by a newly loading document.
6044 // Such documents cannot handle DOM events.
6045 // It might actually be in a node not attached to any document,
6046 // in which case there is not parent presshell to retarget it to.
6047 nsIDocument
*doc
= aContent
->GetDocument();
6048 return !doc
|| !doc
->GetWindow();
6051 already_AddRefed
<nsPIDOMWindow
>
6052 PresShell::GetRootWindow()
6054 nsCOMPtr
<nsPIDOMWindow
> window
=
6055 do_QueryInterface(mDocument
->GetWindow());
6057 nsCOMPtr
<nsPIDOMWindow
> rootWindow
= window
->GetPrivateRoot();
6058 NS_ASSERTION(rootWindow
, "nsPIDOMWindow::GetPrivateRoot() returns NULL");
6059 return rootWindow
.forget();
6062 // If we don't have DOM window, we're zombie, we should find the root window
6063 // with our parent shell.
6064 nsCOMPtr
<nsIPresShell
> parent
= GetParentPresShell();
6065 NS_ENSURE_TRUE(parent
, nsnull
);
6066 return parent
->GetRootWindow();
6069 already_AddRefed
<nsIPresShell
>
6070 PresShell::GetParentPresShell()
6072 NS_ENSURE_TRUE(mPresContext
, nsnull
);
6073 nsCOMPtr
<nsISupports
> container
= mPresContext
->GetContainer();
6075 container
= do_QueryReferent(mForwardingContainer
);
6078 // Now, find the parent pres shell and send the event there
6079 nsCOMPtr
<nsIDocShellTreeItem
> treeItem
= do_QueryInterface(container
);
6080 // Might have gone away, or never been around to start with
6081 NS_ENSURE_TRUE(treeItem
, nsnull
);
6083 nsCOMPtr
<nsIDocShellTreeItem
> parentTreeItem
;
6084 treeItem
->GetParent(getter_AddRefs(parentTreeItem
));
6085 nsCOMPtr
<nsIDocShell
> parentDocShell
= do_QueryInterface(parentTreeItem
);
6086 NS_ENSURE_TRUE(parentDocShell
&& treeItem
!= parentTreeItem
, nsnull
);
6088 nsIPresShell
* parentPresShell
= nsnull
;
6089 parentDocShell
->GetPresShell(&parentPresShell
);
6090 return parentPresShell
;
6094 PresShell::RetargetEventToParent(nsGUIEvent
* aEvent
,
6095 nsEventStatus
* aEventStatus
)
6097 // Send this events straight up to the parent pres shell.
6098 // We do this for keystroke events in zombie documents or if either a frame
6099 // or a root content is not present.
6100 // That way at least the UI key bindings can work.
6102 nsCOMPtr
<nsIPresShell
> kungFuDeathGrip(this);
6103 nsCOMPtr
<nsIPresShell
> parentPresShell
= GetParentPresShell();
6104 NS_ENSURE_TRUE(parentPresShell
, NS_ERROR_FAILURE
);
6105 nsCOMPtr
<nsIViewObserver
> parentViewObserver
=
6106 do_QueryInterface(parentPresShell
);
6107 if (!parentViewObserver
) {
6108 return NS_ERROR_FAILURE
;
6111 // Fake the event as though it'ss from the parent pres shell's root view.
6112 nsIView
*parentRootView
;
6113 parentPresShell
->GetViewManager()->GetRootView(parentRootView
);
6115 sDontRetargetEvents
= PR_TRUE
;
6116 nsresult rv
= parentViewObserver
->HandleEvent(parentRootView
, aEvent
, aEventStatus
);
6117 sDontRetargetEvents
= PR_FALSE
;
6122 PresShell::DisableNonTestMouseEvents(PRBool aDisable
)
6124 sDisableNonTestMouseEvents
= aDisable
;
6127 already_AddRefed
<nsPIDOMWindow
>
6128 PresShell::GetFocusedDOMWindowInOurWindow()
6130 nsCOMPtr
<nsPIDOMWindow
> rootWindow
= GetRootWindow();
6131 NS_ENSURE_TRUE(rootWindow
, nsnull
);
6132 nsPIDOMWindow
* focusedWindow
;
6133 nsFocusManager::GetFocusedDescendant(rootWindow
, PR_TRUE
, &focusedWindow
);
6134 return focusedWindow
;
6138 PresShell::HandleEvent(nsIView
*aView
,
6140 nsEventStatus
* aEventStatus
)
6142 NS_ASSERTION(aView
, "null view");
6144 if (mIsDestroying
|| !nsContentUtils::IsSafeToRunScript() ||
6145 (sDisableNonTestMouseEvents
&& NS_IS_MOUSE_EVENT(aEvent
) &&
6146 !(aEvent
->flags
& NS_EVENT_FLAG_SYNTHETIC_TEST_EVENT
))) {
6150 NS_TIME_FUNCTION_MIN(1.0);
6152 #ifdef ACCESSIBILITY
6153 if (aEvent
->eventStructType
== NS_ACCESSIBLE_EVENT
) {
6154 // Accessibility events come through OS requests and not from scripts,
6155 // so it is safe to handle here
6156 return HandleEventInternal(aEvent
, aView
, aEventStatus
);
6160 nsIContent
* capturingContent
=
6161 NS_IS_MOUSE_EVENT(aEvent
) ? GetCapturingContent() : nsnull
;
6163 nsCOMPtr
<nsIDocument
> retargetEventDoc
;
6164 if (!sDontRetargetEvents
) {
6165 // key and IME related events should not cross top level window boundary.
6166 // Basically, such input events should be fired only on focused widget.
6167 // However, some IMEs might need to clean up composition after focused
6168 // window is deactivated. And also some tests on MozMill want to test key
6169 // handling on deactivated window because MozMill window can be activated
6170 // during tests. So, there is no merit the events should be redirected to
6171 // active window. So, the events should be handled on the last focused
6172 // content in the last focused DOM window in same top level window.
6173 // Note, if no DOM window has been focused yet, we can discard the events.
6174 if (NS_IsEventTargetedAtFocusedWindow(aEvent
)) {
6175 nsCOMPtr
<nsPIDOMWindow
> window
= GetFocusedDOMWindowInOurWindow();
6176 // No DOM window in same top level window has not been focused yet,
6177 // discard the events.
6182 retargetEventDoc
= do_QueryInterface(window
->GetExtantDocument());
6183 if (!retargetEventDoc
)
6185 } else if (capturingContent
) {
6186 // if the mouse is being captured then retarget the mouse event at the
6187 // document that is being captured.
6188 retargetEventDoc
= capturingContent
->GetCurrentDoc();
6191 if (retargetEventDoc
) {
6192 nsIPresShell
* presShell
= retargetEventDoc
->GetShell();
6196 if (presShell
!= this) {
6197 nsCOMPtr
<nsIViewObserver
> viewObserver
= do_QueryInterface(presShell
);
6199 return NS_ERROR_FAILURE
;
6202 presShell
->GetViewManager()->GetRootView(view
);
6203 sDontRetargetEvents
= PR_TRUE
;
6204 nsresult rv
= viewObserver
->HandleEvent(view
, aEvent
, aEventStatus
);
6205 sDontRetargetEvents
= PR_FALSE
;
6211 // Check for a theme change up front, since the frame type is irrelevant
6212 if (aEvent
->message
== NS_THEMECHANGED
&& mPresContext
) {
6213 mPresContext
->ThemeChanged();
6217 if (aEvent
->message
== NS_UISTATECHANGED
&& mDocument
) {
6218 nsPIDOMWindow
* win
= mDocument
->GetWindow();
6220 nsUIStateChangeEvent
* event
= (nsUIStateChangeEvent
*)aEvent
;
6221 win
->SetKeyboardIndicators(event
->showAccelerators
, event
->showFocusRings
);
6226 // Check for a system color change up front, since the frame type is
6228 if ((aEvent
->message
== NS_SYSCOLORCHANGED
) && mPresContext
) {
6229 nsIViewManager
* vm
= GetViewManager();
6231 // Only dispatch system color change when the message originates from
6232 // from the root views widget. This is necessary to prevent us from
6233 // dispatching the SysColorChanged notification for each child window
6234 // which may be redundant.
6236 vm
->GetRootView(view
);
6237 if (view
== aView
) {
6238 *aEventStatus
= nsEventStatus_eConsumeDoDefault
;
6239 mPresContext
->SysColorChanged();
6246 if (aEvent
->eventStructType
== NS_KEY_EVENT
&&
6247 mDocument
&& mDocument
->EventHandlingSuppressed()) {
6248 if (aEvent
->message
== NS_KEY_DOWN
) {
6249 mNoDelayedKeyEvents
= PR_TRUE
;
6250 } else if (!mNoDelayedKeyEvents
) {
6251 nsDelayedEvent
* event
=
6252 new nsDelayedKeyEvent(static_cast<nsKeyEvent
*>(aEvent
));
6253 if (event
&& !mDelayedEvents
.AppendElement(event
)) {
6260 nsIFrame
* frame
= static_cast<nsIFrame
*>(aView
->GetClientData());
6261 PRBool dispatchUsingCoordinates
= NS_IsEventUsingCoordinates(aEvent
);
6263 // if this event has no frame, we need to retarget it at a parent
6264 // view that has a frame.
6266 (dispatchUsingCoordinates
|| NS_IS_KEY_EVENT(aEvent
) ||
6267 NS_IS_IME_RELATED_EVENT(aEvent
) || NS_IS_NON_RETARGETED_PLUGIN_EVENT(aEvent
) ||
6268 aEvent
->message
== NS_PLUGIN_ACTIVATE
)) {
6269 nsIView
* targetView
= aView
;
6270 while (targetView
&& !targetView
->GetClientData()) {
6271 targetView
= targetView
->GetParent();
6276 frame
= static_cast<nsIFrame
*>(aView
->GetClientData());
6280 if (dispatchUsingCoordinates
) {
6281 NS_WARN_IF_FALSE(frame
, "Nothing to handle this event!");
6285 nsPresContext
* framePresContext
= frame
->PresContext();
6286 nsPresContext
* rootPresContext
= framePresContext
->GetRootPresContext();
6287 NS_ASSERTION(rootPresContext
== mPresContext
->GetRootPresContext(),
6288 "How did we end up outside the connected prescontext/viewmanager hierarchy?");
6289 // If we aren't starting our event dispatch from the root frame of the root prescontext,
6290 // then someone must be capturing the mouse. In that case we don't want to search the popup
6292 if (framePresContext
== rootPresContext
&&
6293 frame
== FrameManager()->GetRootFrame()) {
6294 nsIFrame
* popupFrame
=
6295 nsLayoutUtils::GetPopupFrameForEventCoordinates(rootPresContext
, aEvent
);
6296 // If the popupFrame is an ancestor of the 'frame', the frame should
6297 // handle the event, otherwise, the popup should handle it.
6299 !nsContentUtils::ContentIsCrossDocDescendantOf(
6300 framePresContext
->GetPresShell()->GetDocument(),
6301 popupFrame
->GetContent())) {
6306 PRBool captureRetarget
= PR_FALSE
;
6307 if (capturingContent
) {
6308 // If a capture is active, determine if the docshell is visible. If not,
6309 // clear the capture and target the mouse event normally instead. This
6310 // would occur if the mouse button is held down while a tab change occurs.
6311 // If the docshell is visible, look for a scrolling container.
6313 nsCOMPtr
<nsISupports
> supports
= mPresContext
->GetContainer();
6314 nsCOMPtr
<nsIBaseWindow
> baseWin(do_QueryInterface(supports
));
6315 if (baseWin
&& NS_SUCCEEDED(baseWin
->GetVisibility(&vis
)) && vis
) {
6316 captureRetarget
= gCaptureInfo
.mRetargetToElement
;
6317 if (!captureRetarget
) {
6318 // A check was already done above to ensure that capturingContent is
6319 // in this presshell.
6320 NS_ASSERTION(capturingContent
->GetCurrentDoc() == GetDocument(),
6321 "Unexpected document");
6322 nsIFrame
* captureFrame
= capturingContent
->GetPrimaryFrame();
6324 if (capturingContent
->Tag() == nsGkAtoms::select
&&
6325 capturingContent
->IsHTML()) {
6326 // a dropdown <select> has a child in its selectPopupList and we should
6327 // capture on that instead.
6328 nsIFrame
* childFrame
= captureFrame
->GetChildList(nsGkAtoms::selectPopupList
).FirstChild();
6330 captureFrame
= childFrame
;
6334 // scrollable frames should use the scrolling container as
6335 // the root instead of the document
6336 nsIScrollableFrame
* scrollFrame
= do_QueryFrame(captureFrame
);
6338 frame
= scrollFrame
->GetScrolledFrame();
6344 ClearMouseCapture(nsnull
);
6345 capturingContent
= nsnull
;
6349 // Get the frame at the event point. However, don't do this if we're
6350 // capturing and retargeting the event because the captured frame will
6351 // be used instead below.
6352 if (!captureRetarget
) {
6354 = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent
, frame
);
6356 PRBool ignoreRootScrollFrame
= PR_FALSE
;
6357 if (aEvent
->eventStructType
== NS_MOUSE_EVENT
) {
6358 ignoreRootScrollFrame
= static_cast<nsMouseEvent
*>(aEvent
)->ignoreRootScrollFrame
;
6360 nsIFrame
* target
= nsLayoutUtils::GetFrameForPoint(frame
, eventPoint
,
6361 PR_FALSE
, ignoreRootScrollFrame
);
6368 // if a node is capturing the mouse, check if the event needs to be
6369 // retargeted at the capturing content instead. This will be the case when
6370 // capture retargeting is being used, no frame was found or the frame's
6371 // content is not a descendant of the capturing content.
6372 if (capturingContent
&&
6373 (gCaptureInfo
.mRetargetToElement
|| !frame
->GetContent() ||
6374 !nsContentUtils::ContentIsCrossDocDescendantOf(frame
->GetContent(),
6375 capturingContent
))) {
6376 // A check was already done above to ensure that capturingContent is
6377 // in this presshell.
6378 NS_ASSERTION(capturingContent
->GetCurrentDoc() == GetDocument(),
6379 "Unexpected document");
6380 nsIFrame
* capturingFrame
= capturingContent
->GetPrimaryFrame();
6381 if (capturingFrame
) {
6382 frame
= capturingFrame
;
6383 aView
= frame
->GetClosestView();
6387 // Suppress mouse event if it's being targeted at an element inside
6388 // a document which needs events suppressed
6389 if (aEvent
->eventStructType
== NS_MOUSE_EVENT
&&
6390 frame
->PresContext()->Document()->EventHandlingSuppressed()) {
6391 if (aEvent
->message
== NS_MOUSE_BUTTON_DOWN
) {
6392 mNoDelayedMouseEvents
= PR_TRUE
;
6393 } else if (!mNoDelayedMouseEvents
&& aEvent
->message
== NS_MOUSE_BUTTON_UP
) {
6394 nsDelayedEvent
* event
=
6395 new nsDelayedMouseEvent(static_cast<nsMouseEvent
*>(aEvent
));
6396 if (!mDelayedEvents
.AppendElement(event
)) {
6405 static_cast<PresShell
*>(frame
->PresContext()->PresShell());
6406 if (shell
!= this) {
6407 // Handle the event in the correct shell.
6408 // Prevent deletion until we're done with event handling (bug 336582).
6409 nsCOMPtr
<nsIPresShell
> kungFuDeathGrip(shell
);
6410 nsIView
* subshellRootView
;
6411 shell
->GetViewManager()->GetRootView(subshellRootView
);
6412 // We pass the subshell's root view as the view to start from. This is
6413 // the only correct alternative; if the event was captured then it
6414 // must have been captured by us or some ancestor shell and we
6415 // now ask the subshell to dispatch it normally.
6416 return shell
->HandlePositionedEvent(subshellRootView
, frame
,
6417 aEvent
, aEventStatus
);
6420 return HandlePositionedEvent(aView
, frame
, aEvent
, aEventStatus
);
6423 nsresult rv
= NS_OK
;
6426 PushCurrentEventInfo(nsnull
, nsnull
);
6428 // key and IME related events go to the focused frame in this DOM window.
6429 if (NS_IsEventTargetedAtFocusedContent(aEvent
)) {
6430 NS_ASSERTION(mDocument
, "mDocument is null");
6431 nsCOMPtr
<nsPIDOMWindow
> window
=
6432 do_QueryInterface(mDocument
->GetWindow());
6433 nsCOMPtr
<nsPIDOMWindow
> focusedWindow
;
6434 mCurrentEventContent
=
6435 nsFocusManager::GetFocusedDescendant(window
, PR_FALSE
,
6436 getter_AddRefs(focusedWindow
));
6438 // otherwise, if there is no focused content or the focused content has
6439 // no frame, just use the root content. This ensures that key events
6440 // still get sent to the window properly if nothing is focused or if a
6441 // frame goes away while it is focused.
6442 if (!mCurrentEventContent
|| !GetCurrentEventFrame())
6443 mCurrentEventContent
= mDocument
->GetRootElement();
6445 if (aEvent
->message
== NS_KEY_DOWN
) {
6446 NS_IF_RELEASE(gKeyDownTarget
);
6447 NS_IF_ADDREF(gKeyDownTarget
= mCurrentEventContent
);
6449 else if ((aEvent
->message
== NS_KEY_PRESS
|| aEvent
->message
== NS_KEY_UP
) &&
6451 // If a different element is now focused for the keypress/keyup event
6452 // than what was focused during the keydown event, check if the new
6453 // focused element is not in a chrome document any more, and if so,
6454 // retarget the event back at the keydown target. This prevents a
6455 // content area from grabbing the focus from chrome in-between key
6457 if (mCurrentEventContent
&&
6458 nsContentUtils::IsChromeDoc(gKeyDownTarget
->GetCurrentDoc()) &&
6459 !nsContentUtils::IsChromeDoc(mCurrentEventContent
->GetCurrentDoc())) {
6460 mCurrentEventContent
= gKeyDownTarget
;
6463 if (aEvent
->message
== NS_KEY_UP
) {
6464 NS_RELEASE(gKeyDownTarget
);
6468 mCurrentEventFrame
= nsnull
;
6470 if (!mCurrentEventContent
|| !GetCurrentEventFrame() ||
6471 InZombieDocument(mCurrentEventContent
)) {
6472 rv
= RetargetEventToParent(aEvent
, aEventStatus
);
6473 PopCurrentEventInfo();
6477 mCurrentEventFrame
= frame
;
6479 if (GetCurrentEventFrame()) {
6480 rv
= HandleEventInternal(aEvent
, aView
, aEventStatus
);
6484 ShowEventTargetDebug();
6486 PopCurrentEventInfo();
6488 // Activation events need to be dispatched even if no frame was found, since
6489 // we don't want the focus to be out of sync.
6491 if (!NS_EVENT_NEEDS_FRAME(aEvent
)) {
6492 mCurrentEventFrame
= nsnull
;
6493 return HandleEventInternal(aEvent
, aView
, aEventStatus
);
6495 else if (NS_IS_KEY_EVENT(aEvent
)) {
6496 // Keypress events in new blank tabs should not be completely thrown away.
6497 // Retarget them -- the parent chrome shell might make use of them.
6498 return RetargetEventToParent(aEvent
, aEventStatus
);
6507 PresShell::ShowEventTargetDebug()
6509 if (nsFrame::GetShowEventTargetFrameBorder() &&
6510 GetCurrentEventFrame()) {
6511 if (mDrawEventTargetFrame
) {
6512 mDrawEventTargetFrame
->Invalidate(
6513 nsRect(nsPoint(0, 0), mDrawEventTargetFrame
->GetSize()));
6516 mDrawEventTargetFrame
= mCurrentEventFrame
;
6517 mDrawEventTargetFrame
->Invalidate(
6518 nsRect(nsPoint(0, 0), mDrawEventTargetFrame
->GetSize()));
6524 PresShell::HandlePositionedEvent(nsIView
* aView
,
6525 nsIFrame
* aTargetFrame
,
6527 nsEventStatus
* aEventStatus
)
6529 nsresult rv
= NS_OK
;
6531 PushCurrentEventInfo(nsnull
, nsnull
);
6533 mCurrentEventFrame
= aTargetFrame
;
6535 if (mCurrentEventFrame
) {
6536 nsCOMPtr
<nsIContent
> targetElement
;
6537 mCurrentEventFrame
->GetContentForEvent(mPresContext
, aEvent
,
6538 getter_AddRefs(targetElement
));
6540 // If there is no content for this frame, target it anyway. Some
6541 // frames can be targeted but do not have content, particularly
6542 // windows with scrolling off.
6543 if (targetElement
) {
6544 // Bug 103055, bug 185889: mouse events apply to *elements*, not all
6545 // nodes. Thus we get the nearest element parent here.
6546 // XXX we leave the frame the same even if we find an element
6547 // parent, so that the text frame will receive the event (selection
6548 // and friends are the ones who care about that anyway)
6550 // We use weak pointers because during this tight loop, the node
6551 // will *not* go away. And this happens on every mousemove.
6552 while (targetElement
&& !targetElement
->IsElement()) {
6553 targetElement
= targetElement
->GetParent();
6556 // If we found an element, target it. Otherwise, target *nothing*.
6557 if (!targetElement
) {
6558 mCurrentEventContent
= nsnull
;
6559 mCurrentEventFrame
= nsnull
;
6560 } else if (targetElement
!= mCurrentEventContent
) {
6561 mCurrentEventContent
= targetElement
;
6566 if (GetCurrentEventFrame()) {
6567 rv
= HandleEventInternal(aEvent
, aView
, aEventStatus
);
6571 ShowEventTargetDebug();
6573 PopCurrentEventInfo();
6578 PresShell::HandleEventWithTarget(nsEvent
* aEvent
, nsIFrame
* aFrame
,
6579 nsIContent
* aContent
, nsEventStatus
* aStatus
)
6581 PushCurrentEventInfo(aFrame
, aContent
);
6582 nsresult rv
= HandleEventInternal(aEvent
, nsnull
, aStatus
);
6583 PopCurrentEventInfo();
6587 static inline PRBool
6588 IsSynthesizedMouseEvent(nsEvent
* aEvent
)
6590 return aEvent
->eventStructType
== NS_MOUSE_EVENT
&&
6591 static_cast<nsMouseEvent
*>(aEvent
)->reason
!= nsMouseEvent::eReal
;
6594 static PRBool
CanHandleContextMenuEvent(nsMouseEvent
* aMouseEvent
,
6597 #if defined(XP_MACOSX) && defined(MOZ_XUL)
6598 nsXULPopupManager
* pm
= nsXULPopupManager::GetInstance();
6600 nsIFrame
* popupFrame
= pm
->GetTopPopup(ePopupTypeMenu
);
6602 // context menus should not be opened while another menu is open on Mac,
6603 // so return false so that the event is not fired.
6604 if (aMouseEvent
->context
== nsMouseEvent::eContextMenuKey
) {
6606 } else if (aMouseEvent
->widget
) {
6607 nsWindowType windowType
;
6608 aMouseEvent
->widget
->GetWindowType(windowType
);
6609 if (windowType
== eWindowType_popup
) {
6610 for (nsIFrame
* current
= aFrame
; current
;
6611 current
= nsLayoutUtils::GetCrossDocParentFrame(current
)) {
6612 if (current
->GetType() == nsGkAtoms::menuPopupFrame
) {
6625 PresShell::HandleEventInternal(nsEvent
* aEvent
, nsIView
*aView
,
6626 nsEventStatus
* aStatus
)
6628 NS_TIME_FUNCTION_MIN(1.0);
6630 #ifdef ACCESSIBILITY
6631 if (aEvent
->eventStructType
== NS_ACCESSIBLE_EVENT
)
6633 nsAccessibleEvent
*accEvent
= static_cast<nsAccessibleEvent
*>(aEvent
);
6634 accEvent
->mAccessible
= nsnull
;
6636 nsCOMPtr
<nsIAccessibilityService
> accService
=
6637 do_GetService("@mozilla.org/accessibilityService;1");
6639 nsCOMPtr
<nsISupports
> container
= mPresContext
->GetContainer();
6641 // This presshell is not active. This often happens when a
6642 // preshell is being held onto for fastback.
6646 accEvent
->mAccessible
= accService
->GetAccessibleInShell(mDocument
, this);
6648 // Ensure this is set in case a11y was activated before any
6649 // nsPresShells existed to observe "a11y-init-or-shutdown" topic
6650 gIsAccessibilityActive
= PR_TRUE
;
6656 nsCOMPtr
<nsIEventStateManager
> manager
= mPresContext
->EventStateManager();
6657 nsresult rv
= NS_OK
;
6659 if (!NS_EVENT_NEEDS_FRAME(aEvent
) || GetCurrentEventFrame()) {
6660 PRBool isHandlingUserInput
= PR_FALSE
;
6662 if (NS_IS_TRUSTED_EVENT(aEvent
)) {
6663 switch (aEvent
->message
) {
6664 case NS_MOUSE_BUTTON_DOWN
:
6665 case NS_MOUSE_BUTTON_UP
:
6669 isHandlingUserInput
= PR_TRUE
;
6671 case NS_DRAGDROP_DROP
:
6672 nsCOMPtr
<nsIDragSession
> session
= nsContentUtils::GetDragSession();
6674 PRBool onlyChromeDrop
= PR_FALSE
;
6675 session
->GetOnlyChromeDrop(&onlyChromeDrop
);
6676 if (onlyChromeDrop
) {
6677 aEvent
->flags
|= NS_EVENT_FLAG_ONLY_CHROME_DISPATCH
;
6684 if (aEvent
->message
== NS_CONTEXTMENU
) {
6685 nsMouseEvent
* me
= static_cast<nsMouseEvent
*>(aEvent
);
6686 if (!CanHandleContextMenuEvent(me
, GetCurrentEventFrame())) {
6689 if (me
->context
== nsMouseEvent::eContextMenuKey
&&
6690 !AdjustContextMenuKeyEvent(me
)) {
6695 nsAutoHandlingUserInputStatePusher
userInpStatePusher(isHandlingUserInput
,
6696 aEvent
->message
== NS_MOUSE_BUTTON_DOWN
);
6698 nsAutoPopupStatePusher
popupStatePusher(nsDOMEvent::GetEventPopupControlState(aEvent
));
6700 // FIXME. If the event was reused, we need to clear the old target,
6702 aEvent
->target
= nsnull
;
6704 nsWeakView
weakView(aView
);
6705 // 1. Give event to event manager for pre event state changes and
6706 // generation of synthetic events.
6707 rv
= manager
->PreHandleEvent(mPresContext
, aEvent
, mCurrentEventFrame
,
6710 // 2. Give event to the DOM for third party and JS use.
6711 if (GetCurrentEventFrame() && NS_SUCCEEDED(rv
)) {
6712 PRBool wasHandlingKeyBoardEvent
=
6713 nsContentUtils::IsHandlingKeyBoardEvent();
6714 if (aEvent
->eventStructType
== NS_KEY_EVENT
) {
6715 nsContentUtils::SetIsHandlingKeyBoardEvent(PR_TRUE
);
6717 // We want synthesized mouse moves to cause mouseover and mouseout
6718 // DOM events (PreHandleEvent above), but not mousemove DOM events.
6719 // Synthesized button up events also do not cause DOM events
6720 // because they do not have a reliable refPoint.
6721 if (!IsSynthesizedMouseEvent(aEvent
)) {
6722 nsPresShellEventCB
eventCB(this);
6723 if (mCurrentEventContent
) {
6724 nsEventDispatcher::Dispatch(mCurrentEventContent
, mPresContext
,
6725 aEvent
, nsnull
, aStatus
, &eventCB
);
6728 nsCOMPtr
<nsIContent
> targetContent
;
6729 rv
= mCurrentEventFrame
->GetContentForEvent(mPresContext
, aEvent
,
6730 getter_AddRefs(targetContent
));
6731 if (NS_SUCCEEDED(rv
) && targetContent
) {
6732 nsEventDispatcher::Dispatch(targetContent
, mPresContext
, aEvent
,
6733 nsnull
, aStatus
, &eventCB
);
6734 } else if (mDocument
) {
6735 nsEventDispatcher::Dispatch(mDocument
, mPresContext
, aEvent
,
6736 nsnull
, aStatus
, nsnull
);
6741 nsContentUtils::SetIsHandlingKeyBoardEvent(wasHandlingKeyBoardEvent
);
6743 // 3. Give event to event manager for post event state changes and
6744 // generation of synthetic events.
6745 if (!mIsDestroying
&& NS_SUCCEEDED(rv
)) {
6746 rv
= manager
->PostHandleEvent(mPresContext
, aEvent
,
6747 GetCurrentEventFrame(), aStatus
,
6748 weakView
.GetView());
6752 if (aEvent
->message
== NS_MOUSE_BUTTON_UP
) {
6753 // reset the capturing content now that the mouse button is up
6754 SetCapturingContent(nsnull
, 0);
6760 // Dispatch event to content only (NOT full processing)
6761 // See also HandleEventWithTarget which does full event processing.
6763 PresShell::HandleDOMEventWithTarget(nsIContent
* aTargetContent
, nsEvent
* aEvent
,
6764 nsEventStatus
* aStatus
)
6766 nsresult rv
= NS_OK
;
6768 PushCurrentEventInfo(nsnull
, aTargetContent
);
6770 // Bug 41013: Check if the event should be dispatched to content.
6771 // It's possible that we are in the middle of destroying the window
6772 // and the js context is out of date. This check detects the case
6773 // that caused a crash in bug 41013, but there may be a better way
6774 // to handle this situation!
6775 nsCOMPtr
<nsISupports
> container
= mPresContext
->GetContainer();
6778 // Dispatch event to content
6779 rv
= nsEventDispatcher::Dispatch(aTargetContent
, mPresContext
, aEvent
, nsnull
,
6783 PopCurrentEventInfo();
6787 // See the method above.
6789 PresShell::HandleDOMEventWithTarget(nsIContent
* aTargetContent
,
6790 nsIDOMEvent
* aEvent
,
6791 nsEventStatus
* aStatus
)
6793 nsresult rv
= NS_OK
;
6795 PushCurrentEventInfo(nsnull
, aTargetContent
);
6796 nsCOMPtr
<nsISupports
> container
= mPresContext
->GetContainer();
6798 rv
= nsEventDispatcher::DispatchDOMEvent(aTargetContent
, nsnull
, aEvent
,
6799 mPresContext
, aStatus
);
6802 PopCurrentEventInfo();
6807 PresShell::AdjustContextMenuKeyEvent(nsMouseEvent
* aEvent
)
6810 // if a menu is open, open the context menu relative to the active item on the menu.
6811 nsXULPopupManager
* pm
= nsXULPopupManager::GetInstance();
6813 nsIFrame
* popupFrame
= pm
->GetTopPopup(ePopupTypeMenu
);
6815 nsIFrame
* itemFrame
=
6816 (static_cast<nsMenuPopupFrame
*>(popupFrame
))->GetCurrentMenuItem();
6818 itemFrame
= popupFrame
;
6820 nsCOMPtr
<nsIWidget
> widget
= popupFrame
->GetNearestWidget();
6821 aEvent
->widget
= widget
;
6822 nsIntPoint widgetPoint
= widget
->WidgetToScreenOffset();
6823 aEvent
->refPoint
= itemFrame
->GetScreenRect().BottomLeft() - widgetPoint
;
6825 mCurrentEventContent
= itemFrame
->GetContent();
6826 mCurrentEventFrame
= itemFrame
;
6833 // If we're here because of the key-equiv for showing context menus, we
6834 // have to twiddle with the NS event to make sure the context menu comes
6835 // up in the upper left of the relevant content area before we create
6836 // the DOM event. Since we never call InitMouseEvent() on the event,
6837 // the client X/Y will be 0,0. We can make use of that if the widget is null.
6838 // Use the root view manager's widget since it's most likely to have one,
6839 // and the coordinates returned by GetCurrentItemAndPositionForElement
6840 // are relative to the widget of the root of the root view manager.
6841 nsRootPresContext
* rootPC
= mPresContext
->GetRootPresContext();
6842 aEvent
->refPoint
.x
= 0;
6843 aEvent
->refPoint
.y
= 0;
6845 rootPC
->PresShell()->GetViewManager()->
6846 GetRootWidget(getter_AddRefs(aEvent
->widget
));
6848 if (aEvent
->widget
) {
6849 // default the refpoint to the topleft of our document
6850 nsPoint
offset(0, 0);
6851 nsIFrame
* rootFrame
= FrameManager()->GetRootFrame();
6853 nsIView
* view
= rootFrame
->GetClosestView(&offset
);
6854 offset
+= view
->GetOffsetToWidget(aEvent
->widget
);
6856 offset
.ToNearestPixels(mPresContext
->AppUnitsPerDevPixel());
6860 aEvent
->widget
= nsnull
;
6863 // see if we should use the caret position for the popup
6864 nsIntPoint caretPoint
;
6865 // Beware! This may flush notifications via synchronous
6866 // ScrollSelectionIntoView.
6867 if (PrepareToUseCaretPosition(aEvent
->widget
, caretPoint
)) {
6868 // caret position is good
6869 aEvent
->refPoint
= caretPoint
;
6873 // If we're here because of the key-equiv for showing context menus, we
6874 // have to reset the event target to the currently focused element. Get it
6875 // from the focus controller.
6876 nsCOMPtr
<nsIDOMElement
> currentFocus
;
6877 nsIFocusManager
* fm
= nsFocusManager::GetFocusManager();
6879 fm
->GetFocusedElement(getter_AddRefs(currentFocus
));
6881 // Reset event coordinates relative to focused frame in view
6883 nsCOMPtr
<nsIContent
> currentPointElement
;
6884 GetCurrentItemAndPositionForElement(currentFocus
,
6885 getter_AddRefs(currentPointElement
),
6888 if (currentPointElement
) {
6889 mCurrentEventContent
= currentPointElement
;
6890 mCurrentEventFrame
= nsnull
;
6891 GetCurrentEventFrame();
6898 // PresShell::PrepareToUseCaretPosition
6900 // This checks to see if we should use the caret position for popup context
6901 // menus. Returns true if the caret position should be used, and the
6902 // coordinates of that position is returned in aTargetPt. This function
6903 // will also scroll the window as needed to make the caret visible.
6905 // The event widget should be the widget that generated the event, and
6906 // whose coordinate system the resulting event's refPoint should be
6907 // relative to. The returned point is in device pixels realtive to the
6908 // widget passed in.
6910 PresShell::PrepareToUseCaretPosition(nsIWidget
* aEventWidget
, nsIntPoint
& aTargetPt
)
6914 // check caret visibility
6915 nsRefPtr
<nsCaret
> caret
= GetCaret();
6916 NS_ENSURE_TRUE(caret
, PR_FALSE
);
6918 PRBool caretVisible
= PR_FALSE
;
6919 rv
= caret
->GetCaretVisible(&caretVisible
);
6920 if (NS_FAILED(rv
) || ! caretVisible
)
6923 // caret selection, this is a temporary weak reference, so no refcounting is
6925 nsISelection
* domSelection
= caret
->GetCaretDOMSelection();
6926 NS_ENSURE_TRUE(domSelection
, PR_FALSE
);
6928 // since the match could be an anonymous textnode inside a
6929 // <textarea> or text <input>, we need to get the outer frame
6930 // note: frames are not refcounted
6931 nsIFrame
* frame
= nsnull
; // may be NULL
6932 nsCOMPtr
<nsIDOMNode
> node
;
6933 rv
= domSelection
->GetFocusNode(getter_AddRefs(node
));
6934 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
6935 NS_ENSURE_TRUE(node
, PR_FALSE
);
6936 nsCOMPtr
<nsIContent
> content(do_QueryInterface(node
));
6938 nsIContent
* nonNative
= content
->FindFirstNonNativeAnonymous();
6939 content
= nonNative
;
6943 // It seems like ScrollSelectionIntoView should be enough, but it's
6944 // not. The problem is that scrolling the selection into view when it is
6945 // below the current viewport will align the top line of the frame exactly
6946 // with the bottom of the window. This is fine, BUT, the popup event causes
6947 // the control to be re-focused which does this exact call to
6948 // ScrollContentIntoView, which has a one-pixel disagreement of whether the
6949 // frame is actually in view. The result is that the frame is aligned with
6950 // the top of the window, but the menu is still at the bottom.
6952 // Doing this call first forces the frame to be in view, eliminating the
6953 // problem. The only difference in the result is that if your cursor is in
6954 // an edit box below the current view, you'll get the edit box aligned with
6955 // the top of the window. This is arguably better behavior anyway.
6956 rv
= ScrollContentIntoView(content
, NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE
,
6957 NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE
);
6958 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
6959 frame
= content
->GetPrimaryFrame();
6960 NS_WARN_IF_FALSE(frame
, "No frame for focused content?");
6963 // Actually scroll the selection (ie caret) into view. Note that this must
6964 // be synchronous since we will be checking the caret position on the screen.
6966 // Be easy about errors, and just don't scroll in those cases. Better to have
6967 // the correct menu at a weird place than the wrong menu.
6968 // After ScrollSelectionIntoView(), the pending notifications might be
6969 // flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
6970 nsCOMPtr
<nsISelectionController
> selCon
;
6972 frame
->GetSelectionController(GetPresContext(), getter_AddRefs(selCon
));
6974 selCon
= static_cast<nsISelectionController
*>(this);
6976 rv
= selCon
->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL
,
6977 nsISelectionController::SELECTION_FOCUS_REGION
, PR_TRUE
);
6978 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
6981 nsPresContext
* presContext
= GetPresContext();
6983 // get caret position relative to the closest view
6985 nsIFrame
* caretFrame
= caret
->GetGeometry(domSelection
, &caretCoords
);
6989 nsIView
* view
= caretFrame
->GetClosestView(&viewOffset
);
6992 // and then get the caret coords relative to the event widget
6994 viewOffset
+= view
->GetOffsetToWidget(aEventWidget
);
6996 caretCoords
.MoveBy(viewOffset
);
6998 // caret coordinates are in app units, convert to pixels
7000 presContext
->AppUnitsToDevPixels(caretCoords
.x
+ caretCoords
.width
);
7002 presContext
->AppUnitsToDevPixels(caretCoords
.y
+ caretCoords
.height
);
7004 // make sure rounding doesn't return a pixel which is outside the caret
7005 // (e.g. one line lower)
7012 PresShell::GetCurrentItemAndPositionForElement(nsIDOMElement
*aCurrentEl
,
7013 nsIContent
** aTargetToUse
,
7014 nsIntPoint
& aTargetPt
,
7015 nsIWidget
*aRootWidget
)
7017 nsCOMPtr
<nsIContent
> focusedContent(do_QueryInterface(aCurrentEl
));
7018 ScrollContentIntoView(focusedContent
, NS_PRESSHELL_SCROLL_ANYWHERE
,
7019 NS_PRESSHELL_SCROLL_ANYWHERE
);
7021 nsPresContext
* presContext
= GetPresContext();
7023 PRBool istree
= PR_FALSE
, checkLineHeight
= PR_TRUE
;
7024 nscoord extraTreeY
= 0;
7027 // Set the position to just underneath the current item for multi-select
7028 // lists or just underneath the selected item for single-select lists. If
7029 // the element is not a list, or there is no selection, leave the position
7031 nsCOMPtr
<nsIDOMXULSelectControlItemElement
> item
;
7032 nsCOMPtr
<nsIDOMXULMultiSelectControlElement
> multiSelect
=
7033 do_QueryInterface(aCurrentEl
);
7035 checkLineHeight
= PR_FALSE
;
7037 PRInt32 currentIndex
;
7038 multiSelect
->GetCurrentIndex(¤tIndex
);
7039 if (currentIndex
>= 0) {
7040 nsCOMPtr
<nsIDOMXULElement
> xulElement(do_QueryInterface(aCurrentEl
));
7042 nsCOMPtr
<nsIBoxObject
> box
;
7043 xulElement
->GetBoxObject(getter_AddRefs(box
));
7044 nsCOMPtr
<nsITreeBoxObject
> treeBox(do_QueryInterface(box
));
7045 // Tree view special case (tree items have no frames)
7046 // Get the focused row and add its coordinates, which are already in pixels
7047 // XXX Boris, should we create a new interface so that this doesn't
7048 // need to know about trees? Something like nsINodelessChildCreator which
7049 // could provide the current focus coordinates?
7051 treeBox
->EnsureRowIsVisible(currentIndex
);
7052 PRInt32 firstVisibleRow
, rowHeight
;
7053 treeBox
->GetFirstVisibleRow(&firstVisibleRow
);
7054 treeBox
->GetRowHeight(&rowHeight
);
7056 extraTreeY
+= presContext
->CSSPixelsToAppUnits(
7057 (currentIndex
- firstVisibleRow
+ 1) * rowHeight
);
7060 nsCOMPtr
<nsITreeColumns
> cols
;
7061 treeBox
->GetColumns(getter_AddRefs(cols
));
7063 nsCOMPtr
<nsITreeColumn
> col
;
7064 cols
->GetFirstColumn(getter_AddRefs(col
));
7066 nsCOMPtr
<nsIDOMElement
> colElement
;
7067 col
->GetElement(getter_AddRefs(colElement
));
7068 nsCOMPtr
<nsIContent
> colContent(do_QueryInterface(colElement
));
7070 nsIFrame
* frame
= colContent
->GetPrimaryFrame();
7072 extraTreeY
+= frame
->GetSize().height
;
7079 multiSelect
->GetCurrentItem(getter_AddRefs(item
));
7085 // don't check menulists as the selected item will be inside a popup.
7086 nsCOMPtr
<nsIDOMXULMenuListElement
> menulist
= do_QueryInterface(aCurrentEl
);
7088 nsCOMPtr
<nsIDOMXULSelectControlElement
> select
=
7089 do_QueryInterface(aCurrentEl
);
7091 checkLineHeight
= PR_FALSE
;
7092 select
->GetSelectedItem(getter_AddRefs(item
));
7098 focusedContent
= do_QueryInterface(item
);
7101 nsIFrame
*frame
= focusedContent
->GetPrimaryFrame();
7103 NS_ASSERTION(frame
->PresContext() == GetPresContext(),
7104 "handling event for focused content that is not in our document?");
7106 nsPoint
frameOrigin(0, 0);
7108 // Get the frame's origin within its view
7109 nsIView
*view
= frame
->GetClosestView(&frameOrigin
);
7110 NS_ASSERTION(view
, "No view for frame");
7112 // View's origin relative the widget
7114 frameOrigin
+= view
->GetOffsetToWidget(aRootWidget
);
7117 // Start context menu down and to the right from top left of frame
7118 // use the lineheight. This is a good distance to move the context
7119 // menu away from the top left corner of the frame. If we always
7120 // used the frame height, the context menu could end up far away,
7121 // for example when we're focused on linked images.
7122 // On the other hand, we want to use the frame height if it's less
7123 // than the current line height, so that the context menu appears
7124 // associated with the correct frame.
7127 extra
= frame
->GetSize().height
;
7128 if (checkLineHeight
) {
7129 nsIScrollableFrame
*scrollFrame
=
7130 nsLayoutUtils::GetNearestScrollableFrame(frame
);
7132 nsSize scrollAmount
= scrollFrame
->GetLineScrollAmount();
7133 nsIFrame
* f
= do_QueryFrame(scrollFrame
);
7134 PRInt32 APD
= presContext
->AppUnitsPerDevPixel();
7135 PRInt32 scrollAPD
= f
->PresContext()->AppUnitsPerDevPixel();
7136 scrollAmount
= scrollAmount
.ConvertAppUnits(scrollAPD
, APD
);
7137 if (extra
> scrollAmount
.height
) {
7138 extra
= scrollAmount
.height
;
7144 aTargetPt
.x
= presContext
->AppUnitsToDevPixels(frameOrigin
.x
);
7145 aTargetPt
.y
= presContext
->AppUnitsToDevPixels(
7146 frameOrigin
.y
+ extra
+ extraTreeY
);
7149 NS_IF_ADDREF(*aTargetToUse
= focusedContent
);
7153 PresShell::ResizeReflow(nsIView
*aView
, nscoord aWidth
, nscoord aHeight
)
7155 return ResizeReflow(aWidth
, aHeight
);
7158 NS_IMETHODIMP_(PRBool
)
7159 PresShell::IsVisible()
7161 nsCOMPtr
<nsISupports
> container
= mPresContext
->GetContainer();
7162 nsCOMPtr
<nsIBaseWindow
> bw
= do_QueryInterface(container
);
7165 PRBool res
= PR_TRUE
;
7166 bw
->GetVisibility(&res
);
7170 NS_IMETHODIMP_(PRBool
)
7171 PresShell::ShouldIgnoreInvalidation()
7173 return mPaintingSuppressed
;
7176 NS_IMETHODIMP_(void)
7177 PresShell::WillPaint(PRBool aWillSendDidPaint
)
7179 // Don't bother doing anything if some viewmanager in our tree is
7180 // painting while we still have painting suppressed.
7181 if (mPaintingSuppressed
) {
7185 if (!aWillSendDidPaint
) {
7186 nsRootPresContext
* rootPresContext
= mPresContext
->GetRootPresContext();
7187 if (!rootPresContext
) {
7190 if (rootPresContext
== mPresContext
) {
7191 rootPresContext
->UpdatePluginGeometry();
7195 // Process reflows, if we have them, to reduce flicker due to invalidates and
7196 // reflow being interspersed. Note that we _do_ allow this to be
7197 // interruptible; if we can't do all the reflows it's better to flicker a bit
7198 // than to freeze up.
7199 FlushPendingNotifications(Flush_InterruptibleLayout
);
7202 NS_IMETHODIMP_(void)
7203 PresShell::DidPaint()
7205 nsRootPresContext
* rootPresContext
= mPresContext
->GetRootPresContext();
7206 if (!rootPresContext
) {
7209 if (rootPresContext
== mPresContext
) {
7210 rootPresContext
->UpdatePluginGeometry();
7215 PresShell::GetAgentStyleSheets(nsCOMArray
<nsIStyleSheet
>& aSheets
)
7218 PRInt32 sheetCount
= mStyleSet
->SheetCount(nsStyleSet::eAgentSheet
);
7220 for (PRInt32 i
= 0; i
< sheetCount
; ++i
) {
7221 nsIStyleSheet
*sheet
= mStyleSet
->StyleSheetAt(nsStyleSet::eAgentSheet
, i
);
7222 if (!aSheets
.AppendObject(sheet
))
7223 return NS_ERROR_OUT_OF_MEMORY
;
7230 PresShell::SetAgentStyleSheets(const nsCOMArray
<nsIStyleSheet
>& aSheets
)
7232 return mStyleSet
->ReplaceSheets(nsStyleSet::eAgentSheet
, aSheets
);
7236 PresShell::AddOverrideStyleSheet(nsIStyleSheet
*aSheet
)
7238 return mStyleSet
->PrependStyleSheet(nsStyleSet::eOverrideSheet
, aSheet
);
7242 PresShell::RemoveOverrideStyleSheet(nsIStyleSheet
*aSheet
)
7244 return mStyleSet
->RemoveStyleSheet(nsStyleSet::eOverrideSheet
, aSheet
);
7248 FreezeElement(nsIContent
*aContent
, void * /* unused */)
7250 nsIFrame
*frame
= aContent
->GetPrimaryFrame();
7251 nsIObjectFrame
*objectFrame
= do_QueryFrame(frame
);
7253 objectFrame
->StopPlugin();
7258 FreezeSubDocument(nsIDocument
*aDocument
, void *aData
)
7260 nsIPresShell
*shell
= aDocument
->GetShell();
7270 MaybeReleaseCapturingContent();
7272 mDocument
->EnumerateFreezableElements(FreezeElement
, nsnull
);
7275 mCaret
->SetCaretVisible(PR_FALSE
);
7277 mPaintingSuppressed
= PR_TRUE
;
7280 mDocument
->EnumerateSubDocuments(FreezeSubDocument
, nsnull
);
7282 nsPresContext
* presContext
= GetPresContext();
7284 presContext
->RefreshDriver()->PresContext() == presContext
) {
7285 presContext
->RefreshDriver()->Freeze();
7289 UpdateImageLockingState();
7293 PresShell::FireOrClearDelayedEvents(PRBool aFireEvents
)
7295 mNoDelayedMouseEvents
= PR_FALSE
;
7296 mNoDelayedKeyEvents
= PR_FALSE
;
7298 mDelayedEvents
.Clear();
7303 nsCOMPtr
<nsIDocument
> doc
= mDocument
;
7304 while (!mIsDestroying
&& mDelayedEvents
.Length() &&
7305 !doc
->EventHandlingSuppressed()) {
7306 nsAutoPtr
<nsDelayedEvent
> ev(mDelayedEvents
[0].forget());
7307 mDelayedEvents
.RemoveElementAt(0);
7310 if (!doc
->EventHandlingSuppressed()) {
7311 mDelayedEvents
.Clear();
7317 ThawElement(nsIContent
*aContent
, void *aShell
)
7319 nsCOMPtr
<nsIObjectLoadingContent
> objlc(do_QueryInterface(aContent
));
7321 nsCOMPtr
<nsIPluginInstance
> inst
;
7322 objlc
->EnsureInstantiation(getter_AddRefs(inst
));
7327 ThawSubDocument(nsIDocument
*aDocument
, void *aData
)
7329 nsIPresShell
*shell
= aDocument
->GetShell();
7339 nsPresContext
* presContext
= GetPresContext();
7341 presContext
->RefreshDriver()->PresContext() == presContext
) {
7342 presContext
->RefreshDriver()->Thaw();
7345 mDocument
->EnumerateFreezableElements(ThawElement
, this);
7348 mDocument
->EnumerateSubDocuments(ThawSubDocument
, nsnull
);
7350 UnsuppressPainting();
7352 // Get the activeness of our presshell, as this might have changed
7353 // while we were in the bfcache
7356 // We're now unfrozen
7358 UpdateImageLockingState();
7361 //--------------------------------------------------------
7362 // Start of protected and private methods on the PresShell
7363 //--------------------------------------------------------
7366 PresShell::MaybeScheduleReflow()
7368 ASSERT_REFLOW_SCHEDULED_STATE();
7369 if (mReflowScheduled
|| mIsDestroying
|| mIsReflowing
||
7370 mDirtyRoots
.Length() == 0)
7373 if (!mPresContext
->HasPendingInterrupt() || !ScheduleReflowOffTimer()) {
7377 ASSERT_REFLOW_SCHEDULED_STATE();
7381 PresShell::ScheduleReflow()
7383 NS_PRECONDITION(!mReflowScheduled
, "Why are we trying to schedule a reflow?");
7384 ASSERT_REFLOW_SCHEDULED_STATE();
7386 if (GetPresContext()->RefreshDriver()->AddLayoutFlushObserver(this)) {
7387 mReflowScheduled
= PR_TRUE
;
7390 ASSERT_REFLOW_SCHEDULED_STATE();
7394 PresShell::DidCauseReflow()
7396 NS_ASSERTION(mChangeNestCount
!= 0, "Unexpected call to DidCauseReflow()");
7398 nsContentUtils::RemoveScriptBlocker();
7404 PresShell::WillDoReflow()
7406 // We just reflowed, tell the caret that its frame might have moved.
7407 // XXXbz that comment makes no sense
7409 mCaret
->InvalidateOutsideCaret();
7410 mCaret
->UpdateCaretPosition();
7413 mPresContext
->FlushUserFontSet();
7415 mFrameConstructor
->BeginUpdate();
7419 PresShell::DidDoReflow(PRBool aInterruptible
)
7421 mFrameConstructor
->EndUpdate();
7423 HandlePostedReflowCallbacks(aInterruptible
);
7424 // Null-check mViewManager in case this happens during Destroy. See
7425 // bugs 244435 and 238546.
7426 if (!mPaintingSuppressed
&& mViewManager
)
7427 mViewManager
->SynthesizeMouseMove(PR_FALSE
);
7429 // Update the caret's position now to account for any changes created by
7431 mCaret
->InvalidateOutsideCaret();
7432 mCaret
->UpdateCaretPosition();
7436 static PLDHashOperator
7437 MarkFramesDirtyToRoot(nsPtrHashKey
<nsIFrame
>* p
, void* closure
)
7439 nsIFrame
* target
= static_cast<nsIFrame
*>(closure
);
7440 for (nsIFrame
* f
= p
->GetKey(); f
&& !NS_SUBTREE_DIRTY(f
);
7441 f
= f
->GetParent()) {
7442 f
->AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN
);
7449 return PL_DHASH_NEXT
;
7453 PresShell::sReflowContinueCallback(nsITimer
* aTimer
, void* aPresShell
)
7455 nsRefPtr
<PresShell
> self
= static_cast<PresShell
*>(aPresShell
);
7457 NS_PRECONDITION(aTimer
== self
->mReflowContinueTimer
, "Unexpected timer");
7458 self
->mReflowContinueTimer
= nsnull
;
7459 self
->ScheduleReflow();
7463 PresShell::ScheduleReflowOffTimer()
7465 NS_PRECONDITION(!mReflowScheduled
, "Shouldn't get here");
7466 ASSERT_REFLOW_SCHEDULED_STATE();
7468 if (!mReflowContinueTimer
) {
7469 mReflowContinueTimer
= do_CreateInstance("@mozilla.org/timer;1");
7470 if (!mReflowContinueTimer
||
7471 NS_FAILED(mReflowContinueTimer
->
7472 InitWithFuncCallback(sReflowContinueCallback
, this, 30,
7473 nsITimer::TYPE_ONE_SHOT
))) {
7481 PresShell::DoReflow(nsIFrame
* target
, PRBool aInterruptible
)
7483 NS_TIME_FUNCTION_WITH_DOCURL
;
7485 if (mReflowContinueTimer
) {
7486 mReflowContinueTimer
->Cancel();
7487 mReflowContinueTimer
= nsnull
;
7490 nsIFrame
* rootFrame
= FrameManager()->GetRootFrame();
7492 nsCOMPtr
<nsIRenderingContext
> rcx
= GetReferenceRenderingContext();
7494 NS_NOTREACHED("CreateRenderingContext failure");
7499 mCurrentReflowRoot
= target
;
7502 target
->WillReflow(mPresContext
);
7504 // If the target frame is the root of the frame hierarchy, then
7505 // use all the available space. If it's simply a `reflow root',
7506 // then use the target frame's size as the available space.
7508 if (target
== rootFrame
) {
7509 size
= mPresContext
->GetVisibleArea().Size();
7511 // target->GetRect() has the old size of the frame,
7512 // mPresContext->GetVisibleArea() has the new size.
7513 target
->InvalidateRectDifference(mPresContext
->GetVisibleArea(),
7516 size
= target
->GetSize();
7519 NS_ASSERTION(!target
->GetNextInFlow() && !target
->GetPrevInFlow(),
7520 "reflow roots should never split");
7522 // Don't pass size directly to the reflow state, since a
7523 // constrained height implies page/column breaking.
7524 nsSize
reflowSize(size
.width
, NS_UNCONSTRAINEDSIZE
);
7525 nsHTMLReflowState
reflowState(mPresContext
, target
, rcx
, reflowSize
);
7527 // fix the computed height
7528 NS_ASSERTION(reflowState
.mComputedMargin
== nsMargin(0, 0, 0, 0),
7529 "reflow state should not set margin for reflow roots");
7530 if (size
.height
!= NS_UNCONSTRAINEDSIZE
) {
7531 nscoord computedHeight
=
7532 size
.height
- reflowState
.mComputedBorderPadding
.TopBottom();
7533 computedHeight
= NS_MAX(computedHeight
, 0);
7534 reflowState
.SetComputedHeight(computedHeight
);
7536 NS_ASSERTION(reflowState
.ComputedWidth() ==
7538 reflowState
.mComputedBorderPadding
.LeftRight(),
7539 "reflow state computed incorrect width");
7541 mPresContext
->ReflowStarted(aInterruptible
);
7542 mIsReflowing
= PR_TRUE
;
7544 nsReflowStatus status
;
7545 nsHTMLReflowMetrics desiredSize
;
7546 target
->Reflow(mPresContext
, desiredSize
, reflowState
, status
);
7548 // If an incremental reflow is initiated at a frame other than the
7549 // root frame, then its desired size had better not change! If it's
7550 // initiated at the root, then the size better not change unless its
7551 // height was unconstrained to start with.
7552 NS_ASSERTION((target
== rootFrame
&& size
.height
== NS_UNCONSTRAINEDSIZE
) ||
7553 (desiredSize
.width
== size
.width
&&
7554 desiredSize
.height
== size
.height
),
7555 "non-root frame's desired size changed during an "
7556 "incremental reflow");
7557 NS_ASSERTION(desiredSize
.mOverflowArea
==
7558 nsRect(nsPoint(0, 0),
7559 nsSize(desiredSize
.width
, desiredSize
.height
)),
7560 "reflow roots must not have visible overflow");
7561 NS_ASSERTION(status
== NS_FRAME_COMPLETE
,
7562 "reflow roots should never split");
7564 target
->SetSize(nsSize(desiredSize
.width
, desiredSize
.height
));
7566 nsContainerFrame::SyncFrameViewAfterReflow(mPresContext
, target
,
7568 &desiredSize
.mOverflowArea
);
7569 nsContainerFrame::SyncWindowProperties(mPresContext
, target
,
7572 target
->DidReflow(mPresContext
, nsnull
, NS_FRAME_REFLOW_FINISHED
);
7573 if (target
== rootFrame
&& size
.height
== NS_UNCONSTRAINEDSIZE
) {
7574 mPresContext
->SetVisibleArea(nsRect(0, 0, desiredSize
.width
,
7575 desiredSize
.height
));
7579 mCurrentReflowRoot
= nsnull
;
7582 NS_ASSERTION(mPresContext
->HasPendingInterrupt() ||
7583 mFramesToDirty
.Count() == 0,
7584 "Why do we need to dirty anything if not interrupted?");
7586 mIsReflowing
= PR_FALSE
;
7587 PRBool interrupted
= mPresContext
->HasPendingInterrupt();
7589 // Make sure target gets reflowed again.
7590 mFramesToDirty
.EnumerateEntries(&MarkFramesDirtyToRoot
, target
);
7591 NS_ASSERTION(NS_SUBTREE_DIRTY(target
), "Why is the target not dirty?");
7592 mDirtyRoots
.AppendElement(target
);
7594 // Clear mFramesToDirty after we've done the NS_SUBTREE_DIRTY(target)
7595 // assertion so that if it fails it's easier to see what's going on.
7596 #ifdef NOISY_INTERRUPTIBLE_REFLOW
7597 printf("mFramesToDirty.Count() == %u\n", mFramesToDirty
.Count());
7598 #endif /* NOISY_INTERRUPTIBLE_REFLOW */
7599 mFramesToDirty
.Clear();
7601 // Any FlushPendingNotifications with interruptible reflows
7602 // should be suppressed now. We don't want to do extra reflow work
7603 // before our reflow event happens.
7604 mSuppressInterruptibleReflows
= PR_TRUE
;
7605 MaybeScheduleReflow();
7608 nsRootPresContext
* rootPC
= mPresContext
->GetRootPresContext();
7610 rootPC
->RequestUpdatePluginGeometry(target
);
7613 return !interrupted
;
7618 PresShell::DoVerifyReflow()
7620 if (GetVerifyReflowEnable()) {
7621 // First synchronously render what we have so far so that we can
7624 mViewManager
->GetRootView(rootView
);
7625 mViewManager
->UpdateView(rootView
, NS_VMREFRESH_IMMEDIATE
);
7627 FlushPendingNotifications(Flush_Layout
);
7628 mInVerifyReflow
= PR_TRUE
;
7629 PRBool ok
= VerifyIncrementalReflow();
7630 mInVerifyReflow
= PR_FALSE
;
7631 if (VERIFY_REFLOW_ALL
& gVerifyReflowFlags
) {
7632 printf("ProcessReflowCommands: finished (%s)\n",
7633 ok
? "ok" : "failed");
7636 if (0 != mDirtyRoots
.Length()) {
7637 printf("XXX yikes! reflow commands queued during verify-reflow\n");
7644 PresShell::ProcessReflowCommands(PRBool aInterruptible
)
7646 NS_TIME_FUNCTION_WITH_DOCURL
;
7648 PRBool interrupted
= PR_FALSE
;
7649 if (0 != mDirtyRoots
.Length()) {
7652 if (VERIFY_REFLOW_DUMP_COMMANDS
& gVerifyReflowFlags
) {
7653 printf("ProcessReflowCommands: begin incremental reflow\n");
7657 // If reflow is interruptible, then make a note of our deadline.
7658 const PRIntervalTime deadline
= aInterruptible
7659 ? PR_IntervalNow() + PR_MicrosecondsToInterval(gMaxRCProcessingTime
)
7660 : (PRIntervalTime
)0;
7662 // Scope for the reflow entry point
7664 nsAutoScriptBlocker scriptBlocker
;
7666 AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Reflow
);
7669 // Send an incremental reflow notification to the target frame.
7670 PRInt32 idx
= mDirtyRoots
.Length() - 1;
7671 nsIFrame
*target
= mDirtyRoots
[idx
];
7672 mDirtyRoots
.RemoveElementAt(idx
);
7674 if (!NS_SUBTREE_DIRTY(target
)) {
7675 // It's not dirty anymore, which probably means the notification
7676 // was posted in the middle of a reflow (perhaps with a reflow
7677 // root in the middle). Don't do anything.
7681 interrupted
= !DoReflow(target
, aInterruptible
);
7683 // Keep going until we're out of reflow commands, or we've run
7684 // past our deadline, or we're interrupted.
7685 } while (!interrupted
&& mDirtyRoots
.Length() &&
7686 (!aInterruptible
|| PR_IntervalNow() < deadline
));
7688 interrupted
= mDirtyRoots
.Length() != 0;
7691 // Exiting the scriptblocker might have killed us
7692 if (!mIsDestroying
) {
7693 DidDoReflow(aInterruptible
);
7696 // DidDoReflow might have killed us
7697 if (!mIsDestroying
) {
7699 if (VERIFY_REFLOW_DUMP_COMMANDS
& gVerifyReflowFlags
) {
7700 printf("\nPresShell::ProcessReflowCommands() finished: this=%p\n",
7706 // If any new reflow commands were enqueued during the reflow, schedule
7707 // another reflow event to process them. Note that we want to do this
7708 // after DidDoReflow(), since that method can change whether there are
7709 // dirty roots around by flushing, and there's no point in posting a
7710 // reflow event just to have the flush revoke it.
7711 if (mDirtyRoots
.Length())
7712 MaybeScheduleReflow();
7716 if (!mIsDestroying
&& mShouldUnsuppressPainting
&&
7717 mDirtyRoots
.Length() == 0) {
7718 // We only unlock if we're out of reflows. It's pointless
7719 // to unlock if reflows are still pending, since reflows
7720 // are just going to thrash the frames around some more. By
7721 // waiting we avoid an overeager "jitter" effect.
7722 mShouldUnsuppressPainting
= PR_FALSE
;
7723 UnsuppressAndInvalidate();
7726 return !interrupted
;
7731 * It's better to add stuff to the |DidSetStyleContext| method of the
7732 * relevant frames than adding it here. These methods should (ideally,
7736 // Return value says whether to walk children.
7737 typedef PRBool (* frameWalkerFn
)(nsIFrame
*aFrame
, void *aClosure
);
7740 ReResolveMenusAndTrees(nsIFrame
*aFrame
, void *aClosure
)
7742 // Trees have a special style cache that needs to be flushed when
7743 // the theme changes.
7744 nsTreeBodyFrame
*treeBody
= do_QueryFrame(aFrame
);
7746 treeBody
->ClearStyleAndImageCaches();
7748 // We deliberately don't re-resolve style on a menu's popup
7749 // sub-content, since doing so slows menus to a crawl. That means we
7750 // have to special-case them on a skin switch, and ensure that the
7751 // popup frames just get destroyed completely.
7752 if (aFrame
&& aFrame
->GetType() == nsGkAtoms::menuFrame
)
7753 (static_cast<nsMenuFrame
*>(aFrame
))->CloseMenu(PR_TRUE
);
7758 ReframeImageBoxes(nsIFrame
*aFrame
, void *aClosure
)
7760 nsStyleChangeList
*list
= static_cast<nsStyleChangeList
*>(aClosure
);
7761 if (aFrame
->GetType() == nsGkAtoms::imageBoxFrame
) {
7762 list
->AppendChange(aFrame
, aFrame
->GetContent(),
7763 NS_STYLE_HINT_FRAMECHANGE
);
7764 return PR_FALSE
; // don't walk descendants
7766 return PR_TRUE
; // walk descendants
7770 WalkFramesThroughPlaceholders(nsPresContext
*aPresContext
, nsIFrame
*aFrame
,
7771 frameWalkerFn aFunc
, void *aClosure
)
7773 PRBool walkChildren
= (*aFunc
)(aFrame
, aClosure
);
7777 PRInt32 listIndex
= 0;
7778 nsIAtom
* childList
= nsnull
;
7781 nsIFrame
*child
= aFrame
->GetFirstChild(childList
);
7783 if (!(child
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
)) {
7784 // only do frames that are in flow, and recur through the
7785 // out-of-flows of placeholders.
7786 WalkFramesThroughPlaceholders(aPresContext
,
7787 nsPlaceholderFrame::GetRealFrameFor(child
),
7790 child
= child
->GetNextSibling();
7793 childList
= aFrame
->GetAdditionalChildListName(listIndex
++);
7794 } while (childList
);
7799 PresShell::Observe(nsISupports
* aSubject
,
7801 const PRUnichar
* aData
)
7804 if (!nsCRT::strcmp(aTopic
, "chrome-flush-skin-caches")) {
7805 nsIFrame
*rootFrame
= FrameManager()->GetRootFrame();
7806 // Need to null-check because "chrome-flush-skin-caches" can happen
7807 // at interesting times during startup.
7809 NS_ASSERTION(mViewManager
, "View manager must exist");
7810 nsIViewManager::UpdateViewBatch
batch(mViewManager
);
7812 nsWeakFrame
weakRoot(rootFrame
);
7813 // Have to make sure that the content notifications are flushed before we
7814 // start messing with the frame model; otherwise we can get content doubling.
7815 mDocument
->FlushPendingNotifications(Flush_ContentAndNotify
);
7817 if (weakRoot
.IsAlive()) {
7818 WalkFramesThroughPlaceholders(mPresContext
, rootFrame
,
7819 &ReResolveMenusAndTrees
, nsnull
);
7821 // Because "chrome:" URL equality is messy, reframe image box
7823 nsStyleChangeList changeList
;
7824 WalkFramesThroughPlaceholders(mPresContext
, rootFrame
,
7825 ReframeImageBoxes
, &changeList
);
7826 // Mark ourselves as not safe to flush while we're doing frame
7829 nsAutoScriptBlocker scriptBlocker
;
7831 mFrameConstructor
->ProcessRestyledFrames(changeList
);
7835 batch
.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC
);
7836 #ifdef ACCESSIBILITY
7837 InvalidateAccessibleSubtree(nsnull
);
7844 if (!nsCRT::strcmp(aTopic
, "agent-sheet-added") && mStyleSet
) {
7845 AddAgentSheet(aSubject
);
7849 if (!nsCRT::strcmp(aTopic
, "user-sheet-added") && mStyleSet
) {
7850 AddUserSheet(aSubject
);
7854 if (!nsCRT::strcmp(aTopic
, "agent-sheet-removed") && mStyleSet
) {
7855 RemoveSheet(nsStyleSet::eAgentSheet
, aSubject
);
7859 if (!nsCRT::strcmp(aTopic
, "user-sheet-removed") && mStyleSet
) {
7860 RemoveSheet(nsStyleSet::eUserSheet
, aSubject
);
7864 #ifdef ACCESSIBILITY
7865 if (!nsCRT::strcmp(aTopic
, "a11y-init-or-shutdown")) {
7866 gIsAccessibilityActive
= aData
&& *aData
== '1';
7869 NS_WARNING("unrecognized topic in PresShell::Observe");
7870 return NS_ERROR_FAILURE
;
7874 nsIPresShell::AddRefreshObserverInternal(nsARefreshObserver
* aObserver
,
7875 mozFlushType aFlushType
)
7877 return GetPresContext()->RefreshDriver()->
7878 AddRefreshObserver(aObserver
, aFlushType
);
7881 /* virtual */ PRBool
7882 nsIPresShell::AddRefreshObserverExternal(nsARefreshObserver
* aObserver
,
7883 mozFlushType aFlushType
)
7885 return AddRefreshObserverInternal(aObserver
, aFlushType
);
7889 nsIPresShell::RemoveRefreshObserverInternal(nsARefreshObserver
* aObserver
,
7890 mozFlushType aFlushType
)
7892 return GetPresContext()->RefreshDriver()->
7893 RemoveRefreshObserver(aObserver
, aFlushType
);
7896 /* virtual */ PRBool
7897 nsIPresShell::RemoveRefreshObserverExternal(nsARefreshObserver
* aObserver
,
7898 mozFlushType aFlushType
)
7900 return RemoveRefreshObserverInternal(aObserver
, aFlushType
);
7903 //------------------------------------------------------
7904 // End of protected and private methods on the PresShell
7905 //------------------------------------------------------
7907 // Start of DEBUG only code
7910 #include "nsViewsCID.h"
7911 #include "nsWidgetsCID.h"
7912 #include "nsIDeviceContext.h"
7914 #include "nsILinkHandler.h"
7916 static NS_DEFINE_CID(kViewManagerCID
, NS_VIEW_MANAGER_CID
);
7919 LogVerifyMessage(nsIFrame
* k1
, nsIFrame
* k2
, const char* aMsg
)
7921 nsAutoString n1
, n2
;
7923 k1
->GetFrameName(n1
);
7925 n1
.Assign(NS_LITERAL_STRING("(null)"));
7929 k2
->GetFrameName(n2
);
7931 n2
.Assign(NS_LITERAL_STRING("(null)"));
7934 printf("verifyreflow: %s %p != %s %p %s\n",
7935 NS_LossyConvertUTF16toASCII(n1
).get(), (void*)k1
,
7936 NS_LossyConvertUTF16toASCII(n2
).get(), (void*)k2
, aMsg
);
7940 LogVerifyMessage(nsIFrame
* k1
, nsIFrame
* k2
, const char* aMsg
,
7941 const nsRect
& r1
, const nsRect
& r2
)
7943 printf("VerifyReflow Error:\n");
7947 k1
->GetFrameName(name
);
7948 printf(" %s %p ", NS_LossyConvertUTF16toASCII(name
).get(), (void*)k1
);
7950 printf("{%d, %d, %d, %d} != \n", r1
.x
, r1
.y
, r1
.width
, r1
.height
);
7953 k2
->GetFrameName(name
);
7954 printf(" %s %p ", NS_LossyConvertUTF16toASCII(name
).get(), (void*)k2
);
7956 printf("{%d, %d, %d, %d}\n %s\n",
7957 r2
.x
, r2
.y
, r2
.width
, r2
.height
, aMsg
);
7961 LogVerifyMessage(nsIFrame
* k1
, nsIFrame
* k2
, const char* aMsg
,
7962 const nsIntRect
& r1
, const nsIntRect
& r2
)
7964 printf("VerifyReflow Error:\n");
7968 k1
->GetFrameName(name
);
7969 printf(" %s %p ", NS_LossyConvertUTF16toASCII(name
).get(), (void*)k1
);
7971 printf("{%d, %d, %d, %d} != \n", r1
.x
, r1
.y
, r1
.width
, r1
.height
);
7974 k2
->GetFrameName(name
);
7975 printf(" %s %p ", NS_LossyConvertUTF16toASCII(name
).get(), (void*)k2
);
7977 printf("{%d, %d, %d, %d}\n %s\n",
7978 r2
.x
, r2
.y
, r2
.width
, r2
.height
, aMsg
);
7982 CompareTrees(nsPresContext
* aFirstPresContext
, nsIFrame
* aFirstFrame
,
7983 nsPresContext
* aSecondPresContext
, nsIFrame
* aSecondFrame
)
7985 if (!aFirstPresContext
|| !aFirstFrame
|| !aSecondPresContext
|| !aSecondFrame
)
7987 // XXX Evil hack to reduce false positives; I can't seem to figure
7988 // out how to flush scrollbar changes correctly
7989 //if (aFirstFrame->GetType() == nsGkAtoms::scrollbarFrame)
7991 PRBool ok
= PR_TRUE
;
7992 nsIAtom
* listName
= nsnull
;
7993 PRInt32 listIndex
= 0;
7995 const nsFrameList
& kids1
= aFirstFrame
->GetChildList(listName
);
7996 const nsFrameList
& kids2
= aSecondFrame
->GetChildList(listName
);
7997 PRInt32 l1
= kids1
.GetLength();
7998 PRInt32 l2
= kids2
.GetLength();;
8001 LogVerifyMessage(kids1
.FirstChild(), kids2
.FirstChild(),
8002 "child counts don't match: ");
8003 printf("%d != %d\n", l1
, l2
);
8004 if (0 == (VERIFY_REFLOW_ALL
& gVerifyReflowFlags
)) {
8011 for (nsFrameList::Enumerator
e1(kids1
), e2(kids2
);
8013 e1
.Next(), e2
.Next()) {
8014 nsIFrame
* k1
= e1
.get();
8015 nsIFrame
* k2
= e2
.get();
8016 if (((nsnull
== k1
) && (nsnull
!= k2
)) ||
8017 ((nsnull
!= k1
) && (nsnull
== k2
))) {
8019 LogVerifyMessage(k1
, k2
, "child lists are different\n");
8022 else if (nsnull
!= k1
) {
8023 // Verify that the frames are the same size
8024 if (k1
->GetRect() != k2
->GetRect()) {
8026 LogVerifyMessage(k1
, k2
, "(frame rects)", k1
->GetRect(), k2
->GetRect());
8029 // Make sure either both have views or neither have views; if they
8030 // do have views, make sure the views are the same size. If the
8031 // views have widgets, make sure they both do or neither does. If
8032 // they do, make sure the widgets are the same size.
8035 if (((nsnull
== v1
) && (nsnull
!= v2
)) ||
8036 ((nsnull
!= v1
) && (nsnull
== v2
))) {
8038 LogVerifyMessage(k1
, k2
, "child views are not matched\n");
8040 else if (nsnull
!= v1
) {
8041 if (v1
->GetBounds() != v2
->GetBounds()) {
8042 LogVerifyMessage(k1
, k2
, "(view rects)", v1
->GetBounds(), v2
->GetBounds());
8045 nsIWidget
* w1
= v1
->GetWidget();
8046 nsIWidget
* w2
= v2
->GetWidget();
8047 if (((nsnull
== w1
) && (nsnull
!= w2
)) ||
8048 ((nsnull
!= w1
) && (nsnull
== w2
))) {
8050 LogVerifyMessage(k1
, k2
, "child widgets are not matched\n");
8052 else if (nsnull
!= w1
) {
8056 LogVerifyMessage(k1
, k2
, "(widget rects)", r1
, r2
);
8060 if (!ok
&& (0 == (VERIFY_REFLOW_ALL
& gVerifyReflowFlags
))) {
8064 // XXX Should perhaps compare their float managers.
8066 // Compare the sub-trees too
8067 if (!CompareTrees(aFirstPresContext
, k1
, aSecondPresContext
, k2
)) {
8069 if (0 == (VERIFY_REFLOW_ALL
& gVerifyReflowFlags
)) {
8078 if (!ok
&& (0 == (VERIFY_REFLOW_ALL
& gVerifyReflowFlags
))) {
8082 nsIAtom
* listName1
= aFirstFrame
->GetAdditionalChildListName(listIndex
);
8083 nsIAtom
* listName2
= aSecondFrame
->GetAdditionalChildListName(listIndex
);
8085 if (listName1
!= listName2
) {
8086 if (0 == (VERIFY_REFLOW_ALL
& gVerifyReflowFlags
)) {
8089 LogVerifyMessage(kids1
.FirstChild(), kids2
.FirstChild(),
8090 "child list names are not matched: ");
8092 if (nsnull
!= listName1
) {
8093 listName1
->ToString(tmp
);
8094 fputs(NS_LossyConvertUTF16toASCII(tmp
).get(), stdout
);
8097 fputs("(null)", stdout
);
8099 if (nsnull
!= listName2
) {
8100 listName2
->ToString(tmp
);
8101 fputs(NS_LossyConvertUTF16toASCII(tmp
).get(), stdout
);
8104 fputs("(null)", stdout
);
8108 listName
= listName1
;
8109 } while (ok
&& (listName
!= nsnull
));
8117 FindTopFrame(nsIFrame
* aRoot
)
8120 nsIContent
* content
= aRoot
->GetContent();
8123 content
->GetTag(tag
);
8124 if (nsnull
!= tag
) {
8130 // Try one of the children
8131 nsIFrame
* kid
= aRoot
->GetFirstChild(nsnull
);
8132 while (nsnull
!= kid
) {
8133 nsIFrame
* result
= FindTopFrame(kid
);
8134 if (nsnull
!= result
) {
8137 kid
= kid
->GetNextSibling();
8148 PresShell::CloneStyleSet(nsStyleSet
* aSet
, nsStyleSet
** aResult
)
8150 nsStyleSet
*clone
= new nsStyleSet();
8152 return NS_ERROR_OUT_OF_MEMORY
;
8155 PRInt32 i
, n
= aSet
->SheetCount(nsStyleSet::eOverrideSheet
);
8156 for (i
= 0; i
< n
; i
++) {
8157 nsIStyleSheet
* ss
= aSet
->StyleSheetAt(nsStyleSet::eOverrideSheet
, i
);
8159 clone
->AppendStyleSheet(nsStyleSet::eOverrideSheet
, ss
);
8162 // The document expects to insert document stylesheets itself
8164 n
= aSet
->SheetCount(nsStyleSet::eDocSheet
);
8165 for (i
= 0; i
< n
; i
++) {
8166 nsIStyleSheet
* ss
= aSet
->StyleSheetAt(nsStyleSet::eDocSheet
, i
);
8168 clone
->AddDocStyleSheet(ss
, mDocument
);
8172 n
= aSet
->SheetCount(nsStyleSet::eUserSheet
);
8173 for (i
= 0; i
< n
; i
++) {
8174 nsIStyleSheet
* ss
= aSet
->StyleSheetAt(nsStyleSet::eUserSheet
, i
);
8176 clone
->AppendStyleSheet(nsStyleSet::eUserSheet
, ss
);
8179 n
= aSet
->SheetCount(nsStyleSet::eAgentSheet
);
8180 for (i
= 0; i
< n
; i
++) {
8181 nsIStyleSheet
* ss
= aSet
->StyleSheetAt(nsStyleSet::eAgentSheet
, i
);
8183 clone
->AppendStyleSheet(nsStyleSet::eAgentSheet
, ss
);
8191 DumpToPNG(nsIPresShell
* shell
, nsAString
& name
) {
8192 PRInt32 width
=1000, height
=1000;
8193 nsRect
r(0, 0, shell
->GetPresContext()->DevPixelsToAppUnits(width
),
8194 shell
->GetPresContext()->DevPixelsToAppUnits(height
));
8196 nsRefPtr
<gfxImageSurface
> imgSurface
=
8197 new gfxImageSurface(gfxIntSize(width
, height
),
8198 gfxImageSurface::ImageFormatARGB32
);
8199 NS_ENSURE_TRUE(imgSurface
, NS_ERROR_OUT_OF_MEMORY
);
8201 nsRefPtr
<gfxContext
> imgContext
= new gfxContext(imgSurface
);
8203 nsRefPtr
<gfxASurface
> surface
=
8204 gfxPlatform::GetPlatform()->
8205 CreateOffscreenSurface(gfxIntSize(width
, height
),
8206 gfxASurface::ImageFormatARGB32
);
8207 NS_ENSURE_TRUE(surface
, NS_ERROR_OUT_OF_MEMORY
);
8209 nsRefPtr
<gfxContext
> context
= new gfxContext(surface
);
8210 NS_ENSURE_TRUE(context
, NS_ERROR_OUT_OF_MEMORY
);
8212 shell
->RenderDocument(r
, 0, NS_RGB(255, 255, 0), context
);
8214 imgContext
->DrawSurface(surface
, gfxSize(width
, height
));
8216 nsCOMPtr
<imgIEncoder
> encoder
= do_CreateInstance("@mozilla.org/image/encoder;2?type=image/png");
8217 NS_ENSURE_TRUE(encoder
, NS_ERROR_FAILURE
);
8218 encoder
->InitFromData(imgSurface
->Data(), imgSurface
->Stride() * height
,
8219 width
, height
, imgSurface
->Stride(),
8220 imgIEncoder::INPUT_FORMAT_HOSTARGB
, EmptyString());
8222 // XXX not sure if this is the right way to write to a file
8223 nsCOMPtr
<nsILocalFile
> file
= do_CreateInstance("@mozilla.org/file/local;1");
8224 NS_ENSURE_TRUE(file
, NS_ERROR_FAILURE
);
8225 rv
= file
->InitWithPath(name
);
8226 NS_ENSURE_SUCCESS(rv
, rv
);
8229 encoder
->Available(&length
);
8231 nsCOMPtr
<nsIOutputStream
> outputStream
;
8232 rv
= NS_NewLocalFileOutputStream(getter_AddRefs(outputStream
), file
);
8233 NS_ENSURE_SUCCESS(rv
, rv
);
8235 nsCOMPtr
<nsIOutputStream
> bufferedOutputStream
;
8236 rv
= NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream
),
8237 outputStream
, length
);
8239 PRUint32 numWritten
;
8240 rv
= bufferedOutputStream
->WriteFrom(encoder
, length
, &numWritten
);
8241 NS_ENSURE_SUCCESS(rv
, rv
);
8247 // After an incremental reflow, we verify the correctness by doing a
8248 // full reflow into a fresh frame tree.
8250 PresShell::VerifyIncrementalReflow()
8252 if (VERIFY_REFLOW_NOISY
& gVerifyReflowFlags
) {
8253 printf("Building Verification Tree...\n");
8256 // Create a presentation context to view the new frame tree
8257 nsRefPtr
<nsPresContext
> cx
=
8258 new nsRootPresContext(mDocument
, mPresContext
->IsPaginated() ?
8259 nsPresContext::eContext_PrintPreview
:
8260 nsPresContext::eContext_Galley
);
8261 NS_ENSURE_TRUE(cx
, PR_FALSE
);
8263 nsIDeviceContext
*dc
= mPresContext
->DeviceContext();
8264 nsresult rv
= cx
->Init(dc
);
8265 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
8267 // Get our scrolling preference
8269 mViewManager
->GetRootView(rootView
);
8270 NS_ENSURE_TRUE(rootView
->HasWidget(), PR_FALSE
);
8271 nsIWidget
* parentWidget
= rootView
->GetWidget();
8273 // Create a new view manager.
8274 nsCOMPtr
<nsIViewManager
> vm
= do_CreateInstance(kViewManagerCID
);
8275 NS_ENSURE_TRUE(vm
, PR_FALSE
);
8277 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
8279 // Create a child window of the parent that is our "root view/window"
8281 nsRect tbounds
= mPresContext
->GetVisibleArea();
8282 nsIView
* view
= vm
->CreateView(tbounds
, nsnull
);
8283 NS_ENSURE_TRUE(view
, PR_FALSE
);
8285 //now create the widget for the view
8286 rv
= view
->CreateWidgetForParent(parentWidget
, nsnull
, PR_TRUE
);
8287 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
8289 // Setup hierarchical relationship in view manager
8290 vm
->SetRootView(view
);
8292 // Make the new presentation context the same size as our
8293 // presentation context.
8294 nsRect r
= mPresContext
->GetVisibleArea();
8295 cx
->SetVisibleArea(r
);
8297 // Create a new presentation shell to view the document. Use the
8298 // exact same style information that this document has.
8299 nsAutoPtr
<nsStyleSet
> newSet
;
8300 rv
= CloneStyleSet(mStyleSet
, getter_Transfers(newSet
));
8301 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
8302 nsCOMPtr
<nsIPresShell
> sh
;
8303 rv
= mDocument
->CreateShell(cx
, vm
, newSet
, getter_AddRefs(sh
));
8304 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
8306 // Note that after we create the shell, we must make sure to destroy it
8307 sh
->SetVerifyReflowEnable(PR_FALSE
); // turn off verify reflow while we're reflowing the test frame tree
8308 vm
->SetViewObserver((nsIViewObserver
*)((PresShell
*)sh
.get()));
8310 nsAutoCauseReflowNotifier
crNotifier(this);
8311 sh
->InitialReflow(r
.width
, r
.height
);
8313 mDocument
->BindingManager()->ProcessAttachedQueue();
8314 sh
->FlushPendingNotifications(Flush_Layout
);
8315 sh
->SetVerifyReflowEnable(PR_TRUE
); // turn on verify reflow again now that we're done reflowing the test frame tree
8316 // Force the non-primary presshell to unsuppress; it doesn't want to normally
8317 // because it thinks it's hidden
8318 ((PresShell
*)sh
.get())->mPaintingSuppressed
= PR_FALSE
;
8319 if (VERIFY_REFLOW_NOISY
& gVerifyReflowFlags
) {
8320 printf("Verification Tree built, comparing...\n");
8323 // Now that the document has been reflowed, use its frame tree to
8324 // compare against our frame tree.
8325 nsIFrame
* root1
= FrameManager()->GetRootFrame();
8326 nsIFrame
* root2
= sh
->FrameManager()->GetRootFrame();
8327 PRBool ok
= CompareTrees(mPresContext
, root1
, cx
, root2
);
8328 if (!ok
&& (VERIFY_REFLOW_NOISY
& gVerifyReflowFlags
)) {
8329 printf("Verify reflow failed, primary tree:\n");
8330 root1
->List(stdout
, 0);
8331 printf("Verification tree:\n");
8332 root2
->List(stdout
, 0);
8336 // Sample code for dumping page to png
8337 // XXX Needs to be made more flexible
8341 stra
.AppendLiteral("C:\\mozilla\\mozilla\\debug\\filea");
8342 stra
.AppendInt(num
);
8343 stra
.AppendLiteral(".png");
8344 DumpToPNG(sh
, stra
);
8346 strb
.AppendLiteral("C:\\mozilla\\mozilla\\debug\\fileb");
8347 strb
.AppendInt(num
);
8348 strb
.AppendLiteral(".png");
8349 DumpToPNG(this, strb
);
8354 sh
->EndObservingDocument();
8356 if (VERIFY_REFLOW_NOISY
& gVerifyReflowFlags
) {
8357 printf("Finished Verifying Reflow...\n");
8363 // Layout debugging hooks
8365 PresShell::ListStyleContexts(nsIFrame
*aRootFrame
, FILE *out
, PRInt32 aIndent
)
8367 nsStyleContext
*sc
= aRootFrame
->GetStyleContext();
8369 sc
->List(out
, aIndent
);
8373 PresShell::ListStyleSheets(FILE *out
, PRInt32 aIndent
)
8375 PRInt32 sheetCount
= mStyleSet
->SheetCount(nsStyleSet::eDocSheet
);
8376 for (PRInt32 i
= 0; i
< sheetCount
; ++i
) {
8377 mStyleSet
->StyleSheetAt(nsStyleSet::eDocSheet
, i
)->List(out
, aIndent
);
8383 PresShell::VerifyStyleTree()
8389 //=============================================================
8390 //=============================================================
8391 //-- Debug Reflow Counts
8392 //=============================================================
8393 //=============================================================
8394 #ifdef MOZ_REFLOW_PERF
8395 //-------------------------------------------------------------
8397 PresShell::DumpReflows()
8399 if (mReflowCountMgr
) {
8400 nsCAutoString uriStr
;
8402 nsIURI
*uri
= mDocument
->GetDocumentURI();
8404 uri
->GetPath(uriStr
);
8407 mReflowCountMgr
->DisplayTotals(uriStr
.get());
8408 mReflowCountMgr
->DisplayHTMLTotals(uriStr
.get());
8409 mReflowCountMgr
->DisplayDiffsInTotals("Differences");
8413 //-------------------------------------------------------------
8415 PresShell::CountReflows(const char * aName
, nsIFrame
* aFrame
)
8417 if (mReflowCountMgr
) {
8418 mReflowCountMgr
->Add(aName
, aFrame
);
8422 //-------------------------------------------------------------
8424 PresShell::PaintCount(const char * aName
,
8425 nsIRenderingContext
* aRenderingContext
,
8426 nsPresContext
* aPresContext
,
8430 if (mReflowCountMgr
) {
8431 mReflowCountMgr
->PaintCount(aName
, aRenderingContext
, aPresContext
, aFrame
, aColor
);
8435 //-------------------------------------------------------------
8437 PresShell::SetPaintFrameCount(PRBool aPaintFrameCounts
)
8439 if (mReflowCountMgr
) {
8440 mReflowCountMgr
->SetPaintFrameCounts(aPaintFrameCounts
);
8445 PresShell::IsPaintingFrameCounts()
8447 if (mReflowCountMgr
)
8448 return mReflowCountMgr
->IsPaintingFrameCounts();
8452 //------------------------------------------------------------------
8453 //-- Reflow Counter Classes Impls
8454 //------------------------------------------------------------------
8456 //------------------------------------------------------------------
8457 ReflowCounter::ReflowCounter(ReflowCountMgr
* aMgr
) :
8464 //------------------------------------------------------------------
8465 ReflowCounter::~ReflowCounter()
8470 //------------------------------------------------------------------
8471 void ReflowCounter::ClearTotals()
8476 //------------------------------------------------------------------
8477 void ReflowCounter::SetTotalsCache()
8479 mCacheTotal
= mTotal
;
8482 //------------------------------------------------------------------
8483 void ReflowCounter::CalcDiffInTotals()
8485 mCacheTotal
= mTotal
- mCacheTotal
;
8488 //------------------------------------------------------------------
8489 void ReflowCounter::DisplayTotals(const char * aStr
)
8491 DisplayTotals(mTotal
, aStr
?aStr
:"Totals");
8494 //------------------------------------------------------------------
8495 void ReflowCounter::DisplayDiffTotals(const char * aStr
)
8497 DisplayTotals(mCacheTotal
, aStr
?aStr
:"Diff Totals");
8500 //------------------------------------------------------------------
8501 void ReflowCounter::DisplayHTMLTotals(const char * aStr
)
8503 DisplayHTMLTotals(mTotal
, aStr
?aStr
:"Totals");
8506 //------------------------------------------------------------------
8507 void ReflowCounter::DisplayTotals(PRUint32 aTotal
, const char * aTitle
)
8513 ReflowCounter
* gTots
= (ReflowCounter
*)mMgr
->LookUp(kGrandTotalsStr
);
8515 printf("%25s\t", aTitle
);
8516 printf("%d\t", aTotal
);
8517 if (gTots
!= this && aTotal
> 0) {
8522 //------------------------------------------------------------------
8523 void ReflowCounter::DisplayHTMLTotals(PRUint32 aTotal
, const char * aTitle
)
8529 ReflowCounter
* gTots
= (ReflowCounter
*)mMgr
->LookUp(kGrandTotalsStr
);
8530 FILE * fd
= mMgr
->GetOutFile();
8535 fprintf(fd
, "<tr><td><center>%s</center></td>", aTitle
);
8536 fprintf(fd
, "<td><center>%d</center></td></tr>\n", aTotal
);
8538 if (gTots
!= this && aTotal
> 0) {
8543 //------------------------------------------------------------------
8545 //------------------------------------------------------------------
8546 ReflowCountMgr::ReflowCountMgr()
8548 mCounts
= PL_NewHashTable(10, PL_HashString
, PL_CompareStrings
,
8549 PL_CompareValues
, nsnull
, nsnull
);
8550 mIndiFrameCounts
= PL_NewHashTable(10, PL_HashString
, PL_CompareStrings
,
8551 PL_CompareValues
, nsnull
, nsnull
);
8552 mCycledOnce
= PR_FALSE
;
8553 mDumpFrameCounts
= PR_FALSE
;
8554 mDumpFrameByFrameCounts
= PR_FALSE
;
8555 mPaintFrameByFrameCounts
= PR_FALSE
;
8558 //------------------------------------------------------------------
8559 ReflowCountMgr::~ReflowCountMgr()
8564 //------------------------------------------------------------------
8565 ReflowCounter
* ReflowCountMgr::LookUp(const char * aName
)
8567 if (nsnull
!= mCounts
) {
8568 ReflowCounter
* counter
= (ReflowCounter
*)PL_HashTableLookup(mCounts
, aName
);
8575 //------------------------------------------------------------------
8576 void ReflowCountMgr::Add(const char * aName
, nsIFrame
* aFrame
)
8578 NS_ASSERTION(aName
!= nsnull
, "Name shouldn't be null!");
8580 if (mDumpFrameCounts
&& nsnull
!= mCounts
) {
8581 ReflowCounter
* counter
= (ReflowCounter
*)PL_HashTableLookup(mCounts
, aName
);
8582 if (counter
== nsnull
) {
8583 counter
= new ReflowCounter(this);
8584 NS_ASSERTION(counter
!= nsnull
, "null ptr");
8585 char * name
= NS_strdup(aName
);
8586 NS_ASSERTION(name
!= nsnull
, "null ptr");
8587 PL_HashTableAdd(mCounts
, name
, counter
);
8592 if ((mDumpFrameByFrameCounts
|| mPaintFrameByFrameCounts
) &&
8593 nsnull
!= mIndiFrameCounts
&&
8595 char * key
= new char[16];
8596 sprintf(key
, "%p", (void*)aFrame
);
8597 IndiReflowCounter
* counter
= (IndiReflowCounter
*)PL_HashTableLookup(mIndiFrameCounts
, key
);
8598 if (counter
== nsnull
) {
8599 counter
= new IndiReflowCounter(this);
8600 NS_ASSERTION(counter
!= nsnull
, "null ptr");
8601 counter
->mFrame
= aFrame
;
8602 counter
->mName
.AssignASCII(aName
);
8603 PL_HashTableAdd(mIndiFrameCounts
, key
, counter
);
8605 // this eliminates extra counts from super classes
8606 if (counter
!= nsnull
&& counter
->mName
.EqualsASCII(aName
)) {
8608 counter
->mCounter
.Add(1);
8613 //------------------------------------------------------------------
8614 void ReflowCountMgr::PaintCount(const char * aName
,
8615 nsIRenderingContext
* aRenderingContext
,
8616 nsPresContext
* aPresContext
,
8620 if (mPaintFrameByFrameCounts
&&
8621 nsnull
!= mIndiFrameCounts
&&
8623 char * key
= new char[16];
8624 sprintf(key
, "%p", (void*)aFrame
);
8625 IndiReflowCounter
* counter
= (IndiReflowCounter
*)PL_HashTableLookup(mIndiFrameCounts
, key
);
8626 if (counter
!= nsnull
&& counter
->mName
.EqualsASCII(aName
)) {
8627 aRenderingContext
->PushState();
8628 nsFont
font("Times", NS_FONT_STYLE_NORMAL
, NS_FONT_VARIANT_NORMAL
,
8629 NS_FONT_WEIGHT_NORMAL
, NS_FONT_STRETCH_NORMAL
, 0,
8630 nsPresContext::CSSPixelsToAppUnits(11));
8632 nsCOMPtr
<nsIFontMetrics
> fm
= aPresContext
->GetMetricsFor(font
);
8633 aRenderingContext
->SetFont(fm
);
8635 sprintf(buf
, "%d", counter
->mCount
);
8637 nscoord width
, height
;
8638 aRenderingContext
->SetTextRunRTL(PR_FALSE
);
8639 aRenderingContext
->GetWidth((char*)buf
, width
);
8640 fm
->GetHeight(height
);
8641 fm
->GetMaxAscent(y
);
8647 color2
= NS_RGB(0,0,0);
8649 PRUint8 rc
= 0, gc
= 0, bc
= 0;
8650 if (counter
->mCount
< 5) {
8653 } else if ( counter
->mCount
< 11) {
8658 color
= NS_RGB(rc
,gc
,bc
);
8659 color2
= NS_RGB(rc
/2,gc
/2,bc
/2);
8662 nsRect
rect(0,0, width
+15, height
+15);
8663 aRenderingContext
->SetColor(NS_RGB(0,0,0));
8664 aRenderingContext
->FillRect(rect
);
8665 aRenderingContext
->SetColor(color2
);
8666 aRenderingContext
->DrawString(buf
, strlen(buf
), x
+15,y
+15);
8667 aRenderingContext
->SetColor(color
);
8668 aRenderingContext
->DrawString(buf
, strlen(buf
), x
,y
);
8670 aRenderingContext
->PopState();
8675 //------------------------------------------------------------------
8676 PRIntn
ReflowCountMgr::RemoveItems(PLHashEntry
*he
, PRIntn i
, void *arg
)
8678 char *str
= (char *)he
->key
;
8679 ReflowCounter
* counter
= (ReflowCounter
*)he
->value
;
8683 return HT_ENUMERATE_REMOVE
;
8686 //------------------------------------------------------------------
8687 PRIntn
ReflowCountMgr::RemoveIndiItems(PLHashEntry
*he
, PRIntn i
, void *arg
)
8689 char *str
= (char *)he
->key
;
8690 IndiReflowCounter
* counter
= (IndiReflowCounter
*)he
->value
;
8694 return HT_ENUMERATE_REMOVE
;
8697 //------------------------------------------------------------------
8698 void ReflowCountMgr::CleanUp()
8700 if (nsnull
!= mCounts
) {
8701 PL_HashTableEnumerateEntries(mCounts
, RemoveItems
, nsnull
);
8702 PL_HashTableDestroy(mCounts
);
8706 if (nsnull
!= mIndiFrameCounts
) {
8707 PL_HashTableEnumerateEntries(mIndiFrameCounts
, RemoveIndiItems
, nsnull
);
8708 PL_HashTableDestroy(mIndiFrameCounts
);
8709 mIndiFrameCounts
= nsnull
;
8713 //------------------------------------------------------------------
8714 PRIntn
ReflowCountMgr::DoSingleTotal(PLHashEntry
*he
, PRIntn i
, void *arg
)
8716 char *str
= (char *)he
->key
;
8717 ReflowCounter
* counter
= (ReflowCounter
*)he
->value
;
8719 counter
->DisplayTotals(str
);
8721 return HT_ENUMERATE_NEXT
;
8724 //------------------------------------------------------------------
8725 void ReflowCountMgr::DoGrandTotals()
8727 if (nsnull
!= mCounts
) {
8728 ReflowCounter
* gTots
= (ReflowCounter
*)PL_HashTableLookup(mCounts
, kGrandTotalsStr
);
8729 if (gTots
== nsnull
) {
8730 gTots
= new ReflowCounter(this);
8731 PL_HashTableAdd(mCounts
, NS_strdup(kGrandTotalsStr
), gTots
);
8733 gTots
->ClearTotals();
8736 printf("\t\t\t\tTotal\n");
8737 for (PRUint32 i
=0;i
<78;i
++) {
8741 PL_HashTableEnumerateEntries(mCounts
, DoSingleTotal
, this);
8745 static void RecurseIndiTotals(nsPresContext
* aPresContext
,
8747 nsIFrame
* aParentFrame
,
8750 if (aParentFrame
== nsnull
) {
8755 sprintf(key
, "%p", (void*)aParentFrame
);
8756 IndiReflowCounter
* counter
= (IndiReflowCounter
*)PL_HashTableLookup(aHT
, key
);
8758 counter
->mHasBeenOutput
= PR_TRUE
;
8759 char * name
= ToNewCString(counter
->mName
);
8760 for (PRInt32 i
=0;i
<aLevel
;i
++) printf(" ");
8761 printf("%s - %p [%d][", name
, (void*)aParentFrame
, counter
->mCount
);
8762 printf("%d", counter
->mCounter
.GetTotal());
8764 nsMemory::Free(name
);
8767 nsIFrame
* child
= aParentFrame
->GetFirstChild(nsnull
);
8769 RecurseIndiTotals(aPresContext
, aHT
, child
, aLevel
+1);
8770 child
= child
->GetNextSibling();
8775 //------------------------------------------------------------------
8776 PRIntn
ReflowCountMgr::DoSingleIndi(PLHashEntry
*he
, PRIntn i
, void *arg
)
8778 IndiReflowCounter
* counter
= (IndiReflowCounter
*)he
->value
;
8779 if (counter
&& !counter
->mHasBeenOutput
) {
8780 char * name
= ToNewCString(counter
->mName
);
8781 printf("%s - %p [%d][", name
, (void*)counter
->mFrame
, counter
->mCount
);
8782 printf("%d", counter
->mCounter
.GetTotal());
8784 nsMemory::Free(name
);
8786 return HT_ENUMERATE_NEXT
;
8789 //------------------------------------------------------------------
8790 void ReflowCountMgr::DoIndiTotalsTree()
8792 if (nsnull
!= mCounts
) {
8793 printf("\n------------------------------------------------\n");
8794 printf("-- Individual Frame Counts\n");
8795 printf("------------------------------------------------\n");
8798 nsIFrame
* rootFrame
= mPresShell
->FrameManager()->GetRootFrame();
8799 RecurseIndiTotals(mPresContext
, mIndiFrameCounts
, rootFrame
, 0);
8800 printf("------------------------------------------------\n");
8801 printf("-- Individual Counts of Frames not in Root Tree\n");
8802 printf("------------------------------------------------\n");
8803 PL_HashTableEnumerateEntries(mIndiFrameCounts
, DoSingleIndi
, this);
8808 //------------------------------------------------------------------
8809 PRIntn
ReflowCountMgr::DoSingleHTMLTotal(PLHashEntry
*he
, PRIntn i
, void *arg
)
8811 char *str
= (char *)he
->key
;
8812 ReflowCounter
* counter
= (ReflowCounter
*)he
->value
;
8814 counter
->DisplayHTMLTotals(str
);
8816 return HT_ENUMERATE_NEXT
;
8819 //------------------------------------------------------------------
8820 void ReflowCountMgr::DoGrandHTMLTotals()
8822 if (nsnull
!= mCounts
) {
8823 ReflowCounter
* gTots
= (ReflowCounter
*)PL_HashTableLookup(mCounts
, kGrandTotalsStr
);
8824 if (gTots
== nsnull
) {
8825 gTots
= new ReflowCounter(this);
8826 PL_HashTableAdd(mCounts
, NS_strdup(kGrandTotalsStr
), gTots
);
8828 gTots
->ClearTotals();
8831 static const char * title
[] = {"Class", "Reflows"};
8832 fprintf(mFD
, "<tr>");
8833 for (PRUint32 i
=0; i
< NS_ARRAY_LENGTH(title
); i
++) {
8834 fprintf(mFD
, "<td><center><b>%s<b></center></td>", title
[i
]);
8836 fprintf(mFD
, "</tr>\n");
8837 PL_HashTableEnumerateEntries(mCounts
, DoSingleHTMLTotal
, this);
8841 //------------------------------------
8842 void ReflowCountMgr::DisplayTotals(const char * aStr
)
8845 printf("%s\n", aStr
?aStr
:"No name");
8847 if (mDumpFrameCounts
) {
8850 if (mDumpFrameByFrameCounts
) {
8855 //------------------------------------
8856 void ReflowCountMgr::DisplayHTMLTotals(const char * aStr
)
8858 #ifdef WIN32x // XXX NOT XP!
8861 char * sptr
= strrchr(aStr
, '/');
8865 char * eptr
= strrchr(name
, '.');
8869 strcat(name
, "_stats.html");
8871 mFD
= fopen(name
, "w");
8873 fprintf(mFD
, "<html><head><title>Reflow Stats</title></head><body>\n");
8874 const char * title
= aStr
?aStr
:"No name";
8875 fprintf(mFD
, "<center><b>%s</b><br><table border=1 style=\"background-color:#e0e0e0\">", title
);
8876 DoGrandHTMLTotals();
8877 fprintf(mFD
, "</center></table>\n");
8878 fprintf(mFD
, "</body></html>\n");
8885 //------------------------------------------------------------------
8886 PRIntn
ReflowCountMgr::DoClearTotals(PLHashEntry
*he
, PRIntn i
, void *arg
)
8888 ReflowCounter
* counter
= (ReflowCounter
*)he
->value
;
8889 counter
->ClearTotals();
8891 return HT_ENUMERATE_NEXT
;
8894 //------------------------------------------------------------------
8895 void ReflowCountMgr::ClearTotals()
8897 PL_HashTableEnumerateEntries(mCounts
, DoClearTotals
, this);
8900 //------------------------------------------------------------------
8901 void ReflowCountMgr::ClearGrandTotals()
8903 if (nsnull
!= mCounts
) {
8904 ReflowCounter
* gTots
= (ReflowCounter
*)PL_HashTableLookup(mCounts
, kGrandTotalsStr
);
8905 if (gTots
== nsnull
) {
8906 gTots
= new ReflowCounter(this);
8907 PL_HashTableAdd(mCounts
, NS_strdup(kGrandTotalsStr
), gTots
);
8909 gTots
->ClearTotals();
8910 gTots
->SetTotalsCache();
8915 //------------------------------------------------------------------
8916 PRIntn
ReflowCountMgr::DoDisplayDiffTotals(PLHashEntry
*he
, PRIntn i
, void *arg
)
8918 PRBool cycledOnce
= (arg
!= 0);
8920 char *str
= (char *)he
->key
;
8921 ReflowCounter
* counter
= (ReflowCounter
*)he
->value
;
8924 counter
->CalcDiffInTotals();
8925 counter
->DisplayDiffTotals(str
);
8927 counter
->SetTotalsCache();
8929 return HT_ENUMERATE_NEXT
;
8932 //------------------------------------------------------------------
8933 void ReflowCountMgr::DisplayDiffsInTotals(const char * aStr
)
8936 printf("Differences\n");
8937 for (PRInt32 i
=0;i
<78;i
++) {
8943 PL_HashTableEnumerateEntries(mCounts
, DoDisplayDiffTotals
, (void *)mCycledOnce
);
8945 mCycledOnce
= PR_TRUE
;
8948 #endif // MOZ_REFLOW_PERF
8950 // make a color string like #RRGGBB
8951 void ColorToString(nscolor aColor
, nsAutoString
&aString
)
8955 PR_snprintf(buf
, sizeof(buf
), "#%02x%02x%02x",
8956 NS_GET_R(aColor
), NS_GET_G(aColor
), NS_GET_B(aColor
));
8957 CopyASCIItoUTF16(buf
, aString
);
8960 nsIFrame
* nsIPresShell::GetAbsoluteContainingBlock(nsIFrame
*aFrame
)
8962 return FrameConstructor()->GetAbsoluteContainingBlock(aFrame
);
8965 void nsIPresShell::InitializeStatics()
8967 NS_ASSERTION(sLiveShells
== nsnull
, "InitializeStatics called multiple times!");
8968 sLiveShells
= new nsTHashtable
<PresShellPtrKey
>();
8969 sLiveShells
->Init();
8972 void nsIPresShell::ReleaseStatics()
8974 NS_ASSERTION(sLiveShells
, "ReleaseStatics called without Initialize!");
8976 sLiveShells
= nsnull
;
8979 // Asks our docshell whether we're active.
8980 void PresShell::QueryIsActive()
8982 nsCOMPtr
<nsISupports
> container
= mPresContext
->GetContainer();
8983 nsCOMPtr
<nsIDocShell
> docshell(do_QueryInterface(container
));
8986 nsresult rv
= docshell
->GetIsActive(&isActive
);
8987 if (NS_SUCCEEDED(rv
))
8988 SetIsActive(isActive
);
8993 PresShell::SetIsActive(PRBool aIsActive
)
8995 mIsActive
= aIsActive
;
8996 return UpdateImageLockingState();
9000 * Determines the current image locking state. Called when one of the
9001 * dependent factors changes.
9004 PresShell::UpdateImageLockingState()
9006 // We're locked if we're both thawed and active.
9007 return mDocument
->SetImageLockingState(!mFrozen
&& mIsActive
);