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 <mats.palmgren@bredband.net>
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 #define PL_ARENA_CONST_ALIGN_MASK 3
60 #include "nsIPresShell.h"
61 #include "nsPresContext.h"
62 #include "nsIContent.h"
63 #include "nsIDocument.h"
64 #include "nsIDOMXULDocument.h"
65 #include "nsStubDocumentObserver.h"
66 #include "nsStyleSet.h"
67 #include "nsICSSStyleSheet.h" // XXX for UA sheet loading hack, can this go away please?
68 #include "nsIDOMCSSStyleSheet.h" // for Pref-related rule management (bugs 22963,20760,31816)
69 #include "nsINameSpaceManager.h" // for Pref-related rule management (bugs 22963,20760,31816)
70 #include "nsIServiceManager.h"
72 #include "nsIViewManager.h"
74 #include "nsCRTGlue.h"
79 #include "nsVoidArray.h"
80 #include "nsCOMArray.h"
81 #include "nsHashtable.h"
82 #include "nsIViewObserver.h"
83 #include "nsContainerFrame.h"
84 #include "nsIDeviceContext.h"
85 #include "nsEventStateManager.h"
86 #include "nsDOMEvent.h"
87 #include "nsGUIEvent.h"
88 #include "nsHTMLParts.h"
89 #include "nsContentUtils.h"
90 #include "nsISelection.h"
91 #include "nsISelectionController.h"
92 #include "nsISelectionPrivate.h"
93 #include "nsLayoutCID.h"
94 #include "nsGkAtoms.h"
95 #include "nsIDOMRange.h"
96 #include "nsIDOMDocument.h"
97 #include "nsIDOMNode.h"
98 #include "nsIDOM3Node.h"
99 #include "nsIDOMNodeList.h"
100 #include "nsIDOMElement.h"
102 #include "nsCSSPseudoElements.h"
103 #include "nsCOMPtr.h"
104 #include "nsAutoPtr.h"
105 #include "nsReadableUtils.h"
106 #include "nsUnicharUtils.h"
107 #include "nsWeakReference.h"
108 #include "nsIPageSequenceFrame.h"
110 #include "nsIDOMHTMLDocument.h"
111 #include "nsIXPointer.h"
112 #include "nsIDOMXMLDocument.h"
113 #include "nsIScrollableView.h"
114 #include "nsIParser.h"
115 #include "nsParserCIID.h"
116 #include "nsFrameSelection.h"
117 #include "nsIDOMNSHTMLInputElement.h" //optimization for ::DoXXX commands
118 #include "nsIDOMNSHTMLTextAreaElement.h"
119 #include "nsViewsCID.h"
120 #include "nsFrameManager.h"
122 #include "nsISupportsPrimitives.h"
123 #include "nsILayoutHistoryState.h"
124 #include "nsILineIterator.h" // for ScrollContentIntoView
126 #include "nsWeakPtr.h"
129 #include "nsIObserverService.h"
130 #include "nsIObserver.h"
131 #include "nsIDocShell.h" // for reflow observation
132 #include "nsIBaseWindow.h"
133 #include "nsLayoutErrors.h"
134 #include "nsLayoutUtils.h"
135 #include "nsCSSRendering.h"
137 #include "nsIFrameDebug.h"
139 // for |#ifdef DEBUG| code
140 #include "nsSpaceManager.h"
142 #include "nsIAttribute.h"
143 #include "nsIGlobalHistory2.h"
144 #include "nsDisplayList.h"
145 #include "nsIRegion.h"
146 #include "nsRegion.h"
148 #ifdef MOZ_REFLOW_PERF_DSP
149 #include "nsIRenderingContext.h"
150 #include "nsIFontMetrics.h"
153 #include "nsIReflowCallback.h"
155 #include "nsPIDOMWindow.h"
156 #include "nsIFocusController.h"
157 #include "nsIPluginInstance.h"
158 #include "nsIObjectFrame.h"
159 #include "nsIObjectLoadingContent.h"
160 #include "nsNetUtil.h"
161 #include "nsEventDispatcher.h"
162 #include "nsThreadUtils.h"
163 #include "nsStyleSheetService.h"
164 #include "gfxImageSurface.h"
165 #include "gfxContext.h"
167 #include "nsHTMLMediaElement.h"
170 // Drag & Drop, Clipboard
171 #include "nsWidgetsCID.h"
172 #include "nsIClipboard.h"
173 #include "nsIClipboardHelper.h"
174 #include "nsIDocShellTreeItem.h"
176 #include "nsIScrollableFrame.h"
179 #include "nsIDragService.h"
180 #include "nsCopySupport.h"
181 #include "nsIDOMHTMLAnchorElement.h"
182 #include "nsIDOMHTMLAreaElement.h"
183 #include "nsIDOMHTMLLinkElement.h"
184 #include "nsITimer.h"
186 #include "nsIAccessibilityService.h"
187 #include "nsIAccessible.h"
188 #include "nsIAccessibleEvent.h"
191 // For style data reconstruction
192 #include "nsStyleChangeList.h"
193 #include "nsCSSFrameConstructor.h"
195 #include "nsMenuFrame.h"
196 #include "nsTreeBodyFrame.h"
198 #include "nsPlaceholderFrame.h"
200 // Content viewer interfaces
201 #include "nsIContentViewer.h"
202 #include "imgIEncoder.h"
203 #include "gfxPlatform.h"
205 #include "nsContentCID.h"
206 static NS_DEFINE_CID(kCSSStyleSheetCID
, NS_CSS_STYLESHEET_CID
);
207 static NS_DEFINE_IID(kRangeCID
, NS_RANGE_CID
);
209 PRBool
nsIPresShell::gIsAccessibilityActive
= PR_FALSE
;
211 // convert a color value to a string, in the CSS format #RRGGBB
212 // * - initially created for bugs 31816, 20760, 22963
213 static void ColorToString(nscolor aColor
, nsAutoString
&aString
);
216 static NS_DEFINE_CID(kFrameSelectionCID
, NS_FRAMESELECTION_CID
);
218 // RangePaintInfo is used to paint ranges to offscreen buffers
219 struct RangePaintInfo
{
220 nsCOMPtr
<nsIRange
> mRange
;
221 nsDisplayListBuilder mBuilder
;
224 // offset of builder's reference frame to the root frame
227 RangePaintInfo(nsIRange
* aRange
, nsIFrame
* aFrame
)
228 : mRange(aRange
), mBuilder(aFrame
, PR_FALSE
, PR_FALSE
)
240 // ----------------------------------------------------------------------
243 // Set the environment variable GECKO_VERIFY_REFLOW_FLAGS to one or
244 // more of the following flags (comma separated) for handy debug
246 static PRUint32 gVerifyReflowFlags
;
248 struct VerifyReflowFlags
{
253 static const VerifyReflowFlags gFlags
[] = {
254 { "verify", VERIFY_REFLOW_ON
},
255 { "reflow", VERIFY_REFLOW_NOISY
},
256 { "all", VERIFY_REFLOW_ALL
},
257 { "list-commands", VERIFY_REFLOW_DUMP_COMMANDS
},
258 { "noisy-commands", VERIFY_REFLOW_NOISY_RC
},
259 { "really-noisy-commands", VERIFY_REFLOW_REALLY_NOISY_RC
},
260 { "space-manager", VERIFY_REFLOW_INCLUDE_SPACE_MANAGER
},
261 { "resize", VERIFY_REFLOW_DURING_RESIZE_REFLOW
},
264 #define NUM_VERIFY_REFLOW_FLAGS (sizeof(gFlags) / sizeof(gFlags[0]))
267 ShowVerifyReflowFlags()
269 printf("Here are the available GECKO_VERIFY_REFLOW_FLAGS:\n");
270 const VerifyReflowFlags
* flag
= gFlags
;
271 const VerifyReflowFlags
* limit
= gFlags
+ NUM_VERIFY_REFLOW_FLAGS
;
272 while (flag
< limit
) {
273 printf(" %s\n", flag
->name
);
276 printf("Note: GECKO_VERIFY_REFLOW_FLAGS is a comma separated list of flag\n");
277 printf("names (no whitespace)\n");
281 //========================================================================
282 //========================================================================
283 //========================================================================
284 #ifdef MOZ_REFLOW_PERF
285 class ReflowCountMgr
;
287 static const char kGrandTotalsStr
[] = "Grand Totals";
290 class ReflowCounter
{
292 ReflowCounter(ReflowCountMgr
* aMgr
= nsnull
);
296 void DisplayTotals(const char * aStr
);
297 void DisplayDiffTotals(const char * aStr
);
298 void DisplayHTMLTotals(const char * aStr
);
300 void Add() { mTotal
++; }
301 void Add(PRUint32 aTotal
) { mTotal
+= aTotal
; }
303 void CalcDiffInTotals();
304 void SetTotalsCache();
306 void SetMgr(ReflowCountMgr
* aMgr
) { mMgr
= aMgr
; }
308 PRUint32
GetTotal() { return mTotal
; }
311 void DisplayTotals(PRUint32 aTotal
, const char * aTitle
);
312 void DisplayHTMLTotals(PRUint32 aTotal
, const char * aTitle
);
315 PRUint32 mCacheTotal
;
317 ReflowCountMgr
* mMgr
; // weak reference (don't delete)
321 class IndiReflowCounter
{
323 IndiReflowCounter(ReflowCountMgr
* aMgr
= nsnull
)
328 mHasBeenOutput(PR_FALSE
)
330 virtual ~IndiReflowCounter() {}
333 nsIFrame
* mFrame
; // weak reference (don't delete)
336 ReflowCountMgr
* mMgr
; // weak reference (don't delete)
338 ReflowCounter mCounter
;
339 PRBool mHasBeenOutput
;
343 //--------------------
345 //--------------------
346 class ReflowCountMgr
{
349 virtual ~ReflowCountMgr();
352 void ClearGrandTotals();
353 void DisplayTotals(const char * aStr
);
354 void DisplayHTMLTotals(const char * aStr
);
355 void DisplayDiffsInTotals(const char * aStr
);
357 void Add(const char * aName
, nsIFrame
* aFrame
);
358 ReflowCounter
* LookUp(const char * aName
);
360 void PaintCount(const char * aName
, nsIRenderingContext
* aRenderingContext
, nsPresContext
* aPresContext
, nsIFrame
* aFrame
, PRUint32 aColor
);
362 FILE * GetOutFile() { return mFD
; }
364 PLHashTable
* GetIndiFrameHT() { return mIndiFrameCounts
; }
366 void SetPresContext(nsPresContext
* aPresContext
) { mPresContext
= aPresContext
; } // weak reference
367 void SetPresShell(nsIPresShell
* aPresShell
) { mPresShell
= aPresShell
; } // weak reference
369 void SetDumpFrameCounts(PRBool aVal
) { mDumpFrameCounts
= aVal
; }
370 void SetDumpFrameByFrameCounts(PRBool aVal
) { mDumpFrameByFrameCounts
= aVal
; }
371 void SetPaintFrameCounts(PRBool aVal
) { mPaintFrameByFrameCounts
= aVal
; }
374 void DisplayTotals(PRUint32 aTotal
, PRUint32
* aDupArray
, char * aTitle
);
375 void DisplayHTMLTotals(PRUint32 aTotal
, PRUint32
* aDupArray
, char * aTitle
);
377 static PRIntn
RemoveItems(PLHashEntry
*he
, PRIntn i
, void *arg
);
378 static PRIntn
RemoveIndiItems(PLHashEntry
*he
, PRIntn i
, void *arg
);
381 // stdout Output Methods
382 static PRIntn
DoSingleTotal(PLHashEntry
*he
, PRIntn i
, void *arg
);
383 static PRIntn
DoSingleIndi(PLHashEntry
*he
, PRIntn i
, void *arg
);
385 void DoGrandTotals();
386 void DoIndiTotalsTree();
388 // HTML Output Methods
389 static PRIntn
DoSingleHTMLTotal(PLHashEntry
*he
, PRIntn i
, void *arg
);
390 void DoGrandHTMLTotals();
392 // Zero Out the Totals
393 static PRIntn
DoClearTotals(PLHashEntry
*he
, PRIntn i
, void *arg
);
395 // Displays the Diff Totals
396 static PRIntn
DoDisplayDiffTotals(PLHashEntry
*he
, PRIntn i
, void *arg
);
398 PLHashTable
* mCounts
;
399 PLHashTable
* mIndiFrameCounts
;
402 PRBool mDumpFrameCounts
;
403 PRBool mDumpFrameByFrameCounts
;
404 PRBool mPaintFrameByFrameCounts
;
408 // Root Frame for Individual Tracking
409 nsPresContext
* mPresContext
;
410 nsIPresShell
* mPresShell
;
412 // ReflowCountMgr gReflowCountMgr;
415 //========================================================================
417 // comment out to hide caret
420 // The upper bound on the amount of time to spend reflowing, in
421 // microseconds. When this bound is exceeded and reflow commands are
422 // still queued up, a reflow event is posted. The idea is for reflow
423 // to not hog the processor beyond the time specifed in
424 // gMaxRCProcessingTime. This data member is initialized from the
425 // layout.reflow.timeslice pref.
426 #define NS_MAX_REFLOW_TIME 1000000
427 static PRInt32 gMaxRCProcessingTime
= -1;
429 // Largest chunk size we recycle
430 static const size_t gMaxRecycledSize
= 400;
432 #define MARK_INCREMENT 50
433 #define BLOCK_INCREMENT 4044 /* a bit under 4096, for malloc overhead */
435 /**A block of memory that the stack will
436 * chop up and hand out
440 // a block of memory. Note that this must be first so that it will
442 char mBlock
[BLOCK_INCREMENT
];
444 // another block of memory that would only be created
445 // if our stack overflowed. Yes we have the ability
446 // to grow on a stack overflow
449 StackBlock() : mNext(nsnull
) { }
453 /* we hold an array of marks. A push pushes a mark on the stack
457 // the block of memory we are currently handing out chunks of
460 // our current position in the memory
465 /* A stack arena allows a stack based interface to a block of memory.
466 * It should be used when you need to allocate some temporary memory that
467 * you will immediately return.
474 nsresult
Init() { return mBlocks
? NS_OK
: NS_ERROR_OUT_OF_MEMORY
; }
476 // Memory management functions
477 void* Allocate(size_t aSize
);
482 // our current position in memory
485 // a list of memory block. Usually there is only one
486 // but if we overrun our stack size we can get more memory.
489 // the current block of memory we are passing our chucks of
490 StackBlock
* mCurBlock
;
492 // our stack of mark where push has been called
495 // the current top of the mark list
498 // the size of the mark array
499 PRUint32 mMarkLength
;
504 StackArena::StackArena()
509 // allocate our stack memory
510 mBlocks
= new StackBlock();
517 StackArena::~StackArena()
523 StackBlock
* toDelete
= mBlocks
;
524 mBlocks
= mBlocks
->mNext
;
532 // Resize the mark array if we overrun it. Failure to allocate the
533 // mark array is not fatal; we just won't free to that mark. This
534 // allows callers not to worry about error checking.
535 if (mStackTop
>= mMarkLength
)
537 PRUint32 newLength
= mStackTop
+ MARK_INCREMENT
;
538 StackMark
* newMarks
= new StackMark
[newLength
];
541 memcpy(newMarks
, mMarks
, sizeof(StackMark
)*mMarkLength
);
542 // Fill in any marks that we couldn't allocate during a prior call
544 for (; mMarkLength
< mStackTop
; ++mMarkLength
) {
545 NS_NOTREACHED("should only hit this on out-of-memory");
546 newMarks
[mMarkLength
].mBlock
= mCurBlock
;
547 newMarks
[mMarkLength
].mPos
= mPos
;
551 mMarkLength
= newLength
;
555 // set a mark at the top (if we can)
556 NS_ASSERTION(mStackTop
< mMarkLength
, "out of memory");
557 if (mStackTop
< mMarkLength
) {
558 mMarks
[mStackTop
].mBlock
= mCurBlock
;
559 mMarks
[mStackTop
].mPos
= mPos
;
566 StackArena::Allocate(size_t aSize
)
568 NS_ASSERTION(mStackTop
> 0, "Allocate called without Push");
570 // make sure we are aligned. Beard said 8 was safer then 4.
571 // Round size to multiple of 8
572 aSize
= PR_ROUNDUP(aSize
, 8);
574 // if the size makes the stack overflow. Grab another block for the stack
575 if (mPos
+ aSize
>= BLOCK_INCREMENT
)
577 NS_ASSERTION(aSize
<= BLOCK_INCREMENT
,"Requested memory is greater that our block size!!");
578 if (mCurBlock
->mNext
== nsnull
)
579 mCurBlock
->mNext
= new StackBlock();
581 mCurBlock
= mCurBlock
->mNext
;
585 // return the chunk they need.
586 void *result
= mCurBlock
->mBlock
+ mPos
;
596 NS_ASSERTION(mStackTop
> 0, "unmatched pop");
599 if (mStackTop
>= mMarkLength
) {
600 // We couldn't allocate the marks array at the time of the push, so
601 // we don't know where we're freeing to.
602 NS_NOTREACHED("out of memory");
603 if (mStackTop
== 0) {
604 // But we do know if we've completely pushed the stack.
612 // Mark the "freed" memory with 0xdd to help with debugging of memory
613 // allocation problems.
615 StackBlock
*block
= mMarks
[mStackTop
].mBlock
, *block_end
= mCurBlock
;
616 size_t pos
= mMarks
[mStackTop
].mPos
;
617 for (; block
!= block_end
; block
= block
->mNext
, pos
= 0) {
618 memset(block
->mBlock
+ pos
, 0xdd, sizeof(block
->mBlock
) - pos
);
620 memset(block
->mBlock
+ pos
, 0xdd, mPos
- pos
);
624 mCurBlock
= mMarks
[mStackTop
].mBlock
;
625 mPos
= mMarks
[mStackTop
].mPos
;
628 // Uncomment this to disable the frame arena.
629 //#define DEBUG_TRACEMALLOC_FRAMEARENA 1
631 // Memory is allocated 4-byte aligned. We have recyclers for chunks up to
635 FrameArena(PRUint32 aArenaSize
= 4096);
638 // Memory management functions
639 NS_HIDDEN_(void*) AllocateFrame(size_t aSize
);
640 NS_HIDDEN_(void) FreeFrame(size_t aSize
, void* aPtr
);
644 // Number of frames in the pool
645 PRUint32 mFrameCount
;
648 #if !defined(DEBUG_TRACEMALLOC_FRAMEARENA)
649 // Underlying arena pool
652 // The recycler array is sparse with the indices being multiples of 4,
653 // i.e., 0, 4, 8, 12, 16, 20, ...
654 void* mRecyclers
[gMaxRecycledSize
>> 2];
658 FrameArena::FrameArena(PRUint32 aArenaSize
)
663 #if !defined(DEBUG_TRACEMALLOC_FRAMEARENA)
664 // Initialize the arena pool
665 PL_INIT_ARENA_POOL(&mPool
, "FrameArena", aArenaSize
);
667 // Zero out the recyclers array
668 memset(mRecyclers
, 0, sizeof(mRecyclers
));
672 FrameArena::~FrameArena()
674 NS_ASSERTION(mFrameCount
== 0,
675 "Some objects allocated with AllocateFrame were not freed");
677 #if !defined(DEBUG_TRACEMALLOC_FRAMEARENA)
678 // Free the arena in the pool and finish using it
679 PL_FinishArenaPool(&mPool
);
684 FrameArena::AllocateFrame(size_t aSize
)
686 void* result
= nsnull
;
688 #if defined(DEBUG_TRACEMALLOC_FRAMEARENA)
690 result
= PR_Malloc(aSize
);
694 // Ensure we have correct alignment for pointers. Important for Tru64
695 aSize
= PR_ROUNDUP(aSize
, sizeof(void*));
697 // Check recyclers first
698 if (aSize
< gMaxRecycledSize
) {
699 const int index
= aSize
>> 2;
701 result
= mRecyclers
[index
];
703 // Need to move to the next object
704 void* next
= *((void**)result
);
705 mRecyclers
[index
] = next
;
710 // Allocate a new chunk from the arena
711 PL_ARENA_ALLOCATE(result
, &mPool
, aSize
);
717 if (result
!= nsnull
)
725 FrameArena::FreeFrame(size_t aSize
, void* aPtr
)
730 // Mark the memory with 0xdd in DEBUG builds so that there will be
731 // problems if someone tries to access memory that they've freed.
732 memset(aPtr
, 0xdd, aSize
);
734 #if defined(DEBUG_TRACEMALLOC_FRAMEARENA)
737 // Ensure we have correct alignment for pointers. Important for Tru64
738 aSize
= PR_ROUNDUP(aSize
, sizeof(void*));
740 // See if it's a size that we recycle
741 if (aSize
< gMaxRecycledSize
) {
742 const int index
= aSize
>> 2;
743 void* currentTop
= mRecyclers
[index
];
744 mRecyclers
[index
] = aPtr
;
745 *((void**)aPtr
) = currentTop
;
750 "WARNING: FrameArena::FreeFrame leaking chunk of %d bytes.\n",
757 struct nsCallbackEventRequest
759 nsIReflowCallback
* callback
;
760 nsCallbackEventRequest
* next
;
763 // ----------------------------------------------------------------------------
764 class nsPresShellEventCB
;
766 class PresShell
: public nsIPresShell
, public nsIViewObserver
,
767 public nsStubDocumentObserver
,
768 public nsISelectionController
, public nsIObserver
,
769 public nsSupportsWeakReference
774 NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
780 NS_IMETHOD
Init(nsIDocument
* aDocument
,
781 nsPresContext
* aPresContext
,
782 nsIViewManager
* aViewManager
,
783 nsStyleSet
* aStyleSet
,
784 nsCompatibility aCompatMode
);
785 NS_IMETHOD
Destroy();
787 virtual NS_HIDDEN_(void*) AllocateFrame(size_t aSize
);
788 virtual NS_HIDDEN_(void) FreeFrame(size_t aSize
, void* aFreeChunk
);
790 // Dynamic stack memory allocation
791 virtual NS_HIDDEN_(void) PushStackMemory();
792 virtual NS_HIDDEN_(void) PopStackMemory();
793 virtual NS_HIDDEN_(void*) AllocateStackMemory(size_t aSize
);
795 NS_IMETHOD
SetPreferenceStyleRules(PRBool aForceReflow
);
797 NS_IMETHOD
GetSelection(SelectionType aType
, nsISelection
** aSelection
);
798 virtual nsISelection
* GetCurrentSelection(SelectionType aType
);
800 NS_IMETHOD
SetDisplaySelection(PRInt16 aToggle
);
801 NS_IMETHOD
GetDisplaySelection(PRInt16
*aToggle
);
802 NS_IMETHOD
ScrollSelectionIntoView(SelectionType aType
, SelectionRegion aRegion
, PRBool aIsSynchronous
);
803 NS_IMETHOD
RepaintSelection(SelectionType aType
);
805 NS_IMETHOD
BeginObservingDocument();
806 NS_IMETHOD
EndObservingDocument();
807 NS_IMETHOD
GetDidInitialReflow(PRBool
*aDidInitialReflow
);
808 NS_IMETHOD
InitialReflow(nscoord aWidth
, nscoord aHeight
);
809 NS_IMETHOD
ResizeReflow(nscoord aWidth
, nscoord aHeight
);
810 NS_IMETHOD
StyleChangeReflow();
811 NS_IMETHOD
GetPageSequenceFrame(nsIPageSequenceFrame
** aResult
) const;
812 virtual NS_HIDDEN_(nsIFrame
*) GetPrimaryFrameFor(nsIContent
* aContent
) const;
813 virtual NS_HIDDEN_(nsIFrame
*) GetRealPrimaryFrameFor(nsIContent
* aContent
) const;
815 NS_IMETHOD
GetPlaceholderFrameFor(nsIFrame
* aFrame
,
816 nsIFrame
** aPlaceholderFrame
) const;
817 NS_IMETHOD
FrameNeedsReflow(nsIFrame
*aFrame
, IntrinsicDirty aIntrinsicDirty
,
818 nsFrameState aBitToAdd
);
819 NS_IMETHOD
CancelAllPendingReflows();
820 NS_IMETHOD
IsSafeToFlush(PRBool
& aIsSafeToFlush
);
821 NS_IMETHOD
FlushPendingNotifications(mozFlushType aType
);
824 * Recreates the frames for a node
826 NS_IMETHOD
RecreateFramesFor(nsIContent
* aContent
);
829 * Post a callback that should be handled after reflow has finished.
831 NS_IMETHOD
PostReflowCallback(nsIReflowCallback
* aCallback
);
832 NS_IMETHOD
CancelReflowCallback(nsIReflowCallback
* aCallback
);
834 NS_IMETHOD
ClearFrameRefs(nsIFrame
* aFrame
);
835 NS_IMETHOD
CreateRenderingContext(nsIFrame
*aFrame
,
836 nsIRenderingContext
** aContext
);
837 NS_IMETHOD
GoToAnchor(const nsAString
& aAnchorName
, PRBool aScroll
);
838 NS_IMETHOD
ScrollToAnchor();
840 NS_IMETHOD
ScrollContentIntoView(nsIContent
* aContent
,
842 PRIntn aHPercent
) const;
844 NS_IMETHOD
SetIgnoreFrameDestruction(PRBool aIgnore
);
845 NS_IMETHOD
NotifyDestroyingFrame(nsIFrame
* aFrame
);
848 NS_IMETHOD
GetSelectionForCopy(nsISelection
** outSelection
);
850 NS_IMETHOD
GetLinkLocation(nsIDOMNode
* aNode
, nsAString
& aLocationString
);
851 NS_IMETHOD
DoGetContents(const nsACString
& aMimeType
, PRUint32 aFlags
, PRBool aSelectionOnly
, nsAString
& outValue
);
853 NS_IMETHOD
CaptureHistoryState(nsILayoutHistoryState
** aLayoutHistoryState
, PRBool aLeavingPage
);
855 NS_IMETHOD
IsPaintingSuppressed(PRBool
* aResult
);
856 NS_IMETHOD
UnsuppressPainting();
858 NS_IMETHOD
DisableThemeSupport();
859 virtual PRBool
IsThemeSupportEnabled();
861 virtual nsresult
GetAgentStyleSheets(nsCOMArray
<nsIStyleSheet
>& aSheets
);
862 virtual nsresult
SetAgentStyleSheets(const nsCOMArray
<nsIStyleSheet
>& aSheets
);
864 virtual nsresult
AddOverrideStyleSheet(nsIStyleSheet
*aSheet
);
865 virtual nsresult
RemoveOverrideStyleSheet(nsIStyleSheet
*aSheet
);
867 NS_IMETHOD
HandleEventWithTarget(nsEvent
* aEvent
, nsIFrame
* aFrame
,
868 nsIContent
* aContent
,
869 nsEventStatus
* aStatus
);
870 NS_IMETHOD
GetEventTargetFrame(nsIFrame
** aFrame
);
871 NS_IMETHOD
GetEventTargetContent(nsEvent
* aEvent
, nsIContent
** aContent
);
873 NS_IMETHOD
IsReflowLocked(PRBool
* aIsLocked
);
875 virtual nsresult
ReconstructFrames(void);
876 virtual void Freeze();
879 virtual nsIFrame
* GetFrameForPoint(nsIFrame
* aFrame
, nsPoint aPt
);
881 NS_IMETHOD
RenderDocument(const nsRect
& aRect
, PRUint32 aFlags
,
882 nscolor aBackgroundColor
,
883 gfxContext
* aThebesContext
);
885 virtual already_AddRefed
<gfxASurface
> RenderNode(nsIDOMNode
* aNode
,
888 nsRect
* aScreenRect
);
890 virtual already_AddRefed
<gfxASurface
> RenderSelection(nsISelection
* aSelection
,
892 nsRect
* aScreenRect
);
894 //nsIViewObserver interface
896 NS_IMETHOD
Paint(nsIView
*aView
,
897 nsIRenderingContext
* aRenderingContext
,
898 const nsRegion
& aDirtyRegion
);
899 NS_IMETHOD
ComputeRepaintRegionForCopy(nsIView
* aRootView
,
900 nsIView
* aMovingView
,
902 const nsRect
& aCopyRect
,
903 nsRegion
* aRepaintRegion
);
904 NS_IMETHOD
HandleEvent(nsIView
* aView
,
906 nsEventStatus
* aEventStatus
);
907 NS_IMETHOD
HandleDOMEventWithTarget(nsIContent
* aTargetContent
,
909 nsEventStatus
* aStatus
);
910 NS_IMETHOD
ResizeReflow(nsIView
*aView
, nscoord aWidth
, nscoord aHeight
);
911 NS_IMETHOD_(PRBool
) IsVisible();
912 NS_IMETHOD_(void) WillPaint();
913 NS_IMETHOD_(void) InvalidateFrameForView(nsIView
*view
);
914 NS_IMETHOD_(void) DispatchSynthMouseMove(nsGUIEvent
*aEvent
,
915 PRBool aFlushOnHoverChange
);
918 NS_IMETHOD
GetCaret(nsCaret
**aOutCaret
);
919 NS_IMETHOD_(void) MaybeInvalidateCaretPosition();
920 NS_IMETHOD
SetCaretEnabled(PRBool aInEnable
);
921 NS_IMETHOD
SetCaretReadOnly(PRBool aReadOnly
);
922 NS_IMETHOD
GetCaretEnabled(PRBool
*aOutEnabled
);
923 NS_IMETHOD
SetCaretVisibilityDuringSelection(PRBool aVisibility
);
924 NS_IMETHOD
GetCaretVisible(PRBool
*_retval
);
925 virtual void SetCaret(nsCaret
*aNewCaret
);
926 virtual void RestoreCaret();
928 NS_IMETHOD
SetSelectionFlags(PRInt16 aInEnable
);
929 NS_IMETHOD
GetSelectionFlags(PRInt16
*aOutEnable
);
931 // nsISelectionController
933 NS_IMETHOD
CharacterMove(PRBool aForward
, PRBool aExtend
);
934 NS_IMETHOD
CharacterExtendForDelete();
935 NS_IMETHOD
WordMove(PRBool aForward
, PRBool aExtend
);
936 NS_IMETHOD
WordExtendForDelete(PRBool aForward
);
937 NS_IMETHOD
LineMove(PRBool aForward
, PRBool aExtend
);
938 NS_IMETHOD
IntraLineMove(PRBool aForward
, PRBool aExtend
);
939 NS_IMETHOD
PageMove(PRBool aForward
, PRBool aExtend
);
940 NS_IMETHOD
ScrollPage(PRBool aForward
);
941 NS_IMETHOD
ScrollLine(PRBool aForward
);
942 NS_IMETHOD
ScrollHorizontal(PRBool aLeft
);
943 NS_IMETHOD
CompleteScroll(PRBool aForward
);
944 NS_IMETHOD
CompleteMove(PRBool aForward
, PRBool aExtend
);
945 NS_IMETHOD
SelectAll();
946 NS_IMETHOD
CheckVisibility(nsIDOMNode
*node
, PRInt16 startOffset
, PRInt16 EndOffset
, PRBool
*_retval
);
948 // nsIDocumentObserver
949 virtual void BeginUpdate(nsIDocument
* aDocument
, nsUpdateType aUpdateType
);
950 virtual void EndUpdate(nsIDocument
* aDocument
, nsUpdateType aUpdateType
);
951 virtual void BeginLoad(nsIDocument
* aDocument
);
952 virtual void EndLoad(nsIDocument
* aDocument
);
953 virtual void ContentStatesChanged(nsIDocument
* aDocument
,
954 nsIContent
* aContent1
,
955 nsIContent
* aContent2
,
957 virtual void StyleSheetAdded(nsIDocument
* aDocument
,
958 nsIStyleSheet
* aStyleSheet
,
959 PRBool aDocumentSheet
);
960 virtual void StyleSheetRemoved(nsIDocument
* aDocument
,
961 nsIStyleSheet
* aStyleSheet
,
962 PRBool aDocumentSheet
);
963 virtual void StyleSheetApplicableStateChanged(nsIDocument
* aDocument
,
964 nsIStyleSheet
* aStyleSheet
,
966 virtual void StyleRuleChanged(nsIDocument
* aDocument
,
967 nsIStyleSheet
* aStyleSheet
,
968 nsIStyleRule
* aOldStyleRule
,
969 nsIStyleRule
* aNewStyleRule
);
970 virtual void StyleRuleAdded(nsIDocument
* aDocument
,
971 nsIStyleSheet
* aStyleSheet
,
972 nsIStyleRule
* aStyleRule
);
973 virtual void StyleRuleRemoved(nsIDocument
* aDocument
,
974 nsIStyleSheet
* aStyleSheet
,
975 nsIStyleRule
* aStyleRule
);
977 // nsIMutationObserver
978 NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
979 NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
980 NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
981 NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
982 NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
986 #ifdef MOZ_REFLOW_PERF
987 NS_IMETHOD
DumpReflows();
988 NS_IMETHOD
CountReflows(const char * aName
, nsIFrame
* aFrame
);
989 NS_IMETHOD
PaintCount(const char * aName
, nsIRenderingContext
* aRenderingContext
, nsPresContext
* aPresContext
, nsIFrame
* aFrame
, PRUint32 aColor
);
991 NS_IMETHOD
SetPaintFrameCount(PRBool aOn
);
996 virtual void ListStyleContexts(nsIFrame
*aRootFrame
, FILE *out
,
997 PRInt32 aIndent
= 0);
999 virtual void ListStyleSheets(FILE *out
, PRInt32 aIndent
= 0);
1000 virtual void VerifyStyleTree();
1004 static PRLogModuleInfo
* gLog
;
1008 virtual ~PresShell();
1010 void HandlePostedReflowCallbacks();
1011 void CancelPostedReflowCallbacks();
1013 void UnsuppressAndInvalidate();
1015 void WillDoReflow();
1017 nsresult
ProcessReflowCommands(PRBool aInterruptible
);
1018 void ClearReflowEventStatus();
1019 void PostReflowEvent();
1021 void DoReflow(nsIFrame
* aFrame
);
1023 void DoVerifyReflow();
1024 void VerifyHasDirtyRootAncestor(nsIFrame
* aFrame
);
1027 friend class nsPresShellEventCB
;
1030 friend class ReflowEvent
;
1032 class ReflowEvent
: public nsRunnable
{
1035 ReflowEvent(PresShell
*aPresShell
) : mPresShell(aPresShell
) {
1036 NS_ASSERTION(aPresShell
, "Null parameters!");
1038 void Revoke() { mPresShell
= nsnull
; }
1040 PresShell
*mPresShell
;
1043 // Utility to find which view to scroll.
1044 nsIScrollableView
* GetViewToScroll(nsLayoutUtils::Direction aDirection
);
1046 PRBool mCaretEnabled
;
1048 nsresult
CloneStyleSet(nsStyleSet
* aSet
, nsStyleSet
** aResult
);
1049 PRBool
VerifyIncrementalReflow();
1050 PRBool mInVerifyReflow
;
1051 void ShowEventTargetDebug();
1055 * methods that manage rules that are used to implement the associated preferences
1056 * - initially created for bugs 31816, 20760, 22963
1058 nsresult
ClearPreferenceStyleRules(void);
1059 nsresult
CreatePreferenceStyleSheet(void);
1060 nsresult
SetPrefLinkRules(void);
1061 nsresult
SetPrefFocusRules(void);
1062 nsresult
SetPrefNoScriptRule();
1063 nsresult
SetPrefNoFramesRule(void);
1065 // methods for painting a range to an offscreen buffer
1067 // given a display list, clip the items within the list to
1069 nsRect
ClipListToRange(nsDisplayListBuilder
*aBuilder
,
1070 nsDisplayList
* aList
,
1073 // create a RangePaintInfo for the range aRange containing the
1074 // display list needed to paint the range to a surface
1075 RangePaintInfo
* CreateRangePaintInfo(nsIDOMRange
* aRange
,
1076 nsRect
& aSurfaceRect
);
1079 * Paint the items to a new surface and return it.
1081 * aSelection - selection being painted, if any
1082 * aRegion - clip region, if any
1083 * aArea - area that the surface occupies, relative to the root frame
1084 * aPoint - reference point, typically the mouse position
1085 * aScreenRect - [out] set to the area of the screen the painted area should
1088 already_AddRefed
<gfxASurface
>
1089 PaintRangePaintInfo(nsTArray
<nsAutoPtr
<RangePaintInfo
> >* aItems
,
1090 nsISelection
* aSelection
,
1094 nsRect
* aScreenRect
);
1097 * Methods to handle changes to user and UA sheet lists that we get
1100 void AddUserSheet(nsISupports
* aSheet
);
1101 void AddAgentSheet(nsISupports
* aSheet
);
1102 void RemoveSheet(nsStyleSet::sheetType aType
, nsISupports
* aSheet
);
1104 // Hide a view if it is a popup
1105 void HideViewIfPopup(nsIView
* aView
);
1107 // Utility method to restore the root scrollframe state
1108 void RestoreRootScrollPosition();
1110 // Method to handle actually flushing. This allows the caller to control
1111 // whether the reflow flush (if any) should be interruptible.
1112 nsresult
DoFlushPendingNotifications(mozFlushType aType
,
1113 PRBool aInterruptibleReflow
);
1115 nsCOMPtr
<nsICSSStyleSheet
> mPrefStyleSheet
; // mStyleSet owns it but we
1116 // maintain a ref, may be null
1118 PRUint32 mUpdateCount
;
1120 // reflow roots that need to be reflowed, as both a queue and a hashtable
1121 nsVoidArray mDirtyRoots
;
1123 PRPackedBool mDocumentLoading
;
1124 PRPackedBool mIsReflowing
;
1126 PRPackedBool mIgnoreFrameDestruction
;
1127 PRPackedBool mHaveShutDown
;
1129 nsIFrame
* mCurrentEventFrame
;
1130 nsCOMPtr
<nsIContent
> mCurrentEventContent
;
1131 nsVoidArray mCurrentEventFrameStack
;
1132 nsCOMArray
<nsIContent
> mCurrentEventContentStack
;
1134 nsCOMPtr
<nsIContent
> mLastAnchorScrolledTo
;
1135 nscoord mLastAnchorScrollPositionY
;
1136 nsRefPtr
<nsCaret
> mCaret
;
1137 nsRefPtr
<nsCaret
> mOriginalCaret
;
1138 PRInt16 mSelectionFlags
;
1139 FrameArena mFrameArena
;
1140 StackArena mStackArena
;
1141 nsCOMPtr
<nsIDragService
> mDragService
;
1143 nsRevocableEventPtr
<ReflowEvent
> mReflowEvent
;
1145 nsCallbackEventRequest
* mFirstCallbackEventRequest
;
1146 nsCallbackEventRequest
* mLastCallbackEventRequest
;
1148 PRPackedBool mIsThemeSupportDisabled
; // Whether or not form controls should use nsITheme in this shell.
1150 PRPackedBool mIsDocumentGone
; // We've been disconnected from the document.
1151 PRPackedBool mPaintingSuppressed
; // For all documents we initially lock down painting.
1152 // We will refuse to paint the document until either
1153 // (a) our timer fires or (b) all frames are constructed.
1154 PRPackedBool mShouldUnsuppressPainting
; // Indicates that it is safe to unlock painting once all pending
1155 // reflows have been processed.
1156 nsCOMPtr
<nsITimer
> mPaintSuppressionTimer
; // This timer controls painting suppression. Until it fires
1157 // or all frames are constructed, we won't paint anything but
1158 // our <body> background and scrollbars.
1159 #define PAINTLOCK_EVENT_DELAY 250 // 250ms. This is actually
1160 // pref-controlled, but we use this
1161 // value if we fail to get the pref
1164 static void sPaintSuppressionCallback(nsITimer
* aTimer
, void* aPresShell
); // A callback for the timer.
1166 MOZ_TIMER_DECLARE(mReflowWatch
) // Used for measuring time spent in reflow
1167 MOZ_TIMER_DECLARE(mFrameCreationWatch
) // Used for measuring time spent in frame creation
1169 #ifdef MOZ_REFLOW_PERF
1170 ReflowCountMgr
* mReflowCountMgr
;
1175 PRBool
InZombieDocument(nsIContent
*aContent
);
1176 nsresult
RetargetEventToParent(nsGUIEvent
* aEvent
,
1177 nsEventStatus
* aEventStatus
);
1179 //helper funcs for event handling
1181 //protected because nsPresShellEventCB needs this.
1182 nsIFrame
* GetCurrentEventFrame();
1184 void PushCurrentEventInfo(nsIFrame
* aFrame
, nsIContent
* aContent
);
1185 void PopCurrentEventInfo();
1186 nsresult
HandleEventInternal(nsEvent
* aEvent
, nsIView
* aView
,
1187 nsEventStatus
*aStatus
);
1188 nsresult
HandlePositionedEvent(nsIView
* aView
,
1189 nsIFrame
* aTargetFrame
,
1191 nsEventStatus
* aEventStatus
);
1193 //help funcs for resize events
1194 void CreateResizeEventTimer();
1195 void KillResizeEventTimer();
1196 void FireResizeEvent();
1197 static void sResizeEventCallback(nsITimer
* aTimer
, void* aPresShell
) ;
1198 nsCOMPtr
<nsITimer
> mResizeEventTimer
;
1200 typedef void (*nsPluginEnumCallback
)(PresShell
*, nsIContent
*);
1201 void EnumeratePlugins(nsIDOMDocument
*aDocument
,
1202 const nsString
&aPluginTag
,
1203 nsPluginEnumCallback aCallback
);
1206 class NS_STACK_CLASS nsPresShellEventCB
: public nsDispatchingCallback
1209 nsPresShellEventCB(PresShell
* aPresShell
) : mPresShell(aPresShell
) {}
1211 virtual void HandleEvent(nsEventChainPostVisitor
& aVisitor
)
1213 if (aVisitor
.mPresContext
&& aVisitor
.mEvent
->eventStructType
!= NS_EVENT
) {
1214 nsIFrame
* frame
= mPresShell
->GetCurrentEventFrame();
1216 frame
->HandleEvent(aVisitor
.mPresContext
,
1217 (nsGUIEvent
*) aVisitor
.mEvent
,
1218 &aVisitor
.mEventStatus
);
1223 nsRefPtr
<PresShell
> mPresShell
;
1227 PRLogModuleInfo
* PresShell::gLog
;
1232 VerifyStyleTree(nsPresContext
* aPresContext
, nsFrameManager
* aFrameManager
)
1234 if (nsIFrameDebug::GetVerifyStyleTreeEnable()) {
1235 nsIFrame
* rootFrame
= aFrameManager
->GetRootFrame();
1236 aFrameManager
->DebugVerifyStyleTree(rootFrame
);
1239 #define VERIFY_STYLE_TREE ::VerifyStyleTree(mPresContext, FrameManager())
1241 #define VERIFY_STYLE_TREE
1244 static PRBool gVerifyReflowEnabled
;
1247 nsIPresShell::GetVerifyReflowEnable()
1250 static PRBool firstTime
= PR_TRUE
;
1252 firstTime
= PR_FALSE
;
1253 char* flags
= PR_GetEnv("GECKO_VERIFY_REFLOW_FLAGS");
1255 PRBool error
= PR_FALSE
;
1258 char* comma
= PL_strchr(flags
, ',');
1262 PRBool found
= PR_FALSE
;
1263 const VerifyReflowFlags
* flag
= gFlags
;
1264 const VerifyReflowFlags
* limit
= gFlags
+ NUM_VERIFY_REFLOW_FLAGS
;
1265 while (flag
< limit
) {
1266 if (PL_strcasecmp(flag
->name
, flags
) == 0) {
1267 gVerifyReflowFlags
|= flag
->bit
;
1285 ShowVerifyReflowFlags();
1288 if (VERIFY_REFLOW_ON
& gVerifyReflowFlags
) {
1289 gVerifyReflowEnabled
= PR_TRUE
;
1291 printf("Note: verifyreflow is enabled");
1292 if (VERIFY_REFLOW_NOISY
& gVerifyReflowFlags
) {
1295 if (VERIFY_REFLOW_ALL
& gVerifyReflowFlags
) {
1298 if (VERIFY_REFLOW_DUMP_COMMANDS
& gVerifyReflowFlags
) {
1299 printf(" (show reflow commands)");
1301 if (VERIFY_REFLOW_NOISY_RC
& gVerifyReflowFlags
) {
1302 printf(" (noisy reflow commands)");
1303 if (VERIFY_REFLOW_REALLY_NOISY_RC
& gVerifyReflowFlags
) {
1304 printf(" (REALLY noisy reflow commands)");
1311 return gVerifyReflowEnabled
;
1315 nsIPresShell::SetVerifyReflowEnable(PRBool aEnabled
)
1317 gVerifyReflowEnabled
= aEnabled
;
1321 nsIPresShell::GetVerifyReflowFlags()
1324 return gVerifyReflowFlags
;
1331 nsIPresShell::AddWeakFrame(nsWeakFrame
* aWeakFrame
)
1333 if (aWeakFrame
->GetFrame()) {
1334 aWeakFrame
->GetFrame()->AddStateBits(NS_FRAME_EXTERNAL_REFERENCE
);
1336 aWeakFrame
->SetPreviousWeakFrame(mWeakFrames
);
1337 mWeakFrames
= aWeakFrame
;
1341 nsIPresShell::RemoveWeakFrame(nsWeakFrame
* aWeakFrame
)
1343 if (mWeakFrames
== aWeakFrame
) {
1344 mWeakFrames
= aWeakFrame
->GetPreviousWeakFrame();
1347 nsWeakFrame
* nextWeak
= mWeakFrames
;
1348 while (nextWeak
&& nextWeak
->GetPreviousWeakFrame() != aWeakFrame
) {
1349 nextWeak
= nextWeak
->GetPreviousWeakFrame();
1352 nextWeak
->SetPreviousWeakFrame(aWeakFrame
->GetPreviousWeakFrame());
1356 already_AddRefed
<nsFrameSelection
>
1357 nsIPresShell::FrameSelection()
1359 NS_IF_ADDREF(mSelection
);
1363 //----------------------------------------------------------------------
1366 NS_NewPresShell(nsIPresShell
** aInstancePtrResult
)
1368 NS_PRECONDITION(nsnull
!= aInstancePtrResult
, "null ptr");
1369 if (nsnull
== aInstancePtrResult
) {
1370 return NS_ERROR_NULL_POINTER
;
1372 PresShell
* it
= new PresShell();
1374 return NS_ERROR_OUT_OF_MEMORY
;
1376 return it
->QueryInterface(NS_GET_IID(nsIPresShell
),
1377 (void **) aInstancePtrResult
);
1380 PresShell::PresShell()
1382 mSelection
= nsnull
;
1383 #ifdef MOZ_REFLOW_PERF
1384 mReflowCountMgr
= new ReflowCountMgr();
1385 mReflowCountMgr
->SetPresContext(mPresContext
);
1386 mReflowCountMgr
->SetPresShell(this);
1390 gLog
= PR_NewLogModule("PresShell");
1392 mSelectionFlags
= nsISelectionDisplay::DISPLAY_TEXT
| nsISelectionDisplay::DISPLAY_IMAGES
;
1393 mIsThemeSupportDisabled
= PR_FALSE
;
1395 new (this) nsFrameManager();
1398 NS_IMPL_ISUPPORTS8(PresShell
, nsIPresShell
, nsIDocumentObserver
,
1399 nsIViewObserver
, nsISelectionController
,
1400 nsISelectionDisplay
, nsIObserver
, nsISupportsWeakReference
,
1401 nsIMutationObserver
)
1403 PresShell::~PresShell()
1405 if (!mHaveShutDown
) {
1406 NS_NOTREACHED("Someone did not call nsIPresShell::destroy");
1410 NS_ASSERTION(mCurrentEventContentStack
.Count() == 0,
1411 "Huh, event content left on the stack in pres shell dtor!");
1412 NS_ASSERTION(mFirstCallbackEventRequest
== nsnull
&&
1413 mLastCallbackEventRequest
== nsnull
,
1414 "post-reflow queues not empty. This means we're leaking");
1417 delete mFrameConstructor
;
1419 mCurrentEventContent
= nsnull
;
1421 NS_IF_RELEASE(mPresContext
);
1422 NS_IF_RELEASE(mDocument
);
1423 NS_IF_RELEASE(mSelection
);
1427 * Initialize the presentation shell. Create view manager and style
1431 PresShell::Init(nsIDocument
* aDocument
,
1432 nsPresContext
* aPresContext
,
1433 nsIViewManager
* aViewManager
,
1434 nsStyleSet
* aStyleSet
,
1435 nsCompatibility aCompatMode
)
1437 NS_PRECONDITION(nsnull
!= aDocument
, "null ptr");
1438 NS_PRECONDITION(nsnull
!= aPresContext
, "null ptr");
1439 NS_PRECONDITION(nsnull
!= aViewManager
, "null ptr");
1442 if ((nsnull
== aDocument
) || (nsnull
== aPresContext
) ||
1443 (nsnull
== aViewManager
)) {
1444 return NS_ERROR_NULL_POINTER
;
1447 NS_WARNING("PresShell double init'ed");
1448 return NS_ERROR_ALREADY_INITIALIZED
;
1450 result
= mStackArena
.Init();
1451 NS_ENSURE_SUCCESS(result
, result
);
1453 mDocument
= aDocument
;
1454 NS_ADDREF(mDocument
);
1455 mViewManager
= aViewManager
;
1457 // Create our frame constructor.
1458 mFrameConstructor
= new nsCSSFrameConstructor(mDocument
, this);
1459 NS_ENSURE_TRUE(mFrameConstructor
, NS_ERROR_OUT_OF_MEMORY
);
1461 // The document viewer owns both view manager and pres shell.
1462 mViewManager
->SetViewObserver(this);
1464 // Bind the context to the presentation shell.
1465 mPresContext
= aPresContext
;
1466 NS_ADDREF(mPresContext
);
1467 aPresContext
->SetShell(this);
1469 // Now we can initialize the style set.
1470 result
= aStyleSet
->Init(aPresContext
);
1471 NS_ENSURE_SUCCESS(result
, result
);
1473 // From this point on, any time we return an error we need to make
1474 // sure to null out mStyleSet first, since an error return from this
1475 // method will cause the caller to delete the style set, so we don't
1476 // want to delete it in our destructor.
1477 mStyleSet
= aStyleSet
;
1479 // Notify our prescontext that it now has a compatibility mode. Note that
1480 // this MUST happen after we set up our style set but before we create any
1482 mPresContext
->CompatibilityModeChanged();
1484 // setup the preference style rules (no forced reflow), and do it
1485 // before creating any frames.
1486 SetPreferenceStyleRules(PR_FALSE
);
1488 result
= CallCreateInstance(kFrameSelectionCID
, &mSelection
);
1489 if (NS_FAILED(result
)) {
1494 // Create and initialize the frame manager
1495 result
= FrameManager()->Init(this, mStyleSet
);
1496 if (NS_FAILED(result
)) {
1497 NS_WARNING("Frame manager initialization failed");
1502 mSelection
->Init(this, nsnull
);
1504 // Important: this has to happen after the selection has been set up
1507 nsresult err
= NS_NewCaret(getter_AddRefs(mCaret
));
1508 if (NS_SUCCEEDED(err
))
1511 mOriginalCaret
= mCaret
;
1514 //SetCaretEnabled(PR_TRUE); // make it show in browser windows
1516 //set up selection to be displayed in document
1517 // Don't enable selection for print media
1518 nsPresContext::nsPresContextType type
= aPresContext
->Type();
1519 if (type
!= nsPresContext::eContext_PrintPreview
&&
1520 type
!= nsPresContext::eContext_Print
)
1521 SetDisplaySelection(nsISelectionController::SELECTION_DISABLED
);
1523 if (gMaxRCProcessingTime
== -1) {
1524 gMaxRCProcessingTime
=
1525 nsContentUtils::GetIntPref("layout.reflow.timeslice",
1526 NS_MAX_REFLOW_TIME
);
1530 nsCOMPtr
<nsIObserverService
> os
=
1531 do_GetService("@mozilla.org/observer-service;1", &result
);
1533 os
->AddObserver(this, NS_LINK_VISITED_EVENT_TOPIC
, PR_FALSE
);
1534 os
->AddObserver(this, "agent-sheet-added", PR_FALSE
);
1535 os
->AddObserver(this, "user-sheet-added", PR_FALSE
);
1536 os
->AddObserver(this, "agent-sheet-removed", PR_FALSE
);
1537 os
->AddObserver(this, "user-sheet-removed", PR_FALSE
);
1539 os
->AddObserver(this, "chrome-flush-skin-caches", PR_FALSE
);
1541 #ifdef ACCESSIBILITY
1542 os
->AddObserver(this, "a11y-init-or-shutdown", PR_FALSE
);
1547 // cache the drag service so we can check it during reflows
1548 mDragService
= do_GetService("@mozilla.org/widget/dragservice;1");
1550 #ifdef MOZ_REFLOW_PERF
1551 if (mReflowCountMgr
) {
1552 PRBool paintFrameCounts
=
1553 nsContentUtils::GetBoolPref("layout.reflow.showframecounts");
1555 PRBool dumpFrameCounts
=
1556 nsContentUtils::GetBoolPref("layout.reflow.dumpframecounts");
1558 PRBool dumpFrameByFrameCounts
=
1559 nsContentUtils::GetBoolPref("layout.reflow.dumpframebyframecounts");
1561 mReflowCountMgr
->SetDumpFrameCounts(dumpFrameCounts
);
1562 mReflowCountMgr
->SetDumpFrameByFrameCounts(dumpFrameByFrameCounts
);
1563 mReflowCountMgr
->SetPaintFrameCounts(paintFrameCounts
);
1571 PresShell::Destroy()
1573 #ifdef MOZ_REFLOW_PERF
1575 if (mReflowCountMgr
) {
1576 delete mReflowCountMgr
;
1577 mReflowCountMgr
= nsnull
;
1585 // We need to notify the destroying the nsPresContext to ESM for
1586 // suppressing to use from ESM.
1587 mPresContext
->EventStateManager()->NotifyDestroyPresContext(mPresContext
);
1591 nsCOMPtr
<nsIObserverService
> os
=
1592 do_GetService("@mozilla.org/observer-service;1");
1594 os
->RemoveObserver(this, NS_LINK_VISITED_EVENT_TOPIC
);
1595 os
->RemoveObserver(this, "agent-sheet-added");
1596 os
->RemoveObserver(this, "user-sheet-added");
1597 os
->RemoveObserver(this, "agent-sheet-removed");
1598 os
->RemoveObserver(this, "user-sheet-removed");
1600 os
->RemoveObserver(this, "chrome-flush-skin-caches");
1602 #ifdef ACCESSIBILITY
1603 os
->RemoveObserver(this, "a11y-init-or-shutdown");
1608 // If our paint suppression timer is still active, kill it.
1609 if (mPaintSuppressionTimer
) {
1610 mPaintSuppressionTimer
->Cancel();
1611 mPaintSuppressionTimer
= nsnull
;
1615 mCaret
->Terminate();
1620 mSelection
->DisconnectFromPresShell();
1623 // release our pref style sheet, if we have one still
1624 ClearPreferenceStyleRules();
1626 mIsDestroying
= PR_TRUE
;
1628 // We can't release all the event content in
1629 // mCurrentEventContentStack here since there might be code on the
1630 // stack that will release the event content too. Double release
1633 // The frames will be torn down, so remove them from the current
1634 // event frame stack (since they'd be dangling references if we'd
1635 // leave them in) and null out the mCurrentEventFrame pointer as
1638 mCurrentEventFrame
= nsnull
;
1640 PRInt32 i
, count
= mCurrentEventFrameStack
.Count();
1641 for (i
= 0; i
< count
; i
++) {
1642 mCurrentEventFrameStack
.ReplaceElementAt(nsnull
, i
);
1646 // Clear the view manager's weak pointer back to |this| in case it
1648 mViewManager
->SetViewObserver(nsnull
);
1649 mViewManager
= nsnull
;
1652 mStyleSet
->BeginShutdown(mPresContext
);
1654 // This shell must be removed from the document before the frame
1655 // hierarchy is torn down to avoid finding deleted frames through
1656 // this presshell while the frames are being torn down
1658 mDocument
->DeleteShell(this);
1661 // Revoke any pending reflow event. We need to do this and cancel
1662 // pending reflows before we destroy the frame manager, since
1663 // apparently frame destruction sometimes spins the event queue when
1664 // plug-ins are involved(!).
1665 mReflowEvent
.Revoke();
1667 CancelAllPendingReflows();
1668 CancelPostedReflowCallbacks();
1670 // Destroy the frame manager. This will destroy the frame hierarchy
1671 mFrameConstructor
->WillDestroyFrameTree(PR_TRUE
);
1672 FrameManager()->Destroy();
1674 NS_WARN_IF_FALSE(!mWeakFrames
, "Weak frames alive after destroying FrameManager");
1675 while (mWeakFrames
) {
1676 mWeakFrames
->Clear(this);
1679 // Let the style set do its cleanup.
1680 mStyleSet
->Shutdown(mPresContext
);
1683 // Clear out the prescontext's property table -- since our frame tree is
1684 // now dead, we shouldn't be looking up any more properties in that table.
1685 // We want to do this before we call SetShell() on the prescontext, so
1686 // property destructors can usefully call GetPresShell() on the
1688 mPresContext
->PropertyTable()->DeleteAllProperties();
1690 // We hold a reference to the pres context, and it holds a weak link back
1691 // to us. To avoid the pres context having a dangling reference, set its
1692 // pres shell to NULL
1693 mPresContext
->SetShell(nsnull
);
1695 // Clear the link handler (weak reference) as well
1696 mPresContext
->SetLinkHandler(nsnull
);
1699 KillResizeEventTimer();
1701 mHaveShutDown
= PR_TRUE
;
1706 // Dynamic stack memory allocation
1708 PresShell::PushStackMemory()
1714 PresShell::PopStackMemory()
1720 PresShell::AllocateStackMemory(size_t aSize
)
1722 return mStackArena
.Allocate(aSize
);
1726 PresShell::FreeFrame(size_t aSize
, void* aPtr
)
1728 mFrameArena
.FreeFrame(aSize
, aPtr
);
1732 PresShell::AllocateFrame(size_t aSize
)
1734 return mFrameArena
.AllocateFrame(aSize
);
1738 nsIPresShell::SetAuthorStyleDisabled(PRBool aStyleDisabled
)
1740 if (aStyleDisabled
!= mStyleSet
->GetAuthorStyleDisabled()) {
1741 mStyleSet
->SetAuthorStyleDisabled(aStyleDisabled
);
1742 ReconstructStyleData();
1747 nsIPresShell::GetAuthorStyleDisabled()
1749 return mStyleSet
->GetAuthorStyleDisabled();
1753 PresShell::SetPreferenceStyleRules(PRBool aForceReflow
)
1756 return NS_ERROR_NULL_POINTER
;
1759 nsPIDOMWindow
*window
= mDocument
->GetWindow();
1761 // If the document doesn't have a window there's no need to notify
1762 // its presshell about changes to preferences since the document is
1763 // in a state where it doesn't matter any more (see
1764 // DocumentViewerImpl::Close()).
1767 return NS_ERROR_NULL_POINTER
;
1770 NS_PRECONDITION(mPresContext
, "presContext cannot be null");
1772 // first, make sure this is not a chrome shell
1773 if (nsContentUtils::IsInChromeDocshell(mDocument
)) {
1777 #ifdef DEBUG_attinasi
1778 printf("Setting Preference Style Rules:\n");
1780 // if here, we need to create rules for the prefs
1781 // - this includes the background-color, the text-color,
1782 // the link color, the visited link color and the link-underlining
1784 // first clear any exising rules
1785 nsresult result
= ClearPreferenceStyleRules();
1787 // now the link rules (must come after the color rules, or links will not be correct color!)
1788 // XXX - when there is both an override and agent pref stylesheet this won't matter,
1789 // as the color rules will be overrides and the links rules will be agent
1790 if (NS_SUCCEEDED(result
)) {
1791 result
= SetPrefLinkRules();
1793 if (NS_SUCCEEDED(result
)) {
1794 result
= SetPrefFocusRules();
1796 if (NS_SUCCEEDED(result
)) {
1797 result
= SetPrefNoScriptRule();
1799 if (NS_SUCCEEDED(result
)) {
1800 result
= SetPrefNoFramesRule();
1802 #ifdef DEBUG_attinasi
1803 printf( "Preference Style Rules set: error=%ld\n", (long)result
);
1806 // Note that this method never needs to force any calculation; the caller
1807 // will recalculate style if needed
1812 return NS_ERROR_NULL_POINTER
;
1815 nsresult
PresShell::ClearPreferenceStyleRules(void)
1817 nsresult result
= NS_OK
;
1818 if (mPrefStyleSheet
) {
1819 NS_ASSERTION(mStyleSet
, "null styleset entirely unexpected!");
1821 // remove the sheet from the styleset:
1822 // - note that we have to check for success by comparing the count before and after...
1824 PRInt32 numBefore
= mStyleSet
->SheetCount(nsStyleSet::eUserSheet
);
1825 NS_ASSERTION(numBefore
> 0, "no user stylesheets in styleset, but we have one!");
1827 mStyleSet
->RemoveStyleSheet(nsStyleSet::eUserSheet
, mPrefStyleSheet
);
1829 #ifdef DEBUG_attinasi
1830 NS_ASSERTION((numBefore
- 1) == mStyleSet
->GetNumberOfUserStyleSheets(),
1831 "Pref stylesheet was not removed");
1832 printf("PrefStyleSheet removed\n");
1834 // clear the sheet pointer: it is strictly historical now
1835 mPrefStyleSheet
= nsnull
;
1841 nsresult
PresShell::CreatePreferenceStyleSheet(void)
1843 NS_ASSERTION(!mPrefStyleSheet
, "prefStyleSheet already exists");
1845 mPrefStyleSheet
= do_CreateInstance(kCSSStyleSheetCID
, &result
);
1846 if (NS_SUCCEEDED(result
)) {
1847 NS_ASSERTION(mPrefStyleSheet
, "null but no error");
1848 nsCOMPtr
<nsIURI
> uri
;
1849 result
= NS_NewURI(getter_AddRefs(uri
), "about:PreferenceStyleSheet", nsnull
);
1850 if (NS_SUCCEEDED(result
)) {
1851 NS_ASSERTION(uri
, "null but no error");
1852 result
= mPrefStyleSheet
->SetURIs(uri
, uri
, uri
);
1853 if (NS_SUCCEEDED(result
)) {
1854 mPrefStyleSheet
->SetComplete();
1857 mPrefStyleSheet
->InsertRuleInternal(NS_LITERAL_STRING("@namespace url(http://www.w3.org/1999/xhtml);"),
1859 if (NS_SUCCEEDED(result
)) {
1860 mStyleSet
->AppendStyleSheet(nsStyleSet::eUserSheet
, mPrefStyleSheet
);
1866 #ifdef DEBUG_attinasi
1867 printf("CreatePrefStyleSheet completed: error=%ld\n",(long)result
);
1870 if (NS_FAILED(result
)) {
1871 mPrefStyleSheet
= nsnull
;
1877 // XXX We want these after the @namespace rule. Does order matter
1878 // for these rules, or can we call nsICSSStyleRule::StyleRuleCount()
1879 // and just "append"?
1880 static PRUint32 sInsertPrefSheetRulesAt
= 1;
1883 PresShell::SetPrefNoScriptRule()
1885 nsresult rv
= NS_OK
;
1887 // also handle the case where print is done from print preview
1888 // see bug #342439 for more details
1889 PRBool scriptEnabled
= mDocument
->IsScriptEnabled() ||
1890 ((mPresContext
->Type() == nsPresContext::eContext_PrintPreview
||
1891 mPresContext
->Type() == nsPresContext::eContext_Print
) &&
1892 NS_PTR_TO_INT32(mDocument
->GetProperty(
1893 nsGkAtoms::scriptEnabledBeforePrintPreview
)));
1895 if (scriptEnabled
) {
1896 if (!mPrefStyleSheet
) {
1897 rv
= CreatePreferenceStyleSheet();
1898 NS_ENSURE_SUCCESS(rv
, rv
);
1903 InsertRuleInternal(NS_LITERAL_STRING("noscript{display:none!important}"),
1904 sInsertPrefSheetRulesAt
, &index
);
1910 nsresult
PresShell::SetPrefNoFramesRule(void)
1912 NS_ASSERTION(mPresContext
,"null prescontext not allowed");
1913 if (!mPresContext
) {
1914 return NS_ERROR_FAILURE
;
1917 nsresult rv
= NS_OK
;
1919 if (!mPrefStyleSheet
) {
1920 rv
= CreatePreferenceStyleSheet();
1921 NS_ENSURE_SUCCESS(rv
, rv
);
1924 NS_ASSERTION(mPrefStyleSheet
, "prefstylesheet should not be null");
1926 PRBool allowSubframes
= PR_TRUE
;
1927 nsCOMPtr
<nsISupports
> container
= mPresContext
->GetContainer();
1928 nsCOMPtr
<nsIDocShell
> docShell(do_QueryInterface(container
));
1930 docShell
->GetAllowSubframes(&allowSubframes
);
1932 if (!allowSubframes
) {
1934 rv
= mPrefStyleSheet
->
1935 InsertRuleInternal(NS_LITERAL_STRING("noframes{display:block}"),
1936 sInsertPrefSheetRulesAt
, &index
);
1937 NS_ENSURE_SUCCESS(rv
, rv
);
1938 rv
= mPrefStyleSheet
->
1939 InsertRuleInternal(NS_LITERAL_STRING("frame, frameset, iframe {display:none!important}"),
1940 sInsertPrefSheetRulesAt
, &index
);
1945 nsresult
PresShell::SetPrefLinkRules(void)
1947 NS_ASSERTION(mPresContext
,"null prescontext not allowed");
1948 if (!mPresContext
) {
1949 return NS_ERROR_FAILURE
;
1952 nsresult rv
= NS_OK
;
1954 if (!mPrefStyleSheet
) {
1955 rv
= CreatePreferenceStyleSheet();
1956 NS_ENSURE_SUCCESS(rv
, rv
);
1959 NS_ASSERTION(mPrefStyleSheet
, "prefstylesheet should not be null");
1961 // support default link colors:
1962 // this means the link colors need to be overridable,
1963 // which they are if we put them in the agent stylesheet,
1964 // though if using an override sheet this will cause authors grief still
1965 // In the agent stylesheet, they are !important when we are ignoring document colors
1967 nscolor
linkColor(mPresContext
->DefaultLinkColor());
1968 nscolor
activeColor(mPresContext
->DefaultActiveLinkColor());
1969 nscolor
visitedColor(mPresContext
->DefaultVisitedLinkColor());
1971 NS_NAMED_LITERAL_STRING(ruleClose
, "}");
1973 nsAutoString strColor
;
1975 // insert a rule to color links: '*|*:link {color: #RRGGBB [!important];}'
1976 ColorToString(linkColor
, strColor
);
1977 rv
= mPrefStyleSheet
->
1978 InsertRuleInternal(NS_LITERAL_STRING("*|*:link{color:") +
1979 strColor
+ ruleClose
,
1980 sInsertPrefSheetRulesAt
, &index
);
1981 NS_ENSURE_SUCCESS(rv
, rv
);
1983 // - visited links: '*|*:visited {color: #RRGGBB [!important];}'
1984 ColorToString(visitedColor
, strColor
);
1985 rv
= mPrefStyleSheet
->
1986 InsertRuleInternal(NS_LITERAL_STRING("*|*:visited{color:") +
1987 strColor
+ ruleClose
,
1988 sInsertPrefSheetRulesAt
, &index
);
1989 NS_ENSURE_SUCCESS(rv
, rv
);
1991 // - active links: '*|*:-moz-any-link:active {color: #RRGGBB [!important];}'
1992 ColorToString(activeColor
, strColor
);
1993 rv
= mPrefStyleSheet
->
1994 InsertRuleInternal(NS_LITERAL_STRING("*|*:-moz-any-link:active{color:") +
1995 strColor
+ ruleClose
,
1996 sInsertPrefSheetRulesAt
, &index
);
1997 NS_ENSURE_SUCCESS(rv
, rv
);
1999 PRBool underlineLinks
=
2000 mPresContext
->GetCachedBoolPref(kPresContext_UnderlineLinks
);
2002 if (underlineLinks
) {
2003 // create a rule to make underlining happen
2004 // '*|*:-moz-any-link {text-decoration:[underline|none];}'
2005 // no need for important, we want these to be overridable
2006 // NOTE: these must go in the agent stylesheet or they cannot be
2007 // overridden by authors
2008 rv
= mPrefStyleSheet
->
2009 InsertRuleInternal(NS_LITERAL_STRING("*|*:-moz-any-link{text-decoration:underline}"),
2010 sInsertPrefSheetRulesAt
, &index
);
2012 rv
= mPrefStyleSheet
->
2013 InsertRuleInternal(NS_LITERAL_STRING("*|*:-moz-any-link{text-decoration:none}"),
2014 sInsertPrefSheetRulesAt
, &index
);
2020 nsresult
PresShell::SetPrefFocusRules(void)
2022 NS_ASSERTION(mPresContext
,"null prescontext not allowed");
2023 nsresult result
= NS_OK
;
2026 result
= NS_ERROR_FAILURE
;
2028 if (NS_SUCCEEDED(result
) && !mPrefStyleSheet
)
2029 result
= CreatePreferenceStyleSheet();
2031 if (NS_SUCCEEDED(result
)) {
2032 NS_ASSERTION(mPrefStyleSheet
, "prefstylesheet should not be null");
2034 if (mPresContext
->GetUseFocusColors()) {
2035 nscolor
focusBackground(mPresContext
->FocusBackgroundColor());
2036 nscolor
focusText(mPresContext
->FocusTextColor());
2038 // insert a rule to make focus the preferred color
2040 nsAutoString strRule
, strColor
;
2042 ///////////////////////////////////////////////////////////////
2043 // - focus: '*:focus
2044 ColorToString(focusText
,strColor
);
2045 strRule
.AppendLiteral("*:focus,*:focus>font {color: ");
2046 strRule
.Append(strColor
);
2047 strRule
.AppendLiteral(" !important; background-color: ");
2048 ColorToString(focusBackground
,strColor
);
2049 strRule
.Append(strColor
);
2050 strRule
.AppendLiteral(" !important; } ");
2052 result
= mPrefStyleSheet
->
2053 InsertRuleInternal(strRule
, sInsertPrefSheetRulesAt
, &index
);
2055 PRUint8 focusRingWidth
= mPresContext
->FocusRingWidth();
2056 PRBool focusRingOnAnything
= mPresContext
->GetFocusRingOnAnything();
2057 PRUint8 focusRingStyle
= mPresContext
->GetFocusRingStyle();
2059 if ((NS_SUCCEEDED(result
) && focusRingWidth
!= 1 && focusRingWidth
<= 4 ) || focusRingOnAnything
) {
2061 nsAutoString strRule
;
2062 if (!focusRingOnAnything
)
2063 strRule
.AppendLiteral("*|*:link:focus, *|*:visited"); // If we only want focus rings on the normal things like links
2064 strRule
.AppendLiteral(":focus {outline: "); // For example 3px dotted WindowText (maximum 4)
2065 strRule
.AppendInt(focusRingWidth
);
2066 if (focusRingStyle
== 0) // solid
2067 strRule
.AppendLiteral("px solid -moz-mac-focusring !important; -moz-outline-radius: 3px; outline-offset: 1px; } ");
2069 strRule
.AppendLiteral("px dotted WindowText !important; } ");
2071 result
= mPrefStyleSheet
->
2072 InsertRuleInternal(strRule
, sInsertPrefSheetRulesAt
, &index
);
2073 NS_ENSURE_SUCCESS(result
, result
);
2074 if (focusRingWidth
!= 1) {
2075 // If the focus ring width is different from the default, fix buttons with rings
2076 strRule
.AssignLiteral("button::-moz-focus-inner, input[type=\"reset\"]::-moz-focus-inner,");
2077 strRule
.AppendLiteral("input[type=\"button\"]::-moz-focus-inner, ");
2078 strRule
.AppendLiteral("input[type=\"submit\"]::-moz-focus-inner { padding: 1px 2px 1px 2px; border: ");
2079 strRule
.AppendInt(focusRingWidth
);
2080 if (focusRingStyle
== 0) // solid
2081 strRule
.AppendLiteral("px solid transparent !important; } ");
2083 strRule
.AppendLiteral("px dotted transparent !important; } ");
2084 result
= mPrefStyleSheet
->
2085 InsertRuleInternal(strRule
, sInsertPrefSheetRulesAt
, &index
);
2086 NS_ENSURE_SUCCESS(result
, result
);
2088 strRule
.AssignLiteral("button:focus::-moz-focus-inner, input[type=\"reset\"]:focus::-moz-focus-inner,");
2089 strRule
.AppendLiteral("input[type=\"button\"]:focus::-moz-focus-inner, input[type=\"submit\"]:focus::-moz-focus-inner {");
2090 strRule
.AppendLiteral("border-color: ButtonText !important; }");
2091 result
= mPrefStyleSheet
->
2092 InsertRuleInternal(strRule
, sInsertPrefSheetRulesAt
, &index
);
2100 PresShell::AddUserSheet(nsISupports
* aSheet
)
2102 // Make sure this does what DocumentViewerImpl::CreateStyleSet does wrt
2103 // ordering. We want this new sheet to come after all the existing stylesheet
2104 // service sheets, but before other user sheets; see nsIStyleSheetService.idl
2105 // for the ordering. Just remove and readd all the nsStyleSheetService
2107 nsCOMPtr
<nsIStyleSheetService
> dummy
=
2108 do_GetService(NS_STYLESHEETSERVICE_CONTRACTID
);
2110 mStyleSet
->BeginUpdate();
2112 nsStyleSheetService
*sheetService
= nsStyleSheetService::gInstance
;
2113 nsCOMArray
<nsIStyleSheet
> & userSheets
= *sheetService
->UserStyleSheets();
2115 // Iterate forwards when removing so the searches for RemoveStyleSheet are as
2116 // short as possible.
2117 for (i
= 0; i
< userSheets
.Count(); ++i
) {
2118 mStyleSet
->RemoveStyleSheet(nsStyleSet::eUserSheet
, userSheets
[i
]);
2121 // Now iterate backwards, so that the order of userSheets will be the same as
2122 // the order of sheets from it in the style set.
2123 for (i
= userSheets
.Count() - 1; i
>= 0; --i
) {
2124 mStyleSet
->PrependStyleSheet(nsStyleSet::eUserSheet
, userSheets
[i
]);
2127 mStyleSet
->EndUpdate();
2129 ReconstructStyleData();
2133 PresShell::AddAgentSheet(nsISupports
* aSheet
)
2135 // Make sure this does what DocumentViewerImpl::CreateStyleSet does
2137 nsCOMPtr
<nsIStyleSheet
> sheet
= do_QueryInterface(aSheet
);
2142 mStyleSet
->AppendStyleSheet(nsStyleSet::eAgentSheet
, sheet
);
2143 ReconstructStyleData();
2147 PresShell::RemoveSheet(nsStyleSet::sheetType aType
, nsISupports
* aSheet
)
2149 nsCOMPtr
<nsIStyleSheet
> sheet
= do_QueryInterface(aSheet
);
2154 mStyleSet
->RemoveStyleSheet(aType
, sheet
);
2155 ReconstructStyleData();
2159 PresShell::SetDisplaySelection(PRInt16 aToggle
)
2161 mSelection
->SetDisplaySelection(aToggle
);
2166 PresShell::GetDisplaySelection(PRInt16
*aToggle
)
2168 *aToggle
= mSelection
->GetDisplaySelection();
2173 PresShell::GetSelection(SelectionType aType
, nsISelection
**aSelection
)
2175 if (!aSelection
|| !mSelection
)
2176 return NS_ERROR_NULL_POINTER
;
2178 *aSelection
= mSelection
->GetSelection(aType
);
2181 return NS_ERROR_INVALID_ARG
;
2183 NS_ADDREF(*aSelection
);
2189 PresShell::GetCurrentSelection(SelectionType aType
)
2194 return mSelection
->GetSelection(aType
);
2198 PresShell::ScrollSelectionIntoView(SelectionType aType
, SelectionRegion aRegion
, PRBool aIsSynchronous
)
2201 return NS_ERROR_NULL_POINTER
;
2203 return mSelection
->ScrollSelectionIntoView(aType
, aRegion
, aIsSynchronous
);
2207 PresShell::RepaintSelection(SelectionType aType
)
2210 return NS_ERROR_NULL_POINTER
;
2212 return mSelection
->RepaintSelection(aType
);
2215 // Make shell be a document observer
2217 PresShell::BeginObservingDocument()
2219 if (mDocument
&& !mIsDestroying
) {
2220 mDocument
->AddObserver(this);
2221 if (mIsDocumentGone
) {
2222 NS_WARNING("Adding a presshell that was disconnected from the document "
2223 "as a document observer? Sounds wrong...");
2224 mIsDocumentGone
= PR_FALSE
;
2230 // Make shell stop being a document observer
2232 PresShell::EndObservingDocument()
2234 // XXXbz do we need to tell the frame constructor that the document
2235 // is gone, perhaps? Except for printing it's NOT gone, sometimes.
2236 mIsDocumentGone
= PR_TRUE
;
2238 mDocument
->RemoveObserver(this);
2244 char* nsPresShell_ReflowStackPointerTop
;
2247 static void CheckForFocus(nsPIDOMWindow
* aOurWindow
,
2248 nsIFocusController
* aFocusController
,
2249 nsIDocument
* aDocument
)
2251 NS_ASSERTION(aOurWindow
->IsOuterWindow(),
2252 "Uh, our window has to be an outer window!");
2254 // Now that we have a root frame, we can set focus on the presshell.
2255 // We do this only if our DOM window is currently focused or is an
2256 // an ancestor of a previously focused window.
2258 if (!aFocusController
)
2261 nsCOMPtr
<nsIDOMWindowInternal
> focusedWindow
;
2262 aFocusController
->GetFocusedWindow(getter_AddRefs(focusedWindow
));
2263 if (!focusedWindow
) {
2264 // This happens if the window has not been shown yet. We don't need to
2265 // focus anything now because showing the window will set the focus.
2269 // Walk up the document chain, starting with focusedWindow's document.
2270 // We stop walking when we find a document that has a null DOMWindow
2271 // (meaning that the DOMWindow has a new document now) or find aOurWindow
2272 // as the document's window. We also stop if we hit aDocument, since
2273 // that means there is a child document which loaded before us that's
2274 // already been given focus.
2276 nsCOMPtr
<nsIDOMDocument
> focusedDOMDoc
;
2277 focusedWindow
->GetDocument(getter_AddRefs(focusedDOMDoc
));
2279 nsCOMPtr
<nsIDocument
> curDoc
= do_QueryInterface(focusedDOMDoc
);
2281 // This can happen if the previously focused DOM window has been
2282 // unhooked from its document during document teardown. We don't
2283 // really have any other information to help us determine where
2284 // focusedWindow fits into the DOM window hierarchy. For now, we'll
2285 // go ahead and allow this window to take focus, so that something
2292 nsPIDOMWindow
*curWin
= curDoc
->GetWindow();
2294 if (!curWin
|| curWin
== aOurWindow
)
2297 curDoc
= curDoc
->GetParentDocument();
2298 if (curDoc
== aDocument
)
2303 // We reached the top of the document chain, and did not encounter
2304 // aOurWindow or a windowless document. So, focus should be unaffected
2305 // by this document load.
2310 aFocusController
->GetActive(&active
);
2312 aOurWindow
->Focus();
2314 // We need to ensure that the focus controller is updated, since it may be
2315 // suppressed when this function is called.
2316 aFocusController
->SetFocusedWindow(aOurWindow
);
2320 PresShell::GetDidInitialReflow(PRBool
*aDidInitialReflow
)
2322 if (!aDidInitialReflow
)
2323 return NS_ERROR_FAILURE
;
2325 *aDidInitialReflow
= mDidInitialReflow
;
2331 PresShell::InitialReflow(nscoord aWidth
, nscoord aHeight
)
2333 if (mIsDestroying
) {
2337 NS_ASSERTION(!mDidInitialReflow
, "Why are we being called?");
2339 nsCOMPtr
<nsIPresShell
> kungFuDeathGrip(this);
2340 mDidInitialReflow
= PR_TRUE
;
2343 if (VERIFY_REFLOW_NOISY_RC
& gVerifyReflowFlags
) {
2345 nsIURI
*uri
= mDocument
->GetDocumentURI();
2349 printf("*** PresShell::InitialReflow (this=%p, url='%s')\n", (void*)this, url
.get());
2356 mCaret
->EraseCaret();
2358 // XXX Do a full invalidate at the beginning so that invalidates along
2359 // the way don't have region accumulation issues?
2361 mPresContext
->SetVisibleArea(nsRect(0, 0, aWidth
, aHeight
));
2363 nsIContent
*root
= mDocument
? mDocument
->GetRootContent() : nsnull
;
2365 // Get the root frame from the frame manager
2366 nsIFrame
* rootFrame
= FrameManager()->GetRootFrame();
2369 MOZ_TIMER_DEBUGLOG(("Reset and start: Frame Creation: PresShell::InitialReflow(), this=%p\n",
2371 MOZ_TIMER_RESET(mFrameCreationWatch
);
2372 MOZ_TIMER_START(mFrameCreationWatch
);
2375 nsAutoScriptBlocker scriptBlocker
;
2376 mFrameConstructor
->BeginUpdate();
2379 // Have style sheet processor construct a frame for the
2380 // precursors to the root content object's frame
2381 mFrameConstructor
->ConstructRootFrame(root
, &rootFrame
);
2382 FrameManager()->SetRootFrame(rootFrame
);
2385 // Have the style sheet processor construct frame for the root
2386 // content object down
2387 mFrameConstructor
->ContentInserted(nsnull
, root
, 0, nsnull
);
2389 MOZ_TIMER_DEBUGLOG(("Stop: Frame Creation: PresShell::InitialReflow(), this=%p\n",
2391 MOZ_TIMER_STOP(mFrameCreationWatch
);
2393 // Something in mFrameConstructor->ContentInserted may have caused
2394 // Destroy() to get called, bug 337586.
2395 NS_ENSURE_STATE(!mHaveShutDown
);
2397 mFrameConstructor
->EndUpdate();
2400 // DidCauseReflow may have killed us too
2401 NS_ENSURE_STATE(!mHaveShutDown
);
2403 // Run the XBL binding constructors for any new frames we've constructed
2404 mDocument
->BindingManager()->ProcessAttachedQueue();
2406 // Constructors may have killed us too
2407 NS_ENSURE_STATE(!mHaveShutDown
);
2409 // Now flush out pending restyles before we actually reflow, in
2410 // case XBL constructors changed styles somewhere.
2411 mFrameConstructor
->ProcessPendingRestyles();
2413 // And that might have run _more_ XBL constructors
2414 NS_ENSURE_STATE(!mHaveShutDown
);
2416 // Now reget the root frame, since all that script might have affected it
2417 // somehow. Currently that can't happen, as long as mHaveShutDown is
2418 // false, but let's not rely on that.
2419 rootFrame
= FrameManager()->GetRootFrame();
2423 // Note: Because the frame just got created, it has the NS_FRAME_IS_DIRTY
2424 // bit set. Unset it so that FrameNeedsReflow() will work right.
2425 NS_ASSERTION(mDirtyRoots
.IndexOf(rootFrame
) == -1,
2426 "Why is the root in mDirtyRoots already?");
2428 rootFrame
->RemoveStateBits(NS_FRAME_IS_DIRTY
|
2429 NS_FRAME_HAS_DIRTY_CHILDREN
);
2430 FrameNeedsReflow(rootFrame
, eResize
, NS_FRAME_IS_DIRTY
);
2432 NS_ASSERTION(mDirtyRoots
.IndexOf(rootFrame
) != -1,
2433 "Should be in mDirtyRoots now");
2434 NS_ASSERTION(mReflowEvent
.IsPending(), "Why no reflow event pending?");
2437 // Restore our root scroll position now if we're getting here after EndLoad
2438 // got called, since this is our one chance to do it. Note that we need not
2439 // have reflowed for this to work; when the scrollframe is finally reflowed
2440 // it'll puick up the position we store in it here.
2441 if (!mDocumentLoading
) {
2442 RestoreRootScrollPosition();
2445 // For printing, we just immediately unsuppress.
2446 if (!mPresContext
->IsPaginated()) {
2447 // Kick off a one-shot timer based off our pref value. When this timer
2448 // fires, if painting is still locked down, then we will go ahead and
2449 // trigger a full invalidate and allow painting to proceed normally.
2450 mPaintingSuppressed
= PR_TRUE
;
2451 mPaintSuppressionTimer
= do_CreateInstance("@mozilla.org/timer;1");
2452 if (!mPaintSuppressionTimer
)
2453 // Uh-oh. We must be out of memory. No point in keeping painting locked down.
2454 mPaintingSuppressed
= PR_FALSE
;
2456 // Initialize the timer.
2458 // Default to PAINTLOCK_EVENT_DELAY if we can't get the pref value.
2460 nsContentUtils::GetIntPref("nglayout.initialpaint.delay",
2461 PAINTLOCK_EVENT_DELAY
);
2463 mPaintSuppressionTimer
->InitWithFuncCallback(sPaintSuppressionCallback
,
2465 nsITimer::TYPE_ONE_SHOT
);
2469 return NS_OK
; //XXX this needs to be real. MMP
2473 PresShell::sPaintSuppressionCallback(nsITimer
*aTimer
, void* aPresShell
)
2475 PresShell
* self
= static_cast<PresShell
*>(aPresShell
);
2477 self
->UnsuppressPainting();
2481 PresShell::ResizeReflow(nscoord aWidth
, nscoord aHeight
)
2483 NS_PRECONDITION(!mIsReflowing
, "Shouldn't be in reflow here!");
2484 NS_PRECONDITION(aWidth
!= NS_UNCONSTRAINEDSIZE
,
2485 "shouldn't use unconstrained widths anymore");
2487 // If we don't have a root frame yet, that means we haven't had our initial
2488 // reflow... If that's the case, and aWidth or aHeight is unconstrained,
2489 // ignore them altogether.
2490 nsIFrame
* rootFrame
= FrameManager()->GetRootFrame();
2492 if (!rootFrame
&& aHeight
== NS_UNCONSTRAINEDSIZE
) {
2493 // We can't do the work needed for SizeToContent without a root
2494 // frame, and we want to return before setting the visible area.
2495 return NS_ERROR_NOT_AVAILABLE
;
2498 mPresContext
->SetVisibleArea(nsRect(0, 0, aWidth
, aHeight
));
2500 // There isn't anything useful we can do if the initial reflow hasn't happened
2504 if (!GetPresContext()->SupressingResizeReflow())
2506 NS_ASSERTION(mViewManager
, "Must have view manager");
2507 nsCOMPtr
<nsIViewManager
> viewManagerDeathGrip
= mViewManager
;
2508 nsIViewManager::UpdateViewBatch
batch(mViewManager
);
2510 // Take this ref after viewManager so it'll make sure to go away first
2511 nsCOMPtr
<nsIPresShell
> kungFuDeathGrip(this);
2513 // Make sure style is up to date
2514 mFrameConstructor
->ProcessPendingRestyles();
2516 if (!mIsDestroying
) {
2517 // XXX Do a full invalidate at the beginning so that invalidates along
2518 // the way don't have region accumulation issues?
2521 nsAutoScriptBlocker scriptBlocker
;
2524 // Kick off a top-down reflow
2525 AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Reflow
);
2526 mIsReflowing
= PR_TRUE
;
2528 mDirtyRoots
.RemoveElement(rootFrame
);
2529 DoReflow(rootFrame
);
2530 mIsReflowing
= PR_FALSE
;
2536 batch
.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC
);
2539 if (aHeight
== NS_UNCONSTRAINEDSIZE
) {
2540 mPresContext
->SetVisibleArea(
2541 nsRect(0, 0, aWidth
, rootFrame
->GetRect().height
));
2544 if (!mIsDestroying
) {
2545 CreateResizeEventTimer();
2548 return NS_OK
; //XXX this needs to be real. MMP
2551 #define RESIZE_EVENT_DELAY 200
2554 PresShell::CreateResizeEventTimer ()
2556 // if we already have a timer set, ignore this call
2557 if (mResizeEventTimer
)
2560 if (mIsDocumentGone
)
2563 mResizeEventTimer
= do_CreateInstance("@mozilla.org/timer;1");
2564 if (mResizeEventTimer
) {
2565 mResizeEventTimer
->InitWithFuncCallback(sResizeEventCallback
, this, RESIZE_EVENT_DELAY
,
2566 nsITimer::TYPE_ONE_SHOT
);
2571 PresShell::KillResizeEventTimer()
2573 if (mResizeEventTimer
) {
2574 mResizeEventTimer
->Cancel();
2575 mResizeEventTimer
= nsnull
;
2580 PresShell::sResizeEventCallback(nsITimer
*aTimer
, void* aPresShell
)
2582 PresShell
* self
= static_cast<PresShell
*>(aPresShell
);
2584 self
->FireResizeEvent();
2589 PresShell::FireResizeEvent()
2591 if (mIsDocumentGone
)
2594 // allow a new timer to be set
2595 mResizeEventTimer
= nsnull
;
2597 //Send resize event from here.
2598 nsEvent
event(PR_TRUE
, NS_RESIZE_EVENT
);
2599 nsEventStatus status
= nsEventStatus_eIgnore
;
2601 nsPIDOMWindow
*window
= mDocument
->GetWindow();
2603 nsEventDispatcher::Dispatch(window
, mPresContext
, &event
, nsnull
, &status
);
2604 // |this| may now be destroyed
2609 PresShell::SetIgnoreFrameDestruction(PRBool aIgnore
)
2611 mIgnoreFrameDestruction
= aIgnore
;
2616 PresShell::NotifyDestroyingFrame(nsIFrame
* aFrame
)
2618 if (!mIgnoreFrameDestruction
) {
2619 mFrameConstructor
->NotifyDestroyingFrame(aFrame
);
2621 for (PRInt32 idx
= mDirtyRoots
.Count(); idx
; ) {
2623 if (mDirtyRoots
[idx
] == aFrame
) {
2624 mDirtyRoots
.RemoveElementAt(idx
);
2628 // Notify the frame manager
2629 FrameManager()->NotifyDestroyingFrame(aFrame
);
2631 // Remove frame properties
2632 mPresContext
->PropertyTable()->DeleteAllPropertiesFor(aFrame
);
2638 // note that this can return a null caret, but NS_OK
2639 NS_IMETHODIMP
PresShell::GetCaret(nsCaret
**outCaret
)
2641 NS_ENSURE_ARG_POINTER(outCaret
);
2644 NS_IF_ADDREF(*outCaret
);
2648 NS_IMETHODIMP_(void) PresShell::MaybeInvalidateCaretPosition()
2651 mCaret
->InvalidateOutsideCaret();
2655 void PresShell::SetCaret(nsCaret
*aNewCaret
)
2660 void PresShell::RestoreCaret()
2662 mCaret
= mOriginalCaret
;
2665 NS_IMETHODIMP
PresShell::SetCaretEnabled(PRBool aInEnable
)
2667 PRBool oldEnabled
= mCaretEnabled
;
2669 mCaretEnabled
= aInEnable
;
2671 if (mCaret
&& (mCaretEnabled
!= oldEnabled
))
2673 /* Don't change the caret's selection here! This was an evil side-effect of SetCaretEnabled()
2674 nsCOMPtr<nsIDOMSelection> domSel;
2675 if (NS_SUCCEEDED(GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(domSel))) && domSel)
2676 mCaret->SetCaretDOMSelection(domSel);
2678 mCaret
->SetCaretVisible(mCaretEnabled
);
2684 NS_IMETHODIMP
PresShell::SetCaretReadOnly(PRBool aReadOnly
)
2687 mCaret
->SetCaretReadOnly(aReadOnly
);
2691 NS_IMETHODIMP
PresShell::GetCaretEnabled(PRBool
*aOutEnabled
)
2693 NS_ENSURE_ARG_POINTER(aOutEnabled
);
2694 *aOutEnabled
= mCaretEnabled
;
2698 NS_IMETHODIMP
PresShell::SetCaretVisibilityDuringSelection(PRBool aVisibility
)
2701 mCaret
->SetVisibilityDuringSelection(aVisibility
);
2705 NS_IMETHODIMP
PresShell::GetCaretVisible(PRBool
*aOutIsVisible
)
2707 *aOutIsVisible
= PR_FALSE
;
2709 nsresult rv
= mCaret
->GetCaretVisible(aOutIsVisible
);
2710 NS_ENSURE_SUCCESS(rv
,rv
);
2715 NS_IMETHODIMP
PresShell::SetSelectionFlags(PRInt16 aInEnable
)
2717 mSelectionFlags
= aInEnable
;
2721 NS_IMETHODIMP
PresShell::GetSelectionFlags(PRInt16
*aOutEnable
)
2724 return NS_ERROR_INVALID_ARG
;
2725 *aOutEnable
= mSelectionFlags
;
2729 //implementation of nsISelectionController
2732 PresShell::CharacterMove(PRBool aForward
, PRBool aExtend
)
2734 return mSelection
->CharacterMove(aForward
, aExtend
);
2738 PresShell::CharacterExtendForDelete()
2740 return mSelection
->CharacterExtendForDelete();
2744 PresShell::WordMove(PRBool aForward
, PRBool aExtend
)
2746 return mSelection
->WordMove(aForward
, aExtend
);
2750 PresShell::WordExtendForDelete(PRBool aForward
)
2752 return mSelection
->WordExtendForDelete(aForward
);
2756 PresShell::LineMove(PRBool aForward
, PRBool aExtend
)
2758 nsresult result
= mSelection
->LineMove(aForward
, aExtend
);
2759 // if we can't go down/up any more we must then move caret completely to
2760 // end/beginning respectively.
2761 if (NS_FAILED(result
))
2762 result
= CompleteMove(aForward
,aExtend
);
2767 PresShell::IntraLineMove(PRBool aForward
, PRBool aExtend
)
2769 return mSelection
->IntraLineMove(aForward
, aExtend
);
2775 PresShell::PageMove(PRBool aForward
, PRBool aExtend
)
2778 nsIViewManager
* viewManager
= GetViewManager();
2779 nsIScrollableView
*scrollableView
;
2781 return NS_ERROR_UNEXPECTED
;
2782 result
= viewManager
->GetRootScrollableView(&scrollableView
);
2783 if (NS_FAILED(result
))
2785 if (!scrollableView
)
2786 return NS_ERROR_UNEXPECTED
;
2787 nsIView
*scrolledView
;
2788 result
= scrollableView
->GetScrolledView(scrolledView
);
2789 mSelection
->CommonPageMove(aForward
, aExtend
, scrollableView
);
2790 // After ScrollSelectionIntoView(), the pending notifications might be
2791 // flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
2792 return ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL
, nsISelectionController::SELECTION_FOCUS_REGION
, PR_TRUE
);
2798 PresShell::ScrollPage(PRBool aForward
)
2800 nsIScrollableView
* scrollView
= GetViewToScroll(nsLayoutUtils::eVertical
);
2802 scrollView
->ScrollByPages(0, aForward
? 1 : -1, NS_VMREFRESH_SMOOTHSCROLL
);
2808 PresShell::ScrollLine(PRBool aForward
)
2810 nsIScrollableView
* scrollView
= GetViewToScroll(nsLayoutUtils::eVertical
);
2812 #ifdef MOZ_WIDGET_COCOA
2813 // Emulate the Mac IE behavior of scrolling a minimum of 2 lines
2814 // rather than 1. This vastly improves scrolling speed.
2815 scrollView
->ScrollByLines(0, aForward
? 2 : -2, NS_VMREFRESH_SMOOTHSCROLL
);
2817 scrollView
->ScrollByLines(0, aForward
? 1 : -1, NS_VMREFRESH_SMOOTHSCROLL
);
2821 // force the update to happen now, otherwise multiple scrolls can
2822 // occur before the update is processed. (bug #7354)
2824 // I'd use Composite here, but it doesn't always work.
2826 nsIViewManager
* viewManager
= GetViewManager();
2828 viewManager
->ForceUpdate();
2835 PresShell::ScrollHorizontal(PRBool aLeft
)
2837 nsIScrollableView
* scrollView
= GetViewToScroll(nsLayoutUtils::eHorizontal
);
2839 scrollView
->ScrollByLines(aLeft
? -1 : 1, 0, NS_VMREFRESH_SMOOTHSCROLL
);
2841 // force the update to happen now, otherwise multiple scrolls can
2842 // occur before the update is processed. (bug #7354)
2844 // I'd use Composite here, but it doesn't always work.
2846 nsIViewManager
* viewManager
= GetViewManager();
2848 viewManager
->ForceUpdate();
2855 PresShell::CompleteScroll(PRBool aForward
)
2857 nsIScrollableView
* scrollView
= GetViewToScroll(nsLayoutUtils::eVertical
);
2859 scrollView
->ScrollByWhole(!aForward
);//TRUE = top, aForward TRUE=bottom
2865 PresShell::CompleteMove(PRBool aForward
, PRBool aExtend
)
2867 // Beware! This may flush notifications via synchronous
2868 // ScrollSelectionIntoView.
2870 nsIContent
* root
= mSelection
->GetAncestorLimiter();
2872 if (root
&& (doc
= root
->GetOwnerDoc()) && doc
->GetRootContent() != root
) {
2873 // Make the caret be either at the very beginning (0) or the very end of
2874 // root. Only do this when not moving to the beginning or end of the
2875 // document (root is null or root is the documentElement), that's handled
2876 // below by moving to beginning or end of the scrollable view.
2877 nsIContent
* node
= root
;
2879 nsFrameSelection::HINT hint
= nsFrameSelection::HINTLEFT
;
2881 nsIContent
* next
= node
;
2883 while ((count
= next
->GetChildCount()) > 0) {
2886 next
= next
->GetChildAt(count
- 1);
2889 if (offset
> 0 && node
->GetChildAt(offset
- 1)->Tag() == nsGkAtoms::br
) {
2891 hint
= nsFrameSelection::HINTRIGHT
; // for bug 106855
2895 mSelection
->HandleClick(node
, offset
, offset
, aExtend
, PR_FALSE
, hint
);
2897 // HandleClick resets ancestorLimiter, so set it again.
2898 mSelection
->SetAncestorLimiter(root
);
2900 // After ScrollSelectionIntoView(), the pending notifications might be
2901 // flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
2903 ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL
,
2904 nsISelectionController::SELECTION_FOCUS_REGION
,
2908 nsIFrame
*frame
= FrameConstructor()->GetRootElementFrame();
2910 return NS_ERROR_FAILURE
;
2911 nsPeekOffsetStruct pos
= frame
->GetExtremeCaretPosition(!aForward
);
2913 mSelection
->HandleClick(pos
.mResultContent
,pos
.mContentOffset
,pos
.mContentOffset
/*End*/ ,aExtend
, PR_FALSE
, aForward
);
2915 // After ScrollSelectionIntoView(), the pending notifications might be
2916 // flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
2917 return ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL
,
2918 nsISelectionController::SELECTION_FOCUS_REGION
,
2923 PresShell::SelectAll()
2925 return mSelection
->SelectAll();
2929 PresShell::CheckVisibility(nsIDOMNode
*node
, PRInt16 startOffset
, PRInt16 EndOffset
, PRBool
*_retval
)
2931 if (!node
|| startOffset
>EndOffset
|| !_retval
|| startOffset
<0 || EndOffset
<0)
2932 return NS_ERROR_INVALID_ARG
;
2933 *_retval
= PR_FALSE
; //initialize return parameter
2934 nsCOMPtr
<nsIContent
> content(do_QueryInterface(node
));
2936 return NS_ERROR_FAILURE
;
2937 nsIFrame
*frame
= GetPrimaryFrameFor(content
);
2938 if (!frame
) //no frame to look at so it must not be visible
2940 //start process now to go through all frames to find startOffset. then check chars after that to see
2941 //if anything until EndOffset is visible.
2942 PRBool finished
= PR_FALSE
;
2943 frame
->CheckVisibility(mPresContext
,startOffset
,EndOffset
,PR_TRUE
,&finished
, _retval
);
2944 return NS_OK
;//dont worry about other return val
2947 //end implementations nsISelectionController
2951 PresShell::StyleChangeReflow()
2953 nsIFrame
* rootFrame
= FrameManager()->GetRootFrame();
2954 // At the moment at least, we don't have a root frame before the initial
2955 // reflow; it's safe to just ignore the request in that case
2959 return FrameNeedsReflow(rootFrame
, eStyleChange
, NS_FRAME_IS_DIRTY
);
2963 nsIPresShell::GetRootFrame() const
2965 return FrameManager()->GetRootFrame();
2969 nsIPresShell::GetRootScrollFrame() const
2971 nsIFrame
* rootFrame
= FrameManager()->GetRootFrame();
2972 // Ensure root frame is a viewport frame
2973 if (!rootFrame
|| nsGkAtoms::viewportFrame
!= rootFrame
->GetType())
2975 nsIFrame
* theFrame
= rootFrame
->GetFirstChild(nsnull
);
2976 if (!theFrame
|| nsGkAtoms::scrollFrame
!= theFrame
->GetType())
2982 nsIPresShell::GetRootScrollFrameAsScrollable() const
2984 nsIFrame
* frame
= GetRootScrollFrame();
2987 nsIScrollableFrame
* scrollableFrame
= nsnull
;
2988 CallQueryInterface(frame
, &scrollableFrame
);
2989 NS_ASSERTION(scrollableFrame
,
2990 "All scroll frames must implement nsIScrollableFrame");
2991 return scrollableFrame
;
2995 PresShell::GetPageSequenceFrame(nsIPageSequenceFrame
** aResult
) const
2997 NS_PRECONDITION(nsnull
!= aResult
, "null ptr");
2998 if (nsnull
== aResult
) {
2999 return NS_ERROR_NULL_POINTER
;
3003 nsIFrame
* frame
= mFrameConstructor
->GetPageSequenceFrame();
3005 CallQueryInterface(frame
, aResult
);
3007 return *aResult
? NS_OK
: NS_ERROR_FAILURE
;
3011 PresShell::GetFrameForPoint(nsIFrame
* aFrame
, nsPoint aPt
)
3013 return nsLayoutUtils::GetFrameForPoint(aFrame
, aPt
);
3017 PresShell::BeginUpdate(nsIDocument
*aDocument
, nsUpdateType aUpdateType
)
3022 mFrameConstructor
->BeginUpdate();
3024 if (aUpdateType
& UPDATE_STYLE
)
3025 mStyleSet
->BeginUpdate();
3029 PresShell::EndUpdate(nsIDocument
*aDocument
, nsUpdateType aUpdateType
)
3032 NS_PRECONDITION(0 != mUpdateCount
, "too many EndUpdate's");
3036 if (aUpdateType
& UPDATE_STYLE
) {
3037 mStyleSet
->EndUpdate();
3038 if (mStylesHaveChanged
)
3039 ReconstructStyleData();
3042 mFrameConstructor
->EndUpdate();
3046 PresShell::RestoreRootScrollPosition()
3048 // Restore frame state for the root scroll frame
3049 nsCOMPtr
<nsILayoutHistoryState
> historyState
=
3050 mDocument
->GetLayoutHistoryState();
3051 // Make sure we don't reenter reflow via the sync paint that happens while
3052 // we're scrolling to our restored position. Entering reflow for the
3053 // scrollable frame will cause it to reenter ScrollToRestoredPosition(), and
3054 // it'll get all confused.
3055 nsAutoScriptBlocker scriptBlocker
;
3058 nsIFrame
* scrollFrame
= GetRootScrollFrame();
3060 nsIScrollableFrame
* scrollableFrame
;
3061 CallQueryInterface(scrollFrame
, &scrollableFrame
);
3062 if (scrollableFrame
) {
3063 FrameManager()->RestoreFrameStateFor(scrollFrame
, historyState
,
3064 nsIStatefulFrame::eDocumentScrollState
);
3065 scrollableFrame
->ScrollToRestoredPosition();
3072 PresShell::BeginLoad(nsIDocument
*aDocument
)
3074 #ifdef MOZ_PERF_METRICS
3075 // Reset style resolution stopwatch maintained by style set
3076 MOZ_TIMER_DEBUGLOG(("Reset: Style Resolution: PresShell::BeginLoad(), this=%p\n", (void*)this));
3078 mDocumentLoading
= PR_TRUE
;
3082 PresShell::EndLoad(nsIDocument
*aDocument
)
3084 NS_PRECONDITION(aDocument
== mDocument
, "Wrong document");
3086 RestoreRootScrollPosition();
3088 #ifdef MOZ_PERF_METRICS
3089 // Dump reflow, style resolution and frame construction times here.
3090 MOZ_TIMER_DEBUGLOG(("Stop: Reflow: PresShell::EndLoad(), this=%p\n", this));
3091 MOZ_TIMER_STOP(mReflowWatch
);
3092 MOZ_TIMER_LOG(("Reflow time (this=%p): ", this));
3093 MOZ_TIMER_PRINT(mReflowWatch
);
3095 MOZ_TIMER_DEBUGLOG(("Stop: Frame Creation: PresShell::EndLoad(), this=%p\n", this));
3096 MOZ_TIMER_STOP(mFrameCreationWatch
);
3097 MOZ_TIMER_LOG(("Frame construction plus style resolution time (this=%p): ", this));
3098 MOZ_TIMER_PRINT(mFrameCreationWatch
);
3100 // Print style resolution stopwatch maintained by style set
3101 MOZ_TIMER_DEBUGLOG(("Stop: Style Resolution: PresShell::EndLoad(), this=%p\n", this));
3103 mDocumentLoading
= PR_FALSE
;
3108 PresShell::VerifyHasDirtyRootAncestor(nsIFrame
* aFrame
)
3110 // XXXbz due to bug 372769, can't actually assert anything here...
3113 // XXXbz shouldn't need this part; remove it once FrameNeedsReflow
3114 // handles the root frame correctly.
3115 if (!aFrame
->GetParent()) {
3119 // Make sure that there is a reflow root ancestor of |aFrame| that's
3120 // in mDirtyRoots already.
3121 while (aFrame
&& (aFrame
->GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN
)) {
3122 if (((aFrame
->GetStateBits() & NS_FRAME_REFLOW_ROOT
) ||
3123 !aFrame
->GetParent()) &&
3124 mDirtyRoots
.IndexOf(aFrame
) != -1) {
3128 aFrame
= aFrame
->GetParent();
3130 NS_NOTREACHED("Frame has dirty bits set but isn't scheduled to be "
3136 PresShell::FrameNeedsReflow(nsIFrame
*aFrame
, IntrinsicDirty aIntrinsicDirty
,
3137 nsFrameState aBitToAdd
)
3139 NS_PRECONDITION(aBitToAdd
== NS_FRAME_IS_DIRTY
||
3140 aBitToAdd
== NS_FRAME_HAS_DIRTY_CHILDREN
,
3141 "Unexpected bits being added");
3143 NS_ASSERTION(!mIsReflowing
, "can't mark frame dirty during reflow");
3145 // If we've not yet done the initial reflow, then don't bother
3146 // enqueuing a reflow command yet.
3147 if (! mDidInitialReflow
)
3150 // If we're already destroying, don't bother with this either.
3155 //printf("gShellCounter: %d\n", gShellCounter++);
3156 if (mInVerifyReflow
) {
3160 if (VERIFY_REFLOW_NOISY_RC
& gVerifyReflowFlags
) {
3161 printf("\nPresShell@%p: frame %p needs reflow\n", (void*)this, (void*)aFrame
);
3162 if (VERIFY_REFLOW_REALLY_NOISY_RC
& gVerifyReflowFlags
) {
3163 printf("Current content model:\n");
3164 nsIContent
*rootContent
= mDocument
->GetRootContent();
3166 rootContent
->List(stdout
, 0);
3172 // Grab |wasDirty| now so we can go ahead and update the bits on aFrame.
3173 PRBool wasDirty
= NS_SUBTREE_DIRTY(aFrame
);
3174 aFrame
->AddStateBits(aBitToAdd
);
3176 // Now if aFrame is a reflow root we can cut off this reflow at it if the bit
3177 // being added is NS_FRAME_HAS_DIRTY_CHILDREN.
3178 PRBool targetFrameDirty
= (aBitToAdd
== NS_FRAME_IS_DIRTY
);
3180 #define FRAME_IS_REFLOW_ROOT(_f) \
3181 ((_f->GetStateBits() & NS_FRAME_REFLOW_ROOT) && \
3182 (_f != aFrame || !targetFrameDirty))
3185 // Mark the intrinsic widths as dirty on the frame, all of its ancestors,
3186 // and all of its descendants, if needed:
3188 if (aIntrinsicDirty
!= eResize
) {
3189 // Mark argument and all ancestors dirty. (Unless we hit a reflow root that
3190 // should contain the reflow. That root could be aFrame itself if it's not
3191 // dirty, or it could be some ancestor of aFrame.)
3192 for (nsIFrame
*a
= aFrame
;
3193 a
&& !FRAME_IS_REFLOW_ROOT(a
);
3195 a
->MarkIntrinsicWidthsDirty();
3198 if (aIntrinsicDirty
== eStyleChange
) {
3199 // Mark all descendants dirty (using an nsVoidArray stack rather than
3202 stack
.AppendElement(aFrame
);
3204 while (stack
.Count() != 0) {
3206 static_cast<nsIFrame
*>(stack
.FastElementAt(stack
.Count() - 1));
3207 stack
.RemoveElementAt(stack
.Count() - 1);
3209 PRInt32 childListIndex
= 0;
3210 nsIAtom
*childListName
;
3212 childListName
= f
->GetAdditionalChildListName(childListIndex
++);
3213 for (nsIFrame
*kid
= f
->GetFirstChild(childListName
); kid
;
3214 kid
= kid
->GetNextSibling()) {
3215 kid
->MarkIntrinsicWidthsDirty();
3216 stack
.AppendElement(kid
);
3218 } while (childListName
);
3222 // Set NS_FRAME_HAS_DIRTY_CHILDREN bits (via nsIFrame::ChildIsDirty) up the
3223 // tree until we reach either a frame that's already dirty or a reflow root.
3224 nsIFrame
*f
= aFrame
;
3226 if (FRAME_IS_REFLOW_ROOT(f
) || !f
->GetParent()) {
3227 // we've hit a reflow root or the root frame
3229 mDirtyRoots
.AppendElement(f
);
3233 VerifyHasDirtyRootAncestor(f
);
3240 nsIFrame
*child
= f
;
3242 wasDirty
= NS_SUBTREE_DIRTY(f
);
3243 f
->ChildIsDirty(child
);
3244 NS_ASSERTION(f
->GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN
,
3245 "ChildIsDirty didn't do its job");
3247 // This frame was already marked dirty.
3249 VerifyHasDirtyRootAncestor(f
);
3261 PresShell::GetViewToScroll(nsLayoutUtils::Direction aDirection
)
3263 nsCOMPtr
<nsIEventStateManager
> esm
= mPresContext
->EventStateManager();
3264 nsIScrollableView
* scrollView
= nsnull
;
3265 nsCOMPtr
<nsIContent
> focusedContent
;
3266 esm
->GetFocusedContent(getter_AddRefs(focusedContent
));
3267 if (!focusedContent
&& mSelection
) {
3268 nsISelection
* domSelection
= mSelection
->
3269 GetSelection(nsISelectionController::SELECTION_NORMAL
);
3271 nsCOMPtr
<nsIDOMNode
> focusedNode
;
3272 domSelection
->GetFocusNode(getter_AddRefs(focusedNode
));
3273 focusedContent
= do_QueryInterface(focusedNode
);
3276 if (focusedContent
) {
3277 nsIFrame
* startFrame
= GetPrimaryFrameFor(focusedContent
);
3279 nsIScrollableViewProvider
* svp
;
3280 CallQueryInterface(startFrame
, &svp
);
3281 // If this very frame provides a scroll view, start there instead of frame's
3282 // closest view, because the scroll view may be inside a child frame.
3283 // For example, this happens in the case of overflow:scroll.
3284 // In that case we still use GetNearestScrollingView() because
3285 // we need a scrolling view that matches aDirection.
3286 nsIScrollableView
* sv
;
3287 nsIView
* startView
= svp
&& (sv
= svp
->GetScrollableView()) ? sv
->View() : startFrame
->GetClosestView();
3288 NS_ASSERTION(startView
, "No view to start searching for scrollable view from");
3289 scrollView
= nsLayoutUtils::GetNearestScrollingView(startView
, aDirection
);
3293 nsIViewManager
* viewManager
= GetViewManager();
3295 viewManager
->GetRootScrollableView(&scrollView
);
3302 PresShell::CancelAllPendingReflows()
3304 mDirtyRoots
.Clear();
3309 #ifdef ACCESSIBILITY
3310 void nsIPresShell::InvalidateAccessibleSubtree(nsIContent
*aContent
)
3312 if (gIsAccessibilityActive
) {
3313 nsCOMPtr
<nsIAccessibilityService
> accService
=
3314 do_GetService("@mozilla.org/accessibilityService;1");
3316 accService
->InvalidateSubtreeFor(this, aContent
,
3317 nsIAccessibleEvent::EVENT_ASYNCH_SIGNIFICANT_CHANGE
);
3324 PresShell::RecreateFramesFor(nsIContent
* aContent
)
3326 NS_ENSURE_TRUE(mPresContext
, NS_ERROR_FAILURE
);
3327 if (!mDidInitialReflow
) {
3328 // Nothing to do here. In fact, if we proceed and aContent is the
3329 // root we will crash.
3333 // Don't call RecreateFramesForContent since that is not exported and we want
3334 // to keep the number of entrypoints down.
3336 NS_ASSERTION(mViewManager
, "Should have view manager");
3337 nsIViewManager::UpdateViewBatch
batch(mViewManager
);
3339 // Have to make sure that the content notifications are flushed before we
3340 // start messing with the frame model; otherwise we can get content doubling.
3341 mDocument
->FlushPendingNotifications(Flush_ContentAndNotify
);
3343 nsAutoScriptBlocker scriptBlocker
;
3345 nsStyleChangeList changeList
;
3346 changeList
.AppendChange(nsnull
, aContent
, nsChangeHint_ReconstructFrame
);
3348 nsresult rv
= mFrameConstructor
->ProcessRestyledFrames(changeList
);
3350 batch
.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC
);
3351 #ifdef ACCESSIBILITY
3352 InvalidateAccessibleSubtree(aContent
);
3358 nsIPresShell::PostRecreateFramesFor(nsIContent
* aContent
)
3360 FrameConstructor()->PostRestyleEvent(aContent
, eReStyle_Self
,
3361 nsChangeHint_ReconstructFrame
);
3365 PresShell::ClearFrameRefs(nsIFrame
* aFrame
)
3367 mPresContext
->EventStateManager()->ClearFrameRefs(aFrame
);
3369 if (aFrame
== mCurrentEventFrame
) {
3370 mCurrentEventContent
= aFrame
->GetContent();
3371 mCurrentEventFrame
= nsnull
;
3375 if (aFrame
== mDrawEventTargetFrame
) {
3376 mDrawEventTargetFrame
= nsnull
;
3380 for (int i
=0; i
<mCurrentEventFrameStack
.Count(); i
++) {
3381 if (aFrame
== (nsIFrame
*)mCurrentEventFrameStack
.ElementAt(i
)) {
3382 //One of our stack frames was deleted. Get its content so that when we
3383 //pop it we can still get its new frame from its content
3384 nsIContent
*currentEventContent
= aFrame
->GetContent();
3385 mCurrentEventContentStack
.ReplaceObjectAt(currentEventContent
, i
);
3386 mCurrentEventFrameStack
.ReplaceElementAt(nsnull
, i
);
3390 nsWeakFrame
* weakFrame
= mWeakFrames
;
3392 nsWeakFrame
* prev
= weakFrame
->GetPreviousWeakFrame();
3393 if (weakFrame
->GetFrame() == aFrame
) {
3394 // This removes weakFrame from mWeakFrames.
3395 weakFrame
->Clear(this);
3404 PresShell::CreateRenderingContext(nsIFrame
*aFrame
,
3405 nsIRenderingContext
** aResult
)
3407 NS_PRECONDITION(nsnull
!= aResult
, "null ptr");
3408 if (nsnull
== aResult
) {
3409 return NS_ERROR_NULL_POINTER
;
3412 nsIWidget
* widget
= nsnull
;
3413 nsPoint
offset(0,0);
3414 if (mPresContext
->IsScreen()) {
3415 // Get the widget to create the rendering context for and calculate
3416 // the offset from the frame to it. (Calculating the offset is important
3417 // if the frame isn't the root frame.)
3419 nsIView
* view
= aFrame
->GetClosestView(&viewOffset
);
3420 nsPoint widgetOffset
;
3421 widget
= view
->GetNearestWidget(&widgetOffset
);
3422 offset
= viewOffset
+ widgetOffset
;
3424 nsIFrame
* pageFrame
= nsLayoutUtils::GetPageFrame(aFrame
);
3425 // This might not always come up with a frame, i.e. during reflow;
3426 // that's fine, because the translation doesn't matter during reflow.
3428 offset
= aFrame
->GetOffsetTo(pageFrame
);
3432 nsIRenderingContext
* result
= nsnull
;
3433 nsIDeviceContext
*deviceContext
= mPresContext
->DeviceContext();
3435 rv
= deviceContext
->CreateRenderingContext(widget
, result
);
3438 rv
= deviceContext
->CreateRenderingContext(result
);
3442 if (NS_SUCCEEDED(rv
)) {
3443 result
->Translate(offset
.x
, offset
.y
);
3450 PresShell::GoToAnchor(const nsAString
& aAnchorName
, PRBool aScroll
)
3453 return NS_ERROR_FAILURE
;
3456 // Hold a reference to the ESM in case event dispatch tears us down.
3457 nsCOMPtr
<nsIEventStateManager
> esm
= mPresContext
->EventStateManager();
3459 if (aAnchorName
.IsEmpty()) {
3460 NS_ASSERTION(!aScroll
, "can't scroll to empty anchor name");
3461 esm
->SetContentState(nsnull
, NS_EVENT_STATE_URLTARGET
);
3465 nsCOMPtr
<nsIDOMDocument
> doc
= do_QueryInterface(mDocument
);
3466 nsCOMPtr
<nsIDOMHTMLDocument
> htmlDoc
= do_QueryInterface(mDocument
);
3467 nsresult rv
= NS_OK
;
3468 nsCOMPtr
<nsIContent
> content
;
3470 // Search for an element with a matching "id" attribute
3472 nsCOMPtr
<nsIDOMElement
> element
;
3473 rv
= doc
->GetElementById(aAnchorName
, getter_AddRefs(element
));
3474 if (NS_SUCCEEDED(rv
) && element
) {
3475 // Get the nsIContent interface, because that's what we need to
3476 // get the primary frame
3477 content
= do_QueryInterface(element
);
3481 // Search for an anchor element with a matching "name" attribute
3482 if (!content
&& htmlDoc
) {
3483 nsCOMPtr
<nsIDOMNodeList
> list
;
3484 // Find a matching list of named nodes
3485 rv
= htmlDoc
->GetElementsByName(aAnchorName
, getter_AddRefs(list
));
3486 if (NS_SUCCEEDED(rv
) && list
) {
3488 // Loop through the named nodes looking for the first anchor
3489 for (i
= 0; PR_TRUE
; i
++) {
3490 nsCOMPtr
<nsIDOMNode
> node
;
3491 rv
= list
->Item(i
, getter_AddRefs(node
));
3492 if (!node
) { // End of list
3495 // Ensure it's an anchor element
3496 content
= do_QueryInterface(node
);
3498 if (content
->Tag() == nsGkAtoms::a
&&
3499 content
->IsNodeOfType(nsINode::eHTML
)) {
3508 // Search for anchor in the HTML namespace with a matching name
3509 if (!content
&& !htmlDoc
)
3511 nsCOMPtr
<nsIDOMNodeList
> list
;
3512 NS_NAMED_LITERAL_STRING(nameSpace
, "http://www.w3.org/1999/xhtml");
3513 // Get the list of anchor elements
3514 rv
= doc
->GetElementsByTagNameNS(nameSpace
, NS_LITERAL_STRING("a"), getter_AddRefs(list
));
3515 if (NS_SUCCEEDED(rv
) && list
) {
3517 // Loop through the named nodes looking for the first anchor
3518 for (i
= 0; PR_TRUE
; i
++) {
3519 nsCOMPtr
<nsIDOMNode
> node
;
3520 rv
= list
->Item(i
, getter_AddRefs(node
));
3521 if (!node
) { // End of list
3524 // Compare the name attribute
3525 nsCOMPtr
<nsIDOMElement
> element
= do_QueryInterface(node
);
3527 if (element
&& NS_SUCCEEDED(element
->GetAttribute(NS_LITERAL_STRING("name"), value
))) {
3528 if (value
.Equals(aAnchorName
)) {
3529 content
= do_QueryInterface(element
);
3537 nsCOMPtr
<nsIDOMRange
> jumpToRange
;
3538 nsCOMPtr
<nsIXPointerResult
> xpointerResult
;
3540 nsCOMPtr
<nsIDOMXMLDocument
> xmldoc
= do_QueryInterface(mDocument
);
3543 xmldoc
->EvaluateXPointer(aAnchorName
, getter_AddRefs(xpointerResult
));
3544 if (xpointerResult
) {
3545 xpointerResult
->Item(0, getter_AddRefs(jumpToRange
));
3547 // We know it was an XPointer, so there is no point in
3548 // trying any other pointer types, let's just return
3550 return NS_ERROR_FAILURE
;
3554 // Finally try FIXptr
3556 xmldoc
->EvaluateFIXptr(aAnchorName
,getter_AddRefs(jumpToRange
));
3560 nsCOMPtr
<nsIDOMNode
> node
;
3561 jumpToRange
->GetStartContainer(getter_AddRefs(node
));
3564 node
->GetNodeType(&nodeType
);
3565 PRInt32 offset
= -1;
3566 jumpToRange
->GetStartOffset(&offset
);
3568 case nsIDOMNode::ATTRIBUTE_NODE
:
3570 // XXX Assuming jumping to the ownerElement is the sanest action.
3571 nsCOMPtr
<nsIAttribute
> attr
= do_QueryInterface(node
);
3572 content
= attr
->GetContent();
3575 case nsIDOMNode::DOCUMENT_NODE
:
3578 nsCOMPtr
<nsIDocument
> document
= do_QueryInterface(node
);
3579 content
= document
->GetChildAt(offset
);
3583 case nsIDOMNode::DOCUMENT_FRAGMENT_NODE
:
3584 case nsIDOMNode::ELEMENT_NODE
:
3585 case nsIDOMNode::ENTITY_REFERENCE_NODE
:
3588 nsCOMPtr
<nsIContent
> parent
= do_QueryInterface(node
);
3589 content
= parent
->GetChildAt(offset
);
3593 case nsIDOMNode::CDATA_SECTION_NODE
:
3594 case nsIDOMNode::COMMENT_NODE
:
3595 case nsIDOMNode::TEXT_NODE
:
3596 case nsIDOMNode::PROCESSING_INSTRUCTION_NODE
:
3598 // XXX This should scroll to a specific position in the text.
3599 content
= do_QueryInterface(node
);
3608 esm
->SetContentState(content
, NS_EVENT_STATE_URLTARGET
);
3612 rv
= ScrollContentIntoView(content
, NS_PRESSHELL_SCROLL_TOP
,
3613 NS_PRESSHELL_SCROLL_ANYWHERE
);
3614 NS_ENSURE_SUCCESS(rv
, rv
);
3616 nsIScrollableFrame
* rootScroll
= GetRootScrollFrameAsScrollable();
3618 mLastAnchorScrolledTo
= content
;
3619 mLastAnchorScrollPositionY
= rootScroll
->GetScrollPosition().y
;
3623 // Should we select the target? This action is controlled by a
3624 // preference: the default is to not select.
3625 PRBool selectAnchor
= nsContentUtils::GetBoolPref("layout.selectanchor");
3627 // Even if select anchor pref is false, we must still move the
3628 // caret there. That way tabbing will start from the new
3631 jumpToRange
= do_CreateInstance(kRangeCID
);
3633 while (content
&& content
->GetChildCount() > 0) {
3634 content
= content
->GetChildAt(0);
3636 nsCOMPtr
<nsIDOMNode
> node(do_QueryInterface(content
));
3637 NS_ASSERTION(node
, "No nsIDOMNode for descendant of anchor");
3638 jumpToRange
->SelectNodeContents(node
);
3642 // Select the anchor
3643 nsISelection
* sel
= mSelection
->
3644 GetSelection(nsISelectionController::SELECTION_NORMAL
);
3646 sel
->RemoveAllRanges();
3647 sel
->AddRange(jumpToRange
);
3648 if (!selectAnchor
) {
3649 // Use a caret (collapsed selection) at the start of the anchor
3650 sel
->CollapseToStart();
3654 if (selectAnchor
&& xpointerResult
) {
3655 // Select the rest (if any) of the ranges in XPointerResult
3657 xpointerResult
->GetLength(&count
);
3658 for (i
= 1; i
< count
; i
++) { // jumpToRange is i = 0
3659 nsCOMPtr
<nsIDOMRange
> range
;
3660 xpointerResult
->Item(i
, getter_AddRefs(range
));
3661 sel
->AddRange(range
);
3664 // Selection is at anchor.
3665 // Now focus the document itself if focus is on an element within it.
3666 nsPIDOMWindow
*win
= mDocument
->GetWindow();
3669 nsCOMPtr
<nsIFocusController
> focusController
= win
->GetRootFocusController();
3670 if (focusController
) {
3671 nsCOMPtr
<nsIDOMWindowInternal
> focusedWin
;
3672 focusController
->GetFocusedWindow(getter_AddRefs(focusedWin
));
3673 if (SameCOMIdentity(win
, focusedWin
)) {
3674 esm
->ChangeFocusWith(nsnull
, nsIEventStateManager::eEventFocusedByApplication
);
3680 rv
= NS_ERROR_FAILURE
; //changed to NS_OK in quirks mode if ScrollTo is called
3682 // Scroll to the top/left if the anchor can not be
3683 // found and it is labelled top (quirks mode only). @see bug 80784
3684 if ((NS_LossyConvertUTF16toASCII(aAnchorName
).LowerCaseEqualsLiteral("top")) &&
3685 (mPresContext
->CompatibilityMode() == eCompatibility_NavQuirks
)) {
3687 // Check |aScroll| after setting |rv| so we set |rv| to the same
3688 // thing whether or not |aScroll| is true.
3689 if (aScroll
&& mViewManager
) {
3690 // Get the viewport scroller
3691 nsIScrollableView
* scrollingView
;
3692 mViewManager
->GetRootScrollableView(&scrollingView
);
3693 if (scrollingView
) {
3694 // Scroll to the top of the page
3695 scrollingView
->ScrollTo(0, 0, 0);
3705 PresShell::ScrollToAnchor()
3707 if (!mLastAnchorScrolledTo
)
3710 nsIScrollableFrame
* rootScroll
= GetRootScrollFrameAsScrollable();
3712 mLastAnchorScrollPositionY
!= rootScroll
->GetScrollPosition().y
)
3715 nsresult rv
= ScrollContentIntoView(mLastAnchorScrolledTo
, NS_PRESSHELL_SCROLL_TOP
,
3716 NS_PRESSHELL_SCROLL_ANYWHERE
);
3717 mLastAnchorScrolledTo
= nsnull
;
3722 * Helper (per-continuation) for ScrollContentIntoView.
3724 * @param aFrame [in] Frame whose bounds should be unioned
3725 * @param aVPercent [in] same as for ScrollContentIntoView
3726 * @param aRect [inout] rect into which its bounds should be unioned
3727 * @param aHaveRect [inout] whether aRect contains data yet
3728 * @param aClosestScrolledView [inout] the view to which aRect is relative.
3729 * If null, should be filled in appropriately. If non-null, the function
3730 * will no-op if the closest scrolling view doesn't match.
3733 UnionRectForClosestScrolledView(nsIFrame
* aFrame
,
3737 nsIView
*& aClosestScrolledView
)
3739 nsRect frameBounds
= aFrame
->GetRect();
3741 nsIView
* closestView
;
3742 aFrame
->GetOffsetFromView(offset
, &closestView
);
3743 frameBounds
.MoveTo(offset
);
3745 // If this is an inline frame and either the bounds height is 0 (quirks
3746 // layout model) or aVPercent is not NS_PRESSHELL_SCROLL_ANYWHERE, we need to
3747 // change the top of the bounds to include the whole line.
3748 if (frameBounds
.height
== 0 || aVPercent
!= NS_PRESSHELL_SCROLL_ANYWHERE
) {
3749 nsIAtom
* frameType
= NULL
;
3750 nsIFrame
*prevFrame
= aFrame
;
3751 nsIFrame
*f
= aFrame
;
3754 (frameType
= f
->GetType()) == nsGkAtoms::inlineFrame
) {
3756 f
= prevFrame
->GetParent();
3761 frameType
== nsGkAtoms::blockFrame
) {
3762 // find the line containing aFrame and increase the top of |offset|.
3763 nsAutoLineIterator lines
= f
->GetLineIterator();
3765 PRInt32 index
= lines
->FindLineContaining(prevFrame
);
3772 if (NS_SUCCEEDED(lines
->GetLine(index
, &trash1
, &trash2
,
3773 lineBounds
, &trash3
))) {
3774 nsPoint blockOffset
;
3776 f
->GetOffsetFromView(blockOffset
, &blockView
);
3778 if (blockView
== closestView
) {
3779 // XXX If views not equal, this is hard. Do we want to bother?
3780 nscoord newoffset
= lineBounds
.y
+ blockOffset
.y
;
3782 if (newoffset
< frameBounds
.y
)
3783 frameBounds
.y
= newoffset
;
3791 NS_ASSERTION(closestView
&& !closestView
->ToScrollableView(),
3792 "What happened to the scrolled view? "
3793 "The frame should not be directly in the scrolling view!");
3795 // Walk up the view hierarchy. Make sure to add the view's position
3796 // _after_ we get the parent and see whether it's scrollable. We want to
3797 // make sure to get the scrolled view's position after it has been scrolled.
3798 while (closestView
) {
3799 nsIView
* parent
= closestView
->GetParent();
3800 if (parent
&& parent
->ToScrollableView())
3802 frameBounds
+= closestView
->GetPosition();
3803 closestView
= parent
;
3806 if (!aClosestScrolledView
)
3807 aClosestScrolledView
= closestView
;
3809 if (aClosestScrolledView
== closestView
) {
3811 // We can't use nsRect::UnionRect since it drops empty rects on
3812 // the floor, and we need to include them. (Thus we need
3813 // aHaveRect to know when to drop the initial value on the floor.)
3814 aRect
.UnionRectIncludeEmpty(aRect
, frameBounds
);
3816 aHaveRect
= PR_TRUE
;
3817 aRect
= frameBounds
;
3823 * This function takes a scrolling view, a rect, and a scroll position and
3824 * attempts to scroll that rect to that position in that view. The rect
3825 * should be in the coordinate system of the _scrolled_ view.
3827 static void ScrollViewToShowRect(nsIScrollableView
* aScrollingView
,
3832 // Determine the visible rect in the scrolling view's coordinate space.
3833 // The size of the visible area is the clip view size
3834 nsRect visibleRect
= aScrollingView
->View()->GetBounds(); // get width and height
3835 aScrollingView
->GetScrollPosition(visibleRect
.x
, visibleRect
.y
);
3837 // The actual scroll offsets
3838 nscoord scrollOffsetX
= visibleRect
.x
;
3839 nscoord scrollOffsetY
= visibleRect
.y
;
3842 aScrollingView
->GetLineHeight(&lineHeight
);
3844 // See how the rect should be positioned vertically
3845 if (NS_PRESSHELL_SCROLL_ANYWHERE
== aVPercent
||
3846 (NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE
== aVPercent
&&
3847 aRect
.height
< lineHeight
)) {
3848 // The caller doesn't care where the frame is positioned vertically,
3849 // so long as it's fully visible
3850 if (aRect
.y
< visibleRect
.y
) {
3851 // Scroll up so the frame's top edge is visible
3852 scrollOffsetY
= aRect
.y
;
3853 } else if (aRect
.YMost() > visibleRect
.YMost()) {
3854 // Scroll down so the frame's bottom edge is visible. Make sure the
3855 // frame's top edge is still visible
3856 scrollOffsetY
+= aRect
.YMost() - visibleRect
.YMost();
3857 if (scrollOffsetY
> aRect
.y
) {
3858 scrollOffsetY
= aRect
.y
;
3861 } else if (NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE
== aVPercent
) {
3862 // Scroll only if no part of the frame is visible in this view
3863 if (aRect
.YMost() - lineHeight
< visibleRect
.y
) {
3864 // Scroll up so the frame's top edge is visible
3865 scrollOffsetY
= aRect
.y
;
3866 } else if (aRect
.y
+ lineHeight
> visibleRect
.YMost()) {
3867 // Scroll down so the frame's bottom edge is visible. Make sure the
3868 // frame's top edge is still visible
3869 scrollOffsetY
+= aRect
.YMost() - visibleRect
.YMost();
3870 if (scrollOffsetY
> aRect
.y
) {
3871 scrollOffsetY
= aRect
.y
;
3875 // Align the frame edge according to the specified percentage
3876 nscoord frameAlignY
=
3877 NSToCoordRound(aRect
.y
+ aRect
.height
* (aVPercent
/ 100.0f
));
3879 NSToCoordRound(frameAlignY
- visibleRect
.height
* (aVPercent
/ 100.0f
));
3882 // See how the frame should be positioned horizontally
3883 if (NS_PRESSHELL_SCROLL_ANYWHERE
== aHPercent
||
3884 (NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE
== aHPercent
&&
3885 aRect
.width
< lineHeight
)) {
3886 // The caller doesn't care where the frame is positioned horizontally,
3887 // so long as it's fully visible
3888 if (aRect
.x
< visibleRect
.x
) {
3889 // Scroll left so the frame's left edge is visible
3890 scrollOffsetX
= aRect
.x
;
3891 } else if (aRect
.XMost() > visibleRect
.XMost()) {
3892 // Scroll right so the frame's right edge is visible. Make sure the
3893 // frame's left edge is still visible
3894 scrollOffsetX
+= aRect
.XMost() - visibleRect
.XMost();
3895 if (scrollOffsetX
> aRect
.x
) {
3896 scrollOffsetX
= aRect
.x
;
3899 } else if (NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE
== aHPercent
) {
3900 // Scroll only if no part of the frame is visible in this view
3901 // XXXbz using the line height here is odd, but there are no
3902 // natural dimensions to use here, really....
3903 if (aRect
.XMost() - lineHeight
< visibleRect
.x
) {
3904 // Scroll left so the frame's left edge is visible
3905 scrollOffsetX
= aRect
.x
;
3906 } else if (aRect
.x
+ lineHeight
> visibleRect
.XMost()) {
3907 // Scroll right so the frame's right edge is visible. Make sure the
3908 // frame's left edge is still visible
3909 scrollOffsetX
+= aRect
.XMost() - visibleRect
.XMost();
3910 if (scrollOffsetX
> aRect
.x
) {
3911 scrollOffsetX
= aRect
.x
;
3915 // Align the frame edge according to the specified percentage
3916 nscoord frameAlignX
=
3917 NSToCoordRound(aRect
.x
+ (aRect
.width
) * (aHPercent
/ 100.0f
));
3919 NSToCoordRound(frameAlignX
- visibleRect
.width
* (aHPercent
/ 100.0f
));
3922 aScrollingView
->ScrollTo(scrollOffsetX
, scrollOffsetY
, 0);
3926 PresShell::ScrollContentIntoView(nsIContent
* aContent
,
3928 PRIntn aHPercent
) const
3930 nsCOMPtr
<nsIContent
> content
= aContent
; // Keep content alive while flushing.
3931 NS_ENSURE_TRUE(content
, NS_ERROR_NULL_POINTER
);
3932 nsCOMPtr
<nsIDocument
> currentDoc
= content
->GetCurrentDoc();
3933 NS_ENSURE_STATE(currentDoc
);
3934 currentDoc
->FlushPendingNotifications(Flush_Layout
);
3935 nsIFrame
* frame
= GetPrimaryFrameFor(content
);
3937 return NS_ERROR_NULL_POINTER
;
3940 // Before we scroll the frame into view, ask the command dispatcher
3941 // if we're resetting focus because a window just got an activate
3942 // event. If we are, we do not want to scroll the frame into view.
3943 // Example: The user clicks on an anchor, and then deactivates the
3944 // window. When they reactivate the window, the expected behavior
3945 // is not for the anchor link to scroll back into view. That is what
3946 // this check is preventing.
3947 // XXX: The dependency on the command dispatcher needs to be fixed.
3948 nsPIDOMWindow
* ourWindow
= currentDoc
->GetWindow();
3950 nsIFocusController
*focusController
= ourWindow
->GetRootFocusController();
3951 if (focusController
) {
3952 PRBool dontScroll
= PR_FALSE
;
3953 focusController
->GetSuppressFocusScroll(&dontScroll
);
3960 // This is a two-step process.
3961 // Step 1: Find the bounds of the rect we want to scroll into view. For
3962 // example, for an inline frame we may want to scroll in the whole
3964 // Step 2: Walk the views that are parents of the frame and scroll them
3967 nsIView
*closestView
= nsnull
;
3969 PRBool haveRect
= PR_FALSE
;
3971 UnionRectForClosestScrolledView(frame
, aVPercent
, frameBounds
, haveRect
,
3973 } while ((frame
= frame
->GetNextContinuation()));
3975 // Walk up the view hierarchy. Make sure to add the view's position
3976 // _after_ we get the parent and see whether it's scrollable. We want to
3977 // make sure to get the scrolled view's position after it has been scrolled.
3978 nsIScrollableView
* scrollingView
= nsnull
;
3979 while (closestView
) {
3980 nsIView
* parent
= closestView
->GetParent();
3982 scrollingView
= parent
->ToScrollableView();
3983 if (scrollingView
) {
3984 ScrollViewToShowRect(scrollingView
, frameBounds
, aVPercent
, aHPercent
);
3987 frameBounds
+= closestView
->GetPosition();
3988 closestView
= parent
;
3994 // GetLinkLocation: copy link location to clipboard
3995 NS_IMETHODIMP
PresShell::GetLinkLocation(nsIDOMNode
* aNode
, nsAString
& aLocationString
)
3998 printf("dr :: PresShell::GetLinkLocation\n");
4001 NS_ENSURE_ARG_POINTER(aNode
);
4003 nsAutoString anchorText
;
4004 static char strippedChars
[] = {'\t','\r','\n'};
4006 // are we an anchor?
4007 nsCOMPtr
<nsIDOMHTMLAnchorElement
> anchor(do_QueryInterface(aNode
));
4008 nsCOMPtr
<nsIDOMHTMLAreaElement
> area
;
4009 nsCOMPtr
<nsIDOMHTMLLinkElement
> link
;
4010 nsAutoString xlinkType
;
4012 rv
= anchor
->GetHref(anchorText
);
4013 NS_ENSURE_SUCCESS(rv
, rv
);
4016 area
= do_QueryInterface(aNode
);
4018 rv
= area
->GetHref(anchorText
);
4019 NS_ENSURE_SUCCESS(rv
, rv
);
4022 link
= do_QueryInterface(aNode
);
4024 rv
= link
->GetHref(anchorText
);
4025 NS_ENSURE_SUCCESS(rv
, rv
);
4028 nsCOMPtr
<nsIDOMElement
> element(do_QueryInterface(aNode
));
4030 NS_NAMED_LITERAL_STRING(xlinkNS
,"http://www.w3.org/1999/xlink");
4031 element
->GetAttributeNS(xlinkNS
,NS_LITERAL_STRING("type"),xlinkType
);
4032 if (xlinkType
.EqualsLiteral("simple")) {
4033 element
->GetAttributeNS(xlinkNS
,NS_LITERAL_STRING("href"),anchorText
);
4034 if (!anchorText
.IsEmpty()) {
4035 // Resolve the full URI using baseURI property
4038 nsCOMPtr
<nsIDOM3Node
> node(do_QueryInterface(aNode
,&rv
));
4039 NS_ENSURE_SUCCESS(rv
, rv
);
4040 node
->GetBaseURI(base
);
4042 nsCOMPtr
<nsIIOService
>
4043 ios(do_GetService("@mozilla.org/network/io-service;1", &rv
));
4044 NS_ENSURE_SUCCESS(rv
, rv
);
4046 nsCOMPtr
<nsIURI
> baseURI
;
4047 rv
= ios
->NewURI(NS_ConvertUTF16toUTF8(base
),nsnull
,nsnull
,getter_AddRefs(baseURI
));
4048 NS_ENSURE_SUCCESS(rv
, rv
);
4051 rv
= baseURI
->Resolve(NS_ConvertUTF16toUTF8(anchorText
),spec
);
4052 NS_ENSURE_SUCCESS(rv
, rv
);
4054 CopyUTF8toUTF16(spec
, anchorText
);
4062 if (anchor
|| area
|| link
|| xlinkType
.EqualsLiteral("simple")) {
4063 //Remove all the '\t', '\r' and '\n' from 'anchorText'
4064 anchorText
.StripChars(strippedChars
);
4066 aLocationString
= anchorText
;
4071 // if no link, fail.
4072 return NS_ERROR_FAILURE
;
4076 PresShell::GetSelectionForCopy(nsISelection
** outSelection
)
4078 nsresult rv
= NS_OK
;
4080 *outSelection
= nsnull
;
4082 if (!mDocument
) return NS_ERROR_FAILURE
;
4084 nsCOMPtr
<nsIContent
> content
;
4085 nsPIDOMWindow
*ourWindow
= mDocument
->GetWindow();
4087 nsIFocusController
*focusController
= ourWindow
->GetRootFocusController();
4088 if (focusController
) {
4089 nsCOMPtr
<nsIDOMElement
> focusedElement
;
4090 focusController
->GetFocusedElement(getter_AddRefs(focusedElement
));
4091 content
= do_QueryInterface(focusedElement
);
4095 nsCOMPtr
<nsISelection
> sel
;
4098 //check to see if we need to get selection from frame
4099 //optimization that MAY need to be expanded as more things implement their own "selection"
4100 nsCOMPtr
<nsIDOMNSHTMLInputElement
> htmlInputElement(do_QueryInterface(content
));
4101 nsCOMPtr
<nsIDOMNSHTMLTextAreaElement
> htmlTextAreaElement(do_QueryInterface(content
));
4102 if (htmlInputElement
|| htmlTextAreaElement
)
4104 nsIFrame
*htmlInputFrame
= GetPrimaryFrameFor(content
);
4105 if (!htmlInputFrame
) return NS_ERROR_FAILURE
;
4107 nsCOMPtr
<nsISelectionController
> selCon
;
4108 rv
= htmlInputFrame
->
4109 GetSelectionController(mPresContext
,getter_AddRefs(selCon
));
4110 if (NS_FAILED(rv
)) return rv
;
4111 if (!selCon
) return NS_ERROR_FAILURE
;
4113 rv
= selCon
->GetSelection(nsISelectionController::SELECTION_NORMAL
,
4114 getter_AddRefs(sel
));
4118 sel
= mSelection
->GetSelection(nsISelectionController::SELECTION_NORMAL
);
4122 *outSelection
= sel
;
4123 NS_IF_ADDREF(*outSelection
);
4127 /* Just hook this call into InvalidateOverflowRect */
4129 PresShell::InvalidateFrameForView(nsIView
*aView
)
4131 nsIFrame
* frame
= nsLayoutUtils::GetFrameFor(aView
);
4133 frame
->InvalidateOverflowRect();
4136 NS_IMETHODIMP_(void)
4137 PresShell::DispatchSynthMouseMove(nsGUIEvent
*aEvent
,
4138 PRBool aFlushOnHoverChange
)
4140 PRUint32 hoverGenerationBefore
= mFrameConstructor
->GetHoverGeneration();
4141 nsEventStatus status
;
4142 mViewManager
->DispatchEvent(aEvent
, &status
);
4143 if (aFlushOnHoverChange
&&
4144 hoverGenerationBefore
!= mFrameConstructor
->GetHoverGeneration()) {
4145 // Flush so that the resulting reflow happens now so that our caller
4146 // can suppress any synthesized mouse moves caused by that reflow.
4147 FlushPendingNotifications(Flush_Layout
);
4152 PresShell::DoGetContents(const nsACString
& aMimeType
, PRUint32 aFlags
, PRBool aSelectionOnly
, nsAString
& aOutValue
)
4154 aOutValue
.Truncate();
4156 if (!mDocument
) return NS_ERROR_FAILURE
;
4159 nsCOMPtr
<nsISelection
> sel
;
4161 // Now we have the selection. Make sure it's nonzero:
4164 rv
= GetSelectionForCopy(getter_AddRefs(sel
));
4165 if (NS_FAILED(rv
)) return rv
;
4166 if (!sel
) return NS_ERROR_FAILURE
;
4169 sel
->GetIsCollapsed(&isCollapsed
);
4174 // call the copy code
4175 return nsCopySupport::GetContents(aMimeType
, aFlags
, sel
,
4176 mDocument
, aOutValue
);
4182 if (!mDocument
) return NS_ERROR_FAILURE
;
4184 nsCOMPtr
<nsISelection
> sel
;
4185 nsresult rv
= GetSelectionForCopy(getter_AddRefs(sel
));
4189 return NS_ERROR_FAILURE
;
4191 // Now we have the selection. Make sure it's nonzero:
4193 sel
->GetIsCollapsed(&isCollapsed
);
4197 // call the copy code
4198 rv
= nsCopySupport::HTMLCopy(sel
, mDocument
, nsIClipboard::kGlobalClipboard
);
4202 // Now that we have copied, update the Paste menu item
4203 nsPIDOMWindow
*domWindow
= mDocument
->GetWindow();
4206 domWindow
->UpdateCommands(NS_LITERAL_STRING("clipboard"));
4213 PresShell::CaptureHistoryState(nsILayoutHistoryState
** aState
, PRBool aLeavingPage
)
4215 nsresult rv
= NS_OK
;
4217 NS_PRECONDITION(nsnull
!= aState
, "null state pointer");
4219 // We actually have to mess with the docshell here, since we want to
4220 // store the state back in it.
4221 // XXXbz this isn't really right, since this is being called in the
4222 // content viewer's Hide() method... by that point the docshell's
4223 // state could be wrong. We should sort out a better ownership
4224 // model for the layout history state.
4225 nsCOMPtr
<nsISupports
> container
= mPresContext
->GetContainer();
4227 return NS_ERROR_FAILURE
;
4229 nsCOMPtr
<nsIDocShell
> docShell(do_QueryInterface(container
));
4231 return NS_ERROR_FAILURE
;
4233 nsCOMPtr
<nsILayoutHistoryState
> historyState
;
4234 docShell
->GetLayoutHistoryState(getter_AddRefs(historyState
));
4235 if (!historyState
) {
4236 // Create the document state object
4237 rv
= NS_NewLayoutHistoryState(getter_AddRefs(historyState
));
4239 if (NS_FAILED(rv
)) {
4244 docShell
->SetLayoutHistoryState(historyState
);
4247 *aState
= historyState
;
4248 NS_IF_ADDREF(*aState
);
4250 // Capture frame state for the entire frame hierarchy
4251 nsIFrame
* rootFrame
= FrameManager()->GetRootFrame();
4252 if (!rootFrame
) return NS_OK
;
4253 // Capture frame state for the root scroll frame
4254 // Don't capture state when first creating doc element hierarchy
4255 // As the scroll position is 0 and this will cause us to loose
4256 // our previously saved place!
4258 nsIFrame
* scrollFrame
= GetRootScrollFrame();
4260 FrameManager()->CaptureFrameStateFor(scrollFrame
, historyState
,
4261 nsIStatefulFrame::eDocumentScrollState
);
4265 FrameManager()->CaptureFrameState(rootFrame
, historyState
);
4271 PresShell::IsPaintingSuppressed(PRBool
* aResult
)
4273 *aResult
= mPaintingSuppressed
;
4278 PresShell::UnsuppressAndInvalidate()
4280 if (!mPresContext
->EnsureVisible(PR_FALSE
)) {
4281 // No point; we're about to be torn down anyway.
4285 mPaintingSuppressed
= PR_FALSE
;
4286 nsIFrame
* rootFrame
= FrameManager()->GetRootFrame();
4288 // let's assume that outline on a root frame is not supported
4289 nsRect
rect(nsPoint(0, 0), rootFrame
->GetSize());
4290 rootFrame
->Invalidate(rect
);
4293 // This makes sure to get the same thing that nsPresContext::EnsureVisible()
4295 nsCOMPtr
<nsISupports
> container
= mPresContext
->GetContainer();
4296 nsCOMPtr
<nsPIDOMWindow
> ourWindow
= do_GetInterface(container
);
4297 nsCOMPtr
<nsIFocusController
> focusController
=
4298 ourWindow
? ourWindow
->GetRootFocusController() : nsnull
;
4301 CheckForFocus(ourWindow
, focusController
, mDocument
);
4303 if (focusController
) // Unsuppress now that we've shown the new window and focused it.
4304 focusController
->SetSuppressFocus(PR_FALSE
, "PresShell suppression on Web page loads");
4307 mViewManager
->SynthesizeMouseMove(PR_FALSE
);
4311 PresShell::UnsuppressPainting()
4313 if (mPaintSuppressionTimer
) {
4314 mPaintSuppressionTimer
->Cancel();
4315 mPaintSuppressionTimer
= nsnull
;
4318 if (mIsDocumentGone
|| !mPaintingSuppressed
)
4321 // If we have reflows pending, just wait until we process
4322 // the reflows and get all the frames where we want them
4323 // before actually unlocking the painting. Otherwise
4324 // go ahead and unlock now.
4325 if (mDirtyRoots
.Count() > 0)
4326 mShouldUnsuppressPainting
= PR_TRUE
;
4328 UnsuppressAndInvalidate();
4333 PresShell::DisableThemeSupport()
4335 // Doesn't have to be dynamic. Just set the bool.
4336 mIsThemeSupportDisabled
= PR_TRUE
;
4341 PresShell::IsThemeSupportEnabled()
4343 return !mIsThemeSupportDisabled
;
4346 // Post a request to handle an arbitrary callback after reflow has finished.
4348 PresShell::PostReflowCallback(nsIReflowCallback
* aCallback
)
4350 void* result
= AllocateFrame(sizeof(nsCallbackEventRequest
));
4351 if (NS_UNLIKELY(!result
)) {
4352 return NS_ERROR_OUT_OF_MEMORY
;
4354 nsCallbackEventRequest
* request
= (nsCallbackEventRequest
*)result
;
4356 request
->callback
= aCallback
;
4357 request
->next
= nsnull
;
4359 if (mLastCallbackEventRequest
) {
4360 mLastCallbackEventRequest
= mLastCallbackEventRequest
->next
= request
;
4362 mFirstCallbackEventRequest
= request
;
4363 mLastCallbackEventRequest
= request
;
4370 PresShell::CancelReflowCallback(nsIReflowCallback
* aCallback
)
4372 nsCallbackEventRequest
* before
= nsnull
;
4373 nsCallbackEventRequest
* node
= mFirstCallbackEventRequest
;
4376 nsIReflowCallback
* callback
= node
->callback
;
4378 if (callback
== aCallback
)
4380 nsCallbackEventRequest
* toFree
= node
;
4381 if (node
== mFirstCallbackEventRequest
) {
4383 mFirstCallbackEventRequest
= node
;
4384 NS_ASSERTION(before
== nsnull
, "impossible");
4387 before
->next
= node
;
4390 if (toFree
== mLastCallbackEventRequest
) {
4391 mLastCallbackEventRequest
= before
;
4394 FreeFrame(sizeof(nsCallbackEventRequest
), toFree
);
4405 PresShell::CancelPostedReflowCallbacks()
4407 while (mFirstCallbackEventRequest
) {
4408 nsCallbackEventRequest
* node
= mFirstCallbackEventRequest
;
4409 mFirstCallbackEventRequest
= node
->next
;
4410 if (!mFirstCallbackEventRequest
) {
4411 mLastCallbackEventRequest
= nsnull
;
4413 nsIReflowCallback
* callback
= node
->callback
;
4414 FreeFrame(sizeof(nsCallbackEventRequest
), node
);
4416 callback
->ReflowCallbackCanceled();
4422 PresShell::HandlePostedReflowCallbacks()
4424 PRBool shouldFlush
= PR_FALSE
;
4426 while (mFirstCallbackEventRequest
) {
4427 nsCallbackEventRequest
* node
= mFirstCallbackEventRequest
;
4428 mFirstCallbackEventRequest
= node
->next
;
4429 if (!mFirstCallbackEventRequest
) {
4430 mLastCallbackEventRequest
= nsnull
;
4432 nsIReflowCallback
* callback
= node
->callback
;
4433 FreeFrame(sizeof(nsCallbackEventRequest
), node
);
4435 if (callback
->ReflowFinished()) {
4436 shouldFlush
= PR_TRUE
;
4442 FlushPendingNotifications(Flush_Layout
);
4446 PresShell::IsSafeToFlush(PRBool
& aIsSafeToFlush
)
4448 aIsSafeToFlush
= nsContentUtils::IsSafeToRunScript();
4450 // Not safe if we are reflowing or in the middle of frame construction
4451 PRBool isSafeToFlush
= !mIsReflowing
;
4452 // Not safe if we are painting
4453 nsIViewManager
* viewManager
= GetViewManager();
4455 PRBool isPainting
= PR_FALSE
;
4456 viewManager
->IsPainting(isPainting
);
4458 isSafeToFlush
= PR_FALSE
;
4461 NS_ASSERTION(!aIsSafeToFlush
|| isSafeToFlush
, "Missing a script blocker!");
4468 PresShell::FlushPendingNotifications(mozFlushType aType
)
4470 return DoFlushPendingNotifications(aType
, PR_FALSE
);
4474 PresShell::DoFlushPendingNotifications(mozFlushType aType
,
4475 PRBool aInterruptibleReflow
)
4477 NS_ASSERTION(aType
>= Flush_Frames
, "Why did we get called?");
4479 PRBool isSafeToFlush
;
4480 IsSafeToFlush(isSafeToFlush
);
4482 NS_ASSERTION(!isSafeToFlush
|| mViewManager
, "Must have view manager");
4483 // Make sure the view manager stays alive while batching view updates.
4484 nsCOMPtr
<nsIViewManager
> viewManagerDeathGrip
= mViewManager
;
4485 if (isSafeToFlush
&& mViewManager
) {
4486 // Processing pending notifications can kill us, and some callers only
4487 // hold weak refs when calling FlushPendingNotifications(). :(
4488 nsCOMPtr
<nsIPresShell
> kungFuDeathGrip(this);
4490 // Style reresolves not in conjunction with reflows can't cause
4491 // painting or geometry changes, so don't bother with view update
4492 // batching if we only have style reresolve
4493 nsIViewManager::UpdateViewBatch
batch(mViewManager
);
4495 // Force flushing of any pending content notifications that might have
4496 // queued up while our event was pending. That will ensure that we don't
4497 // construct frames for content right now that's still waiting to be
4499 mDocument
->FlushPendingNotifications(Flush_ContentAndNotify
);
4501 // Process pending restyles, since any flush of the presshell wants
4502 // up-to-date style data.
4503 if (!mIsDestroying
) {
4504 mPresContext
->FlushPendingMediaFeatureValuesChanged();
4506 // Flush any pending update of the user font set, since that could
4507 // cause style changes (for updating ex/ch units, and to cause a
4509 mPresContext
->FlushUserFontSet();
4511 mFrameConstructor
->ProcessPendingRestyles();
4514 // Process whatever XBL constructors those restyles queued up. This
4515 // ensures that onload doesn't fire too early and that we won't do extra
4516 // reflows after those constructors run.
4517 if (!mIsDestroying
) {
4518 mDocument
->BindingManager()->ProcessAttachedQueue();
4521 // Now those constructors might have posted restyle events. At the same
4522 // time, we still need up-to-date style data. In particular, reflow
4523 // depends on style being completely up to date. If it's not, then style
4524 // context reparenting, which can happen during reflow, might suddenly pick
4525 // up the new rules and we'll end up with frames whose style doesn't match
4527 if (!mIsDestroying
) {
4528 mFrameConstructor
->ProcessPendingRestyles();
4532 // There might be more pending constructors now, but we're not going to
4533 // worry about them. They can't be triggered during reflow, so we should
4536 if (aType
>= Flush_Layout
&& !mIsDestroying
) {
4537 mFrameConstructor
->RecalcQuotesAndCounters();
4538 mViewManager
->FlushDelayedResize();
4539 ProcessReflowCommands(aInterruptibleReflow
);
4542 PRUint32 updateFlags
= NS_VMREFRESH_NO_SYNC
;
4543 if (aType
>= Flush_Display
) {
4544 // Flushing paints, so perform the invalidates and drawing
4546 updateFlags
= NS_VMREFRESH_IMMEDIATE
;
4548 else if (aType
< Flush_Layout
) {
4549 // Not flushing reflows, so do deferred invalidates. This will keep us
4550 // from possibly flushing out reflows due to invalidates being processed
4551 // at the end of this view batch.
4552 updateFlags
= NS_VMREFRESH_DEFERRED
;
4554 batch
.EndUpdateViewBatch(updateFlags
);
4561 PresShell::IsReflowLocked(PRBool
* aIsReflowLocked
)
4563 *aIsReflowLocked
= mIsReflowing
;
4568 PresShell::CharacterDataChanged(nsIDocument
*aDocument
,
4569 nsIContent
* aContent
,
4570 CharacterDataChangeInfo
* aInfo
)
4572 NS_PRECONDITION(!mIsDocumentGone
, "Unexpected CharacterDataChanged");
4573 NS_PRECONDITION(aDocument
== mDocument
, "Unexpected aDocument");
4575 nsAutoScriptBlocker scriptBlocker
;
4578 // Invalidate the caret's current location before we call into the frame
4579 // constructor. It is important to do this now, and not wait until the
4580 // resulting reflow, because this call causes continuation frames of the
4581 // text frame the caret is in to forget what part of the content they
4582 // refer to, making it hard for them to return the correct continuation
4583 // frame to the caret.
4584 mCaret
->InvalidateOutsideCaret();
4587 // Call this here so it only happens for real content mutations and
4588 // not cases when the frame constructor calls its own methods to force
4589 // frame reconstruction.
4590 nsIContent
*container
= aContent
->GetParent();
4591 PRUint32 selectorFlags
=
4592 container
? (container
->GetFlags() & NODE_ALL_SELECTOR_FLAGS
) : 0;
4593 if (selectorFlags
!= 0 && !aContent
->IsRootOfAnonymousSubtree()) {
4595 if (aInfo
->mAppend
&&
4596 container
->GetChildAt((index
= container
->GetChildCount() - 1)) ==
4598 mFrameConstructor
->RestyleForAppend(container
, index
);
4600 mFrameConstructor
->RestyleForInsertOrChange(container
, aContent
);
4603 mFrameConstructor
->CharacterDataChanged(aContent
, aInfo
->mAppend
);
4608 PresShell::ContentStatesChanged(nsIDocument
* aDocument
,
4609 nsIContent
* aContent1
,
4610 nsIContent
* aContent2
,
4613 NS_PRECONDITION(!mIsDocumentGone
, "Unexpected ContentStatesChanged");
4614 NS_PRECONDITION(aDocument
== mDocument
, "Unexpected aDocument");
4616 if (mDidInitialReflow
) {
4617 nsAutoScriptBlocker scriptBlocker
;
4618 mFrameConstructor
->ContentStatesChanged(aContent1
, aContent2
, aStateMask
);
4625 PresShell::AttributeChanged(nsIDocument
* aDocument
,
4626 nsIContent
* aContent
,
4627 PRInt32 aNameSpaceID
,
4628 nsIAtom
* aAttribute
,
4630 PRUint32 aStateMask
)
4632 NS_PRECONDITION(!mIsDocumentGone
, "Unexpected AttributeChanged");
4633 NS_PRECONDITION(aDocument
== mDocument
, "Unexpected aDocument");
4635 // XXXwaterson it might be more elegant to wait until after the
4636 // initial reflow to begin observing the document. That would
4637 // squelch any other inappropriate notifications as well.
4638 if (mDidInitialReflow
) {
4639 nsAutoScriptBlocker scriptBlocker
;
4640 mFrameConstructor
->AttributeChanged(aContent
, aNameSpaceID
,
4641 aAttribute
, aModType
, aStateMask
);
4647 PresShell::ContentAppended(nsIDocument
*aDocument
,
4648 nsIContent
* aContainer
,
4649 PRInt32 aNewIndexInContainer
)
4651 NS_PRECONDITION(!mIsDocumentGone
, "Unexpected ContentAppended");
4652 NS_PRECONDITION(aDocument
== mDocument
, "Unexpected aDocument");
4653 NS_PRECONDITION(aContainer
, "must have container");
4655 if (!mDidInitialReflow
) {
4659 nsAutoScriptBlocker scriptBlocker
;
4660 MOZ_TIMER_DEBUGLOG(("Start: Frame Creation: PresShell::ContentAppended(), this=%p\n", this));
4661 MOZ_TIMER_START(mFrameCreationWatch
);
4663 // Call this here so it only happens for real content mutations and
4664 // not cases when the frame constructor calls its own methods to force
4665 // frame reconstruction.
4666 mFrameConstructor
->RestyleForAppend(aContainer
, aNewIndexInContainer
);
4668 mFrameConstructor
->ContentAppended(aContainer
, aNewIndexInContainer
);
4671 MOZ_TIMER_DEBUGLOG(("Stop: Frame Creation: PresShell::ContentAppended(), this=%p\n", this));
4672 MOZ_TIMER_STOP(mFrameCreationWatch
);
4676 PresShell::ContentInserted(nsIDocument
* aDocument
,
4677 nsIContent
* aContainer
,
4679 PRInt32 aIndexInContainer
)
4681 NS_PRECONDITION(!mIsDocumentGone
, "Unexpected ContentInserted");
4682 NS_PRECONDITION(aDocument
== mDocument
, "Unexpected aDocument");
4684 if (!mDidInitialReflow
) {
4688 nsAutoScriptBlocker scriptBlocker
;
4690 // Call this here so it only happens for real content mutations and
4691 // not cases when the frame constructor calls its own methods to force
4692 // frame reconstruction.
4694 mFrameConstructor
->RestyleForInsertOrChange(aContainer
, aChild
);
4696 mFrameConstructor
->ContentInserted(aContainer
, aChild
,
4697 aIndexInContainer
, nsnull
);
4702 PresShell::ContentRemoved(nsIDocument
*aDocument
,
4703 nsIContent
* aContainer
,
4705 PRInt32 aIndexInContainer
)
4707 NS_PRECONDITION(!mIsDocumentGone
, "Unexpected ContentRemoved");
4708 NS_PRECONDITION(aDocument
== mDocument
, "Unexpected aDocument");
4710 // Make sure that the caret doesn't leave a turd where the child used to be.
4712 mCaret
->InvalidateOutsideCaret();
4715 // Notify the ESM that the content has been removed, so that
4716 // it can clean up any state related to the content.
4717 mPresContext
->EventStateManager()->ContentRemoved(aChild
);
4719 nsAutoScriptBlocker scriptBlocker
;
4721 // Call this here so it only happens for real content mutations and
4722 // not cases when the frame constructor calls its own methods to force
4723 // frame reconstruction.
4725 mFrameConstructor
->RestyleForRemove(aContainer
, aChild
, aIndexInContainer
);
4727 PRBool didReconstruct
;
4728 mFrameConstructor
->ContentRemoved(aContainer
, aChild
,
4729 aIndexInContainer
, &didReconstruct
);
4735 PresShell::ReconstructFrames(void)
4737 nsAutoScriptBlocker scriptBlocker
;
4738 mFrameConstructor
->BeginUpdate();
4739 nsresult rv
= mFrameConstructor
->ReconstructDocElementHierarchy();
4741 mFrameConstructor
->EndUpdate();
4747 nsIPresShell::ReconstructStyleDataInternal()
4749 mStylesHaveChanged
= PR_FALSE
;
4751 if (mIsDestroying
) {
4752 // We don't want to mess with restyles at this point
4757 mPresContext
->RebuildUserFontSet();
4760 nsIContent
* root
= mDocument
->GetRootContent();
4761 if (!mDidInitialReflow
) {
4762 // Nothing to do here, since we have no frames yet
4767 // No content to restyle
4771 mFrameConstructor
->PostRestyleEvent(root
, eReStyle_Self
, NS_STYLE_HINT_NONE
);
4773 #ifdef ACCESSIBILITY
4774 InvalidateAccessibleSubtree(nsnull
);
4779 nsIPresShell::ReconstructStyleDataExternal()
4781 ReconstructStyleDataInternal();
4785 PresShell::StyleSheetAdded(nsIDocument
*aDocument
,
4786 nsIStyleSheet
* aStyleSheet
,
4787 PRBool aDocumentSheet
)
4789 // We only care when enabled sheets are added
4790 NS_PRECONDITION(aStyleSheet
, "Must have a style sheet!");
4792 aStyleSheet
->GetApplicable(applicable
);
4794 if (applicable
&& aStyleSheet
->HasRules()) {
4795 mStylesHaveChanged
= PR_TRUE
;
4800 PresShell::StyleSheetRemoved(nsIDocument
*aDocument
,
4801 nsIStyleSheet
* aStyleSheet
,
4802 PRBool aDocumentSheet
)
4804 // We only care when enabled sheets are removed
4805 NS_PRECONDITION(aStyleSheet
, "Must have a style sheet!");
4807 aStyleSheet
->GetApplicable(applicable
);
4808 if (applicable
&& aStyleSheet
->HasRules()) {
4809 mStylesHaveChanged
= PR_TRUE
;
4814 PresShell::StyleSheetApplicableStateChanged(nsIDocument
*aDocument
,
4815 nsIStyleSheet
* aStyleSheet
,
4818 if (aStyleSheet
->HasRules()) {
4819 mStylesHaveChanged
= PR_TRUE
;
4824 PresShell::StyleRuleChanged(nsIDocument
*aDocument
,
4825 nsIStyleSheet
* aStyleSheet
,
4826 nsIStyleRule
* aOldStyleRule
,
4827 nsIStyleRule
* aNewStyleRule
)
4829 mStylesHaveChanged
= PR_TRUE
;
4833 PresShell::StyleRuleAdded(nsIDocument
*aDocument
,
4834 nsIStyleSheet
* aStyleSheet
,
4835 nsIStyleRule
* aStyleRule
)
4837 mStylesHaveChanged
= PR_TRUE
;
4841 PresShell::StyleRuleRemoved(nsIDocument
*aDocument
,
4842 nsIStyleSheet
* aStyleSheet
,
4843 nsIStyleRule
* aStyleRule
)
4845 mStylesHaveChanged
= PR_TRUE
;
4849 PresShell::GetPrimaryFrameFor(nsIContent
* aContent
) const
4851 return FrameManager()->GetPrimaryFrameFor(aContent
, -1);
4855 PresShell::GetRealPrimaryFrameFor(nsIContent
* aContent
) const
4857 nsIFrame
*primaryFrame
= FrameManager()->GetPrimaryFrameFor(aContent
, -1);
4860 return nsPlaceholderFrame::GetRealFrameFor(primaryFrame
);
4864 PresShell::GetPlaceholderFrameFor(nsIFrame
* aFrame
,
4865 nsIFrame
** aResult
) const
4867 *aResult
= FrameManager()->GetPlaceholderFrameFor(aFrame
);
4874 PresShell::ComputeRepaintRegionForCopy(nsIView
* aRootView
,
4875 nsIView
* aMovingView
,
4877 const nsRect
& aCopyRect
,
4878 nsRegion
* aRepaintRegion
)
4880 return nsLayoutUtils::ComputeRepaintRegionForCopy(
4881 static_cast<nsIFrame
*>(aRootView
->GetClientData()),
4882 static_cast<nsIFrame
*>(aMovingView
->GetClientData()),
4883 aDelta
, aCopyRect
, aRepaintRegion
);
4887 PresShell::RenderDocument(const nsRect
& aRect
, PRUint32 aFlags
,
4888 nscolor aBackgroundColor
,
4889 gfxContext
* aThebesContext
)
4891 NS_ENSURE_TRUE(!(aFlags
& RENDER_IS_UNTRUSTED
), NS_ERROR_NOT_IMPLEMENTED
);
4894 nsPresContext::AppUnitsToFloatCSSPixels(aRect
.width
),
4895 nsPresContext::AppUnitsToFloatCSSPixels(aRect
.height
));
4896 aThebesContext
->Save();
4898 aThebesContext
->NewPath();
4899 #ifdef MOZ_GFX_OPTIMIZE_MOBILE
4900 aThebesContext
->Rectangle(r
, PR_TRUE
);
4902 aThebesContext
->Rectangle(r
);
4904 aThebesContext
->Clip();
4906 // we can avoid using a temporary surface if we're using OPERATOR_OVER
4907 // and our background color has no alpha (so we'll be compositing on top
4908 // of a fully opaque solid color region)
4909 PRBool needsGroup
= PR_TRUE
;
4910 if (aThebesContext
->CurrentOperator() == gfxContext::OPERATOR_OVER
&&
4911 NS_GET_A(aBackgroundColor
) == 0xff)
4912 needsGroup
= PR_FALSE
;
4915 aThebesContext
->PushGroup(NS_GET_A(aBackgroundColor
) == 0xff ?
4916 gfxASurface::CONTENT_COLOR
:
4917 gfxASurface::CONTENT_COLOR_ALPHA
);
4919 aThebesContext
->Save();
4922 // draw background color
4923 if (NS_GET_A(aBackgroundColor
) > 0) {
4924 aThebesContext
->SetColor(gfxRGBA(aBackgroundColor
));
4925 aThebesContext
->SetOperator(gfxContext::OPERATOR_SOURCE
);
4926 aThebesContext
->Paint();
4929 // we want the window to be composited as a single image using
4930 // whatever operator was set; set OPERATOR_OVER here, which is
4931 // either already the case, or overrides the operator in a group.
4932 // the original operator will be present when we PopGroup.
4933 aThebesContext
->SetOperator(gfxContext::OPERATOR_OVER
);
4935 nsIFrame
* rootFrame
= FrameManager()->GetRootFrame();
4937 nsDisplayListBuilder
builder(rootFrame
, PR_FALSE
,
4938 (aFlags
& RENDER_CARET
) != 0);
4942 nsIFrame
* rootScrollFrame
= GetRootScrollFrame();
4943 if ((aFlags
& RENDER_IGNORE_VIEWPORT_SCROLLING
) && rootScrollFrame
) {
4944 nsPoint pos
= GetRootScrollFrameAsScrollable()->GetScrollPosition();
4946 builder
.SetIgnoreScrollFrame(rootScrollFrame
);
4949 builder
.SetBackgroundOnly(PR_FALSE
);
4950 builder
.EnterPresShell(rootFrame
, rect
);
4952 nsresult rv
= rootFrame
->BuildDisplayListForStackingContext(&builder
, rect
, &list
);
4954 builder
.LeavePresShell(rootFrame
, rect
);
4956 if (NS_SUCCEEDED(rv
)) {
4957 // Ensure that r.x,r.y gets drawn at (0,0)
4958 aThebesContext
->Save();
4959 aThebesContext
->Translate(gfxPoint(-nsPresContext::AppUnitsToFloatCSSPixels(rect
.x
),
4960 -nsPresContext::AppUnitsToFloatCSSPixels(rect
.y
)));
4962 nsIDeviceContext
* devCtx
= mPresContext
->DeviceContext();
4963 gfxFloat scale
= gfxFloat(devCtx
->AppUnitsPerDevPixel())/nsPresContext::AppUnitsPerCSSPixel();
4964 aThebesContext
->Scale(scale
, scale
);
4966 nsCOMPtr
<nsIRenderingContext
> rc
;
4967 devCtx
->CreateRenderingContextInstance(*getter_AddRefs(rc
));
4968 rc
->Init(devCtx
, aThebesContext
);
4970 nsRegion
region(rect
);
4971 list
.OptimizeVisibility(&builder
, ®ion
);
4972 list
.Paint(&builder
, rc
, rect
);
4973 // Flush the list so we don't trigger the IsEmpty-on-destruction assertion
4976 aThebesContext
->Restore();
4980 // if we had to use a group, paint it to the destination now
4982 aThebesContext
->Restore();
4983 aThebesContext
->PopGroupToSource();
4984 aThebesContext
->Paint();
4987 aThebesContext
->Restore();
4993 * Clip the display list aList to a range. Returns the clipped
4994 * rectangle surrounding the range.
4997 PresShell::ClipListToRange(nsDisplayListBuilder
*aBuilder
,
4998 nsDisplayList
* aList
,
5001 // iterate though the display items and add up the bounding boxes of each.
5002 // This will allow the total area of the frames within the range to be
5003 // determined. To do this, remove an item from the bottom of the list, check
5004 // whether it should be part of the range, and if so, append it to the top
5005 // of the temporary list tmpList. If the item is a text frame at the end of
5006 // the selection range, wrap it in an nsDisplayClip to clip the display to
5007 // the portion of the text frame that is part of the selection. Then, append
5008 // the wrapper to the top of the list. Otherwise, just delete the item and
5011 nsDisplayList tmpList
;
5014 while ((i
= aList
->RemoveBottom())) {
5015 // itemToInsert indiciates the item that should be inserted into the
5016 // temporary list. If null, no item should be inserted.
5017 nsDisplayItem
* itemToInsert
= nsnull
;
5018 nsIFrame
* frame
= i
->GetUnderlyingFrame();
5020 nsIContent
* content
= frame
->GetContent();
5022 PRBool atStart
= (content
== aRange
->GetStartParent());
5023 PRBool atEnd
= (content
== aRange
->GetEndParent());
5024 if ((atStart
|| atEnd
) && frame
->GetType() == nsGkAtoms::textFrame
) {
5025 PRInt32 frameStartOffset
, frameEndOffset
;
5026 frame
->GetOffsets(frameStartOffset
, frameEndOffset
);
5028 PRInt32 hilightStart
=
5029 atStart
? PR_MAX(aRange
->StartOffset(), frameStartOffset
) : frameStartOffset
;
5030 PRInt32 hilightEnd
=
5031 atEnd
? PR_MIN(aRange
->EndOffset(), frameEndOffset
) : frameEndOffset
;
5032 if (hilightStart
< hilightEnd
) {
5033 // determine the location of the start and end edges of the range.
5034 nsPoint startPoint
, endPoint
;
5035 frame
->GetPointFromOffset(hilightStart
, &startPoint
);
5036 frame
->GetPointFromOffset(hilightEnd
, &endPoint
);
5038 // the clip rectangle is determined by taking the the start and
5039 // end points of the range, offset from the reference frame.
5040 // Because of rtl, the end point may be to the left of the
5041 // start point, so x is set to the lowest value
5042 nsRect
textRect(aBuilder
->ToReferenceFrame(frame
), frame
->GetSize());
5043 nscoord x
= PR_MIN(startPoint
.x
, endPoint
.x
);
5045 textRect
.width
= PR_MAX(startPoint
.x
, endPoint
.x
) - x
;
5046 surfaceRect
.UnionRect(surfaceRect
, textRect
);
5048 // wrap the item in an nsDisplayClip so that it can be clipped to
5049 // the selection. If the allocation fails, fall through and delete
5051 itemToInsert
= new (aBuilder
)nsDisplayClip(frame
, frame
, i
, textRect
);
5055 // if the node is within the range, append it to the temporary list
5056 PRBool before
, after
;
5057 nsRange::CompareNodeToRange(content
, aRange
, &before
, &after
);
5058 if (!before
&& !after
) {
5060 surfaceRect
.UnionRect(surfaceRect
, i
->GetBounds(aBuilder
));
5066 // insert the item into the list if necessary. If the item has a child
5067 // list, insert that as well
5068 nsDisplayList
* sublist
= i
->GetList();
5069 if (itemToInsert
|| sublist
) {
5070 tmpList
.AppendToTop(itemToInsert
? itemToInsert
: i
);
5071 // if the item is a list, iterate over it as well
5073 surfaceRect
.UnionRect(surfaceRect
,
5074 ClipListToRange(aBuilder
, sublist
, aRange
));
5077 // otherwise, just delete the item and don't readd it to the list
5078 i
->~nsDisplayItem();
5082 // now add all the items back onto the original list again
5083 aList
->AppendToTop(&tmpList
);
5089 PresShell::CreateRangePaintInfo(nsIDOMRange
* aRange
,
5090 nsRect
& aSurfaceRect
)
5092 RangePaintInfo
* info
= nsnull
;
5094 nsCOMPtr
<nsIRange
> range
= do_QueryInterface(aRange
);
5098 nsIFrame
* ancestorFrame
;
5099 nsIFrame
* rootFrame
= GetRootFrame();
5101 // If the start or end of the range is the document, just use the root
5102 // frame, otherwise get the common ancestor of the two endpoints of the
5104 nsINode
* startParent
= range
->GetStartParent();
5105 nsINode
* endParent
= range
->GetEndParent();
5106 nsIDocument
* doc
= startParent
->GetCurrentDoc();
5107 if (startParent
== doc
|| endParent
== doc
) {
5108 ancestorFrame
= rootFrame
;
5111 nsINode
* ancestor
= nsContentUtils::GetCommonAncestor(startParent
, endParent
);
5112 NS_ASSERTION(!ancestor
|| ancestor
->IsNodeOfType(nsINode::eCONTENT
),
5113 "common ancestor is not content");
5114 if (!ancestor
|| !ancestor
->IsNodeOfType(nsINode::eCONTENT
))
5117 nsIContent
* ancestorContent
= static_cast<nsIContent
*>(ancestor
);
5118 ancestorFrame
= GetPrimaryFrameFor(ancestorContent
);
5120 // use the nearest ancestor frame that includes all continuations as the
5121 // root for building the display list
5122 while (ancestorFrame
&&
5123 nsLayoutUtils::GetNextContinuationOrSpecialSibling(ancestorFrame
))
5124 ancestorFrame
= ancestorFrame
->GetParent();
5130 info
= new RangePaintInfo(range
, ancestorFrame
);
5134 nsRect ancestorRect
= ancestorFrame
->GetOverflowRect();
5136 // get a display list containing the range
5137 info
->mBuilder
.SetPaintAllFrames();
5138 info
->mBuilder
.EnterPresShell(ancestorFrame
, ancestorRect
);
5139 ancestorFrame
->BuildDisplayListForStackingContext(&info
->mBuilder
,
5140 ancestorRect
, &info
->mList
);
5141 info
->mBuilder
.LeavePresShell(ancestorFrame
, ancestorRect
);
5143 nsRect rangeRect
= ClipListToRange(&info
->mBuilder
, &info
->mList
, range
);
5145 // determine the offset of the reference frame for the display list
5146 // to the root frame. This will allow the coordinates used when painting
5147 // to all be offset from the same point
5148 info
->mRootOffset
= ancestorFrame
->GetOffsetTo(rootFrame
);
5149 rangeRect
.MoveBy(info
->mRootOffset
);
5150 aSurfaceRect
.UnionRect(aSurfaceRect
, rangeRect
);
5155 already_AddRefed
<gfxASurface
>
5156 PresShell::PaintRangePaintInfo(nsTArray
<nsAutoPtr
<RangePaintInfo
> >* aItems
,
5157 nsISelection
* aSelection
,
5161 nsRect
* aScreenRect
)
5163 nsPresContext
* pc
= GetPresContext();
5164 if (!pc
|| aArea
.width
== 0 || aArea
.height
== 0)
5167 nsIDeviceContext
* deviceContext
= pc
->DeviceContext();
5169 // use the rectangle to create the surface
5170 nsRect pixelArea
= aArea
;
5171 pixelArea
.ScaleRoundOut(1.0 / pc
->AppUnitsPerDevPixel());
5173 // if the area of the image is larger than the maximum area, scale it down
5175 nsIntRect rootScreenRect
= GetRootFrame()->GetScreenRect();
5177 // if the image is larger in one or both directions than half the size of
5178 // the available screen area, scale the image down to that size.
5180 deviceContext
->GetClientRect(maxSize
);
5181 nscoord maxWidth
= pc
->AppUnitsToDevPixels(maxSize
.width
>> 1);
5182 nscoord maxHeight
= pc
->AppUnitsToDevPixels(maxSize
.height
>> 1);
5183 PRBool resize
= (pixelArea
.width
> maxWidth
|| pixelArea
.height
> maxHeight
);
5186 // divide the maximum size by the image size in both directions. Whichever
5187 // direction produces the smallest result determines how much should be
5189 if (pixelArea
.width
> maxWidth
)
5190 scale
= PR_MIN(scale
, float(maxWidth
) / pixelArea
.width
);
5191 if (pixelArea
.height
> maxHeight
)
5192 scale
= PR_MIN(scale
, float(maxHeight
) / pixelArea
.height
);
5194 pixelArea
.width
= NSToIntFloor(float(pixelArea
.width
) * scale
);
5195 pixelArea
.height
= NSToIntFloor(float(pixelArea
.height
) * scale
);
5197 // adjust the screen position based on the rescaled size
5198 nscoord left
= rootScreenRect
.x
+ pixelArea
.x
;
5199 nscoord top
= rootScreenRect
.y
+ pixelArea
.y
;
5200 aScreenRect
->x
= NSToIntFloor(aPoint
.x
- float(aPoint
.x
- left
) * scale
);
5201 aScreenRect
->y
= NSToIntFloor(aPoint
.y
- float(aPoint
.y
- top
) * scale
);
5204 // move aScreenRect to the position of the surface in screen coordinates
5205 aScreenRect
->MoveTo(rootScreenRect
.x
+ pixelArea
.x
, rootScreenRect
.y
+ pixelArea
.y
);
5207 aScreenRect
->width
= pixelArea
.width
;
5208 aScreenRect
->height
= pixelArea
.height
;
5210 gfxImageSurface
* surface
=
5211 new gfxImageSurface(gfxIntSize(pixelArea
.width
, pixelArea
.height
),
5212 gfxImageSurface::ImageFormatARGB32
);
5213 if (!surface
|| surface
->CairoStatus()) {
5219 gfxContext
context(surface
);
5220 context
.SetOperator(gfxContext::OPERATOR_CLEAR
);
5221 context
.Rectangle(gfxRect(0, 0, pixelArea
.width
, pixelArea
.height
));
5224 nsCOMPtr
<nsIRenderingContext
> rc
;
5225 deviceContext
->CreateRenderingContextInstance(*getter_AddRefs(rc
));
5226 rc
->Init(deviceContext
, surface
);
5229 rc
->SetClipRegion(*aRegion
, nsClipCombine_kReplace
);
5232 rc
->Scale(scale
, scale
);
5234 // translate so that points are relative to the surface area
5235 rc
->Translate(-aArea
.x
, -aArea
.y
);
5237 // temporarily hide the selection so that text is drawn normally. If a
5238 // selection is being rendered, use that, otherwise use the presshell's
5240 nsCOMPtr
<nsFrameSelection
> frameSelection
;
5242 nsCOMPtr
<nsISelectionPrivate
> selpriv
= do_QueryInterface(aSelection
);
5243 selpriv
->GetFrameSelection(getter_AddRefs(frameSelection
));
5246 frameSelection
= FrameSelection();
5248 PRInt16 oldDisplaySelection
= frameSelection
->GetDisplaySelection();
5249 frameSelection
->SetDisplaySelection(nsISelectionController::SELECTION_HIDDEN
);
5251 // next, paint each range in the selection
5252 PRInt32 count
= aItems
->Length();
5253 for (PRInt32 i
= 0; i
< count
; i
++) {
5254 RangePaintInfo
* rangeInfo
= (*aItems
)[i
];
5255 // the display lists paint relative to the offset from the reference
5256 // frame, so translate the rendering context
5257 nsIRenderingContext::AutoPushTranslation
5258 translate(rc
, rangeInfo
->mRootOffset
.x
, rangeInfo
->mRootOffset
.y
);
5260 aArea
.MoveBy(-rangeInfo
->mRootOffset
.x
, -rangeInfo
->mRootOffset
.y
);
5261 rangeInfo
->mList
.Paint(&rangeInfo
->mBuilder
, rc
, aArea
);
5262 aArea
.MoveBy(rangeInfo
->mRootOffset
.x
, rangeInfo
->mRootOffset
.y
);
5265 // restore the old selection display state
5266 frameSelection
->SetDisplaySelection(oldDisplaySelection
);
5272 already_AddRefed
<gfxASurface
>
5273 PresShell::RenderNode(nsIDOMNode
* aNode
,
5276 nsRect
* aScreenRect
)
5278 // area will hold the size of the surface needed to draw the node, measured
5279 // from the root frame.
5281 nsTArray
<nsAutoPtr
<RangePaintInfo
> > rangeItems
;
5283 // nothing to draw if the node isn't in a document
5284 nsCOMPtr
<nsINode
> node
= do_QueryInterface(aNode
);
5285 if (!node
->IsInDoc())
5288 nsCOMPtr
<nsIDOMRange
> range
;
5289 NS_NewRange(getter_AddRefs(range
));
5290 if (NS_FAILED(range
->SelectNode(aNode
)))
5293 RangePaintInfo
* info
= CreateRangePaintInfo(range
, area
);
5294 if (info
&& !rangeItems
.AppendElement(info
)) {
5300 // combine the area with the supplied region
5302 aRegion
->GetBoundingBox(&rrectPixels
.x
, &rrectPixels
.y
,
5303 &rrectPixels
.width
, &rrectPixels
.height
);
5305 nsRect rrect
= rrectPixels
;
5306 rrect
.ScaleRoundOut(nsPresContext::AppUnitsPerCSSPixel());
5307 area
.IntersectRect(area
, rrect
);
5309 nsPresContext
* pc
= GetPresContext();
5313 // move the region so that it is offset from the topleft corner of the surface
5314 aRegion
->Offset(-rrectPixels
.x
+ (rrectPixels
.x
- pc
->AppUnitsToDevPixels(area
.x
)),
5315 -rrectPixels
.y
+ (rrectPixels
.y
- pc
->AppUnitsToDevPixels(area
.y
)));
5318 return PaintRangePaintInfo(&rangeItems
, nsnull
, aRegion
, area
, aPoint
,
5322 already_AddRefed
<gfxASurface
>
5323 PresShell::RenderSelection(nsISelection
* aSelection
,
5325 nsRect
* aScreenRect
)
5327 // area will hold the size of the surface needed to draw the selection,
5328 // measured from the root frame.
5330 nsTArray
<nsAutoPtr
<RangePaintInfo
> > rangeItems
;
5332 // iterate over each range and collect them into the rangeItems array.
5333 // This is done so that the size of selection can be determined so as
5334 // to allocate a surface area
5336 aSelection
->GetRangeCount(&numRanges
);
5337 NS_ASSERTION(numRanges
> 0, "RenderSelection called with no selection");
5339 for (PRInt32 r
= 0; r
< numRanges
; r
++)
5341 nsCOMPtr
<nsIDOMRange
> range
;
5342 aSelection
->GetRangeAt(r
, getter_AddRefs(range
));
5344 RangePaintInfo
* info
= CreateRangePaintInfo(range
, area
);
5345 if (info
&& !rangeItems
.AppendElement(info
)) {
5351 return PaintRangePaintInfo(&rangeItems
, aSelection
, nsnull
, area
, aPoint
,
5356 PresShell::Paint(nsIView
* aView
,
5357 nsIRenderingContext
* aRenderingContext
,
5358 const nsRegion
& aDirtyRegion
)
5360 AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Paint
);
5362 NS_ASSERTION(!mIsDestroying
, "painting a destroyed PresShell");
5363 NS_ASSERTION(aView
, "null view");
5365 // Compute the backstop color for the view. This color must be
5366 // totally transparent if the view is within a glass or transparent
5367 // widget; otherwise, we compose all the view managers' default
5368 // background colors in order to get something completely opaque.
5369 // Nested view managers might not have an opaque default, but the
5370 // root view manager must. See bug 467459.
5372 PRBool needTransparency
= PR_FALSE
;
5373 nsIViewManager
*lastMgr
= mViewManager
;
5374 nscolor backgroundColor
;
5375 lastMgr
->GetDefaultBackgroundColor(&backgroundColor
);
5377 for (nsIView
*view
= aView
; view
; view
= view
->GetParent()) {
5378 if (view
->HasWidget() &&
5379 view
->GetWidget()->GetTransparencyMode() != eTransparencyOpaque
) {
5380 backgroundColor
= NS_RGBA(0,0,0,0);
5381 needTransparency
= PR_TRUE
;
5384 if (NS_GET_A(backgroundColor
) < 255) {
5385 nsIViewManager
*thisMgr
= view
->GetViewManager();
5386 NS_ASSERTION(thisMgr
, "view without view manager");
5387 if (lastMgr
!= thisMgr
) {
5389 thisMgr
->GetDefaultBackgroundColor(&underColor
);
5390 backgroundColor
= NS_ComposeColors(underColor
, backgroundColor
);
5396 NS_ASSERTION(needTransparency
|| NS_GET_A(backgroundColor
) == 255,
5397 "root view manager's default background isn't opaque");
5399 nsIFrame
* frame
= static_cast<nsIFrame
*>(aView
->GetClientData());
5401 nsLayoutUtils::PaintFrame(aRenderingContext
, frame
, aDirtyRegion
,
5403 } else if (NS_GET_A(backgroundColor
) > 0) {
5404 aRenderingContext
->SetColor(backgroundColor
);
5405 aRenderingContext
->FillRect(aDirtyRegion
.GetBounds());
5412 PresShell::GetCurrentEventFrame()
5414 if (NS_UNLIKELY(mIsDestroying
)) {
5418 if (!mCurrentEventFrame
&& mCurrentEventContent
) {
5419 // Make sure the content still has a document reference. If not,
5420 // then we assume it is no longer in the content tree and the
5421 // frame shouldn't get an event, nor should we even assume its
5422 // safe to try and find the frame.
5423 if (mCurrentEventContent
->GetDocument()) {
5424 mCurrentEventFrame
= GetPrimaryFrameFor(mCurrentEventContent
);
5428 return mCurrentEventFrame
;
5432 PresShell::GetEventTargetFrame(nsIFrame
** aFrame
)
5434 *aFrame
= GetCurrentEventFrame();
5439 PresShell::GetEventTargetContent(nsEvent
* aEvent
, nsIContent
** aContent
)
5441 if (mCurrentEventContent
) {
5442 *aContent
= mCurrentEventContent
;
5443 NS_IF_ADDREF(*aContent
);
5445 nsIFrame
* currentEventFrame
= GetCurrentEventFrame();
5446 if (currentEventFrame
) {
5447 currentEventFrame
->GetContentForEvent(mPresContext
, aEvent
, aContent
);
5456 PresShell::PushCurrentEventInfo(nsIFrame
* aFrame
, nsIContent
* aContent
)
5458 if (mCurrentEventFrame
|| mCurrentEventContent
) {
5459 mCurrentEventFrameStack
.InsertElementAt((void*)mCurrentEventFrame
, 0);
5460 mCurrentEventContentStack
.InsertObjectAt(mCurrentEventContent
, 0);
5462 mCurrentEventFrame
= aFrame
;
5463 mCurrentEventContent
= aContent
;
5467 PresShell::PopCurrentEventInfo()
5469 mCurrentEventFrame
= nsnull
;
5470 mCurrentEventContent
= nsnull
;
5472 if (0 != mCurrentEventFrameStack
.Count()) {
5473 mCurrentEventFrame
= (nsIFrame
*)mCurrentEventFrameStack
.ElementAt(0);
5474 mCurrentEventFrameStack
.RemoveElementAt(0);
5475 mCurrentEventContent
= mCurrentEventContentStack
.ObjectAt(0);
5476 mCurrentEventContentStack
.RemoveObjectAt(0);
5480 PRBool
PresShell::InZombieDocument(nsIContent
*aContent
)
5482 // If a content node points to a null document, or the document is not
5483 // attached to a window, then it is possibly in a zombie document,
5484 // about to be replaced by a newly loading document.
5485 // Such documents cannot handle DOM events.
5486 // It might actually be in a node not attached to any document,
5487 // in which case there is not parent presshell to retarget it to.
5488 nsIDocument
*doc
= aContent
->GetDocument();
5489 return !doc
|| !doc
->GetWindow();
5492 nsresult
PresShell::RetargetEventToParent(nsGUIEvent
* aEvent
,
5493 nsEventStatus
* aEventStatus
)
5495 // Send this events straight up to the parent pres shell.
5496 // We do this for keystroke events in zombie documents or if either a frame
5497 // or a root content is not present.
5498 // That way at least the UI key bindings can work.
5500 nsCOMPtr
<nsIPresShell
> kungFuDeathGrip(this);
5501 nsCOMPtr
<nsISupports
> container
= mPresContext
->GetContainer();
5503 container
= do_QueryReferent(mForwardingContainer
);
5505 // Now, find the parent pres shell and send the event there
5506 nsCOMPtr
<nsIDocShellTreeItem
> treeItem
=
5507 do_QueryInterface(container
);
5509 // Might have gone away, or never been around to start with
5510 return NS_ERROR_FAILURE
;
5513 nsCOMPtr
<nsIDocShellTreeItem
> parentTreeItem
;
5514 treeItem
->GetParent(getter_AddRefs(parentTreeItem
));
5515 nsCOMPtr
<nsIDocShell
> parentDocShell
=
5516 do_QueryInterface(parentTreeItem
);
5517 if (!parentDocShell
|| treeItem
== parentTreeItem
) {
5518 return NS_ERROR_FAILURE
;
5521 nsCOMPtr
<nsIPresShell
> parentPresShell
;
5522 parentDocShell
->GetPresShell(getter_AddRefs(parentPresShell
));
5523 nsCOMPtr
<nsIViewObserver
> parentViewObserver
=
5524 do_QueryInterface(parentPresShell
);
5525 if (!parentViewObserver
) {
5526 return NS_ERROR_FAILURE
;
5529 // Fake the event as though it'ss from the parent pres shell's root view.
5530 nsIView
*parentRootView
;
5531 parentPresShell
->GetViewManager()->GetRootView(parentRootView
);
5533 return parentViewObserver
->HandleEvent(parentRootView
, aEvent
,
5538 PresShell::HandleEvent(nsIView
*aView
,
5540 nsEventStatus
* aEventStatus
)
5542 NS_ASSERTION(aView
, "null view");
5544 if (mIsDestroying
|| !nsContentUtils::IsSafeToRunScript()) {
5548 #ifdef ACCESSIBILITY
5549 if (aEvent
->eventStructType
== NS_ACCESSIBLE_EVENT
) {
5550 // Accessibility events come through OS requests and not from scripts,
5551 // so it is safe to handle here
5552 return HandleEventInternal(aEvent
, aView
, aEventStatus
);
5556 // Check for a theme change up front, since the frame type is irrelevant
5557 if (aEvent
->message
== NS_THEMECHANGED
&& mPresContext
) {
5558 mPresContext
->ThemeChanged();
5562 // Check for a system color change up front, since the frame type is
5564 if ((aEvent
->message
== NS_SYSCOLORCHANGED
) && mPresContext
) {
5565 nsIViewManager
* vm
= GetViewManager();
5567 // Only dispatch system color change when the message originates from
5568 // from the root views widget. This is necessary to prevent us from
5569 // dispatching the SysColorChanged notification for each child window
5570 // which may be redundant.
5572 vm
->GetRootView(view
);
5573 if (view
== aView
) {
5574 *aEventStatus
= nsEventStatus_eConsumeDoDefault
;
5575 mPresContext
->SysColorChanged();
5582 nsIFrame
* frame
= static_cast<nsIFrame
*>(aView
->GetClientData());
5584 PRBool dispatchUsingCoordinates
=
5585 !NS_IS_KEY_EVENT(aEvent
) && !NS_IS_IME_EVENT(aEvent
) &&
5586 !NS_IS_CONTEXT_MENU_KEY(aEvent
) && !NS_IS_FOCUS_EVENT(aEvent
) &&
5587 !NS_IS_PLUGIN_EVENT(aEvent
);
5589 // if this event has no frame, we need to retarget it at a parent
5590 // view that has a frame.
5592 (dispatchUsingCoordinates
|| NS_IS_KEY_EVENT(aEvent
) ||
5593 NS_IS_IME_EVENT(aEvent
))) {
5594 nsIView
* targetView
= aView
;
5595 while (targetView
&& !targetView
->GetClientData()) {
5596 targetView
= targetView
->GetParent();
5601 frame
= static_cast<nsIFrame
*>(aView
->GetClientData());
5605 if (dispatchUsingCoordinates
) {
5606 NS_ASSERTION(frame
, "Nothing to handle this event!");
5610 nsPresContext
* framePresContext
= frame
->PresContext();
5611 nsPresContext
* rootPresContext
= framePresContext
->RootPresContext();
5612 NS_ASSERTION(rootPresContext
== mPresContext
->RootPresContext(),
5613 "How did we end up outside the connected prescontext/viewmanager hierarchy?");
5614 // If we aren't starting our event dispatch from the root frame of the root prescontext,
5615 // then someone must be capturing the mouse. In that case we don't want to search the popup
5617 if (framePresContext
== rootPresContext
&&
5618 frame
== FrameManager()->GetRootFrame()) {
5621 nsXULPopupManager
* pm
= nsXULPopupManager::GetInstance();
5623 nsTArray
<nsIFrame
*> popups
= pm
->GetOpenPopups();
5625 // Search from top to bottom
5626 for (i
= 0; i
< popups
.Length(); i
++) {
5627 nsIFrame
* popup
= popups
[i
];
5628 if (popup
->GetOverflowRect().Contains(
5629 nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent
, popup
))) {
5630 // The event should target the popup
5640 = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent
, frame
);
5641 nsIFrame
* targetFrame
;
5643 nsAutoDisableGetUsedXAssertions disableAssert
;
5644 PRBool ignoreRootScrollFrame
= PR_FALSE
;
5645 if (aEvent
->eventStructType
== NS_MOUSE_EVENT
) {
5646 ignoreRootScrollFrame
= static_cast<nsMouseEvent
*>(aEvent
)->ignoreRootScrollFrame
;
5648 targetFrame
= nsLayoutUtils::GetFrameForPoint(frame
, eventPoint
,
5649 PR_FALSE
, ignoreRootScrollFrame
);
5654 static_cast<PresShell
*>(targetFrame
->PresContext()->PresShell());
5655 if (shell
!= this) {
5656 // Handle the event in the correct shell.
5657 // Prevent deletion until we're done with event handling (bug 336582).
5658 nsCOMPtr
<nsIPresShell
> kungFuDeathGrip(shell
);
5659 nsIView
* subshellRootView
;
5660 shell
->GetViewManager()->GetRootView(subshellRootView
);
5661 // We pass the subshell's root view as the view to start from. This is
5662 // the only correct alternative; if the event was captured then it
5663 // must have been captured by us or some ancestor shell and we
5664 // now ask the subshell to dispatch it normally.
5665 return shell
->HandlePositionedEvent(subshellRootView
, targetFrame
,
5666 aEvent
, aEventStatus
);
5671 targetFrame
= frame
;
5673 return HandlePositionedEvent(aView
, targetFrame
, aEvent
, aEventStatus
);
5676 nsresult rv
= NS_OK
;
5679 PushCurrentEventInfo(nsnull
, nsnull
);
5681 // key and IME events go to the focused frame
5682 nsIEventStateManager
*esm
= mPresContext
->EventStateManager();
5684 if (NS_IS_KEY_EVENT(aEvent
) || NS_IS_IME_EVENT(aEvent
) ||
5685 NS_IS_CONTEXT_MENU_KEY(aEvent
) || NS_IS_PLUGIN_EVENT(aEvent
)) {
5686 esm
->GetFocusedFrame(&mCurrentEventFrame
);
5687 if (mCurrentEventFrame
) {
5688 esm
->GetFocusedContent(getter_AddRefs(mCurrentEventContent
));
5690 if (NS_TargetUnfocusedEventToLastFocusedContent(aEvent
)) {
5691 nsPIDOMWindow
*ourWindow
= mDocument
->GetWindow();
5693 nsIFocusController
*focusController
=
5694 ourWindow
->GetRootFocusController();
5695 if (focusController
) {
5696 PRBool active
= PR_FALSE
;
5697 // check input focus is in Mozilla
5698 focusController
->GetActive(&active
);
5700 // if not, search for pre-focused element
5701 nsCOMPtr
<nsIDOMElement
> focusedElement
;
5702 focusController
->GetFocusedElement(getter_AddRefs(focusedElement
));
5703 if (focusedElement
) {
5704 // get mCurrentEventContent from focusedElement
5705 mCurrentEventContent
= do_QueryInterface(focusedElement
);
5711 if (!mCurrentEventContent
) {
5712 mCurrentEventContent
= mDocument
->GetRootContent();
5714 mCurrentEventFrame
= nsnull
; // XXXldb Isn't it already?
5716 if (!mCurrentEventContent
|| InZombieDocument(mCurrentEventContent
)) {
5717 rv
= RetargetEventToParent(aEvent
, aEventStatus
);
5718 PopCurrentEventInfo();
5722 mCurrentEventFrame
= frame
;
5724 if (GetCurrentEventFrame()) {
5725 rv
= HandleEventInternal(aEvent
, aView
, aEventStatus
);
5729 ShowEventTargetDebug();
5731 PopCurrentEventInfo();
5733 // Focus events need to be dispatched even if no frame was found, since
5734 // we don't want the focus controller to be out of sync.
5736 if (!NS_EVENT_NEEDS_FRAME(aEvent
)) {
5737 mCurrentEventFrame
= nsnull
;
5738 return HandleEventInternal(aEvent
, aView
, aEventStatus
);
5740 else if (NS_IS_KEY_EVENT(aEvent
)) {
5741 // Keypress events in new blank tabs should not be completely thrown away.
5742 // Retarget them -- the parent chrome shell might make use of them.
5743 return RetargetEventToParent(aEvent
, aEventStatus
);
5752 PresShell::ShowEventTargetDebug()
5754 if (nsIFrameDebug::GetShowEventTargetFrameBorder() &&
5755 GetCurrentEventFrame()) {
5756 if (mDrawEventTargetFrame
) {
5757 mDrawEventTargetFrame
->Invalidate(
5758 nsRect(nsPoint(0, 0), mDrawEventTargetFrame
->GetSize()));
5761 mDrawEventTargetFrame
= mCurrentEventFrame
;
5762 mDrawEventTargetFrame
->Invalidate(
5763 nsRect(nsPoint(0, 0), mDrawEventTargetFrame
->GetSize()));
5769 PresShell::HandlePositionedEvent(nsIView
* aView
,
5770 nsIFrame
* aTargetFrame
,
5772 nsEventStatus
* aEventStatus
)
5774 nsresult rv
= NS_OK
;
5776 PushCurrentEventInfo(nsnull
, nsnull
);
5778 mCurrentEventFrame
= aTargetFrame
;
5780 if (mCurrentEventFrame
) {
5781 nsCOMPtr
<nsIContent
> targetElement
;
5782 mCurrentEventFrame
->GetContentForEvent(mPresContext
, aEvent
,
5783 getter_AddRefs(targetElement
));
5785 // If there is no content for this frame, target it anyway. Some
5786 // frames can be targeted but do not have content, particularly
5787 // windows with scrolling off.
5788 if (targetElement
) {
5789 // Bug 103055, bug 185889: mouse events apply to *elements*, not all
5790 // nodes. Thus we get the nearest element parent here.
5791 // XXX we leave the frame the same even if we find an element
5792 // parent, so that the text frame will receive the event (selection
5793 // and friends are the ones who care about that anyway)
5795 // We use weak pointers because during this tight loop, the node
5796 // will *not* go away. And this happens on every mousemove.
5797 while (targetElement
&&
5798 !targetElement
->IsNodeOfType(nsINode::eELEMENT
)) {
5799 targetElement
= targetElement
->GetParent();
5802 // If we found an element, target it. Otherwise, target *nothing*.
5803 if (!targetElement
) {
5804 mCurrentEventContent
= nsnull
;
5805 mCurrentEventFrame
= nsnull
;
5806 } else if (targetElement
!= mCurrentEventContent
) {
5807 mCurrentEventContent
= targetElement
;
5812 if (GetCurrentEventFrame()) {
5813 rv
= HandleEventInternal(aEvent
, aView
, aEventStatus
);
5817 ShowEventTargetDebug();
5819 PopCurrentEventInfo();
5824 PresShell::HandleEventWithTarget(nsEvent
* aEvent
, nsIFrame
* aFrame
,
5825 nsIContent
* aContent
, nsEventStatus
* aStatus
)
5829 PushCurrentEventInfo(aFrame
, aContent
);
5830 ret
= HandleEventInternal(aEvent
, nsnull
, aStatus
);
5831 PopCurrentEventInfo();
5836 IsSynthesizedMouseMove(nsEvent
* aEvent
)
5838 return aEvent
->eventStructType
== NS_MOUSE_EVENT
&&
5839 static_cast<nsMouseEvent
*>(aEvent
)->reason
!= nsMouseEvent::eReal
;
5843 PresShell::HandleEventInternal(nsEvent
* aEvent
, nsIView
*aView
,
5844 nsEventStatus
* aStatus
)
5846 #ifdef ACCESSIBILITY
5847 if (aEvent
->eventStructType
== NS_ACCESSIBLE_EVENT
)
5849 static_cast<nsAccessibleEvent
*>(aEvent
)->accessible
= nsnull
;
5850 nsCOMPtr
<nsIAccessibilityService
> accService
=
5851 do_GetService("@mozilla.org/accessibilityService;1");
5853 nsCOMPtr
<nsISupports
> container
= mPresContext
->GetContainer();
5855 // This presshell is not active. This often happens when a
5856 // preshell is being held onto for fastback.
5860 nsCOMPtr
<nsIDOMNode
> domNode(do_QueryInterface(mDocument
));
5861 NS_ASSERTION(domNode
, "No dom node for doc");
5862 accService
->GetAccessibleInShell(domNode
, this, &acc
);
5863 // Addref this - it's not a COM Ptr
5864 // We'll make sure the right number of Addref's occur before
5865 // handing this back to the accessibility client
5866 static_cast<nsAccessibleEvent
*>(aEvent
)->accessible
= acc
;
5867 // Ensure this is set in case a11y was activated before any
5868 // nsPresShells existed to observe "a11y-init-or-shutdown" topic
5869 gIsAccessibilityActive
= PR_TRUE
;
5875 nsCOMPtr
<nsIEventStateManager
> manager
= mPresContext
->EventStateManager();
5876 nsresult rv
= NS_OK
;
5878 if (!NS_EVENT_NEEDS_FRAME(aEvent
) || GetCurrentEventFrame()) {
5879 PRBool isHandlingUserInput
= PR_FALSE
;
5881 if (NS_IS_TRUSTED_EVENT(aEvent
)) {
5882 switch (aEvent
->message
) {
5887 // Treat focus/blur events as user input if they happen while
5888 // executing trusted script, or no script at all. If they
5889 // happen during execution of non-trusted script, then they
5890 // should not be considered user input.
5891 if (!nsContentUtils::IsCallerChrome()) {
5894 case NS_MOUSE_BUTTON_DOWN
:
5895 case NS_MOUSE_BUTTON_UP
:
5899 isHandlingUserInput
= PR_TRUE
;
5903 nsAutoHandlingUserInputStatePusher
userInpStatePusher(isHandlingUserInput
);
5905 nsAutoPopupStatePusher
popupStatePusher(nsDOMEvent::GetEventPopupControlState(aEvent
));
5907 // FIXME. If the event was reused, we need to clear the old target,
5909 aEvent
->target
= nsnull
;
5911 nsWeakView
weakView(aView
);
5912 // 1. Give event to event manager for pre event state changes and
5913 // generation of synthetic events.
5914 rv
= manager
->PreHandleEvent(mPresContext
, aEvent
, mCurrentEventFrame
,
5917 // 2. Give event to the DOM for third party and JS use.
5918 if (GetCurrentEventFrame() && NS_SUCCEEDED(rv
)) {
5919 // We want synthesized mouse moves to cause mouseover and mouseout
5920 // DOM events (PreHandleEvent above), but not mousemove DOM events.
5921 if (!IsSynthesizedMouseMove(aEvent
)) {
5922 nsPresShellEventCB
eventCB(this);
5923 if (mCurrentEventContent
) {
5924 nsEventDispatcher::Dispatch(mCurrentEventContent
, mPresContext
,
5925 aEvent
, nsnull
, aStatus
, &eventCB
);
5928 nsCOMPtr
<nsIContent
> targetContent
;
5929 rv
= mCurrentEventFrame
->GetContentForEvent(mPresContext
, aEvent
,
5930 getter_AddRefs(targetContent
));
5931 if (NS_SUCCEEDED(rv
) && targetContent
) {
5932 nsEventDispatcher::Dispatch(targetContent
, mPresContext
, aEvent
,
5933 nsnull
, aStatus
, &eventCB
);
5934 } else if (mDocument
) {
5935 nsEventDispatcher::Dispatch(mDocument
, mPresContext
, aEvent
,
5936 nsnull
, aStatus
, nsnull
);
5941 // 3. Give event to event manager for post event state changes and
5942 // generation of synthetic events.
5943 if (!mIsDestroying
&& NS_SUCCEEDED(rv
)) {
5944 rv
= manager
->PostHandleEvent(mPresContext
, aEvent
,
5945 GetCurrentEventFrame(), aStatus
,
5946 weakView
.GetView());
5953 // Dispatch event to content only (NOT full processing)
5954 // See also HandleEventWithTarget which does full event processing.
5956 PresShell::HandleDOMEventWithTarget(nsIContent
* aTargetContent
, nsEvent
* aEvent
,
5957 nsEventStatus
* aStatus
)
5959 PushCurrentEventInfo(nsnull
, aTargetContent
);
5961 // Bug 41013: Check if the event should be dispatched to content.
5962 // It's possible that we are in the middle of destroying the window
5963 // and the js context is out of date. This check detects the case
5964 // that caused a crash in bug 41013, but there may be a better way
5965 // to handle this situation!
5966 nsCOMPtr
<nsISupports
> container
= mPresContext
->GetContainer();
5969 // Dispatch event to content
5970 nsEventDispatcher::Dispatch(aTargetContent
, mPresContext
, aEvent
, nsnull
,
5974 PopCurrentEventInfo();
5979 PresShell::ResizeReflow(nsIView
*aView
, nscoord aWidth
, nscoord aHeight
)
5981 return ResizeReflow(aWidth
, aHeight
);
5984 NS_IMETHODIMP_(PRBool
)
5985 PresShell::IsVisible()
5987 nsCOMPtr
<nsISupports
> container
= mPresContext
->GetContainer();
5988 nsCOMPtr
<nsIBaseWindow
> bw
= do_QueryInterface(container
);
5991 PRBool res
= PR_TRUE
;
5992 bw
->GetVisibility(&res
);
5996 NS_IMETHODIMP_(void)
5997 PresShell::WillPaint()
5999 // Don't bother reflowing if some viewmanager in our tree is painting while
6000 // we still have painting suppressed.
6001 if (mPaintingSuppressed
) {
6005 // Process reflows, if we have them, to reduce flicker due to invalidates and
6006 // reflow being interspersed. Note that we _do_ allow this to be
6007 // interruptible; if we can't do all the reflows it's better to flicker a bit
6008 // than to freeze up.
6009 DoFlushPendingNotifications(Flush_Layout
, PR_TRUE
);
6013 PresShell::GetAgentStyleSheets(nsCOMArray
<nsIStyleSheet
>& aSheets
)
6016 PRInt32 sheetCount
= mStyleSet
->SheetCount(nsStyleSet::eAgentSheet
);
6018 for (PRInt32 i
= 0; i
< sheetCount
; ++i
) {
6019 nsIStyleSheet
*sheet
= mStyleSet
->StyleSheetAt(nsStyleSet::eAgentSheet
, i
);
6020 if (!aSheets
.AppendObject(sheet
))
6021 return NS_ERROR_OUT_OF_MEMORY
;
6028 PresShell::SetAgentStyleSheets(const nsCOMArray
<nsIStyleSheet
>& aSheets
)
6030 return mStyleSet
->ReplaceSheets(nsStyleSet::eAgentSheet
, aSheets
);
6034 PresShell::AddOverrideStyleSheet(nsIStyleSheet
*aSheet
)
6036 return mStyleSet
->PrependStyleSheet(nsStyleSet::eOverrideSheet
, aSheet
);
6040 PresShell::RemoveOverrideStyleSheet(nsIStyleSheet
*aSheet
)
6042 return mStyleSet
->RemoveStyleSheet(nsStyleSet::eOverrideSheet
, aSheet
);
6046 StopPluginInstance(PresShell
*aShell
, nsIContent
*aContent
)
6048 nsIFrame
*frame
= aShell
->FrameManager()->GetPrimaryFrameFor(aContent
, -1);
6050 nsIObjectFrame
*objectFrame
= nsnull
;
6052 CallQueryInterface(frame
, &objectFrame
);
6056 objectFrame
->StopPlugin();
6061 StopMediaInstance(PresShell
*aShell
, nsIContent
*aContent
)
6063 nsCOMPtr
<nsIDOMHTMLMediaElement
> domMediaElem(do_QueryInterface(aContent
));
6067 nsHTMLMediaElement
* mediaElem
= static_cast<nsHTMLMediaElement
*>(aContent
);
6068 mediaElem
->Freeze();
6073 FreezeSubDocument(nsIDocument
*aDocument
, void *aData
)
6075 nsIPresShell
*shell
= aDocument
->GetPrimaryShell();
6085 nsCOMPtr
<nsIDOMDocument
> domDoc
= do_QueryInterface(mDocument
);
6087 EnumeratePlugins(domDoc
, NS_LITERAL_STRING("object"), StopPluginInstance
);
6088 EnumeratePlugins(domDoc
, NS_LITERAL_STRING("applet"), StopPluginInstance
);
6089 EnumeratePlugins(domDoc
, NS_LITERAL_STRING("embed"), StopPluginInstance
);
6091 EnumeratePlugins(domDoc
, NS_LITERAL_STRING("video"), StopMediaInstance
);
6092 EnumeratePlugins(domDoc
, NS_LITERAL_STRING("audio"), StopMediaInstance
);
6097 mCaret
->SetCaretVisible(PR_FALSE
);
6099 mPaintingSuppressed
= PR_TRUE
;
6102 mDocument
->EnumerateSubDocuments(FreezeSubDocument
, nsnull
);
6106 StartPluginInstance(PresShell
*aShell
, nsIContent
*aContent
)
6108 nsCOMPtr
<nsIObjectLoadingContent
> objlc(do_QueryInterface(aContent
));
6112 nsCOMPtr
<nsIPluginInstance
> inst
;
6113 objlc
->EnsureInstantiation(getter_AddRefs(inst
));
6118 StartMediaInstance(PresShell
*aShell
, nsIContent
*aContent
)
6120 nsCOMPtr
<nsIDOMHTMLMediaElement
> domMediaElem(do_QueryInterface(aContent
));
6124 nsHTMLMediaElement
* mediaElem
= static_cast<nsHTMLMediaElement
*>(aContent
);
6130 ThawSubDocument(nsIDocument
*aDocument
, void *aData
)
6132 nsIPresShell
*shell
= aDocument
->GetPrimaryShell();
6142 nsCOMPtr
<nsIDOMDocument
> domDoc
= do_QueryInterface(mDocument
);
6144 EnumeratePlugins(domDoc
, NS_LITERAL_STRING("object"), StartPluginInstance
);
6145 EnumeratePlugins(domDoc
, NS_LITERAL_STRING("applet"), StartPluginInstance
);
6146 EnumeratePlugins(domDoc
, NS_LITERAL_STRING("embed"), StartPluginInstance
);
6148 EnumeratePlugins(domDoc
, NS_LITERAL_STRING("video"), StartMediaInstance
);
6149 EnumeratePlugins(domDoc
, NS_LITERAL_STRING("audio"), StartMediaInstance
);
6154 mDocument
->EnumerateSubDocuments(ThawSubDocument
, nsnull
);
6156 UnsuppressPainting();
6159 //--------------------------------------------------------
6160 // Start of protected and private methods on the PresShell
6161 //--------------------------------------------------------
6163 //-------------- Begin Reflow Event Definition ------------------------
6166 PresShell::ReflowEvent::Run() {
6167 // Take an owning reference to the PresShell during this call to ensure
6168 // that it doesn't get killed off prematurely.
6169 nsRefPtr
<PresShell
> ps
= mPresShell
;
6172 if (VERIFY_REFLOW_NOISY_RC
& gVerifyReflowFlags
) {
6173 printf("\n*** Handling reflow event: PresShell=%p, event=%p\n", (void*)ps
, (void*)this);
6176 // NOTE: the ReflowEvent class is a friend of the PresShell class
6177 ps
->ClearReflowEventStatus();
6178 // Set a kung fu death grip on the view manager associated with the pres shell
6179 // before processing that pres shell's reflow commands. Fixes bug 54868.
6180 nsCOMPtr
<nsIViewManager
> viewManager
= ps
->GetViewManager();
6182 ps
->DoFlushPendingNotifications(Flush_Layout
, PR_TRUE
);
6184 // Now, explicitly release the pres shell before the view manager
6186 viewManager
= nsnull
;
6191 //-------------- End Reflow Event Definition ---------------------------
6194 PresShell::PostReflowEvent()
6196 if (mReflowEvent
.IsPending() || mIsDestroying
|| mIsReflowing
||
6197 mDirtyRoots
.Count() == 0)
6200 nsRefPtr
<ReflowEvent
> ev
= new ReflowEvent(this);
6201 if (NS_FAILED(NS_DispatchToCurrentThread(ev
))) {
6202 NS_WARNING("failed to dispatch reflow event");
6206 if (VERIFY_REFLOW_NOISY_RC
& gVerifyReflowFlags
) {
6207 printf("\n*** PresShell::PostReflowEvent(), this=%p, event=%p\n", (void*)this, (void*)ev
);
6214 PresShell::WillDoReflow()
6216 // We just reflowed, tell the caret that its frame might have moved.
6217 // XXXbz that comment makes no sense
6219 mCaret
->InvalidateOutsideCaret();
6220 mCaret
->UpdateCaretPosition();
6223 mPresContext
->FlushUserFontSet();
6225 mFrameConstructor
->BeginUpdate();
6229 PresShell::DidDoReflow()
6231 mFrameConstructor
->EndUpdate();
6233 HandlePostedReflowCallbacks();
6234 // Null-check mViewManager in case this happens during Destroy. See
6235 // bugs 244435 and 238546.
6236 if (!mPaintingSuppressed
&& mViewManager
)
6237 mViewManager
->SynthesizeMouseMove(PR_FALSE
);
6239 // Update the caret's position now to account for any changes created by
6241 mCaret
->InvalidateOutsideCaret();
6242 mCaret
->UpdateCaretPosition();
6247 PresShell::DoReflow(nsIFrame
* target
)
6249 nsIFrame
* rootFrame
= FrameManager()->GetRootFrame();
6251 nsCOMPtr
<nsIRenderingContext
> rcx
;
6252 // Always create the rendering context relative to the root frame during
6253 // reflow; otherwise, it crashes on the mac (I'm not quite sure why)
6254 nsresult rv
= CreateRenderingContext(rootFrame
, getter_AddRefs(rcx
));
6255 if (NS_FAILED(rv
)) {
6256 NS_NOTREACHED("CreateRenderingContext failure");
6260 target
->WillReflow(mPresContext
);
6262 // If the target frame is the root of the frame hierarchy, then
6263 // use all the available space. If it's simply a `reflow root',
6264 // then use the target frame's size as the available space.
6266 if (target
== rootFrame
)
6267 size
= mPresContext
->GetVisibleArea().Size();
6269 size
= target
->GetSize();
6271 NS_ASSERTION(!target
->GetNextInFlow() && !target
->GetPrevInFlow(),
6272 "reflow roots should never split");
6274 // Don't pass size directly to the reflow state, since a
6275 // constrained height implies page/column breaking.
6276 // Exception: the root frame always uses a constrained reflow
6278 if (target
!= rootFrame
)
6279 reflowSize
= nsSize(size
.width
, NS_UNCONSTRAINEDSIZE
);
6282 nsHTMLReflowState
reflowState(mPresContext
, target
, rcx
, reflowSize
);
6284 // fix the computed height
6285 NS_ASSERTION(reflowState
.mComputedMargin
== nsMargin(0, 0, 0, 0),
6286 "reflow state should not set margin for reflow roots");
6287 if (size
.height
!= NS_UNCONSTRAINEDSIZE
) {
6288 nscoord computedHeight
=
6289 size
.height
- reflowState
.mComputedBorderPadding
.TopBottom();
6290 computedHeight
= PR_MAX(computedHeight
, 0);
6291 reflowState
.SetComputedHeight(computedHeight
);
6293 NS_ASSERTION(reflowState
.ComputedWidth() ==
6295 reflowState
.mComputedBorderPadding
.LeftRight(),
6296 "reflow state computed incorrect width");
6298 nsReflowStatus status
;
6299 nsHTMLReflowMetrics desiredSize
;
6300 target
->Reflow(mPresContext
, desiredSize
, reflowState
, status
);
6302 // If an incremental reflow is initiated at a frame other than the
6303 // root frame, then its desired size had better not change! If it's
6304 // initiated at the root, then the size better not change unless its
6305 // height was unconstrained to start with.
6306 NS_ASSERTION((target
== rootFrame
&& size
.height
== NS_UNCONSTRAINEDSIZE
) ||
6307 (desiredSize
.width
== size
.width
&&
6308 desiredSize
.height
== size
.height
),
6309 "non-root frame's desired size changed during an "
6310 "incremental reflow");
6311 NS_ASSERTION(desiredSize
.mOverflowArea
==
6312 nsRect(nsPoint(0, 0),
6313 nsSize(desiredSize
.width
, desiredSize
.height
)),
6314 "reflow roots must not have visible overflow");
6315 NS_ASSERTION(status
== NS_FRAME_COMPLETE
,
6316 "reflow roots should never split");
6318 target
->SetSize(nsSize(desiredSize
.width
, desiredSize
.height
));
6320 nsContainerFrame::SyncFrameViewAfterReflow(mPresContext
, target
,
6322 &desiredSize
.mOverflowArea
);
6324 target
->DidReflow(mPresContext
, nsnull
, NS_FRAME_REFLOW_FINISHED
);
6325 if (target
== rootFrame
&& size
.height
== NS_UNCONSTRAINEDSIZE
) {
6326 mPresContext
->SetVisibleArea(nsRect(0, 0, desiredSize
.width
,
6327 desiredSize
.height
));
6333 PresShell::DoVerifyReflow()
6335 if (nsIFrameDebug::GetVerifyTreeEnable()) {
6336 nsIFrameDebug
* frameDebug
;
6337 nsIFrame
* rootFrame
= FrameManager()->GetRootFrame();
6338 if (NS_SUCCEEDED(rootFrame
->QueryInterface(NS_GET_IID(nsIFrameDebug
),
6339 (void**)&frameDebug
))) {
6340 frameDebug
->VerifyTree();
6343 if (GetVerifyReflowEnable()) {
6344 // First synchronously render what we have so far so that we can
6347 mViewManager
->GetRootView(rootView
);
6348 mViewManager
->UpdateView(rootView
, NS_VMREFRESH_IMMEDIATE
);
6350 FlushPendingNotifications(Flush_Layout
);
6351 mInVerifyReflow
= PR_TRUE
;
6352 PRBool ok
= VerifyIncrementalReflow();
6353 mInVerifyReflow
= PR_FALSE
;
6354 if (VERIFY_REFLOW_ALL
& gVerifyReflowFlags
) {
6355 printf("ProcessReflowCommands: finished (%s)\n",
6356 ok
? "ok" : "failed");
6359 if (0 != mDirtyRoots
.Count()) {
6360 printf("XXX yikes! reflow commands queued during verify-reflow\n");
6367 PresShell::ProcessReflowCommands(PRBool aInterruptible
)
6369 MOZ_TIMER_DEBUGLOG(("Start: Reflow: PresShell::ProcessReflowCommands(), this=%p\n", this));
6370 MOZ_TIMER_START(mReflowWatch
);
6372 if (0 != mDirtyRoots
.Count()) {
6375 if (VERIFY_REFLOW_DUMP_COMMANDS
& gVerifyReflowFlags
) {
6376 printf("ProcessReflowCommands: begin incremental reflow\n");
6382 // If reflow is interruptible, then make a note of our deadline.
6383 const PRIntervalTime deadline
= aInterruptible
6384 ? PR_IntervalNow() + PR_MicrosecondsToInterval(gMaxRCProcessingTime
)
6385 : (PRIntervalTime
)0;
6387 // Scope for the reflow entry point
6389 nsAutoScriptBlocker scriptBlocker
;
6390 AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Reflow
);
6391 mIsReflowing
= PR_TRUE
;
6394 // Send an incremental reflow notification to the target frame.
6395 PRInt32 idx
= mDirtyRoots
.Count() - 1;
6396 nsIFrame
*target
= static_cast<nsIFrame
*>(mDirtyRoots
[idx
]);
6397 mDirtyRoots
.RemoveElementAt(idx
);
6399 if (!NS_SUBTREE_DIRTY(target
)) {
6400 // It's not dirty anymore, which probably means the notification
6401 // was posted in the middle of a reflow (perhaps with a reflow
6402 // root in the middle). Don't do anything.
6408 // Keep going until we're out of reflow commands, or we've run
6409 // past our deadline.
6410 } while (mDirtyRoots
.Count() &&
6411 (!aInterruptible
|| PR_IntervalNow() < deadline
));
6413 // XXXwaterson for interruptible reflow, examine the tree and
6414 // re-enqueue any unflowed reflow targets.
6416 mIsReflowing
= PR_FALSE
;
6419 // Exiting the scriptblocker might have killed us
6420 if (!mIsDestroying
) {
6424 // DidDoReflow might have killed us
6425 if (!mIsDestroying
) {
6427 if (VERIFY_REFLOW_DUMP_COMMANDS
& gVerifyReflowFlags
) {
6428 printf("\nPresShell::ProcessReflowCommands() finished: this=%p\n",
6434 // If any new reflow commands were enqueued during the reflow, schedule
6435 // another reflow event to process them. Note that we want to do this
6436 // after DidDoReflow(), since that method can change whether there are
6437 // dirty roots around by flushing, and there's no point in posting a
6438 // reflow event just to have the flush revoke it.
6439 if (mDirtyRoots
.Count())
6444 MOZ_TIMER_DEBUGLOG(("Stop: Reflow: PresShell::ProcessReflowCommands(), this=%p\n", this));
6445 MOZ_TIMER_STOP(mReflowWatch
);
6447 if (!mIsDestroying
&& mShouldUnsuppressPainting
&&
6448 mDirtyRoots
.Count() == 0) {
6449 // We only unlock if we're out of reflows. It's pointless
6450 // to unlock if reflows are still pending, since reflows
6451 // are just going to thrash the frames around some more. By
6452 // waiting we avoid an overeager "jitter" effect.
6453 mShouldUnsuppressPainting
= PR_FALSE
;
6454 UnsuppressAndInvalidate();
6461 PresShell::ClearReflowEventStatus()
6463 mReflowEvent
.Forget();
6468 * It's better to add stuff to the |DidSetStyleContext| method of the
6469 * relevant frames than adding it here. These methods should (ideally,
6473 // Return value says whether to walk children.
6474 typedef PRBool (* frameWalkerFn
)(nsIFrame
*aFrame
, void *aClosure
);
6477 ReResolveMenusAndTrees(nsIFrame
*aFrame
, void *aClosure
)
6479 // Trees have a special style cache that needs to be flushed when
6480 // the theme changes.
6481 nsTreeBodyFrame
*treeBody
= nsnull
;
6482 CallQueryInterface(aFrame
, &treeBody
);
6484 treeBody
->ClearStyleAndImageCaches();
6486 // We deliberately don't re-resolve style on a menu's popup
6487 // sub-content, since doing so slows menus to a crawl. That means we
6488 // have to special-case them on a skin switch, and ensure that the
6489 // popup frames just get destroyed completely.
6490 if (aFrame
&& aFrame
->GetType() == nsGkAtoms::menuFrame
)
6491 (static_cast<nsMenuFrame
*>(aFrame
))->CloseMenu(PR_TRUE
);
6496 ReframeImageBoxes(nsIFrame
*aFrame
, void *aClosure
)
6498 nsStyleChangeList
*list
= static_cast<nsStyleChangeList
*>(aClosure
);
6499 if (aFrame
->GetType() == nsGkAtoms::imageBoxFrame
) {
6500 list
->AppendChange(aFrame
, aFrame
->GetContent(),
6501 NS_STYLE_HINT_FRAMECHANGE
);
6502 return PR_FALSE
; // don't walk descendants
6504 return PR_TRUE
; // walk descendants
6508 WalkFramesThroughPlaceholders(nsPresContext
*aPresContext
, nsIFrame
*aFrame
,
6509 frameWalkerFn aFunc
, void *aClosure
)
6511 PRBool walkChildren
= (*aFunc
)(aFrame
, aClosure
);
6515 PRInt32 listIndex
= 0;
6516 nsIAtom
* childList
= nsnull
;
6519 nsIFrame
*child
= aFrame
->GetFirstChild(childList
);
6521 if (!(child
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
)) {
6522 // only do frames that are in flow, and recur through the
6523 // out-of-flows of placeholders.
6524 WalkFramesThroughPlaceholders(aPresContext
,
6525 nsPlaceholderFrame::GetRealFrameFor(child
),
6528 child
= child
->GetNextSibling();
6531 childList
= aFrame
->GetAdditionalChildListName(listIndex
++);
6532 } while (childList
);
6537 PresShell::Observe(nsISupports
* aSubject
,
6539 const PRUnichar
* aData
)
6542 if (!nsCRT::strcmp(aTopic
, "chrome-flush-skin-caches")) {
6543 nsIFrame
*rootFrame
= FrameManager()->GetRootFrame();
6544 // Need to null-check because "chrome-flush-skin-caches" can happen
6545 // at interesting times during startup.
6547 NS_ASSERTION(mViewManager
, "View manager must exist");
6548 nsIViewManager::UpdateViewBatch
batch(mViewManager
);
6550 WalkFramesThroughPlaceholders(mPresContext
, rootFrame
,
6551 &ReResolveMenusAndTrees
, nsnull
);
6553 // Because "chrome:" URL equality is messy, reframe image box
6555 nsStyleChangeList changeList
;
6556 WalkFramesThroughPlaceholders(mPresContext
, rootFrame
,
6557 ReframeImageBoxes
, &changeList
);
6558 // Mark ourselves as not safe to flush while we're doing frame
6561 nsAutoScriptBlocker scriptBlocker
;
6562 mFrameConstructor
->ProcessRestyledFrames(changeList
);
6565 batch
.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC
);
6566 #ifdef ACCESSIBILITY
6567 InvalidateAccessibleSubtree(nsnull
);
6574 if (!nsCRT::strcmp(aTopic
, NS_LINK_VISITED_EVENT_TOPIC
)) {
6575 nsCOMPtr
<nsIURI
> uri
= do_QueryInterface(aSubject
);
6576 if (uri
&& mDocument
) {
6577 mDocument
->NotifyURIVisitednessChanged(uri
);
6582 if (!nsCRT::strcmp(aTopic
, "agent-sheet-added") && mStyleSet
) {
6583 AddAgentSheet(aSubject
);
6587 if (!nsCRT::strcmp(aTopic
, "user-sheet-added") && mStyleSet
) {
6588 AddUserSheet(aSubject
);
6592 if (!nsCRT::strcmp(aTopic
, "agent-sheet-removed") && mStyleSet
) {
6593 RemoveSheet(nsStyleSet::eAgentSheet
, aSubject
);
6597 if (!nsCRT::strcmp(aTopic
, "user-sheet-removed") && mStyleSet
) {
6598 RemoveSheet(nsStyleSet::eUserSheet
, aSubject
);
6602 #ifdef ACCESSIBILITY
6603 if (!nsCRT::strcmp(aTopic
, "a11y-init-or-shutdown")) {
6604 gIsAccessibilityActive
= aData
&& *aData
== '1';
6607 NS_WARNING("unrecognized topic in PresShell::Observe");
6608 return NS_ERROR_FAILURE
;
6612 PresShell::EnumeratePlugins(nsIDOMDocument
*aDocument
,
6613 const nsString
&aPluginTag
,
6614 nsPluginEnumCallback aCallback
)
6616 nsCOMPtr
<nsIDOMNodeList
> nodes
;
6617 aDocument
->GetElementsByTagName(aPluginTag
, getter_AddRefs(nodes
));
6622 nodes
->GetLength(&length
);
6624 for (PRUint32 i
= 0; i
< length
; ++i
) {
6625 nsCOMPtr
<nsIDOMNode
> node
;
6626 nodes
->Item(i
, getter_AddRefs(node
));
6628 nsCOMPtr
<nsIContent
> content
= do_QueryInterface(node
);
6630 aCallback(this, content
);
6634 //------------------------------------------------------
6635 // End of protected and private methods on the PresShell
6636 //------------------------------------------------------
6638 // Start of DEBUG only code
6641 #include "nsViewsCID.h"
6642 #include "nsWidgetsCID.h"
6643 #include "nsIDeviceContext.h"
6645 #include "nsILinkHandler.h"
6647 static NS_DEFINE_CID(kViewManagerCID
, NS_VIEW_MANAGER_CID
);
6648 static NS_DEFINE_CID(kWidgetCID
, NS_CHILD_CID
);
6651 LogVerifyMessage(nsIFrame
* k1
, nsIFrame
* k2
, const char* aMsg
)
6653 printf("verifyreflow: ");
6656 nsIFrameDebug
* frameDebug
;
6658 if (NS_SUCCEEDED(k1
->QueryInterface(NS_GET_IID(nsIFrameDebug
),
6659 (void**)&frameDebug
))) {
6660 frameDebug
->GetFrameName(name
);
6664 name
.Assign(NS_LITERAL_STRING("(null)"));
6666 fputs(NS_LossyConvertUTF16toASCII(name
).get(), stdout
);
6668 fprintf(stdout
, " %p ", (void*)k1
);
6673 nsIFrameDebug
* frameDebug
;
6675 if (NS_SUCCEEDED(k2
->QueryInterface(NS_GET_IID(nsIFrameDebug
),
6676 (void**)&frameDebug
))) {
6677 frameDebug
->GetFrameName(name
);
6681 name
.Assign(NS_LITERAL_STRING("(null)"));
6683 fputs(NS_LossyConvertUTF16toASCII(name
).get(), stdout
);
6685 fprintf(stdout
, " %p ", (void*)k2
);
6687 printf(" %s", aMsg
);
6691 LogVerifyMessage(nsIFrame
* k1
, nsIFrame
* k2
, const char* aMsg
,
6692 const nsRect
& r1
, const nsRect
& r2
)
6694 printf("VerifyReflow Error:\n");
6696 nsIFrameDebug
* frameDebug
;
6698 if (NS_SUCCEEDED(k1
->QueryInterface(NS_GET_IID(nsIFrameDebug
),
6699 (void**)&frameDebug
))) {
6700 fprintf(stdout
, " ");
6701 frameDebug
->GetFrameName(name
);
6702 fputs(NS_LossyConvertUTF16toASCII(name
).get(), stdout
);
6703 fprintf(stdout
, " %p ", (void*)k1
);
6705 printf("{%d, %d, %d, %d}", r1
.x
, r1
.y
, r1
.width
, r1
.height
);
6709 if (NS_SUCCEEDED(k2
->QueryInterface(NS_GET_IID(nsIFrameDebug
),
6710 (void**)&frameDebug
))) {
6711 fprintf(stdout
, " ");
6712 frameDebug
->GetFrameName(name
);
6713 fputs(NS_LossyConvertUTF16toASCII(name
).get(), stdout
);
6714 fprintf(stdout
, " %p ", (void*)k2
);
6716 printf("{%d, %d, %d, %d}\n", r2
.x
, r2
.y
, r2
.width
, r2
.height
);
6718 printf(" %s\n", aMsg
);
6722 CompareTrees(nsPresContext
* aFirstPresContext
, nsIFrame
* aFirstFrame
,
6723 nsPresContext
* aSecondPresContext
, nsIFrame
* aSecondFrame
)
6725 if (!aFirstPresContext
|| !aFirstFrame
|| !aSecondPresContext
|| !aSecondFrame
)
6727 // XXX Evil hack to reduce false positives; I can't seem to figure
6728 // out how to flush scrollbar changes correctly
6729 //if (aFirstFrame->GetType() == nsGkAtoms::scrollbarFrame)
6731 PRBool ok
= PR_TRUE
;
6732 nsIAtom
* listName
= nsnull
;
6733 PRInt32 listIndex
= 0;
6735 nsIFrame
* k1
= aFirstFrame
->GetFirstChild(listName
);
6736 nsIFrame
* k2
= aSecondFrame
->GetFirstChild(listName
);
6737 PRInt32 l1
= nsContainerFrame::LengthOf(k1
);
6738 PRInt32 l2
= nsContainerFrame::LengthOf(k2
);
6741 LogVerifyMessage(k1
, k2
, "child counts don't match: ");
6742 printf("%d != %d\n", l1
, l2
);
6743 if (0 == (VERIFY_REFLOW_ALL
& gVerifyReflowFlags
)) {
6751 if (((nsnull
== k1
) && (nsnull
!= k2
)) ||
6752 ((nsnull
!= k1
) && (nsnull
== k2
))) {
6754 LogVerifyMessage(k1
, k2
, "child lists are different\n");
6757 else if (nsnull
!= k1
) {
6758 // Verify that the frames are the same size
6759 if (k1
->GetRect() != k2
->GetRect()) {
6761 LogVerifyMessage(k1
, k2
, "(frame rects)", k1
->GetRect(), k2
->GetRect());
6764 // Make sure either both have views or neither have views; if they
6765 // do have views, make sure the views are the same size. If the
6766 // views have widgets, make sure they both do or neither does. If
6767 // they do, make sure the widgets are the same size.
6770 if (((nsnull
== v1
) && (nsnull
!= v2
)) ||
6771 ((nsnull
!= v1
) && (nsnull
== v2
))) {
6773 LogVerifyMessage(k1
, k2
, "child views are not matched\n");
6775 else if (nsnull
!= v1
) {
6776 if (v1
->GetBounds() != v2
->GetBounds()) {
6777 LogVerifyMessage(k1
, k2
, "(view rects)", v1
->GetBounds(), v2
->GetBounds());
6780 nsIWidget
* w1
= v1
->GetWidget();
6781 nsIWidget
* w2
= v2
->GetWidget();
6782 if (((nsnull
== w1
) && (nsnull
!= w2
)) ||
6783 ((nsnull
!= w1
) && (nsnull
== w2
))) {
6785 LogVerifyMessage(k1
, k2
, "child widgets are not matched\n");
6787 else if (nsnull
!= w1
) {
6791 LogVerifyMessage(k1
, k2
, "(widget rects)", r1
, r2
);
6795 if (!ok
&& (0 == (VERIFY_REFLOW_ALL
& gVerifyReflowFlags
))) {
6799 // verify that neither frame has a space manager,
6800 // or they both do and the space managers are equivalent
6801 nsSpaceManager
*sm1
= static_cast<nsSpaceManager
*>
6802 (k1
->GetProperty(nsGkAtoms::spaceManagerProperty
));
6804 // look at the test frame
6805 nsSpaceManager
*sm2
= static_cast<nsSpaceManager
*>
6806 (k2
->GetProperty(nsGkAtoms::spaceManagerProperty
));
6808 // now compare the space managers
6809 if (((nsnull
== sm1
) && (nsnull
!= sm2
)) ||
6810 ((nsnull
!= sm1
) && (nsnull
== sm2
))) { // one is null, and the other is not
6812 LogVerifyMessage(k1
, k2
, "space managers are not matched\n");
6814 else if (sm1
&& sm2
) { // both are not null, compare them
6815 // first, compare yMost
6816 nscoord yMost1
, yMost2
;
6817 nsresult smresult
= sm1
->YMost(yMost1
);
6818 if (NS_ERROR_ABORT
!= smresult
)
6820 NS_ASSERTION(NS_SUCCEEDED(smresult
), "bad result");
6821 smresult
= sm2
->YMost(yMost2
);
6822 NS_ASSERTION(NS_SUCCEEDED(smresult
), "bad result");
6823 if (yMost1
!= yMost2
) {
6824 LogVerifyMessage(k1
, k2
, "yMost of space managers differs\n");
6826 // now compare bands by sampling
6827 PRInt32 yIncrement
= yMost1
/100;
6828 if (0==yIncrement
) {
6829 yIncrement
= 1; // guarantee we make progress in the loop below
6831 nscoord yOffset
= 0;
6832 for ( ; ok
&& yOffset
< yMost1
; yOffset
+= yIncrement
)
6834 nscoord small
=5, large
=100;
6835 nsBandData band1
, band2
;
6836 nsBandTrapezoid trap1
[20], trap2
[20];
6837 band1
.mSize
= band2
.mSize
= 20;
6838 band1
.mTrapezoids
= trap1
;
6839 band2
.mTrapezoids
= trap2
;
6840 sm1
->GetBandData(yOffset
, nsSize(small
,small
), band1
);
6841 sm2
->GetBandData(yOffset
, nsSize(small
,small
), band2
);
6842 if (band1
.mCount
!= band2
.mCount
)
6843 { // count mismatch, stop comparing
6844 LogVerifyMessage(k1
, k2
, "band.mCount of space managers differs\n");
6845 printf("count1= %d, count2=%d, yOffset = %d, size=%d\n",
6846 band1
.mCount
, band2
.mCount
, yOffset
, small
);
6850 else // band counts match, compare individual traps
6852 PRInt32 trapIndex
=0;
6853 for ( ;trapIndex
<band1
.mCount
; trapIndex
++)
6855 PRBool match
= (trap1
[trapIndex
].EqualGeometry(trap2
[trapIndex
])) &&
6856 ((trap1
[trapIndex
].mFrames
!=nsnull
) == (trap2
[trapIndex
].mFrames
!=nsnull
));
6859 LogVerifyMessage(k1
, k2
, "band.mTrapezoids of space managers differs\n");
6860 printf ("index %d\n", trapIndex
);
6864 // test the larger maxSize
6865 sm1
->GetBandData(yOffset
, nsSize(large
,large
), band1
);
6866 sm2
->GetBandData(yOffset
, nsSize(large
,large
), band2
);
6867 if (band1
.mCount
!= band2
.mCount
)
6868 { // count mismatch, stop comparing
6869 LogVerifyMessage(k1
, k2
, "band.mCount of space managers differs\n");
6870 printf("count1= %d, count2=%d, yOffset = %d, size=%d\n",
6871 band1
.mCount
, band2
.mCount
, yOffset
, small
);
6875 else // band counts match, compare individual traps
6877 PRInt32 trapIndex
=0;
6878 for ( ; trapIndex
<band1
.mCount
; trapIndex
++)
6880 PRBool match
= (trap1
[trapIndex
].EqualGeometry(trap2
[trapIndex
])) &&
6881 ((trap1
[trapIndex
].mFrames
!=nsnull
) == (trap2
[trapIndex
].mFrames
!=nsnull
));
6884 LogVerifyMessage(k1
, k2
, "band.mTrapezoids of space managers differs\n");
6885 printf ("index %d\n", trapIndex
);
6896 // Compare the sub-trees too
6897 if (!CompareTrees(aFirstPresContext
, k1
, aSecondPresContext
, k2
)) {
6899 if (0 == (VERIFY_REFLOW_ALL
& gVerifyReflowFlags
)) {
6904 // Advance to next sibling
6905 k1
= k1
->GetNextSibling();
6906 k2
= k2
->GetNextSibling();
6912 if (!ok
&& (0 == (VERIFY_REFLOW_ALL
& gVerifyReflowFlags
))) {
6916 nsIAtom
* listName1
= aFirstFrame
->GetAdditionalChildListName(listIndex
);
6917 nsIAtom
* listName2
= aSecondFrame
->GetAdditionalChildListName(listIndex
);
6919 if (listName1
!= listName2
) {
6920 if (0 == (VERIFY_REFLOW_ALL
& gVerifyReflowFlags
)) {
6923 LogVerifyMessage(k1
, k2
, "child list names are not matched: ");
6925 if (nsnull
!= listName1
) {
6926 listName1
->ToString(tmp
);
6927 fputs(NS_LossyConvertUTF16toASCII(tmp
).get(), stdout
);
6930 fputs("(null)", stdout
);
6932 if (nsnull
!= listName2
) {
6933 listName2
->ToString(tmp
);
6934 fputs(NS_LossyConvertUTF16toASCII(tmp
).get(), stdout
);
6937 fputs("(null)", stdout
);
6941 listName
= listName1
;
6942 } while (ok
&& (listName
!= nsnull
));
6950 FindTopFrame(nsIFrame
* aRoot
)
6953 nsIContent
* content
= aRoot
->GetContent();
6956 content
->GetTag(tag
);
6957 if (nsnull
!= tag
) {
6963 // Try one of the children
6964 nsIFrame
* kid
= aRoot
->GetFirstChild(nsnull
);
6965 while (nsnull
!= kid
) {
6966 nsIFrame
* result
= FindTopFrame(kid
);
6967 if (nsnull
!= result
) {
6970 kid
= kid
->GetNextSibling();
6981 PresShell::CloneStyleSet(nsStyleSet
* aSet
, nsStyleSet
** aResult
)
6983 nsStyleSet
*clone
= new nsStyleSet();
6985 return NS_ERROR_OUT_OF_MEMORY
;
6988 PRInt32 i
, n
= aSet
->SheetCount(nsStyleSet::eOverrideSheet
);
6989 for (i
= 0; i
< n
; i
++) {
6990 nsIStyleSheet
* ss
= aSet
->StyleSheetAt(nsStyleSet::eOverrideSheet
, i
);
6992 clone
->AppendStyleSheet(nsStyleSet::eOverrideSheet
, ss
);
6995 // The document expects to insert document stylesheets itself
6997 n
= aSet
->SheetCount(nsStyleSet::eDocSheet
);
6998 for (i
= 0; i
< n
; i
++) {
6999 nsIStyleSheet
* ss
= aSet
->StyleSheetAt(nsStyleSet::eDocSheet
, i
);
7001 clone
->AddDocStyleSheet(ss
, mDocument
);
7005 n
= aSet
->SheetCount(nsStyleSet::eUserSheet
);
7006 for (i
= 0; i
< n
; i
++) {
7007 nsIStyleSheet
* ss
= aSet
->StyleSheetAt(nsStyleSet::eUserSheet
, i
);
7009 clone
->AppendStyleSheet(nsStyleSet::eUserSheet
, ss
);
7012 n
= aSet
->SheetCount(nsStyleSet::eAgentSheet
);
7013 for (i
= 0; i
< n
; i
++) {
7014 nsIStyleSheet
* ss
= aSet
->StyleSheetAt(nsStyleSet::eAgentSheet
, i
);
7016 clone
->AppendStyleSheet(nsStyleSet::eAgentSheet
, ss
);
7024 DumpToPNG(nsIPresShell
* shell
, nsAString
& name
) {
7025 PRInt32 width
=1000, height
=1000;
7026 nsRect
r(0, 0, shell
->GetPresContext()->DevPixelsToAppUnits(width
),
7027 shell
->GetPresContext()->DevPixelsToAppUnits(height
));
7029 nsRefPtr
<gfxImageSurface
> imgSurface
=
7030 new gfxImageSurface(gfxIntSize(width
, height
),
7031 gfxImageSurface::ImageFormatARGB32
);
7032 NS_ENSURE_TRUE(imgSurface
, NS_ERROR_OUT_OF_MEMORY
);
7034 nsRefPtr
<gfxContext
> imgContext
= new gfxContext(imgSurface
);
7036 nsRefPtr
<gfxASurface
> surface
=
7037 gfxPlatform::GetPlatform()->
7038 CreateOffscreenSurface(gfxIntSize(width
, height
),
7039 gfxASurface::ImageFormatARGB32
);
7040 NS_ENSURE_TRUE(surface
, NS_ERROR_OUT_OF_MEMORY
);
7042 nsRefPtr
<gfxContext
> context
= new gfxContext(surface
);
7043 NS_ENSURE_TRUE(context
, NS_ERROR_OUT_OF_MEMORY
);
7045 nsresult rv
= shell
->RenderDocument(r
, 0, NS_RGB(255, 255, 0), context
);
7046 NS_ENSURE_SUCCESS(rv
, rv
);
7048 imgContext
->DrawSurface(surface
, gfxSize(width
, height
));
7050 nsCOMPtr
<imgIEncoder
> encoder
= do_CreateInstance("@mozilla.org/image/encoder;2?type=image/png");
7051 NS_ENSURE_TRUE(encoder
, NS_ERROR_FAILURE
);
7052 encoder
->InitFromData(imgSurface
->Data(), imgSurface
->Stride() * height
,
7053 width
, height
, imgSurface
->Stride(),
7054 imgIEncoder::INPUT_FORMAT_HOSTARGB
, EmptyString());
7056 // XXX not sure if this is the right way to write to a file
7057 nsCOMPtr
<nsILocalFile
> file
= do_CreateInstance("@mozilla.org/file/local;1");
7058 NS_ENSURE_TRUE(file
, NS_ERROR_FAILURE
);
7059 rv
= file
->InitWithPath(name
);
7060 NS_ENSURE_SUCCESS(rv
, rv
);
7063 encoder
->Available(&length
);
7065 nsCOMPtr
<nsIOutputStream
> outputStream
;
7066 rv
= NS_NewLocalFileOutputStream(getter_AddRefs(outputStream
), file
);
7067 NS_ENSURE_SUCCESS(rv
, rv
);
7069 nsCOMPtr
<nsIOutputStream
> bufferedOutputStream
;
7070 rv
= NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream
),
7071 outputStream
, length
);
7073 PRUint32 numWritten
;
7074 rv
= bufferedOutputStream
->WriteFrom(encoder
, length
, &numWritten
);
7075 NS_ENSURE_SUCCESS(rv
, rv
);
7081 // After an incremental reflow, we verify the correctness by doing a
7082 // full reflow into a fresh frame tree.
7084 PresShell::VerifyIncrementalReflow()
7086 if (VERIFY_REFLOW_NOISY
& gVerifyReflowFlags
) {
7087 printf("Building Verification Tree...\n");
7090 // Create a presentation context to view the new frame tree
7091 nsCOMPtr
<nsPresContext
> cx
=
7092 new nsPresContext(mDocument
, mPresContext
->IsPaginated() ?
7093 nsPresContext::eContext_PrintPreview
:
7094 nsPresContext::eContext_Galley
);
7095 NS_ENSURE_TRUE(cx
, PR_FALSE
);
7097 nsIDeviceContext
*dc
= mPresContext
->DeviceContext();
7098 nsresult rv
= cx
->Init(dc
);
7099 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
7101 // Get our scrolling preference
7103 mViewManager
->GetRootView(rootView
);
7104 void* nativeParentWidget
= rootView
->GetWidget()->GetNativeData(NS_NATIVE_WIDGET
);
7106 // Create a new view manager.
7107 nsCOMPtr
<nsIViewManager
> vm
= do_CreateInstance(kViewManagerCID
);
7108 NS_ENSURE_TRUE(vm
, PR_FALSE
);
7110 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
7112 // Create a child window of the parent that is our "root view/window"
7114 nsRect tbounds
= mPresContext
->GetVisibleArea();
7115 nsIView
* view
= vm
->CreateView(tbounds
, nsnull
);
7116 NS_ENSURE_TRUE(view
, PR_FALSE
);
7118 //now create the widget for the view
7119 rv
= view
->CreateWidget(kWidgetCID
, nsnull
, nativeParentWidget
, PR_TRUE
);
7120 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
7122 // Setup hierarchical relationship in view manager
7123 vm
->SetRootView(view
);
7125 // Make the new presentation context the same size as our
7126 // presentation context.
7127 nsRect r
= mPresContext
->GetVisibleArea();
7128 cx
->SetVisibleArea(r
);
7130 // Create a new presentation shell to view the document. Use the
7131 // exact same style information that this document has.
7132 nsAutoPtr
<nsStyleSet
> newSet
;
7133 rv
= CloneStyleSet(mStyleSet
, getter_Transfers(newSet
));
7134 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
7135 nsCOMPtr
<nsIPresShell
> sh
;
7136 rv
= mDocument
->CreateShell(cx
, vm
, newSet
, getter_AddRefs(sh
));
7137 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
7139 // Note that after we create the shell, we must make sure to destroy it
7140 sh
->SetVerifyReflowEnable(PR_FALSE
); // turn off verify reflow while we're reflowing the test frame tree
7141 vm
->SetViewObserver((nsIViewObserver
*)((PresShell
*)sh
.get()));
7143 nsAutoScriptBlocker scriptBlocker
;
7144 sh
->InitialReflow(r
.width
, r
.height
);
7146 mDocument
->BindingManager()->ProcessAttachedQueue();
7147 sh
->FlushPendingNotifications(Flush_Layout
);
7148 sh
->SetVerifyReflowEnable(PR_TRUE
); // turn on verify reflow again now that we're done reflowing the test frame tree
7149 // Force the non-primary presshell to unsuppress; it doesn't want to normally
7150 // because it thinks it's hidden
7151 ((PresShell
*)sh
.get())->mPaintingSuppressed
= PR_FALSE
;
7152 if (VERIFY_REFLOW_NOISY
& gVerifyReflowFlags
) {
7153 printf("Verification Tree built, comparing...\n");
7156 // Now that the document has been reflowed, use its frame tree to
7157 // compare against our frame tree.
7158 nsIFrame
* root1
= FrameManager()->GetRootFrame();
7159 nsIFrame
* root2
= sh
->FrameManager()->GetRootFrame();
7160 PRBool ok
= CompareTrees(mPresContext
, root1
, cx
, root2
);
7161 if (!ok
&& (VERIFY_REFLOW_NOISY
& gVerifyReflowFlags
)) {
7162 printf("Verify reflow failed, primary tree:\n");
7163 nsIFrameDebug
* frameDebug
;
7165 if (NS_SUCCEEDED(CallQueryInterface(root1
, &frameDebug
))) {
7166 frameDebug
->List(stdout
, 0);
7168 printf("Verification tree:\n");
7169 if (NS_SUCCEEDED(CallQueryInterface(root2
, &frameDebug
))) {
7170 frameDebug
->List(stdout
, 0);
7175 // Sample code for dumping page to png
7176 // XXX Needs to be made more flexible
7180 stra
.AppendLiteral("C:\\mozilla\\mozilla\\debug\\filea");
7181 stra
.AppendInt(num
);
7182 stra
.AppendLiteral(".png");
7183 DumpToPNG(sh
, stra
);
7185 strb
.AppendLiteral("C:\\mozilla\\mozilla\\debug\\fileb");
7186 strb
.AppendInt(num
);
7187 strb
.AppendLiteral(".png");
7188 DumpToPNG(this, strb
);
7193 sh
->EndObservingDocument();
7195 if (VERIFY_REFLOW_NOISY
& gVerifyReflowFlags
) {
7196 printf("Finished Verifying Reflow...\n");
7202 // Layout debugging hooks
7204 PresShell::ListStyleContexts(nsIFrame
*aRootFrame
, FILE *out
, PRInt32 aIndent
)
7206 nsStyleContext
*sc
= aRootFrame
->GetStyleContext();
7208 sc
->List(out
, aIndent
);
7212 PresShell::ListStyleSheets(FILE *out
, PRInt32 aIndent
)
7214 PRInt32 sheetCount
= mStyleSet
->SheetCount(nsStyleSet::eDocSheet
);
7215 for (PRInt32 i
= 0; i
< sheetCount
; ++i
) {
7216 mStyleSet
->StyleSheetAt(nsStyleSet::eDocSheet
, i
)->List(out
, aIndent
);
7222 PresShell::VerifyStyleTree()
7228 //=============================================================
7229 //=============================================================
7230 //-- Debug Reflow Counts
7231 //=============================================================
7232 //=============================================================
7233 #ifdef MOZ_REFLOW_PERF
7234 //-------------------------------------------------------------
7236 PresShell::DumpReflows()
7238 if (mReflowCountMgr
) {
7239 nsCAutoString uriStr
;
7241 nsIURI
*uri
= mDocument
->GetDocumentURI();
7243 uri
->GetPath(uriStr
);
7246 mReflowCountMgr
->DisplayTotals(uriStr
.get());
7247 mReflowCountMgr
->DisplayHTMLTotals(uriStr
.get());
7248 mReflowCountMgr
->DisplayDiffsInTotals("Differences");
7253 //-------------------------------------------------------------
7255 PresShell::CountReflows(const char * aName
, nsIFrame
* aFrame
)
7257 if (mReflowCountMgr
) {
7258 mReflowCountMgr
->Add(aName
, aFrame
);
7264 //-------------------------------------------------------------
7266 PresShell::PaintCount(const char * aName
, nsIRenderingContext
* aRenderingContext
, nsPresContext
* aPresContext
, nsIFrame
* aFrame
, PRUint32 aColor
)
7268 if (mReflowCountMgr
) {
7269 mReflowCountMgr
->PaintCount(aName
, aRenderingContext
, aPresContext
, aFrame
, aColor
);
7274 //-------------------------------------------------------------
7276 PresShell::SetPaintFrameCount(PRBool aPaintFrameCounts
)
7278 if (mReflowCountMgr
) {
7279 mReflowCountMgr
->SetPaintFrameCounts(aPaintFrameCounts
);
7284 //------------------------------------------------------------------
7285 //-- Reflow Counter Classes Impls
7286 //------------------------------------------------------------------
7288 //------------------------------------------------------------------
7289 ReflowCounter::ReflowCounter(ReflowCountMgr
* aMgr
) :
7296 //------------------------------------------------------------------
7297 ReflowCounter::~ReflowCounter()
7302 //------------------------------------------------------------------
7303 void ReflowCounter::ClearTotals()
7308 //------------------------------------------------------------------
7309 void ReflowCounter::SetTotalsCache()
7311 mCacheTotal
= mTotal
;
7314 //------------------------------------------------------------------
7315 void ReflowCounter::CalcDiffInTotals()
7317 mCacheTotal
= mTotal
- mCacheTotal
;
7320 //------------------------------------------------------------------
7321 void ReflowCounter::DisplayTotals(const char * aStr
)
7323 DisplayTotals(mTotal
, aStr
?aStr
:"Totals");
7326 //------------------------------------------------------------------
7327 void ReflowCounter::DisplayDiffTotals(const char * aStr
)
7329 DisplayTotals(mCacheTotal
, aStr
?aStr
:"Diff Totals");
7332 //------------------------------------------------------------------
7333 void ReflowCounter::DisplayHTMLTotals(const char * aStr
)
7335 DisplayHTMLTotals(mTotal
, aStr
?aStr
:"Totals");
7338 //------------------------------------------------------------------
7339 void ReflowCounter::DisplayTotals(PRUint32 aTotal
, const char * aTitle
)
7345 ReflowCounter
* gTots
= (ReflowCounter
*)mMgr
->LookUp(kGrandTotalsStr
);
7347 printf("%25s\t", aTitle
);
7348 printf("%d\t", aTotal
);
7349 if (gTots
!= this && aTotal
> 0) {
7354 //------------------------------------------------------------------
7355 void ReflowCounter::DisplayHTMLTotals(PRUint32 aTotal
, const char * aTitle
)
7361 ReflowCounter
* gTots
= (ReflowCounter
*)mMgr
->LookUp(kGrandTotalsStr
);
7362 FILE * fd
= mMgr
->GetOutFile();
7367 fprintf(fd
, "<tr><td><center>%s</center></td>", aTitle
);
7368 fprintf(fd
, "<td><center>%d</center></td></tr>\n", aTotal
);
7370 if (gTots
!= this && aTotal
> 0) {
7375 //------------------------------------------------------------------
7377 //------------------------------------------------------------------
7378 ReflowCountMgr::ReflowCountMgr()
7380 mCounts
= PL_NewHashTable(10, PL_HashString
, PL_CompareStrings
,
7381 PL_CompareValues
, nsnull
, nsnull
);
7382 mIndiFrameCounts
= PL_NewHashTable(10, PL_HashString
, PL_CompareStrings
,
7383 PL_CompareValues
, nsnull
, nsnull
);
7384 mCycledOnce
= PR_FALSE
;
7385 mDumpFrameCounts
= PR_FALSE
;
7386 mDumpFrameByFrameCounts
= PR_FALSE
;
7387 mPaintFrameByFrameCounts
= PR_FALSE
;
7390 //------------------------------------------------------------------
7391 ReflowCountMgr::~ReflowCountMgr()
7396 //------------------------------------------------------------------
7397 ReflowCounter
* ReflowCountMgr::LookUp(const char * aName
)
7399 if (nsnull
!= mCounts
) {
7400 ReflowCounter
* counter
= (ReflowCounter
*)PL_HashTableLookup(mCounts
, aName
);
7407 //------------------------------------------------------------------
7408 void ReflowCountMgr::Add(const char * aName
, nsIFrame
* aFrame
)
7410 NS_ASSERTION(aName
!= nsnull
, "Name shouldn't be null!");
7412 if (mDumpFrameCounts
&& nsnull
!= mCounts
) {
7413 ReflowCounter
* counter
= (ReflowCounter
*)PL_HashTableLookup(mCounts
, aName
);
7414 if (counter
== nsnull
) {
7415 counter
= new ReflowCounter(this);
7416 NS_ASSERTION(counter
!= nsnull
, "null ptr");
7417 char * name
= NS_strdup(aName
);
7418 NS_ASSERTION(name
!= nsnull
, "null ptr");
7419 PL_HashTableAdd(mCounts
, name
, counter
);
7424 if ((mDumpFrameByFrameCounts
|| mPaintFrameByFrameCounts
) &&
7425 nsnull
!= mIndiFrameCounts
&&
7427 char * key
= new char[16];
7428 sprintf(key
, "%p", (void*)aFrame
);
7429 IndiReflowCounter
* counter
= (IndiReflowCounter
*)PL_HashTableLookup(mIndiFrameCounts
, key
);
7430 if (counter
== nsnull
) {
7431 counter
= new IndiReflowCounter(this);
7432 NS_ASSERTION(counter
!= nsnull
, "null ptr");
7433 counter
->mFrame
= aFrame
;
7434 counter
->mName
.AssignASCII(aName
);
7435 PL_HashTableAdd(mIndiFrameCounts
, key
, counter
);
7437 // this eliminates extra counts from super classes
7438 if (counter
!= nsnull
&& counter
->mName
.EqualsASCII(aName
)) {
7440 counter
->mCounter
.Add(1);
7445 //------------------------------------------------------------------
7446 void ReflowCountMgr::PaintCount(const char * aName
,
7447 nsIRenderingContext
* aRenderingContext
,
7448 nsPresContext
* aPresContext
,
7452 if (mPaintFrameByFrameCounts
&&
7453 nsnull
!= mIndiFrameCounts
&&
7455 char * key
= new char[16];
7456 sprintf(key
, "%p", (void*)aFrame
);
7457 IndiReflowCounter
* counter
= (IndiReflowCounter
*)PL_HashTableLookup(mIndiFrameCounts
, key
);
7458 if (counter
!= nsnull
&& counter
->mName
.EqualsASCII(aName
)) {
7459 aRenderingContext
->PushState();
7460 nsFont
font("Times", NS_FONT_STYLE_NORMAL
, NS_FONT_VARIANT_NORMAL
,
7461 NS_FONT_WEIGHT_NORMAL
, 0,
7462 nsPresContext::CSSPixelsToAppUnits(11));
7464 nsCOMPtr
<nsIFontMetrics
> fm
= aPresContext
->GetMetricsFor(font
);
7465 aRenderingContext
->SetFont(fm
);
7467 sprintf(buf
, "%d", counter
->mCount
);
7469 nscoord width
, height
;
7470 aRenderingContext
->SetTextRunRTL(PR_FALSE
);
7471 aRenderingContext
->GetWidth((char*)buf
, width
);
7472 fm
->GetHeight(height
);
7473 fm
->GetMaxAscent(y
);
7479 color2
= NS_RGB(0,0,0);
7481 PRUint8 rc
= 0, gc
= 0, bc
= 0;
7482 if (counter
->mCount
< 5) {
7485 } else if ( counter
->mCount
< 11) {
7490 color
= NS_RGB(rc
,gc
,bc
);
7491 color2
= NS_RGB(rc
/2,gc
/2,bc
/2);
7494 nsRect
rect(0,0, width
+15, height
+15);
7495 aRenderingContext
->SetColor(NS_RGB(0,0,0));
7496 aRenderingContext
->FillRect(rect
);
7497 aRenderingContext
->SetColor(color2
);
7498 aRenderingContext
->DrawString(buf
, strlen(buf
), x
+15,y
+15);
7499 aRenderingContext
->SetColor(color
);
7500 aRenderingContext
->DrawString(buf
, strlen(buf
), x
,y
);
7502 aRenderingContext
->PopState();
7507 //------------------------------------------------------------------
7508 PRIntn
ReflowCountMgr::RemoveItems(PLHashEntry
*he
, PRIntn i
, void *arg
)
7510 char *str
= (char *)he
->key
;
7511 ReflowCounter
* counter
= (ReflowCounter
*)he
->value
;
7515 return HT_ENUMERATE_REMOVE
;
7518 //------------------------------------------------------------------
7519 PRIntn
ReflowCountMgr::RemoveIndiItems(PLHashEntry
*he
, PRIntn i
, void *arg
)
7521 char *str
= (char *)he
->key
;
7522 IndiReflowCounter
* counter
= (IndiReflowCounter
*)he
->value
;
7526 return HT_ENUMERATE_REMOVE
;
7529 //------------------------------------------------------------------
7530 void ReflowCountMgr::CleanUp()
7532 if (nsnull
!= mCounts
) {
7533 PL_HashTableEnumerateEntries(mCounts
, RemoveItems
, nsnull
);
7534 PL_HashTableDestroy(mCounts
);
7538 if (nsnull
!= mIndiFrameCounts
) {
7539 PL_HashTableEnumerateEntries(mIndiFrameCounts
, RemoveIndiItems
, nsnull
);
7540 PL_HashTableDestroy(mIndiFrameCounts
);
7541 mIndiFrameCounts
= nsnull
;
7545 //------------------------------------------------------------------
7546 PRIntn
ReflowCountMgr::DoSingleTotal(PLHashEntry
*he
, PRIntn i
, void *arg
)
7548 char *str
= (char *)he
->key
;
7549 ReflowCounter
* counter
= (ReflowCounter
*)he
->value
;
7551 counter
->DisplayTotals(str
);
7553 return HT_ENUMERATE_NEXT
;
7556 //------------------------------------------------------------------
7557 void ReflowCountMgr::DoGrandTotals()
7559 if (nsnull
!= mCounts
) {
7560 ReflowCounter
* gTots
= (ReflowCounter
*)PL_HashTableLookup(mCounts
, kGrandTotalsStr
);
7561 if (gTots
== nsnull
) {
7562 gTots
= new ReflowCounter(this);
7563 PL_HashTableAdd(mCounts
, NS_strdup(kGrandTotalsStr
), gTots
);
7565 gTots
->ClearTotals();
7568 printf("\t\t\t\tTotal\n");
7569 for (PRUint32 i
=0;i
<78;i
++) {
7573 PL_HashTableEnumerateEntries(mCounts
, DoSingleTotal
, this);
7577 static void RecurseIndiTotals(nsPresContext
* aPresContext
,
7579 nsIFrame
* aParentFrame
,
7582 if (aParentFrame
== nsnull
) {
7587 sprintf(key
, "%p", (void*)aParentFrame
);
7588 IndiReflowCounter
* counter
= (IndiReflowCounter
*)PL_HashTableLookup(aHT
, key
);
7590 counter
->mHasBeenOutput
= PR_TRUE
;
7591 char * name
= ToNewCString(counter
->mName
);
7592 for (PRInt32 i
=0;i
<aLevel
;i
++) printf(" ");
7593 printf("%s - %p [%d][", name
, (void*)aParentFrame
, counter
->mCount
);
7594 printf("%d", counter
->mCounter
.GetTotal());
7596 nsMemory::Free(name
);
7599 nsIFrame
* child
= aParentFrame
->GetFirstChild(nsnull
);
7601 RecurseIndiTotals(aPresContext
, aHT
, child
, aLevel
+1);
7602 child
= child
->GetNextSibling();
7607 //------------------------------------------------------------------
7608 PRIntn
ReflowCountMgr::DoSingleIndi(PLHashEntry
*he
, PRIntn i
, void *arg
)
7610 IndiReflowCounter
* counter
= (IndiReflowCounter
*)he
->value
;
7611 if (counter
&& !counter
->mHasBeenOutput
) {
7612 char * name
= ToNewCString(counter
->mName
);
7613 printf("%s - %p [%d][", name
, (void*)counter
->mFrame
, counter
->mCount
);
7614 printf("%d", counter
->mCounter
.GetTotal());
7616 nsMemory::Free(name
);
7618 return HT_ENUMERATE_NEXT
;
7621 //------------------------------------------------------------------
7622 void ReflowCountMgr::DoIndiTotalsTree()
7624 if (nsnull
!= mCounts
) {
7625 printf("\n------------------------------------------------\n");
7626 printf("-- Individual Frame Counts\n");
7627 printf("------------------------------------------------\n");
7630 nsIFrame
* rootFrame
= mPresShell
->FrameManager()->GetRootFrame();
7631 RecurseIndiTotals(mPresContext
, mIndiFrameCounts
, rootFrame
, 0);
7632 printf("------------------------------------------------\n");
7633 printf("-- Individual Counts of Frames not in Root Tree\n");
7634 printf("------------------------------------------------\n");
7635 PL_HashTableEnumerateEntries(mIndiFrameCounts
, DoSingleIndi
, this);
7640 //------------------------------------------------------------------
7641 PRIntn
ReflowCountMgr::DoSingleHTMLTotal(PLHashEntry
*he
, PRIntn i
, void *arg
)
7643 char *str
= (char *)he
->key
;
7644 ReflowCounter
* counter
= (ReflowCounter
*)he
->value
;
7646 counter
->DisplayHTMLTotals(str
);
7648 return HT_ENUMERATE_NEXT
;
7651 //------------------------------------------------------------------
7652 void ReflowCountMgr::DoGrandHTMLTotals()
7654 if (nsnull
!= mCounts
) {
7655 ReflowCounter
* gTots
= (ReflowCounter
*)PL_HashTableLookup(mCounts
, kGrandTotalsStr
);
7656 if (gTots
== nsnull
) {
7657 gTots
= new ReflowCounter(this);
7658 PL_HashTableAdd(mCounts
, NS_strdup(kGrandTotalsStr
), gTots
);
7660 gTots
->ClearTotals();
7663 static const char * title
[] = {"Class", "Reflows"};
7664 fprintf(mFD
, "<tr>");
7665 for (PRUint32 i
=0; i
< NS_ARRAY_LENGTH(title
); i
++) {
7666 fprintf(mFD
, "<td><center><b>%s<b></center></td>", title
[i
]);
7668 fprintf(mFD
, "</tr>\n");
7669 PL_HashTableEnumerateEntries(mCounts
, DoSingleHTMLTotal
, this);
7673 //------------------------------------
7674 void ReflowCountMgr::DisplayTotals(const char * aStr
)
7677 printf("%s\n", aStr
?aStr
:"No name");
7679 if (mDumpFrameCounts
) {
7682 if (mDumpFrameByFrameCounts
) {
7687 //------------------------------------
7688 void ReflowCountMgr::DisplayHTMLTotals(const char * aStr
)
7690 #ifdef WIN32x // XXX NOT XP!
7693 char * sptr
= strrchr(aStr
, '/');
7697 char * eptr
= strrchr(name
, '.');
7701 strcat(name
, "_stats.html");
7703 mFD
= fopen(name
, "w");
7705 fprintf(mFD
, "<html><head><title>Reflow Stats</title></head><body>\n");
7706 const char * title
= aStr
?aStr
:"No name";
7707 fprintf(mFD
, "<center><b>%s</b><br><table border=1 style=\"background-color:#e0e0e0\">", title
);
7708 DoGrandHTMLTotals();
7709 fprintf(mFD
, "</center></table>\n");
7710 fprintf(mFD
, "</body></html>\n");
7717 //------------------------------------------------------------------
7718 PRIntn
ReflowCountMgr::DoClearTotals(PLHashEntry
*he
, PRIntn i
, void *arg
)
7720 ReflowCounter
* counter
= (ReflowCounter
*)he
->value
;
7721 counter
->ClearTotals();
7723 return HT_ENUMERATE_NEXT
;
7726 //------------------------------------------------------------------
7727 void ReflowCountMgr::ClearTotals()
7729 PL_HashTableEnumerateEntries(mCounts
, DoClearTotals
, this);
7732 //------------------------------------------------------------------
7733 void ReflowCountMgr::ClearGrandTotals()
7735 if (nsnull
!= mCounts
) {
7736 ReflowCounter
* gTots
= (ReflowCounter
*)PL_HashTableLookup(mCounts
, kGrandTotalsStr
);
7737 if (gTots
== nsnull
) {
7738 gTots
= new ReflowCounter(this);
7739 PL_HashTableAdd(mCounts
, NS_strdup(kGrandTotalsStr
), gTots
);
7741 gTots
->ClearTotals();
7742 gTots
->SetTotalsCache();
7747 //------------------------------------------------------------------
7748 PRIntn
ReflowCountMgr::DoDisplayDiffTotals(PLHashEntry
*he
, PRIntn i
, void *arg
)
7750 PRBool cycledOnce
= (arg
!= 0);
7752 char *str
= (char *)he
->key
;
7753 ReflowCounter
* counter
= (ReflowCounter
*)he
->value
;
7756 counter
->CalcDiffInTotals();
7757 counter
->DisplayDiffTotals(str
);
7759 counter
->SetTotalsCache();
7761 return HT_ENUMERATE_NEXT
;
7764 //------------------------------------------------------------------
7765 void ReflowCountMgr::DisplayDiffsInTotals(const char * aStr
)
7768 printf("Differences\n");
7769 for (PRInt32 i
=0;i
<78;i
++) {
7775 PL_HashTableEnumerateEntries(mCounts
, DoDisplayDiffTotals
, (void *)mCycledOnce
);
7777 mCycledOnce
= PR_TRUE
;
7780 #endif // MOZ_REFLOW_PERF
7782 // make a color string like #RRGGBB
7783 void ColorToString(nscolor aColor
, nsAutoString
&aString
)
7787 PR_snprintf(buf
, sizeof(buf
), "#%02x%02x%02x",
7788 NS_GET_R(aColor
), NS_GET_G(aColor
), NS_GET_B(aColor
));
7789 CopyASCIItoUTF16(buf
, aString
);
7792 nsIFrame
* nsIPresShell::GetAbsoluteContainingBlock(nsIFrame
*aFrame
)
7794 return FrameConstructor()->GetAbsoluteContainingBlock(aFrame
);