Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / layout / base / nsPresShell.cpp
blobb037bf8c2472a8dbfe51fe387d355e9423016390
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
14 * License.
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.
23 * Contributor(s):
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
47 * Corporation, 2000
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
54 */
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"
71 #include "nsFrame.h"
72 #include "nsIViewManager.h"
73 #include "nsCRT.h"
74 #include "nsCRTGlue.h"
75 #include "prlog.h"
76 #include "prmem.h"
77 #include "prprf.h"
78 #include "prinrval.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"
101 #include "nsRange.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"
109 #include "nsCaret.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"
121 #include "nsXPCOM.h"
122 #include "nsISupportsPrimitives.h"
123 #include "nsILayoutHistoryState.h"
124 #include "nsILineIterator.h" // for ScrollContentIntoView
125 #include "nsTimer.h"
126 #include "nsWeakPtr.h"
127 #include "plarena.h"
128 #include "pldhash.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"
136 #ifdef NS_DEBUG
137 #include "nsIFrameDebug.h"
138 #endif
139 // for |#ifdef DEBUG| code
140 #include "nsSpaceManager.h"
141 #include "prenv.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"
151 #endif
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"
166 #ifdef MOZ_MEDIA
167 #include "nsHTMLMediaElement.h"
168 #endif
170 // Drag & Drop, Clipboard
171 #include "nsWidgetsCID.h"
172 #include "nsIClipboard.h"
173 #include "nsIClipboardHelper.h"
174 #include "nsIDocShellTreeItem.h"
175 #include "nsIURI.h"
176 #include "nsIScrollableFrame.h"
177 #include "prtime.h"
178 #include "prlong.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"
185 #ifdef ACCESSIBILITY
186 #include "nsIAccessibilityService.h"
187 #include "nsIAccessible.h"
188 #include "nsIAccessibleEvent.h"
189 #endif
191 // For style data reconstruction
192 #include "nsStyleChangeList.h"
193 #include "nsCSSFrameConstructor.h"
194 #ifdef MOZ_XUL
195 #include "nsMenuFrame.h"
196 #include "nsTreeBodyFrame.h"
197 #endif
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);
215 // Class ID's
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;
222 nsDisplayList mList;
224 // offset of builder's reference frame to the root frame
225 nsPoint mRootOffset;
227 RangePaintInfo(nsIRange* aRange, nsIFrame* aFrame)
228 : mRange(aRange), mBuilder(aFrame, PR_FALSE, PR_FALSE)
232 ~RangePaintInfo()
234 mList.DeleteAll();
238 #undef NOISY
240 // ----------------------------------------------------------------------
242 #ifdef NS_DEBUG
243 // Set the environment variable GECKO_VERIFY_REFLOW_FLAGS to one or
244 // more of the following flags (comma separated) for handy debug
245 // output.
246 static PRUint32 gVerifyReflowFlags;
248 struct VerifyReflowFlags {
249 const char* name;
250 PRUint32 bit;
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]))
266 static void
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);
274 ++flag;
276 printf("Note: GECKO_VERIFY_REFLOW_FLAGS is a comma separated list of flag\n");
277 printf("names (no whitespace)\n");
279 #endif
281 //========================================================================
282 //========================================================================
283 //========================================================================
284 #ifdef MOZ_REFLOW_PERF
285 class ReflowCountMgr;
287 static const char kGrandTotalsStr[] = "Grand Totals";
289 // Counting Class
290 class ReflowCounter {
291 public:
292 ReflowCounter(ReflowCountMgr * aMgr = nsnull);
293 ~ReflowCounter();
295 void ClearTotals();
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; }
310 protected:
311 void DisplayTotals(PRUint32 aTotal, const char * aTitle);
312 void DisplayHTMLTotals(PRUint32 aTotal, const char * aTitle);
314 PRUint32 mTotal;
315 PRUint32 mCacheTotal;
317 ReflowCountMgr * mMgr; // weak reference (don't delete)
320 // Counting Class
321 class IndiReflowCounter {
322 public:
323 IndiReflowCounter(ReflowCountMgr * aMgr = nsnull)
324 : mFrame(nsnull),
325 mCount(0),
326 mMgr(aMgr),
327 mCounter(aMgr),
328 mHasBeenOutput(PR_FALSE)
330 virtual ~IndiReflowCounter() {}
332 nsAutoString mName;
333 nsIFrame * mFrame; // weak reference (don't delete)
334 PRInt32 mCount;
336 ReflowCountMgr * mMgr; // weak reference (don't delete)
338 ReflowCounter mCounter;
339 PRBool mHasBeenOutput;
343 //--------------------
344 // Manager Class
345 //--------------------
346 class ReflowCountMgr {
347 public:
348 ReflowCountMgr();
349 virtual ~ReflowCountMgr();
351 void ClearTotals();
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; }
373 protected:
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);
379 void CleanUp();
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;
400 FILE * mFD;
402 PRBool mDumpFrameCounts;
403 PRBool mDumpFrameByFrameCounts;
404 PRBool mPaintFrameByFrameCounts;
406 PRBool mCycledOnce;
408 // Root Frame for Individual Tracking
409 nsPresContext * mPresContext;
410 nsIPresShell* mPresShell;
412 // ReflowCountMgr gReflowCountMgr;
414 #endif
415 //========================================================================
417 // comment out to hide caret
418 #define SHOW_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
438 struct StackBlock {
440 // a block of memory. Note that this must be first so that it will
441 // be aligned.
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
447 StackBlock* mNext;
449 StackBlock() : mNext(nsnull) { }
450 ~StackBlock() { }
453 /* we hold an array of marks. A push pushes a mark on the stack
454 * a pop pops it off.
456 struct StackMark {
457 // the block of memory we are currently handing out chunks of
458 StackBlock* mBlock;
460 // our current position in the memory
461 size_t mPos;
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.
469 class StackArena {
470 public:
471 StackArena();
472 ~StackArena();
474 nsresult Init() { return mBlocks ? NS_OK : NS_ERROR_OUT_OF_MEMORY; }
476 // Memory management functions
477 void* Allocate(size_t aSize);
478 void Push();
479 void Pop();
481 private:
482 // our current position in memory
483 size_t mPos;
485 // a list of memory block. Usually there is only one
486 // but if we overrun our stack size we can get more memory.
487 StackBlock* mBlocks;
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
493 StackMark* mMarks;
495 // the current top of the mark list
496 PRUint32 mStackTop;
498 // the size of the mark array
499 PRUint32 mMarkLength;
504 StackArena::StackArena()
506 mMarkLength = 0;
507 mMarks = nsnull;
509 // allocate our stack memory
510 mBlocks = new StackBlock();
511 mCurBlock = mBlocks;
513 mStackTop = 0;
514 mPos = 0;
517 StackArena::~StackArena()
519 // free up our data
520 delete[] mMarks;
521 while(mBlocks)
523 StackBlock* toDelete = mBlocks;
524 mBlocks = mBlocks->mNext;
525 delete toDelete;
529 void
530 StackArena::Push()
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];
539 if (newMarks) {
540 if (mMarkLength)
541 memcpy(newMarks, mMarks, sizeof(StackMark)*mMarkLength);
542 // Fill in any marks that we couldn't allocate during a prior call
543 // to Push().
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;
549 delete [] mMarks;
550 mMarks = newMarks;
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;
562 mStackTop++;
565 void*
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;
582 mPos = 0;
585 // return the chunk they need.
586 void *result = mCurBlock->mBlock + mPos;
587 mPos += aSize;
589 return result;
592 void
593 StackArena::Pop()
595 // pop off the mark
596 NS_ASSERTION(mStackTop > 0, "unmatched pop");
597 mStackTop--;
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.
605 mCurBlock = mBlocks;
606 mPos = 0;
608 return;
611 #ifdef DEBUG
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);
622 #endif
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
632 // 200 bytes
633 class FrameArena {
634 public:
635 FrameArena(PRUint32 aArenaSize = 4096);
636 ~FrameArena();
638 // Memory management functions
639 NS_HIDDEN_(void*) AllocateFrame(size_t aSize);
640 NS_HIDDEN_(void) FreeFrame(size_t aSize, void* aPtr);
642 private:
643 #ifdef DEBUG
644 // Number of frames in the pool
645 PRUint32 mFrameCount;
646 #endif
648 #if !defined(DEBUG_TRACEMALLOC_FRAMEARENA)
649 // Underlying arena pool
650 PLArenaPool mPool;
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];
655 #endif
658 FrameArena::FrameArena(PRUint32 aArenaSize)
659 #ifdef DEBUG
660 : mFrameCount(0)
661 #endif
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));
669 #endif
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);
680 #endif
683 void*
684 FrameArena::AllocateFrame(size_t aSize)
686 void* result = nsnull;
688 #if defined(DEBUG_TRACEMALLOC_FRAMEARENA)
690 result = PR_Malloc(aSize);
692 #else
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];
702 if (result) {
703 // Need to move to the next object
704 void* next = *((void**)result);
705 mRecyclers[index] = next;
709 if (!result) {
710 // Allocate a new chunk from the arena
711 PL_ARENA_ALLOCATE(result, &mPool, aSize);
714 #endif
716 #ifdef DEBUG
717 if (result != nsnull)
718 ++mFrameCount;
719 #endif
721 return result;
724 void
725 FrameArena::FreeFrame(size_t aSize, void* aPtr)
727 #ifdef DEBUG
728 --mFrameCount;
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);
733 #endif
734 #if defined(DEBUG_TRACEMALLOC_FRAMEARENA)
735 PR_Free(aPtr);
736 #else
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;
747 #ifdef DEBUG_dbaron
748 else {
749 fprintf(stderr,
750 "WARNING: FrameArena::FreeFrame leaking chunk of %d bytes.\n",
751 aSize);
753 #endif
754 #endif
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
771 public:
772 PresShell();
774 NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
776 // nsISupports
777 NS_DECL_ISUPPORTS
779 // nsIPresShell
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,
841 PRIntn aVPercent,
842 PRIntn aHPercent) const;
844 NS_IMETHOD SetIgnoreFrameDestruction(PRBool aIgnore);
845 NS_IMETHOD NotifyDestroyingFrame(nsIFrame* aFrame);
847 NS_IMETHOD DoCopy();
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();
877 virtual void Thaw();
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,
886 nsIRegion* aRegion,
887 nsPoint& aPoint,
888 nsRect* aScreenRect);
890 virtual already_AddRefed<gfxASurface> RenderSelection(nsISelection* aSelection,
891 nsPoint& aPoint,
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,
901 nsPoint aDelta,
902 const nsRect& aCopyRect,
903 nsRegion* aRepaintRegion);
904 NS_IMETHOD HandleEvent(nsIView* aView,
905 nsGUIEvent* aEvent,
906 nsEventStatus* aEventStatus);
907 NS_IMETHOD HandleDOMEventWithTarget(nsIContent* aTargetContent,
908 nsEvent* aEvent,
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);
917 // caret handling
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,
956 PRInt32 aStateMask);
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,
965 PRBool aApplicable);
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
984 NS_DECL_NSIOBSERVER
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);
993 #endif
995 #ifdef DEBUG
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();
1001 #endif
1003 #ifdef PR_LOGGING
1004 static PRLogModuleInfo* gLog;
1005 #endif
1007 protected:
1008 virtual ~PresShell();
1010 void HandlePostedReflowCallbacks();
1011 void CancelPostedReflowCallbacks();
1013 void UnsuppressAndInvalidate();
1015 void WillDoReflow();
1016 void DidDoReflow();
1017 nsresult ProcessReflowCommands(PRBool aInterruptible);
1018 void ClearReflowEventStatus();
1019 void PostReflowEvent();
1021 void DoReflow(nsIFrame* aFrame);
1022 #ifdef DEBUG
1023 void DoVerifyReflow();
1024 void VerifyHasDirtyRootAncestor(nsIFrame* aFrame);
1025 #endif
1027 friend class nsPresShellEventCB;
1029 class ReflowEvent;
1030 friend class ReflowEvent;
1032 class ReflowEvent : public nsRunnable {
1033 public:
1034 NS_DECL_NSIRUNNABLE
1035 ReflowEvent(PresShell *aPresShell) : mPresShell(aPresShell) {
1036 NS_ASSERTION(aPresShell, "Null parameters!");
1038 void Revoke() { mPresShell = nsnull; }
1039 private:
1040 PresShell *mPresShell;
1043 // Utility to find which view to scroll.
1044 nsIScrollableView* GetViewToScroll(nsLayoutUtils::Direction aDirection);
1046 PRBool mCaretEnabled;
1047 #ifdef NS_DEBUG
1048 nsresult CloneStyleSet(nsStyleSet* aSet, nsStyleSet** aResult);
1049 PRBool VerifyIncrementalReflow();
1050 PRBool mInVerifyReflow;
1051 void ShowEventTargetDebug();
1052 #endif
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
1068 // the range
1069 nsRect ClipListToRange(nsDisplayListBuilder *aBuilder,
1070 nsDisplayList* aList,
1071 nsIRange* aRange);
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
1086 * be displayed at
1088 already_AddRefed<gfxASurface>
1089 PaintRangePaintInfo(nsTArray<nsAutoPtr<RangePaintInfo> >* aItems,
1090 nsISelection* aSelection,
1091 nsIRegion* aRegion,
1092 nsRect aArea,
1093 nsPoint& aPoint,
1094 nsRect* aScreenRect);
1097 * Methods to handle changes to user and UA sheet lists that we get
1098 * notified about.
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
1117 #ifdef DEBUG
1118 PRUint32 mUpdateCount;
1119 #endif
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
1162 // for any reason.
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;
1171 #endif
1173 private:
1175 PRBool InZombieDocument(nsIContent *aContent);
1176 nsresult RetargetEventToParent(nsGUIEvent* aEvent,
1177 nsEventStatus* aEventStatus);
1179 //helper funcs for event handling
1180 protected:
1181 //protected because nsPresShellEventCB needs this.
1182 nsIFrame* GetCurrentEventFrame();
1183 private:
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,
1190 nsGUIEvent* aEvent,
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
1208 public:
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();
1215 if (frame) {
1216 frame->HandleEvent(aVisitor.mPresContext,
1217 (nsGUIEvent*) aVisitor.mEvent,
1218 &aVisitor.mEventStatus);
1223 nsRefPtr<PresShell> mPresShell;
1226 #ifdef PR_LOGGING
1227 PRLogModuleInfo* PresShell::gLog;
1228 #endif
1230 #ifdef NS_DEBUG
1231 static void
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())
1240 #else
1241 #define VERIFY_STYLE_TREE
1242 #endif
1244 static PRBool gVerifyReflowEnabled;
1246 PRBool
1247 nsIPresShell::GetVerifyReflowEnable()
1249 #ifdef NS_DEBUG
1250 static PRBool firstTime = PR_TRUE;
1251 if (firstTime) {
1252 firstTime = PR_FALSE;
1253 char* flags = PR_GetEnv("GECKO_VERIFY_REFLOW_FLAGS");
1254 if (flags) {
1255 PRBool error = PR_FALSE;
1257 for (;;) {
1258 char* comma = PL_strchr(flags, ',');
1259 if (comma)
1260 *comma = '\0';
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;
1268 found = PR_TRUE;
1269 break;
1271 ++flag;
1274 if (! found)
1275 error = PR_TRUE;
1277 if (! comma)
1278 break;
1280 *comma = ',';
1281 flags = comma + 1;
1284 if (error)
1285 ShowVerifyReflowFlags();
1288 if (VERIFY_REFLOW_ON & gVerifyReflowFlags) {
1289 gVerifyReflowEnabled = PR_TRUE;
1291 printf("Note: verifyreflow is enabled");
1292 if (VERIFY_REFLOW_NOISY & gVerifyReflowFlags) {
1293 printf(" (noisy)");
1295 if (VERIFY_REFLOW_ALL & gVerifyReflowFlags) {
1296 printf(" (all)");
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)");
1307 printf("\n");
1310 #endif
1311 return gVerifyReflowEnabled;
1314 void
1315 nsIPresShell::SetVerifyReflowEnable(PRBool aEnabled)
1317 gVerifyReflowEnabled = aEnabled;
1320 PRInt32
1321 nsIPresShell::GetVerifyReflowFlags()
1323 #ifdef NS_DEBUG
1324 return gVerifyReflowFlags;
1325 #else
1326 return 0;
1327 #endif
1330 void
1331 nsIPresShell::AddWeakFrame(nsWeakFrame* aWeakFrame)
1333 if (aWeakFrame->GetFrame()) {
1334 aWeakFrame->GetFrame()->AddStateBits(NS_FRAME_EXTERNAL_REFERENCE);
1336 aWeakFrame->SetPreviousWeakFrame(mWeakFrames);
1337 mWeakFrames = aWeakFrame;
1340 void
1341 nsIPresShell::RemoveWeakFrame(nsWeakFrame* aWeakFrame)
1343 if (mWeakFrames == aWeakFrame) {
1344 mWeakFrames = aWeakFrame->GetPreviousWeakFrame();
1345 return;
1347 nsWeakFrame* nextWeak = mWeakFrames;
1348 while (nextWeak && nextWeak->GetPreviousWeakFrame() != aWeakFrame) {
1349 nextWeak = nextWeak->GetPreviousWeakFrame();
1351 if (nextWeak) {
1352 nextWeak->SetPreviousWeakFrame(aWeakFrame->GetPreviousWeakFrame());
1356 already_AddRefed<nsFrameSelection>
1357 nsIPresShell::FrameSelection()
1359 NS_IF_ADDREF(mSelection);
1360 return mSelection;
1363 //----------------------------------------------------------------------
1365 nsresult
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();
1373 if (nsnull == it) {
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);
1387 #endif
1388 #ifdef PR_LOGGING
1389 if (! gLog)
1390 gLog = PR_NewLogModule("PresShell");
1391 #endif
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");
1407 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");
1416 delete mStyleSet;
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
1428 * manager.
1430 NS_IMETHODIMP
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");
1440 nsresult result;
1442 if ((nsnull == aDocument) || (nsnull == aPresContext) ||
1443 (nsnull == aViewManager)) {
1444 return NS_ERROR_NULL_POINTER;
1446 if (mDocument) {
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
1481 // frames.
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)) {
1490 mStyleSet = nsnull;
1491 return 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");
1498 mStyleSet = nsnull;
1499 return result;
1502 mSelection->Init(this, nsnull);
1504 // Important: this has to happen after the selection has been set up
1505 #ifdef SHOW_CARET
1506 // make the caret
1507 nsresult err = NS_NewCaret(getter_AddRefs(mCaret));
1508 if (NS_SUCCEEDED(err))
1510 mCaret->Init(this);
1511 mOriginalCaret = mCaret;
1514 //SetCaretEnabled(PR_TRUE); // make it show in browser windows
1515 #endif
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);
1532 if (os) {
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);
1538 #ifdef MOZ_XUL
1539 os->AddObserver(this, "chrome-flush-skin-caches", PR_FALSE);
1540 #endif
1541 #ifdef ACCESSIBILITY
1542 os->AddObserver(this, "a11y-init-or-shutdown", PR_FALSE);
1543 #endif
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);
1565 #endif
1567 return NS_OK;
1570 NS_IMETHODIMP
1571 PresShell::Destroy()
1573 #ifdef MOZ_REFLOW_PERF
1574 DumpReflows();
1575 if (mReflowCountMgr) {
1576 delete mReflowCountMgr;
1577 mReflowCountMgr = nsnull;
1579 #endif
1581 if (mHaveShutDown)
1582 return NS_OK;
1584 if (mPresContext) {
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");
1593 if (os) {
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");
1599 #ifdef MOZ_XUL
1600 os->RemoveObserver(this, "chrome-flush-skin-caches");
1601 #endif
1602 #ifdef ACCESSIBILITY
1603 os->RemoveObserver(this, "a11y-init-or-shutdown");
1604 #endif
1608 // If our paint suppression timer is still active, kill it.
1609 if (mPaintSuppressionTimer) {
1610 mPaintSuppressionTimer->Cancel();
1611 mPaintSuppressionTimer = nsnull;
1614 if (mCaret) {
1615 mCaret->Terminate();
1616 mCaret = nsnull;
1619 if (mSelection) {
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
1631 // bad!
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
1636 // well.
1638 mCurrentEventFrame = nsnull;
1640 PRInt32 i, count = mCurrentEventFrameStack.Count();
1641 for (i = 0; i < count; i++) {
1642 mCurrentEventFrameStack.ReplaceElementAt(nsnull, i);
1645 if (mViewManager) {
1646 // Clear the view manager's weak pointer back to |this| in case it
1647 // was leaked.
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
1657 if (mDocument) {
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);
1682 if (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
1687 // prescontext.
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;
1703 return NS_OK;
1706 // Dynamic stack memory allocation
1707 /* virtual */ void
1708 PresShell::PushStackMemory()
1710 mStackArena.Push();
1713 /* virtual */ void
1714 PresShell::PopStackMemory()
1716 mStackArena.Pop();
1719 /* virtual */ void*
1720 PresShell::AllocateStackMemory(size_t aSize)
1722 return mStackArena.Allocate(aSize);
1725 void
1726 PresShell::FreeFrame(size_t aSize, void* aPtr)
1728 mFrameArena.FreeFrame(aSize, aPtr);
1731 void*
1732 PresShell::AllocateFrame(size_t aSize)
1734 return mFrameArena.AllocateFrame(aSize);
1737 void
1738 nsIPresShell::SetAuthorStyleDisabled(PRBool aStyleDisabled)
1740 if (aStyleDisabled != mStyleSet->GetAuthorStyleDisabled()) {
1741 mStyleSet->SetAuthorStyleDisabled(aStyleDisabled);
1742 ReconstructStyleData();
1746 PRBool
1747 nsIPresShell::GetAuthorStyleDisabled()
1749 return mStyleSet->GetAuthorStyleDisabled();
1752 NS_IMETHODIMP
1753 PresShell::SetPreferenceStyleRules(PRBool aForceReflow)
1755 if (!mDocument) {
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()).
1766 if (!window) {
1767 return NS_ERROR_NULL_POINTER;
1770 NS_PRECONDITION(mPresContext, "presContext cannot be null");
1771 if (mPresContext) {
1772 // first, make sure this is not a chrome shell
1773 if (nsContentUtils::IsInChromeDocshell(mDocument)) {
1774 return NS_OK;
1777 #ifdef DEBUG_attinasi
1778 printf("Setting Preference Style Rules:\n");
1779 #endif
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);
1804 #endif
1806 // Note that this method never needs to force any calculation; the caller
1807 // will recalculate style if needed
1809 return result;
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!");
1820 if (mStyleSet) {
1821 // remove the sheet from the styleset:
1822 // - note that we have to check for success by comparing the count before and after...
1823 #ifdef NS_DEBUG
1824 PRInt32 numBefore = mStyleSet->SheetCount(nsStyleSet::eUserSheet);
1825 NS_ASSERTION(numBefore > 0, "no user stylesheets in styleset, but we have one!");
1826 #endif
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");
1833 #endif
1834 // clear the sheet pointer: it is strictly historical now
1835 mPrefStyleSheet = nsnull;
1838 return result;
1841 nsresult PresShell::CreatePreferenceStyleSheet(void)
1843 NS_ASSERTION(!mPrefStyleSheet, "prefStyleSheet already exists");
1844 nsresult result;
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();
1855 PRUint32 index;
1856 result =
1857 mPrefStyleSheet->InsertRuleInternal(NS_LITERAL_STRING("@namespace url(http://www.w3.org/1999/xhtml);"),
1858 0, &index);
1859 if (NS_SUCCEEDED(result)) {
1860 mStyleSet->AppendStyleSheet(nsStyleSet::eUserSheet, mPrefStyleSheet);
1866 #ifdef DEBUG_attinasi
1867 printf("CreatePrefStyleSheet completed: error=%ld\n",(long)result);
1868 #endif
1870 if (NS_FAILED(result)) {
1871 mPrefStyleSheet = nsnull;
1874 return result;
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;
1882 nsresult
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);
1901 PRUint32 index = 0;
1902 mPrefStyleSheet->
1903 InsertRuleInternal(NS_LITERAL_STRING("noscript{display:none!important}"),
1904 sInsertPrefSheetRulesAt, &index);
1907 return rv;
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));
1929 if (docShell) {
1930 docShell->GetAllowSubframes(&allowSubframes);
1932 if (!allowSubframes) {
1933 PRUint32 index = 0;
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);
1942 return rv;
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, "}");
1972 PRUint32 index = 0;
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);
2011 } else {
2012 rv = mPrefStyleSheet->
2013 InsertRuleInternal(NS_LITERAL_STRING("*|*:-moz-any-link{text-decoration:none}"),
2014 sInsertPrefSheetRulesAt, &index);
2017 return rv;
2020 nsresult PresShell::SetPrefFocusRules(void)
2022 NS_ASSERTION(mPresContext,"null prescontext not allowed");
2023 nsresult result = NS_OK;
2025 if (!mPresContext)
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
2039 PRUint32 index = 0;
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; } ");
2051 // insert the rules
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) {
2060 PRUint32 index = 0;
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; } ");
2068 else // dotted
2069 strRule.AppendLiteral("px dotted WindowText !important; } ");
2070 // insert the rules
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; } ");
2082 else
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);
2096 return result;
2099 void
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
2106 // sheets.
2107 nsCOMPtr<nsIStyleSheetService> dummy =
2108 do_GetService(NS_STYLESHEETSERVICE_CONTRACTID);
2110 mStyleSet->BeginUpdate();
2112 nsStyleSheetService *sheetService = nsStyleSheetService::gInstance;
2113 nsCOMArray<nsIStyleSheet> & userSheets = *sheetService->UserStyleSheets();
2114 PRInt32 i;
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();
2132 void
2133 PresShell::AddAgentSheet(nsISupports* aSheet)
2135 // Make sure this does what DocumentViewerImpl::CreateStyleSet does
2136 // wrt ordering.
2137 nsCOMPtr<nsIStyleSheet> sheet = do_QueryInterface(aSheet);
2138 if (!sheet) {
2139 return;
2142 mStyleSet->AppendStyleSheet(nsStyleSet::eAgentSheet, sheet);
2143 ReconstructStyleData();
2146 void
2147 PresShell::RemoveSheet(nsStyleSet::sheetType aType, nsISupports* aSheet)
2149 nsCOMPtr<nsIStyleSheet> sheet = do_QueryInterface(aSheet);
2150 if (!sheet) {
2151 return;
2154 mStyleSet->RemoveStyleSheet(aType, sheet);
2155 ReconstructStyleData();
2158 NS_IMETHODIMP
2159 PresShell::SetDisplaySelection(PRInt16 aToggle)
2161 mSelection->SetDisplaySelection(aToggle);
2162 return NS_OK;
2165 NS_IMETHODIMP
2166 PresShell::GetDisplaySelection(PRInt16 *aToggle)
2168 *aToggle = mSelection->GetDisplaySelection();
2169 return NS_OK;
2172 NS_IMETHODIMP
2173 PresShell::GetSelection(SelectionType aType, nsISelection **aSelection)
2175 if (!aSelection || !mSelection)
2176 return NS_ERROR_NULL_POINTER;
2178 *aSelection = mSelection->GetSelection(aType);
2180 if (!(*aSelection))
2181 return NS_ERROR_INVALID_ARG;
2183 NS_ADDREF(*aSelection);
2185 return NS_OK;
2188 nsISelection*
2189 PresShell::GetCurrentSelection(SelectionType aType)
2191 if (!mSelection)
2192 return nsnull;
2194 return mSelection->GetSelection(aType);
2197 NS_IMETHODIMP
2198 PresShell::ScrollSelectionIntoView(SelectionType aType, SelectionRegion aRegion, PRBool aIsSynchronous)
2200 if (!mSelection)
2201 return NS_ERROR_NULL_POINTER;
2203 return mSelection->ScrollSelectionIntoView(aType, aRegion, aIsSynchronous);
2206 NS_IMETHODIMP
2207 PresShell::RepaintSelection(SelectionType aType)
2209 if (!mSelection)
2210 return NS_ERROR_NULL_POINTER;
2212 return mSelection->RepaintSelection(aType);
2215 // Make shell be a document observer
2216 NS_IMETHODIMP
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;
2227 return NS_OK;
2230 // Make shell stop being a document observer
2231 NS_IMETHODIMP
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;
2237 if (mDocument) {
2238 mDocument->RemoveObserver(this);
2240 return NS_OK;
2243 #ifdef DEBUG_kipp
2244 char* nsPresShell_ReflowStackPointerTop;
2245 #endif
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)
2259 return;
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.
2266 return;
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);
2280 if (!curDoc) {
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
2286 // ends up focused.
2288 curDoc = aDocument;
2291 while (curDoc) {
2292 nsPIDOMWindow *curWin = curDoc->GetWindow();
2294 if (!curWin || curWin == aOurWindow)
2295 break;
2297 curDoc = curDoc->GetParentDocument();
2298 if (curDoc == aDocument)
2299 return;
2302 if (!curDoc) {
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.
2306 return;
2309 PRBool active;
2310 aFocusController->GetActive(&active);
2311 if (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);
2319 NS_IMETHODIMP
2320 PresShell::GetDidInitialReflow(PRBool *aDidInitialReflow)
2322 if (!aDidInitialReflow)
2323 return NS_ERROR_FAILURE;
2325 *aDidInitialReflow = mDidInitialReflow;
2327 return NS_OK;
2330 NS_IMETHODIMP
2331 PresShell::InitialReflow(nscoord aWidth, nscoord aHeight)
2333 if (mIsDestroying) {
2334 return NS_OK;
2337 NS_ASSERTION(!mDidInitialReflow, "Why are we being called?");
2339 nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
2340 mDidInitialReflow = PR_TRUE;
2342 #ifdef NS_DEBUG
2343 if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) {
2344 if (mDocument) {
2345 nsIURI *uri = mDocument->GetDocumentURI();
2346 if (uri) {
2347 nsCAutoString url;
2348 uri->GetSpec(url);
2349 printf("*** PresShell::InitialReflow (this=%p, url='%s')\n", (void*)this, url.get());
2353 #endif
2355 if (mCaret)
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();
2368 if (root) {
2369 MOZ_TIMER_DEBUGLOG(("Reset and start: Frame Creation: PresShell::InitialReflow(), this=%p\n",
2370 (void*)this));
2371 MOZ_TIMER_RESET(mFrameCreationWatch);
2372 MOZ_TIMER_START(mFrameCreationWatch);
2375 nsAutoScriptBlocker scriptBlocker;
2376 mFrameConstructor->BeginUpdate();
2378 if (!rootFrame) {
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);
2388 VERIFY_STYLE_TREE;
2389 MOZ_TIMER_DEBUGLOG(("Stop: Frame Creation: PresShell::InitialReflow(), this=%p\n",
2390 (void*)this));
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();
2422 if (rootFrame) {
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;
2455 else {
2456 // Initialize the timer.
2458 // Default to PAINTLOCK_EVENT_DELAY if we can't get the pref value.
2459 PRInt32 delay =
2460 nsContentUtils::GetIntPref("nglayout.initialpaint.delay",
2461 PAINTLOCK_EVENT_DELAY);
2463 mPaintSuppressionTimer->InitWithFuncCallback(sPaintSuppressionCallback,
2464 this, delay,
2465 nsITimer::TYPE_ONE_SHOT);
2469 return NS_OK; //XXX this needs to be real. MMP
2472 void
2473 PresShell::sPaintSuppressionCallback(nsITimer *aTimer, void* aPresShell)
2475 PresShell* self = static_cast<PresShell*>(aPresShell);
2476 if (self)
2477 self->UnsuppressPainting();
2480 NS_IMETHODIMP
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
2501 if (!rootFrame)
2502 return NS_OK;
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;
2522 WillDoReflow();
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;
2533 DidDoReflow();
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
2553 void
2554 PresShell::CreateResizeEventTimer ()
2556 // if we already have a timer set, ignore this call
2557 if (mResizeEventTimer)
2558 return;
2560 if (mIsDocumentGone)
2561 return;
2563 mResizeEventTimer = do_CreateInstance("@mozilla.org/timer;1");
2564 if (mResizeEventTimer) {
2565 mResizeEventTimer->InitWithFuncCallback(sResizeEventCallback, this, RESIZE_EVENT_DELAY,
2566 nsITimer::TYPE_ONE_SHOT);
2570 void
2571 PresShell::KillResizeEventTimer()
2573 if (mResizeEventTimer) {
2574 mResizeEventTimer->Cancel();
2575 mResizeEventTimer = nsnull;
2579 void
2580 PresShell::sResizeEventCallback(nsITimer *aTimer, void* aPresShell)
2582 PresShell* self = static_cast<PresShell*>(aPresShell);
2583 if (self) {
2584 self->FireResizeEvent();
2588 void
2589 PresShell::FireResizeEvent()
2591 if (mIsDocumentGone)
2592 return;
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();
2602 if (window) {
2603 nsEventDispatcher::Dispatch(window, mPresContext, &event, nsnull, &status);
2604 // |this| may now be destroyed
2608 NS_IMETHODIMP
2609 PresShell::SetIgnoreFrameDestruction(PRBool aIgnore)
2611 mIgnoreFrameDestruction = aIgnore;
2612 return NS_OK;
2615 NS_IMETHODIMP
2616 PresShell::NotifyDestroyingFrame(nsIFrame* aFrame)
2618 if (!mIgnoreFrameDestruction) {
2619 mFrameConstructor->NotifyDestroyingFrame(aFrame);
2621 for (PRInt32 idx = mDirtyRoots.Count(); idx; ) {
2622 --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);
2635 return NS_OK;
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);
2643 *outCaret = mCaret;
2644 NS_IF_ADDREF(*outCaret);
2645 return NS_OK;
2648 NS_IMETHODIMP_(void) PresShell::MaybeInvalidateCaretPosition()
2650 if (mCaret) {
2651 mCaret->InvalidateOutsideCaret();
2655 void PresShell::SetCaret(nsCaret *aNewCaret)
2657 mCaret = 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);
2681 return NS_OK;
2684 NS_IMETHODIMP PresShell::SetCaretReadOnly(PRBool aReadOnly)
2686 if (mCaret)
2687 mCaret->SetCaretReadOnly(aReadOnly);
2688 return NS_OK;
2691 NS_IMETHODIMP PresShell::GetCaretEnabled(PRBool *aOutEnabled)
2693 NS_ENSURE_ARG_POINTER(aOutEnabled);
2694 *aOutEnabled = mCaretEnabled;
2695 return NS_OK;
2698 NS_IMETHODIMP PresShell::SetCaretVisibilityDuringSelection(PRBool aVisibility)
2700 if (mCaret)
2701 mCaret->SetVisibilityDuringSelection(aVisibility);
2702 return NS_OK;
2705 NS_IMETHODIMP PresShell::GetCaretVisible(PRBool *aOutIsVisible)
2707 *aOutIsVisible = PR_FALSE;
2708 if (mCaret) {
2709 nsresult rv = mCaret->GetCaretVisible(aOutIsVisible);
2710 NS_ENSURE_SUCCESS(rv,rv);
2712 return NS_OK;
2715 NS_IMETHODIMP PresShell::SetSelectionFlags(PRInt16 aInEnable)
2717 mSelectionFlags = aInEnable;
2718 return NS_OK;
2721 NS_IMETHODIMP PresShell::GetSelectionFlags(PRInt16 *aOutEnable)
2723 if (!aOutEnable)
2724 return NS_ERROR_INVALID_ARG;
2725 *aOutEnable = mSelectionFlags;
2726 return NS_OK;
2729 //implementation of nsISelectionController
2731 NS_IMETHODIMP
2732 PresShell::CharacterMove(PRBool aForward, PRBool aExtend)
2734 return mSelection->CharacterMove(aForward, aExtend);
2737 NS_IMETHODIMP
2738 PresShell::CharacterExtendForDelete()
2740 return mSelection->CharacterExtendForDelete();
2743 NS_IMETHODIMP
2744 PresShell::WordMove(PRBool aForward, PRBool aExtend)
2746 return mSelection->WordMove(aForward, aExtend);
2749 NS_IMETHODIMP
2750 PresShell::WordExtendForDelete(PRBool aForward)
2752 return mSelection->WordExtendForDelete(aForward);
2755 NS_IMETHODIMP
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);
2763 return result;
2766 NS_IMETHODIMP
2767 PresShell::IntraLineMove(PRBool aForward, PRBool aExtend)
2769 return mSelection->IntraLineMove(aForward, aExtend);
2774 NS_IMETHODIMP
2775 PresShell::PageMove(PRBool aForward, PRBool aExtend)
2777 nsresult result;
2778 nsIViewManager* viewManager = GetViewManager();
2779 nsIScrollableView *scrollableView;
2780 if (!viewManager)
2781 return NS_ERROR_UNEXPECTED;
2782 result = viewManager->GetRootScrollableView(&scrollableView);
2783 if (NS_FAILED(result))
2784 return 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);
2797 NS_IMETHODIMP
2798 PresShell::ScrollPage(PRBool aForward)
2800 nsIScrollableView* scrollView = GetViewToScroll(nsLayoutUtils::eVertical);
2801 if (scrollView) {
2802 scrollView->ScrollByPages(0, aForward ? 1 : -1, NS_VMREFRESH_SMOOTHSCROLL);
2804 return NS_OK;
2807 NS_IMETHODIMP
2808 PresShell::ScrollLine(PRBool aForward)
2810 nsIScrollableView* scrollView = GetViewToScroll(nsLayoutUtils::eVertical);
2811 if (scrollView) {
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);
2816 #else
2817 scrollView->ScrollByLines(0, aForward ? 1 : -1, NS_VMREFRESH_SMOOTHSCROLL);
2818 #endif
2820 //NEW FOR LINES
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.
2825 // vm->Composite();
2826 nsIViewManager* viewManager = GetViewManager();
2827 if (viewManager) {
2828 viewManager->ForceUpdate();
2831 return NS_OK;
2834 NS_IMETHODIMP
2835 PresShell::ScrollHorizontal(PRBool aLeft)
2837 nsIScrollableView* scrollView = GetViewToScroll(nsLayoutUtils::eHorizontal);
2838 if (scrollView) {
2839 scrollView->ScrollByLines(aLeft ? -1 : 1, 0, NS_VMREFRESH_SMOOTHSCROLL);
2840 //NEW FOR LINES
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.
2845 // vm->Composite();
2846 nsIViewManager* viewManager = GetViewManager();
2847 if (viewManager) {
2848 viewManager->ForceUpdate();
2851 return NS_OK;
2854 NS_IMETHODIMP
2855 PresShell::CompleteScroll(PRBool aForward)
2857 nsIScrollableView* scrollView = GetViewToScroll(nsLayoutUtils::eVertical);
2858 if (scrollView) {
2859 scrollView->ScrollByWhole(!aForward);//TRUE = top, aForward TRUE=bottom
2861 return NS_OK;
2864 NS_IMETHODIMP
2865 PresShell::CompleteMove(PRBool aForward, PRBool aExtend)
2867 // Beware! This may flush notifications via synchronous
2868 // ScrollSelectionIntoView.
2870 nsIContent* root = mSelection->GetAncestorLimiter();
2871 nsIDocument* doc;
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;
2878 PRInt32 offset = 0;
2879 nsFrameSelection::HINT hint = nsFrameSelection::HINTLEFT;
2880 if (aForward) {
2881 nsIContent* next = node;
2882 PRUint32 count;
2883 while ((count = next->GetChildCount()) > 0) {
2884 node = next;
2885 offset = count;
2886 next = next->GetChildAt(count - 1);
2889 if (offset > 0 && node->GetChildAt(offset - 1)->Tag() == nsGkAtoms::br) {
2890 --offset;
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.
2902 return
2903 ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL,
2904 nsISelectionController::SELECTION_FOCUS_REGION,
2905 PR_TRUE);
2908 nsIFrame *frame = FrameConstructor()->GetRootElementFrame();
2909 if (!frame)
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,
2919 PR_TRUE);
2922 NS_IMETHODIMP
2923 PresShell::SelectAll()
2925 return mSelection->SelectAll();
2928 NS_IMETHODIMP
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));
2935 if (!content)
2936 return NS_ERROR_FAILURE;
2937 nsIFrame *frame = GetPrimaryFrameFor(content);
2938 if (!frame) //no frame to look at so it must not be visible
2939 return NS_OK;
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
2950 NS_IMETHODIMP
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
2956 if (!rootFrame)
2957 return NS_OK;
2959 return FrameNeedsReflow(rootFrame, eStyleChange, NS_FRAME_IS_DIRTY);
2962 nsIFrame*
2963 nsIPresShell::GetRootFrame() const
2965 return FrameManager()->GetRootFrame();
2968 nsIFrame*
2969 nsIPresShell::GetRootScrollFrame() const
2971 nsIFrame* rootFrame = FrameManager()->GetRootFrame();
2972 // Ensure root frame is a viewport frame
2973 if (!rootFrame || nsGkAtoms::viewportFrame != rootFrame->GetType())
2974 return nsnull;
2975 nsIFrame* theFrame = rootFrame->GetFirstChild(nsnull);
2976 if (!theFrame || nsGkAtoms::scrollFrame != theFrame->GetType())
2977 return nsnull;
2978 return theFrame;
2981 nsIScrollableFrame*
2982 nsIPresShell::GetRootScrollFrameAsScrollable() const
2984 nsIFrame* frame = GetRootScrollFrame();
2985 if (!frame)
2986 return nsnull;
2987 nsIScrollableFrame* scrollableFrame = nsnull;
2988 CallQueryInterface(frame, &scrollableFrame);
2989 NS_ASSERTION(scrollableFrame,
2990 "All scroll frames must implement nsIScrollableFrame");
2991 return scrollableFrame;
2994 NS_IMETHODIMP
2995 PresShell::GetPageSequenceFrame(nsIPageSequenceFrame** aResult) const
2997 NS_PRECONDITION(nsnull != aResult, "null ptr");
2998 if (nsnull == aResult) {
2999 return NS_ERROR_NULL_POINTER;
3002 *aResult = nsnull;
3003 nsIFrame* frame = mFrameConstructor->GetPageSequenceFrame();
3004 if (frame) {
3005 CallQueryInterface(frame, aResult);
3007 return *aResult ? NS_OK : NS_ERROR_FAILURE;
3010 nsIFrame*
3011 PresShell::GetFrameForPoint(nsIFrame* aFrame, nsPoint aPt)
3013 return nsLayoutUtils::GetFrameForPoint(aFrame, aPt);
3016 void
3017 PresShell::BeginUpdate(nsIDocument *aDocument, nsUpdateType aUpdateType)
3019 #ifdef DEBUG
3020 mUpdateCount++;
3021 #endif
3022 mFrameConstructor->BeginUpdate();
3024 if (aUpdateType & UPDATE_STYLE)
3025 mStyleSet->BeginUpdate();
3028 void
3029 PresShell::EndUpdate(nsIDocument *aDocument, nsUpdateType aUpdateType)
3031 #ifdef DEBUG
3032 NS_PRECONDITION(0 != mUpdateCount, "too many EndUpdate's");
3033 --mUpdateCount;
3034 #endif
3036 if (aUpdateType & UPDATE_STYLE) {
3037 mStyleSet->EndUpdate();
3038 if (mStylesHaveChanged)
3039 ReconstructStyleData();
3042 mFrameConstructor->EndUpdate();
3045 void
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;
3057 if (historyState) {
3058 nsIFrame* scrollFrame = GetRootScrollFrame();
3059 if (scrollFrame) {
3060 nsIScrollableFrame* scrollableFrame;
3061 CallQueryInterface(scrollFrame, &scrollableFrame);
3062 if (scrollableFrame) {
3063 FrameManager()->RestoreFrameStateFor(scrollFrame, historyState,
3064 nsIStatefulFrame::eDocumentScrollState);
3065 scrollableFrame->ScrollToRestoredPosition();
3071 void
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));
3077 #endif
3078 mDocumentLoading = PR_TRUE;
3081 void
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));
3102 #endif
3103 mDocumentLoading = PR_FALSE;
3106 #ifdef DEBUG
3107 void
3108 PresShell::VerifyHasDirtyRootAncestor(nsIFrame* aFrame)
3110 // XXXbz due to bug 372769, can't actually assert anything here...
3111 return;
3113 // XXXbz shouldn't need this part; remove it once FrameNeedsReflow
3114 // handles the root frame correctly.
3115 if (!aFrame->GetParent()) {
3116 return;
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) {
3125 return;
3128 aFrame = aFrame->GetParent();
3130 NS_NOTREACHED("Frame has dirty bits set but isn't scheduled to be "
3131 "reflowed?");
3133 #endif
3135 NS_IMETHODIMP
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)
3148 return NS_OK;
3150 // If we're already destroying, don't bother with this either.
3151 if (mIsDestroying)
3152 return NS_OK;
3154 #ifdef DEBUG
3155 //printf("gShellCounter: %d\n", gShellCounter++);
3156 if (mInVerifyReflow) {
3157 return NS_OK;
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();
3165 if (rootContent) {
3166 rootContent->List(stdout, 0);
3170 #endif
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);
3194 a = a->GetParent())
3195 a->MarkIntrinsicWidthsDirty();
3198 if (aIntrinsicDirty == eStyleChange) {
3199 // Mark all descendants dirty (using an nsVoidArray stack rather than
3200 // recursion).
3201 nsVoidArray stack;
3202 stack.AppendElement(aFrame);
3204 while (stack.Count() != 0) {
3205 nsIFrame *f =
3206 static_cast<nsIFrame*>(stack.FastElementAt(stack.Count() - 1));
3207 stack.RemoveElementAt(stack.Count() - 1);
3209 PRInt32 childListIndex = 0;
3210 nsIAtom *childListName;
3211 do {
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;
3225 for (;;) {
3226 if (FRAME_IS_REFLOW_ROOT(f) || !f->GetParent()) {
3227 // we've hit a reflow root or the root frame
3228 if (!wasDirty) {
3229 mDirtyRoots.AppendElement(f);
3231 #ifdef DEBUG
3232 else {
3233 VerifyHasDirtyRootAncestor(f);
3235 #endif
3237 break;
3240 nsIFrame *child = f;
3241 f = f->GetParent();
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");
3246 if (wasDirty) {
3247 // This frame was already marked dirty.
3248 #ifdef DEBUG
3249 VerifyHasDirtyRootAncestor(f);
3250 #endif
3251 break;
3255 PostReflowEvent();
3257 return NS_OK;
3260 nsIScrollableView*
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);
3270 if (domSelection) {
3271 nsCOMPtr<nsIDOMNode> focusedNode;
3272 domSelection->GetFocusNode(getter_AddRefs(focusedNode));
3273 focusedContent = do_QueryInterface(focusedNode);
3276 if (focusedContent) {
3277 nsIFrame* startFrame = GetPrimaryFrameFor(focusedContent);
3278 if (startFrame) {
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);
3292 if (!scrollView) {
3293 nsIViewManager* viewManager = GetViewManager();
3294 if (viewManager) {
3295 viewManager->GetRootScrollableView(&scrollView);
3298 return scrollView;
3301 NS_IMETHODIMP
3302 PresShell::CancelAllPendingReflows()
3304 mDirtyRoots.Clear();
3306 return NS_OK;
3309 #ifdef ACCESSIBILITY
3310 void nsIPresShell::InvalidateAccessibleSubtree(nsIContent *aContent)
3312 if (gIsAccessibilityActive) {
3313 nsCOMPtr<nsIAccessibilityService> accService =
3314 do_GetService("@mozilla.org/accessibilityService;1");
3315 if (accService) {
3316 accService->InvalidateSubtreeFor(this, aContent,
3317 nsIAccessibleEvent::EVENT_ASYNCH_SIGNIFICANT_CHANGE);
3321 #endif
3323 NS_IMETHODIMP
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.
3330 return NS_OK;
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);
3353 #endif
3354 return rv;
3357 void
3358 nsIPresShell::PostRecreateFramesFor(nsIContent* aContent)
3360 FrameConstructor()->PostRestyleEvent(aContent, eReStyle_Self,
3361 nsChangeHint_ReconstructFrame);
3364 NS_IMETHODIMP
3365 PresShell::ClearFrameRefs(nsIFrame* aFrame)
3367 mPresContext->EventStateManager()->ClearFrameRefs(aFrame);
3369 if (aFrame == mCurrentEventFrame) {
3370 mCurrentEventContent = aFrame->GetContent();
3371 mCurrentEventFrame = nsnull;
3374 #ifdef NS_DEBUG
3375 if (aFrame == mDrawEventTargetFrame) {
3376 mDrawEventTargetFrame = nsnull;
3378 #endif
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;
3391 while (weakFrame) {
3392 nsWeakFrame* prev = weakFrame->GetPreviousWeakFrame();
3393 if (weakFrame->GetFrame() == aFrame) {
3394 // This removes weakFrame from mWeakFrames.
3395 weakFrame->Clear(this);
3397 weakFrame = prev;
3400 return NS_OK;
3403 NS_IMETHODIMP
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.)
3418 nsPoint viewOffset;
3419 nsIView* view = aFrame->GetClosestView(&viewOffset);
3420 nsPoint widgetOffset;
3421 widget = view->GetNearestWidget(&widgetOffset);
3422 offset = viewOffset + widgetOffset;
3423 } else {
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.
3427 if (pageFrame)
3428 offset = aFrame->GetOffsetTo(pageFrame);
3431 nsresult rv;
3432 nsIRenderingContext* result = nsnull;
3433 nsIDeviceContext *deviceContext = mPresContext->DeviceContext();
3434 if (widget) {
3435 rv = deviceContext->CreateRenderingContext(widget, result);
3437 else {
3438 rv = deviceContext->CreateRenderingContext(result);
3440 *aResult = result;
3442 if (NS_SUCCEEDED(rv)) {
3443 result->Translate(offset.x, offset.y);
3446 return rv;
3449 NS_IMETHODIMP
3450 PresShell::GoToAnchor(const nsAString& aAnchorName, PRBool aScroll)
3452 if (!mDocument) {
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);
3462 return NS_OK;
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
3471 if (doc) {
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) {
3487 PRUint32 i;
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
3493 break;
3495 // Ensure it's an anchor element
3496 content = do_QueryInterface(node);
3497 if (content) {
3498 if (content->Tag() == nsGkAtoms::a &&
3499 content->IsNodeOfType(nsINode::eHTML)) {
3500 break;
3502 content = nsnull;
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) {
3516 PRUint32 i;
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
3522 break;
3524 // Compare the name attribute
3525 nsCOMPtr<nsIDOMElement> element = do_QueryInterface(node);
3526 nsAutoString value;
3527 if (element && NS_SUCCEEDED(element->GetAttribute(NS_LITERAL_STRING("name"), value))) {
3528 if (value.Equals(aAnchorName)) {
3529 content = do_QueryInterface(element);
3530 break;
3537 nsCOMPtr<nsIDOMRange> jumpToRange;
3538 nsCOMPtr<nsIXPointerResult> xpointerResult;
3539 if (!content) {
3540 nsCOMPtr<nsIDOMXMLDocument> xmldoc = do_QueryInterface(mDocument);
3541 if (xmldoc) {
3542 // Try XPointer
3543 xmldoc->EvaluateXPointer(aAnchorName, getter_AddRefs(xpointerResult));
3544 if (xpointerResult) {
3545 xpointerResult->Item(0, getter_AddRefs(jumpToRange));
3546 if (!jumpToRange) {
3547 // We know it was an XPointer, so there is no point in
3548 // trying any other pointer types, let's just return
3549 // an error.
3550 return NS_ERROR_FAILURE;
3554 // Finally try FIXptr
3555 if (!jumpToRange) {
3556 xmldoc->EvaluateFIXptr(aAnchorName,getter_AddRefs(jumpToRange));
3559 if (jumpToRange) {
3560 nsCOMPtr<nsIDOMNode> node;
3561 jumpToRange->GetStartContainer(getter_AddRefs(node));
3562 if (node) {
3563 PRUint16 nodeType;
3564 node->GetNodeType(&nodeType);
3565 PRInt32 offset = -1;
3566 jumpToRange->GetStartOffset(&offset);
3567 switch (nodeType) {
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();
3573 break;
3575 case nsIDOMNode::DOCUMENT_NODE:
3577 if (offset >= 0) {
3578 nsCOMPtr<nsIDocument> document = do_QueryInterface(node);
3579 content = document->GetChildAt(offset);
3581 break;
3583 case nsIDOMNode::DOCUMENT_FRAGMENT_NODE:
3584 case nsIDOMNode::ELEMENT_NODE:
3585 case nsIDOMNode::ENTITY_REFERENCE_NODE:
3587 if (offset >= 0) {
3588 nsCOMPtr<nsIContent> parent = do_QueryInterface(node);
3589 content = parent->GetChildAt(offset);
3591 break;
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);
3600 break;
3608 esm->SetContentState(content, NS_EVENT_STATE_URLTARGET);
3610 if (content) {
3611 if (aScroll) {
3612 rv = ScrollContentIntoView(content, NS_PRESSHELL_SCROLL_TOP,
3613 NS_PRESSHELL_SCROLL_ANYWHERE);
3614 NS_ENSURE_SUCCESS(rv, rv);
3616 nsIScrollableFrame* rootScroll = GetRootScrollFrameAsScrollable();
3617 if (rootScroll) {
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
3629 // location
3630 if (!jumpToRange) {
3631 jumpToRange = do_CreateInstance(kRangeCID);
3632 if (jumpToRange) {
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);
3641 if (jumpToRange) {
3642 // Select the anchor
3643 nsISelection* sel = mSelection->
3644 GetSelection(nsISelectionController::SELECTION_NORMAL);
3645 if (sel) {
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
3656 PRUint32 count, i;
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();
3668 if (win) {
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);
3679 } else {
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)) {
3686 rv = NS_OK;
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);
3701 return rv;
3704 NS_IMETHODIMP
3705 PresShell::ScrollToAnchor()
3707 if (!mLastAnchorScrolledTo)
3708 return NS_OK;
3710 nsIScrollableFrame* rootScroll = GetRootScrollFrameAsScrollable();
3711 if (!rootScroll ||
3712 mLastAnchorScrollPositionY != rootScroll->GetScrollPosition().y)
3713 return NS_OK;
3715 nsresult rv = ScrollContentIntoView(mLastAnchorScrolledTo, NS_PRESSHELL_SCROLL_TOP,
3716 NS_PRESSHELL_SCROLL_ANYWHERE);
3717 mLastAnchorScrolledTo = nsnull;
3718 return rv;
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.
3732 static void
3733 UnionRectForClosestScrolledView(nsIFrame* aFrame,
3734 PRIntn aVPercent,
3735 nsRect& aRect,
3736 PRBool& aHaveRect,
3737 nsIView*& aClosestScrolledView)
3739 nsRect frameBounds = aFrame->GetRect();
3740 nsPoint offset;
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;
3753 while (f &&
3754 (frameType = f->GetType()) == nsGkAtoms::inlineFrame) {
3755 prevFrame = f;
3756 f = prevFrame->GetParent();
3759 if (f != aFrame &&
3760 f &&
3761 frameType == nsGkAtoms::blockFrame) {
3762 // find the line containing aFrame and increase the top of |offset|.
3763 nsAutoLineIterator lines = f->GetLineIterator();
3764 if (lines) {
3765 PRInt32 index = lines->FindLineContaining(prevFrame);
3766 if (index >= 0) {
3767 nsIFrame *trash1;
3768 PRInt32 trash2;
3769 nsRect lineBounds;
3770 PRUint32 trash3;
3772 if (NS_SUCCEEDED(lines->GetLine(index, &trash1, &trash2,
3773 lineBounds, &trash3))) {
3774 nsPoint blockOffset;
3775 nsIView* blockView;
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())
3801 break;
3802 frameBounds += closestView->GetPosition();
3803 closestView = parent;
3806 if (!aClosestScrolledView)
3807 aClosestScrolledView = closestView;
3809 if (aClosestScrolledView == closestView) {
3810 if (aHaveRect) {
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);
3815 } else {
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,
3828 nsRect & aRect,
3829 PRIntn aVPercent,
3830 PRIntn aHPercent)
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;
3841 nscoord lineHeight;
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;
3874 } else {
3875 // Align the frame edge according to the specified percentage
3876 nscoord frameAlignY =
3877 NSToCoordRound(aRect.y + aRect.height * (aVPercent / 100.0f));
3878 scrollOffsetY =
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;
3914 } else {
3915 // Align the frame edge according to the specified percentage
3916 nscoord frameAlignX =
3917 NSToCoordRound(aRect.x + (aRect.width) * (aHPercent / 100.0f));
3918 scrollOffsetX =
3919 NSToCoordRound(frameAlignX - visibleRect.width * (aHPercent / 100.0f));
3922 aScrollingView->ScrollTo(scrollOffsetX, scrollOffsetY, 0);
3925 NS_IMETHODIMP
3926 PresShell::ScrollContentIntoView(nsIContent* aContent,
3927 PRIntn aVPercent,
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);
3936 if (!frame) {
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();
3949 if (ourWindow) {
3950 nsIFocusController *focusController = ourWindow->GetRootFocusController();
3951 if (focusController) {
3952 PRBool dontScroll = PR_FALSE;
3953 focusController->GetSuppressFocusScroll(&dontScroll);
3954 if (dontScroll) {
3955 return NS_OK;
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
3963 // line.
3964 // Step 2: Walk the views that are parents of the frame and scroll them
3965 // appropriately.
3967 nsIView *closestView = nsnull;
3968 nsRect frameBounds;
3969 PRBool haveRect = PR_FALSE;
3970 do {
3971 UnionRectForClosestScrolledView(frame, aVPercent, frameBounds, haveRect,
3972 closestView);
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();
3981 if (parent) {
3982 scrollingView = parent->ToScrollableView();
3983 if (scrollingView) {
3984 ScrollViewToShowRect(scrollingView, frameBounds, aVPercent, aHPercent);
3987 frameBounds += closestView->GetPosition();
3988 closestView = parent;
3991 return NS_OK;
3994 // GetLinkLocation: copy link location to clipboard
3995 NS_IMETHODIMP PresShell::GetLinkLocation(nsIDOMNode* aNode, nsAString& aLocationString)
3997 #ifdef DEBUG_dr
3998 printf("dr :: PresShell::GetLinkLocation\n");
3999 #endif
4001 NS_ENSURE_ARG_POINTER(aNode);
4002 nsresult rv;
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;
4011 if (anchor) {
4012 rv = anchor->GetHref(anchorText);
4013 NS_ENSURE_SUCCESS(rv, rv);
4014 } else {
4015 // area?
4016 area = do_QueryInterface(aNode);
4017 if (area) {
4018 rv = area->GetHref(anchorText);
4019 NS_ENSURE_SUCCESS(rv, rv);
4020 } else {
4021 // link?
4022 link = do_QueryInterface(aNode);
4023 if (link) {
4024 rv = link->GetHref(anchorText);
4025 NS_ENSURE_SUCCESS(rv, rv);
4026 } else {
4027 // Xlink?
4028 nsCOMPtr<nsIDOMElement> element(do_QueryInterface(aNode));
4029 if (element) {
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
4037 nsAutoString base;
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);
4050 nsCAutoString spec;
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;
4068 return NS_OK;
4071 // if no link, fail.
4072 return NS_ERROR_FAILURE;
4075 NS_IMETHODIMP
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();
4086 if (ourWindow) {
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;
4096 if (content)
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));
4117 if (!sel) {
4118 sel = mSelection->GetSelection(nsISelectionController::SELECTION_NORMAL);
4119 rv = NS_OK;
4122 *outSelection = sel;
4123 NS_IF_ADDREF(*outSelection);
4124 return rv;
4127 /* Just hook this call into InvalidateOverflowRect */
4128 void
4129 PresShell::InvalidateFrameForView(nsIView *aView)
4131 nsIFrame* frame = nsLayoutUtils::GetFrameFor(aView);
4132 if (frame)
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);
4151 NS_IMETHODIMP
4152 PresShell::DoGetContents(const nsACString& aMimeType, PRUint32 aFlags, PRBool aSelectionOnly, nsAString& aOutValue)
4154 aOutValue.Truncate();
4156 if (!mDocument) return NS_ERROR_FAILURE;
4158 nsresult rv;
4159 nsCOMPtr<nsISelection> sel;
4161 // Now we have the selection. Make sure it's nonzero:
4162 if (aSelectionOnly)
4164 rv = GetSelectionForCopy(getter_AddRefs(sel));
4165 if (NS_FAILED(rv)) return rv;
4166 if (!sel) return NS_ERROR_FAILURE;
4168 PRBool isCollapsed;
4169 sel->GetIsCollapsed(&isCollapsed);
4170 if (isCollapsed)
4171 return NS_OK;
4174 // call the copy code
4175 return nsCopySupport::GetContents(aMimeType, aFlags, sel,
4176 mDocument, aOutValue);
4179 NS_IMETHODIMP
4180 PresShell::DoCopy()
4182 if (!mDocument) return NS_ERROR_FAILURE;
4184 nsCOMPtr<nsISelection> sel;
4185 nsresult rv = GetSelectionForCopy(getter_AddRefs(sel));
4186 if (NS_FAILED(rv))
4187 return rv;
4188 if (!sel)
4189 return NS_ERROR_FAILURE;
4191 // Now we have the selection. Make sure it's nonzero:
4192 PRBool isCollapsed;
4193 sel->GetIsCollapsed(&isCollapsed);
4194 if (isCollapsed)
4195 return NS_OK;
4197 // call the copy code
4198 rv = nsCopySupport::HTMLCopy(sel, mDocument, nsIClipboard::kGlobalClipboard);
4199 if (NS_FAILED(rv))
4200 return rv;
4202 // Now that we have copied, update the Paste menu item
4203 nsPIDOMWindow *domWindow = mDocument->GetWindow();
4204 if (domWindow)
4206 domWindow->UpdateCommands(NS_LITERAL_STRING("clipboard"));
4209 return NS_OK;
4212 NS_IMETHODIMP
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();
4226 if (!container)
4227 return NS_ERROR_FAILURE;
4229 nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(container));
4230 if (!docShell)
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)) {
4240 *aState = nsnull;
4241 return 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!
4257 if (aLeavingPage) {
4258 nsIFrame* scrollFrame = GetRootScrollFrame();
4259 if (scrollFrame) {
4260 FrameManager()->CaptureFrameStateFor(scrollFrame, historyState,
4261 nsIStatefulFrame::eDocumentScrollState);
4265 FrameManager()->CaptureFrameState(rootFrame, historyState);
4267 return NS_OK;
4270 NS_IMETHODIMP
4271 PresShell::IsPaintingSuppressed(PRBool* aResult)
4273 *aResult = mPaintingSuppressed;
4274 return NS_OK;
4277 void
4278 PresShell::UnsuppressAndInvalidate()
4280 if (!mPresContext->EnsureVisible(PR_FALSE)) {
4281 // No point; we're about to be torn down anyway.
4282 return;
4285 mPaintingSuppressed = PR_FALSE;
4286 nsIFrame* rootFrame = FrameManager()->GetRootFrame();
4287 if (rootFrame) {
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()
4294 // got.
4295 nsCOMPtr<nsISupports> container = mPresContext->GetContainer();
4296 nsCOMPtr<nsPIDOMWindow> ourWindow = do_GetInterface(container);
4297 nsCOMPtr<nsIFocusController> focusController =
4298 ourWindow ? ourWindow->GetRootFocusController() : nsnull;
4300 if (ourWindow)
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");
4306 if (mViewManager)
4307 mViewManager->SynthesizeMouseMove(PR_FALSE);
4310 NS_IMETHODIMP
4311 PresShell::UnsuppressPainting()
4313 if (mPaintSuppressionTimer) {
4314 mPaintSuppressionTimer->Cancel();
4315 mPaintSuppressionTimer = nsnull;
4318 if (mIsDocumentGone || !mPaintingSuppressed)
4319 return NS_OK;
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;
4327 else
4328 UnsuppressAndInvalidate();
4329 return NS_OK;
4332 NS_IMETHODIMP
4333 PresShell::DisableThemeSupport()
4335 // Doesn't have to be dynamic. Just set the bool.
4336 mIsThemeSupportDisabled = PR_TRUE;
4337 return NS_OK;
4340 PRBool
4341 PresShell::IsThemeSupportEnabled()
4343 return !mIsThemeSupportDisabled;
4346 // Post a request to handle an arbitrary callback after reflow has finished.
4347 NS_IMETHODIMP
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;
4361 } else {
4362 mFirstCallbackEventRequest = request;
4363 mLastCallbackEventRequest = request;
4366 return NS_OK;
4369 NS_IMETHODIMP
4370 PresShell::CancelReflowCallback(nsIReflowCallback* aCallback)
4372 nsCallbackEventRequest* before = nsnull;
4373 nsCallbackEventRequest* node = mFirstCallbackEventRequest;
4374 while(node)
4376 nsIReflowCallback* callback = node->callback;
4378 if (callback == aCallback)
4380 nsCallbackEventRequest* toFree = node;
4381 if (node == mFirstCallbackEventRequest) {
4382 node = node->next;
4383 mFirstCallbackEventRequest = node;
4384 NS_ASSERTION(before == nsnull, "impossible");
4385 } else {
4386 node = node->next;
4387 before->next = node;
4390 if (toFree == mLastCallbackEventRequest) {
4391 mLastCallbackEventRequest = before;
4394 FreeFrame(sizeof(nsCallbackEventRequest), toFree);
4395 } else {
4396 before = node;
4397 node = node->next;
4401 return NS_OK;
4404 void
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);
4415 if (callback) {
4416 callback->ReflowCallbackCanceled();
4421 void
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);
4434 if (callback) {
4435 if (callback->ReflowFinished()) {
4436 shouldFlush = PR_TRUE;
4441 if (shouldFlush)
4442 FlushPendingNotifications(Flush_Layout);
4445 NS_IMETHODIMP
4446 PresShell::IsSafeToFlush(PRBool& aIsSafeToFlush)
4448 aIsSafeToFlush = nsContentUtils::IsSafeToRunScript();
4449 #ifdef DEBUG
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();
4454 if (viewManager) {
4455 PRBool isPainting = PR_FALSE;
4456 viewManager->IsPainting(isPainting);
4457 if (isPainting) {
4458 isSafeToFlush = PR_FALSE;
4461 NS_ASSERTION(!aIsSafeToFlush || isSafeToFlush, "Missing a script blocker!");
4462 #endif
4463 return NS_OK;
4467 NS_IMETHODIMP
4468 PresShell::FlushPendingNotifications(mozFlushType aType)
4470 return DoFlushPendingNotifications(aType, PR_FALSE);
4473 nsresult
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
4498 // notified on,
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
4508 // reflow).
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
4526 // the frame type.
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
4534 // be good.
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
4545 // immediately
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);
4557 return NS_OK;
4560 NS_IMETHODIMP
4561 PresShell::IsReflowLocked(PRBool* aIsReflowLocked)
4563 *aIsReflowLocked = mIsReflowing;
4564 return NS_OK;
4567 void
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;
4577 if (mCaret) {
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()) {
4594 PRUint32 index;
4595 if (aInfo->mAppend &&
4596 container->GetChildAt((index = container->GetChildCount() - 1)) ==
4597 aContent)
4598 mFrameConstructor->RestyleForAppend(container, index);
4599 else
4600 mFrameConstructor->RestyleForInsertOrChange(container, aContent);
4603 mFrameConstructor->CharacterDataChanged(aContent, aInfo->mAppend);
4604 VERIFY_STYLE_TREE;
4607 void
4608 PresShell::ContentStatesChanged(nsIDocument* aDocument,
4609 nsIContent* aContent1,
4610 nsIContent* aContent2,
4611 PRInt32 aStateMask)
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);
4619 VERIFY_STYLE_TREE;
4624 void
4625 PresShell::AttributeChanged(nsIDocument* aDocument,
4626 nsIContent* aContent,
4627 PRInt32 aNameSpaceID,
4628 nsIAtom* aAttribute,
4629 PRInt32 aModType,
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);
4642 VERIFY_STYLE_TREE;
4646 void
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) {
4656 return;
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);
4669 VERIFY_STYLE_TREE;
4671 MOZ_TIMER_DEBUGLOG(("Stop: Frame Creation: PresShell::ContentAppended(), this=%p\n", this));
4672 MOZ_TIMER_STOP(mFrameCreationWatch);
4675 void
4676 PresShell::ContentInserted(nsIDocument* aDocument,
4677 nsIContent* aContainer,
4678 nsIContent* aChild,
4679 PRInt32 aIndexInContainer)
4681 NS_PRECONDITION(!mIsDocumentGone, "Unexpected ContentInserted");
4682 NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
4684 if (!mDidInitialReflow) {
4685 return;
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.
4693 if (aContainer)
4694 mFrameConstructor->RestyleForInsertOrChange(aContainer, aChild);
4696 mFrameConstructor->ContentInserted(aContainer, aChild,
4697 aIndexInContainer, nsnull);
4698 VERIFY_STYLE_TREE;
4701 void
4702 PresShell::ContentRemoved(nsIDocument *aDocument,
4703 nsIContent* aContainer,
4704 nsIContent* aChild,
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.
4711 if (mCaret) {
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.
4724 if (aContainer)
4725 mFrameConstructor->RestyleForRemove(aContainer, aChild, aIndexInContainer);
4727 PRBool didReconstruct;
4728 mFrameConstructor->ContentRemoved(aContainer, aChild,
4729 aIndexInContainer, &didReconstruct);
4731 VERIFY_STYLE_TREE;
4734 nsresult
4735 PresShell::ReconstructFrames(void)
4737 nsAutoScriptBlocker scriptBlocker;
4738 mFrameConstructor->BeginUpdate();
4739 nsresult rv = mFrameConstructor->ReconstructDocElementHierarchy();
4740 VERIFY_STYLE_TREE;
4741 mFrameConstructor->EndUpdate();
4743 return rv;
4746 void
4747 nsIPresShell::ReconstructStyleDataInternal()
4749 mStylesHaveChanged = PR_FALSE;
4751 if (mIsDestroying) {
4752 // We don't want to mess with restyles at this point
4753 return;
4756 if (mPresContext) {
4757 mPresContext->RebuildUserFontSet();
4760 nsIContent* root = mDocument->GetRootContent();
4761 if (!mDidInitialReflow) {
4762 // Nothing to do here, since we have no frames yet
4763 return;
4766 if (!root) {
4767 // No content to restyle
4768 return;
4771 mFrameConstructor->PostRestyleEvent(root, eReStyle_Self, NS_STYLE_HINT_NONE);
4773 #ifdef ACCESSIBILITY
4774 InvalidateAccessibleSubtree(nsnull);
4775 #endif
4778 void
4779 nsIPresShell::ReconstructStyleDataExternal()
4781 ReconstructStyleDataInternal();
4784 void
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!");
4791 PRBool applicable;
4792 aStyleSheet->GetApplicable(applicable);
4794 if (applicable && aStyleSheet->HasRules()) {
4795 mStylesHaveChanged = PR_TRUE;
4799 void
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!");
4806 PRBool applicable;
4807 aStyleSheet->GetApplicable(applicable);
4808 if (applicable && aStyleSheet->HasRules()) {
4809 mStylesHaveChanged = PR_TRUE;
4813 void
4814 PresShell::StyleSheetApplicableStateChanged(nsIDocument *aDocument,
4815 nsIStyleSheet* aStyleSheet,
4816 PRBool aApplicable)
4818 if (aStyleSheet->HasRules()) {
4819 mStylesHaveChanged = PR_TRUE;
4823 void
4824 PresShell::StyleRuleChanged(nsIDocument *aDocument,
4825 nsIStyleSheet* aStyleSheet,
4826 nsIStyleRule* aOldStyleRule,
4827 nsIStyleRule* aNewStyleRule)
4829 mStylesHaveChanged = PR_TRUE;
4832 void
4833 PresShell::StyleRuleAdded(nsIDocument *aDocument,
4834 nsIStyleSheet* aStyleSheet,
4835 nsIStyleRule* aStyleRule)
4837 mStylesHaveChanged = PR_TRUE;
4840 void
4841 PresShell::StyleRuleRemoved(nsIDocument *aDocument,
4842 nsIStyleSheet* aStyleSheet,
4843 nsIStyleRule* aStyleRule)
4845 mStylesHaveChanged = PR_TRUE;
4848 nsIFrame*
4849 PresShell::GetPrimaryFrameFor(nsIContent* aContent) const
4851 return FrameManager()->GetPrimaryFrameFor(aContent, -1);
4854 nsIFrame*
4855 PresShell::GetRealPrimaryFrameFor(nsIContent* aContent) const
4857 nsIFrame *primaryFrame = FrameManager()->GetPrimaryFrameFor(aContent, -1);
4858 if (!primaryFrame)
4859 return nsnull;
4860 return nsPlaceholderFrame::GetRealFrameFor(primaryFrame);
4863 NS_IMETHODIMP
4864 PresShell::GetPlaceholderFrameFor(nsIFrame* aFrame,
4865 nsIFrame** aResult) const
4867 *aResult = FrameManager()->GetPlaceholderFrameFor(aFrame);
4868 return NS_OK;
4871 //nsIViewObserver
4873 NS_IMETHODIMP
4874 PresShell::ComputeRepaintRegionForCopy(nsIView* aRootView,
4875 nsIView* aMovingView,
4876 nsPoint aDelta,
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);
4886 NS_IMETHODIMP
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);
4893 gfxRect r(0, 0,
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);
4901 #else
4902 aThebesContext->Rectangle(r);
4903 #endif
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;
4914 if (needsGroup) {
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();
4936 if (rootFrame) {
4937 nsDisplayListBuilder builder(rootFrame, PR_FALSE,
4938 (aFlags & RENDER_CARET) != 0);
4939 nsDisplayList list;
4941 nsRect rect(aRect);
4942 nsIFrame* rootScrollFrame = GetRootScrollFrame();
4943 if ((aFlags & RENDER_IGNORE_VIEWPORT_SCROLLING) && rootScrollFrame) {
4944 nsPoint pos = GetRootScrollFrameAsScrollable()->GetScrollPosition();
4945 rect.MoveBy(-pos);
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, &region);
4972 list.Paint(&builder, rc, rect);
4973 // Flush the list so we don't trigger the IsEmpty-on-destruction assertion
4974 list.DeleteAll();
4976 aThebesContext->Restore();
4980 // if we had to use a group, paint it to the destination now
4981 if (needsGroup) {
4982 aThebesContext->Restore();
4983 aThebesContext->PopGroupToSource();
4984 aThebesContext->Paint();
4987 aThebesContext->Restore();
4989 return NS_OK;
4993 * Clip the display list aList to a range. Returns the clipped
4994 * rectangle surrounding the range.
4996 nsRect
4997 PresShell::ClipListToRange(nsDisplayListBuilder *aBuilder,
4998 nsDisplayList* aList,
4999 nsIRange* aRange)
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
5009 // don't append it.
5010 nsRect surfaceRect;
5011 nsDisplayList tmpList;
5013 nsDisplayItem* i;
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();
5019 if (frame) {
5020 nsIContent* content = frame->GetContent();
5021 if (content) {
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);
5044 textRect.x += 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
5050 // the item below.
5051 itemToInsert = new (aBuilder)nsDisplayClip(frame, frame, i, textRect);
5054 else {
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) {
5059 itemToInsert = i;
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
5072 if (sublist)
5073 surfaceRect.UnionRect(surfaceRect,
5074 ClipListToRange(aBuilder, sublist, aRange));
5076 else {
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);
5085 return surfaceRect;
5088 RangePaintInfo*
5089 PresShell::CreateRangePaintInfo(nsIDOMRange* aRange,
5090 nsRect& aSurfaceRect)
5092 RangePaintInfo* info = nsnull;
5094 nsCOMPtr<nsIRange> range = do_QueryInterface(aRange);
5095 if (!range)
5096 return nsnull;
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
5103 // range.
5104 nsINode* startParent = range->GetStartParent();
5105 nsINode* endParent = range->GetEndParent();
5106 nsIDocument* doc = startParent->GetCurrentDoc();
5107 if (startParent == doc || endParent == doc) {
5108 ancestorFrame = rootFrame;
5110 else {
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))
5115 return nsnull;
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();
5127 if (!ancestorFrame)
5128 return nsnull;
5130 info = new RangePaintInfo(range, ancestorFrame);
5131 if (!info)
5132 return nsnull;
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);
5152 return info;
5155 already_AddRefed<gfxASurface>
5156 PresShell::PaintRangePaintInfo(nsTArray<nsAutoPtr<RangePaintInfo> >* aItems,
5157 nsISelection* aSelection,
5158 nsIRegion* aRegion,
5159 nsRect aArea,
5160 nsPoint& aPoint,
5161 nsRect* aScreenRect)
5163 nsPresContext* pc = GetPresContext();
5164 if (!pc || aArea.width == 0 || aArea.height == 0)
5165 return nsnull;
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
5174 float scale = 0.0;
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.
5179 nsRect maxSize;
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);
5184 if (resize) {
5185 scale = 1.0;
5186 // divide the maximum size by the image size in both directions. Whichever
5187 // direction produces the smallest result determines how much should be
5188 // scaled.
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);
5203 else {
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()) {
5214 delete surface;
5215 return nsnull;
5218 // clear the image
5219 gfxContext context(surface);
5220 context.SetOperator(gfxContext::OPERATOR_CLEAR);
5221 context.Rectangle(gfxRect(0, 0, pixelArea.width, pixelArea.height));
5222 context.Fill();
5224 nsCOMPtr<nsIRenderingContext> rc;
5225 deviceContext->CreateRenderingContextInstance(*getter_AddRefs(rc));
5226 rc->Init(deviceContext, surface);
5228 if (aRegion)
5229 rc->SetClipRegion(*aRegion, nsClipCombine_kReplace);
5231 if (resize)
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
5239 // selection.
5240 nsCOMPtr<nsFrameSelection> frameSelection;
5241 if (aSelection) {
5242 nsCOMPtr<nsISelectionPrivate> selpriv = do_QueryInterface(aSelection);
5243 selpriv->GetFrameSelection(getter_AddRefs(frameSelection));
5245 else {
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);
5268 NS_ADDREF(surface);
5269 return surface;
5272 already_AddRefed<gfxASurface>
5273 PresShell::RenderNode(nsIDOMNode* aNode,
5274 nsIRegion* aRegion,
5275 nsPoint& aPoint,
5276 nsRect* aScreenRect)
5278 // area will hold the size of the surface needed to draw the node, measured
5279 // from the root frame.
5280 nsRect area;
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())
5286 return nsnull;
5288 nsCOMPtr<nsIDOMRange> range;
5289 NS_NewRange(getter_AddRefs(range));
5290 if (NS_FAILED(range->SelectNode(aNode)))
5291 return nsnull;
5293 RangePaintInfo* info = CreateRangePaintInfo(range, area);
5294 if (info && !rangeItems.AppendElement(info)) {
5295 delete info;
5296 return nsnull;
5299 if (aRegion) {
5300 // combine the area with the supplied region
5301 nsRect rrectPixels;
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();
5310 if (!pc)
5311 return nsnull;
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,
5319 aScreenRect);
5322 already_AddRefed<gfxASurface>
5323 PresShell::RenderSelection(nsISelection* aSelection,
5324 nsPoint& aPoint,
5325 nsRect* aScreenRect)
5327 // area will hold the size of the surface needed to draw the selection,
5328 // measured from the root frame.
5329 nsRect area;
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
5335 PRInt32 numRanges;
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)) {
5346 delete info;
5347 return nsnull;
5351 return PaintRangePaintInfo(&rangeItems, aSelection, nsnull, area, aPoint,
5352 aScreenRect);
5355 NS_IMETHODIMP
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;
5382 break;
5384 if (NS_GET_A(backgroundColor) < 255) {
5385 nsIViewManager *thisMgr = view->GetViewManager();
5386 NS_ASSERTION(thisMgr, "view without view manager");
5387 if (lastMgr != thisMgr) {
5388 nscolor underColor;
5389 thisMgr->GetDefaultBackgroundColor(&underColor);
5390 backgroundColor = NS_ComposeColors(underColor, backgroundColor);
5391 lastMgr = thisMgr;
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());
5400 if (frame) {
5401 nsLayoutUtils::PaintFrame(aRenderingContext, frame, aDirtyRegion,
5402 backgroundColor);
5403 } else if (NS_GET_A(backgroundColor) > 0) {
5404 aRenderingContext->SetColor(backgroundColor);
5405 aRenderingContext->FillRect(aDirtyRegion.GetBounds());
5408 return NS_OK;
5411 nsIFrame*
5412 PresShell::GetCurrentEventFrame()
5414 if (NS_UNLIKELY(mIsDestroying)) {
5415 return nsnull;
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;
5431 NS_IMETHODIMP
5432 PresShell::GetEventTargetFrame(nsIFrame** aFrame)
5434 *aFrame = GetCurrentEventFrame();
5435 return NS_OK;
5438 NS_IMETHODIMP
5439 PresShell::GetEventTargetContent(nsEvent* aEvent, nsIContent** aContent)
5441 if (mCurrentEventContent) {
5442 *aContent = mCurrentEventContent;
5443 NS_IF_ADDREF(*aContent);
5444 } else {
5445 nsIFrame* currentEventFrame = GetCurrentEventFrame();
5446 if (currentEventFrame) {
5447 currentEventFrame->GetContentForEvent(mPresContext, aEvent, aContent);
5448 } else {
5449 *aContent = nsnull;
5452 return NS_OK;
5455 void
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;
5466 void
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();
5502 if (!container)
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);
5508 if (!treeItem) {
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,
5534 aEventStatus);
5537 NS_IMETHODIMP
5538 PresShell::HandleEvent(nsIView *aView,
5539 nsGUIEvent* aEvent,
5540 nsEventStatus* aEventStatus)
5542 NS_ASSERTION(aView, "null view");
5544 if (mIsDestroying || !nsContentUtils::IsSafeToRunScript()) {
5545 return NS_OK;
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);
5554 #endif
5556 // Check for a theme change up front, since the frame type is irrelevant
5557 if (aEvent->message == NS_THEMECHANGED && mPresContext) {
5558 mPresContext->ThemeChanged();
5559 return NS_OK;
5562 // Check for a system color change up front, since the frame type is
5563 // irrelevant
5564 if ((aEvent->message == NS_SYSCOLORCHANGED) && mPresContext) {
5565 nsIViewManager* vm = GetViewManager();
5566 if (vm) {
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.
5571 nsIView *view;
5572 vm->GetRootView(view);
5573 if (view == aView) {
5574 *aEventStatus = nsEventStatus_eConsumeDoDefault;
5575 mPresContext->SysColorChanged();
5576 return NS_OK;
5579 return NS_OK;
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.
5591 if (!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();
5599 if (targetView) {
5600 aView = targetView;
5601 frame = static_cast<nsIFrame*>(aView->GetClientData());
5605 if (dispatchUsingCoordinates) {
5606 NS_ASSERTION(frame, "Nothing to handle this event!");
5607 if (!frame)
5608 return NS_OK;
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
5616 // list.
5617 if (framePresContext == rootPresContext &&
5618 frame == FrameManager()->GetRootFrame()) {
5620 #ifdef MOZ_XUL
5621 nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
5622 if (pm) {
5623 nsTArray<nsIFrame*> popups = pm->GetOpenPopups();
5624 PRUint32 i;
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
5631 frame = popup;
5632 break;
5636 #endif
5639 nsPoint eventPoint
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);
5652 if (targetFrame) {
5653 PresShell* shell =
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);
5670 if (!targetFrame) {
5671 targetFrame = frame;
5673 return HandlePositionedEvent(aView, targetFrame, aEvent, aEventStatus);
5676 nsresult rv = NS_OK;
5678 if (frame) {
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));
5689 } else {
5690 if (NS_TargetUnfocusedEventToLastFocusedContent(aEvent)) {
5691 nsPIDOMWindow *ourWindow = mDocument->GetWindow();
5692 if (ourWindow) {
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);
5699 if (!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();
5719 return rv;
5721 } else {
5722 mCurrentEventFrame = frame;
5724 if (GetCurrentEventFrame()) {
5725 rv = HandleEventInternal(aEvent, aView, aEventStatus);
5728 #ifdef NS_DEBUG
5729 ShowEventTargetDebug();
5730 #endif
5731 PopCurrentEventInfo();
5732 } else {
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);
5747 return rv;
5750 #ifdef NS_DEBUG
5751 void
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()));
5766 #endif
5768 nsresult
5769 PresShell::HandlePositionedEvent(nsIView* aView,
5770 nsIFrame* aTargetFrame,
5771 nsGUIEvent* aEvent,
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);
5816 #ifdef NS_DEBUG
5817 ShowEventTargetDebug();
5818 #endif
5819 PopCurrentEventInfo();
5820 return rv;
5823 NS_IMETHODIMP
5824 PresShell::HandleEventWithTarget(nsEvent* aEvent, nsIFrame* aFrame,
5825 nsIContent* aContent, nsEventStatus* aStatus)
5827 nsresult ret;
5829 PushCurrentEventInfo(aFrame, aContent);
5830 ret = HandleEventInternal(aEvent, nsnull, aStatus);
5831 PopCurrentEventInfo();
5832 return NS_OK;
5835 inline PRBool
5836 IsSynthesizedMouseMove(nsEvent* aEvent)
5838 return aEvent->eventStructType == NS_MOUSE_EVENT &&
5839 static_cast<nsMouseEvent*>(aEvent)->reason != nsMouseEvent::eReal;
5842 nsresult
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");
5852 if (accService) {
5853 nsCOMPtr<nsISupports> container = mPresContext->GetContainer();
5854 if (!container) {
5855 // This presshell is not active. This often happens when a
5856 // preshell is being held onto for fastback.
5857 return NS_OK;
5859 nsIAccessible* acc;
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;
5870 return NS_OK;
5873 #endif
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) {
5883 case NS_GOTFOCUS:
5884 case NS_LOSTFOCUS:
5885 case NS_ACTIVATE:
5886 case NS_DEACTIVATE:
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()) {
5892 break;
5894 case NS_MOUSE_BUTTON_DOWN:
5895 case NS_MOUSE_BUTTON_UP:
5896 case NS_KEY_PRESS:
5897 case NS_KEY_DOWN:
5898 case NS_KEY_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,
5908 // bug 329430
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,
5915 aStatus, aView);
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);
5927 else {
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());
5950 return rv;
5953 // Dispatch event to content only (NOT full processing)
5954 // See also HandleEventWithTarget which does full event processing.
5955 NS_IMETHODIMP
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();
5967 if (container) {
5969 // Dispatch event to content
5970 nsEventDispatcher::Dispatch(aTargetContent, mPresContext, aEvent, nsnull,
5971 aStatus);
5974 PopCurrentEventInfo();
5975 return NS_OK;
5978 NS_IMETHODIMP
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);
5989 if (!bw)
5990 return PR_FALSE;
5991 PRBool res = PR_TRUE;
5992 bw->GetVisibility(&res);
5993 return 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) {
6002 return;
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);
6012 nsresult
6013 PresShell::GetAgentStyleSheets(nsCOMArray<nsIStyleSheet>& aSheets)
6015 aSheets.Clear();
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;
6024 return NS_OK;
6027 nsresult
6028 PresShell::SetAgentStyleSheets(const nsCOMArray<nsIStyleSheet>& aSheets)
6030 return mStyleSet->ReplaceSheets(nsStyleSet::eAgentSheet, aSheets);
6033 nsresult
6034 PresShell::AddOverrideStyleSheet(nsIStyleSheet *aSheet)
6036 return mStyleSet->PrependStyleSheet(nsStyleSet::eOverrideSheet, aSheet);
6039 nsresult
6040 PresShell::RemoveOverrideStyleSheet(nsIStyleSheet *aSheet)
6042 return mStyleSet->RemoveStyleSheet(nsStyleSet::eOverrideSheet, aSheet);
6045 static void
6046 StopPluginInstance(PresShell *aShell, nsIContent *aContent)
6048 nsIFrame *frame = aShell->FrameManager()->GetPrimaryFrameFor(aContent, -1);
6050 nsIObjectFrame *objectFrame = nsnull;
6051 if (frame)
6052 CallQueryInterface(frame, &objectFrame);
6053 if (!objectFrame)
6054 return;
6056 objectFrame->StopPlugin();
6059 #ifdef MOZ_MEDIA
6060 static void
6061 StopMediaInstance(PresShell *aShell, nsIContent *aContent)
6063 nsCOMPtr<nsIDOMHTMLMediaElement> domMediaElem(do_QueryInterface(aContent));
6064 if (!domMediaElem)
6065 return;
6067 nsHTMLMediaElement* mediaElem = static_cast<nsHTMLMediaElement*>(aContent);
6068 mediaElem->Freeze();
6070 #endif
6072 static PRBool
6073 FreezeSubDocument(nsIDocument *aDocument, void *aData)
6075 nsIPresShell *shell = aDocument->GetPrimaryShell();
6076 if (shell)
6077 shell->Freeze();
6079 return PR_TRUE;
6082 void
6083 PresShell::Freeze()
6085 nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(mDocument);
6086 if (domDoc) {
6087 EnumeratePlugins(domDoc, NS_LITERAL_STRING("object"), StopPluginInstance);
6088 EnumeratePlugins(domDoc, NS_LITERAL_STRING("applet"), StopPluginInstance);
6089 EnumeratePlugins(domDoc, NS_LITERAL_STRING("embed"), StopPluginInstance);
6090 #ifdef MOZ_MEDIA
6091 EnumeratePlugins(domDoc, NS_LITERAL_STRING("video"), StopMediaInstance);
6092 EnumeratePlugins(domDoc, NS_LITERAL_STRING("audio"), StopMediaInstance);
6093 #endif
6096 if (mCaret)
6097 mCaret->SetCaretVisible(PR_FALSE);
6099 mPaintingSuppressed = PR_TRUE;
6101 if (mDocument)
6102 mDocument->EnumerateSubDocuments(FreezeSubDocument, nsnull);
6105 static void
6106 StartPluginInstance(PresShell *aShell, nsIContent *aContent)
6108 nsCOMPtr<nsIObjectLoadingContent> objlc(do_QueryInterface(aContent));
6109 if (!objlc)
6110 return;
6112 nsCOMPtr<nsIPluginInstance> inst;
6113 objlc->EnsureInstantiation(getter_AddRefs(inst));
6116 #ifdef MOZ_MEDIA
6117 static void
6118 StartMediaInstance(PresShell *aShell, nsIContent *aContent)
6120 nsCOMPtr<nsIDOMHTMLMediaElement> domMediaElem(do_QueryInterface(aContent));
6121 if (!domMediaElem)
6122 return;
6124 nsHTMLMediaElement* mediaElem = static_cast<nsHTMLMediaElement*>(aContent);
6125 mediaElem->Thaw();
6127 #endif
6129 static PRBool
6130 ThawSubDocument(nsIDocument *aDocument, void *aData)
6132 nsIPresShell *shell = aDocument->GetPrimaryShell();
6133 if (shell)
6134 shell->Thaw();
6136 return PR_TRUE;
6139 void
6140 PresShell::Thaw()
6142 nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(mDocument);
6143 if (domDoc) {
6144 EnumeratePlugins(domDoc, NS_LITERAL_STRING("object"), StartPluginInstance);
6145 EnumeratePlugins(domDoc, NS_LITERAL_STRING("applet"), StartPluginInstance);
6146 EnumeratePlugins(domDoc, NS_LITERAL_STRING("embed"), StartPluginInstance);
6147 #ifdef MOZ_MEDIA
6148 EnumeratePlugins(domDoc, NS_LITERAL_STRING("video"), StartMediaInstance);
6149 EnumeratePlugins(domDoc, NS_LITERAL_STRING("audio"), StartMediaInstance);
6150 #endif
6153 if (mDocument)
6154 mDocument->EnumerateSubDocuments(ThawSubDocument, nsnull);
6156 UnsuppressPainting();
6159 //--------------------------------------------------------
6160 // Start of protected and private methods on the PresShell
6161 //--------------------------------------------------------
6163 //-------------- Begin Reflow Event Definition ------------------------
6165 NS_IMETHODIMP
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;
6170 if (ps) {
6171 #ifdef DEBUG
6172 if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) {
6173 printf("\n*** Handling reflow event: PresShell=%p, event=%p\n", (void*)ps, (void*)this);
6175 #endif
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
6185 ps = nsnull;
6186 viewManager = nsnull;
6188 return NS_OK;
6191 //-------------- End Reflow Event Definition ---------------------------
6193 void
6194 PresShell::PostReflowEvent()
6196 if (mReflowEvent.IsPending() || mIsDestroying || mIsReflowing ||
6197 mDirtyRoots.Count() == 0)
6198 return;
6200 nsRefPtr<ReflowEvent> ev = new ReflowEvent(this);
6201 if (NS_FAILED(NS_DispatchToCurrentThread(ev))) {
6202 NS_WARNING("failed to dispatch reflow event");
6203 } else {
6204 mReflowEvent = ev;
6205 #ifdef DEBUG
6206 if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) {
6207 printf("\n*** PresShell::PostReflowEvent(), this=%p, event=%p\n", (void*)this, (void*)ev);
6209 #endif
6213 void
6214 PresShell::WillDoReflow()
6216 // We just reflowed, tell the caret that its frame might have moved.
6217 // XXXbz that comment makes no sense
6218 if (mCaret) {
6219 mCaret->InvalidateOutsideCaret();
6220 mCaret->UpdateCaretPosition();
6223 mPresContext->FlushUserFontSet();
6225 mFrameConstructor->BeginUpdate();
6228 void
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);
6238 if (mCaret) {
6239 // Update the caret's position now to account for any changes created by
6240 // the reflow.
6241 mCaret->InvalidateOutsideCaret();
6242 mCaret->UpdateCaretPosition();
6246 void
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");
6257 return;
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.
6265 nsSize size;
6266 if (target == rootFrame)
6267 size = mPresContext->GetVisibleArea().Size();
6268 else
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
6277 nsSize reflowSize;
6278 if (target != rootFrame)
6279 reflowSize = nsSize(size.width, NS_UNCONSTRAINEDSIZE);
6280 else
6281 reflowSize = size;
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() ==
6294 size.width -
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,
6321 target->GetView(),
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));
6331 #ifdef DEBUG
6332 void
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
6345 // see it.
6346 nsIView* rootView;
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");
6364 #endif
6366 nsresult
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()) {
6374 #ifdef DEBUG
6375 if (VERIFY_REFLOW_DUMP_COMMANDS & gVerifyReflowFlags) {
6376 printf("ProcessReflowCommands: begin incremental reflow\n");
6378 #endif
6380 WillDoReflow();
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;
6393 do {
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.
6403 continue;
6406 DoReflow(target);
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) {
6421 DidDoReflow();
6424 // DidDoReflow might have killed us
6425 if (!mIsDestroying) {
6426 #ifdef DEBUG
6427 if (VERIFY_REFLOW_DUMP_COMMANDS & gVerifyReflowFlags) {
6428 printf("\nPresShell::ProcessReflowCommands() finished: this=%p\n",
6429 (void*)this);
6431 DoVerifyReflow();
6432 #endif
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())
6440 PostReflowEvent();
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();
6457 return NS_OK;
6460 void
6461 PresShell::ClearReflowEventStatus()
6463 mReflowEvent.Forget();
6466 #ifdef MOZ_XUL
6468 * It's better to add stuff to the |DidSetStyleContext| method of the
6469 * relevant frames than adding it here. These methods should (ideally,
6470 * anyway) go away.
6473 // Return value says whether to walk children.
6474 typedef PRBool (* frameWalkerFn)(nsIFrame *aFrame, void *aClosure);
6476 static PRBool
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);
6483 if (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);
6492 return PR_TRUE;
6495 static PRBool
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
6507 static void
6508 WalkFramesThroughPlaceholders(nsPresContext *aPresContext, nsIFrame *aFrame,
6509 frameWalkerFn aFunc, void *aClosure)
6511 PRBool walkChildren = (*aFunc)(aFrame, aClosure);
6512 if (!walkChildren)
6513 return;
6515 PRInt32 listIndex = 0;
6516 nsIAtom* childList = nsnull;
6518 do {
6519 nsIFrame *child = aFrame->GetFirstChild(childList);
6520 while (child) {
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),
6526 aFunc, aClosure);
6528 child = child->GetNextSibling();
6531 childList = aFrame->GetAdditionalChildListName(listIndex++);
6532 } while (childList);
6534 #endif
6536 NS_IMETHODIMP
6537 PresShell::Observe(nsISupports* aSubject,
6538 const char* aTopic,
6539 const PRUnichar* aData)
6541 #ifdef MOZ_XUL
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.
6546 if (rootFrame) {
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
6554 // frames (hack!).
6555 nsStyleChangeList changeList;
6556 WalkFramesThroughPlaceholders(mPresContext, rootFrame,
6557 ReframeImageBoxes, &changeList);
6558 // Mark ourselves as not safe to flush while we're doing frame
6559 // construction.
6561 nsAutoScriptBlocker scriptBlocker;
6562 mFrameConstructor->ProcessRestyledFrames(changeList);
6565 batch.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
6566 #ifdef ACCESSIBILITY
6567 InvalidateAccessibleSubtree(nsnull);
6568 #endif
6570 return NS_OK;
6572 #endif
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);
6579 return NS_OK;
6582 if (!nsCRT::strcmp(aTopic, "agent-sheet-added") && mStyleSet) {
6583 AddAgentSheet(aSubject);
6584 return NS_OK;
6587 if (!nsCRT::strcmp(aTopic, "user-sheet-added") && mStyleSet) {
6588 AddUserSheet(aSubject);
6589 return NS_OK;
6592 if (!nsCRT::strcmp(aTopic, "agent-sheet-removed") && mStyleSet) {
6593 RemoveSheet(nsStyleSet::eAgentSheet, aSubject);
6594 return NS_OK;
6597 if (!nsCRT::strcmp(aTopic, "user-sheet-removed") && mStyleSet) {
6598 RemoveSheet(nsStyleSet::eUserSheet, aSubject);
6599 return NS_OK;
6602 #ifdef ACCESSIBILITY
6603 if (!nsCRT::strcmp(aTopic, "a11y-init-or-shutdown")) {
6604 gIsAccessibilityActive = aData && *aData == '1';
6606 #endif
6607 NS_WARNING("unrecognized topic in PresShell::Observe");
6608 return NS_ERROR_FAILURE;
6611 void
6612 PresShell::EnumeratePlugins(nsIDOMDocument *aDocument,
6613 const nsString &aPluginTag,
6614 nsPluginEnumCallback aCallback)
6616 nsCOMPtr<nsIDOMNodeList> nodes;
6617 aDocument->GetElementsByTagName(aPluginTag, getter_AddRefs(nodes));
6618 if (!nodes)
6619 return;
6621 PRUint32 length;
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);
6629 if (content)
6630 aCallback(this, content);
6634 //------------------------------------------------------
6635 // End of protected and private methods on the PresShell
6636 //------------------------------------------------------
6638 // Start of DEBUG only code
6640 #ifdef NS_DEBUG
6641 #include "nsViewsCID.h"
6642 #include "nsWidgetsCID.h"
6643 #include "nsIDeviceContext.h"
6644 #include "nsIURL.h"
6645 #include "nsILinkHandler.h"
6647 static NS_DEFINE_CID(kViewManagerCID, NS_VIEW_MANAGER_CID);
6648 static NS_DEFINE_CID(kWidgetCID, NS_CHILD_CID);
6650 static void
6651 LogVerifyMessage(nsIFrame* k1, nsIFrame* k2, const char* aMsg)
6653 printf("verifyreflow: ");
6654 nsAutoString name;
6655 if (nsnull != k1) {
6656 nsIFrameDebug* frameDebug;
6658 if (NS_SUCCEEDED(k1->QueryInterface(NS_GET_IID(nsIFrameDebug),
6659 (void**)&frameDebug))) {
6660 frameDebug->GetFrameName(name);
6663 else {
6664 name.Assign(NS_LITERAL_STRING("(null)"));
6666 fputs(NS_LossyConvertUTF16toASCII(name).get(), stdout);
6668 fprintf(stdout, " %p ", (void*)k1);
6670 printf(" != ");
6672 if (nsnull != k2) {
6673 nsIFrameDebug* frameDebug;
6675 if (NS_SUCCEEDED(k2->QueryInterface(NS_GET_IID(nsIFrameDebug),
6676 (void**)&frameDebug))) {
6677 frameDebug->GetFrameName(name);
6680 else {
6681 name.Assign(NS_LITERAL_STRING("(null)"));
6683 fputs(NS_LossyConvertUTF16toASCII(name).get(), stdout);
6685 fprintf(stdout, " %p ", (void*)k2);
6687 printf(" %s", aMsg);
6690 static void
6691 LogVerifyMessage(nsIFrame* k1, nsIFrame* k2, const char* aMsg,
6692 const nsRect& r1, const nsRect& r2)
6694 printf("VerifyReflow Error:\n");
6695 nsAutoString name;
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);
6707 printf(" != \n");
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);
6721 static PRBool
6722 CompareTrees(nsPresContext* aFirstPresContext, nsIFrame* aFirstFrame,
6723 nsPresContext* aSecondPresContext, nsIFrame* aSecondFrame)
6725 if (!aFirstPresContext || !aFirstFrame || !aSecondPresContext || !aSecondFrame)
6726 return PR_TRUE;
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)
6730 // return PR_TRUE;
6731 PRBool ok = PR_TRUE;
6732 nsIAtom* listName = nsnull;
6733 PRInt32 listIndex = 0;
6734 do {
6735 nsIFrame* k1 = aFirstFrame->GetFirstChild(listName);
6736 nsIFrame* k2 = aSecondFrame->GetFirstChild(listName);
6737 PRInt32 l1 = nsContainerFrame::LengthOf(k1);
6738 PRInt32 l2 = nsContainerFrame::LengthOf(k2);
6739 if (l1 != l2) {
6740 ok = PR_FALSE;
6741 LogVerifyMessage(k1, k2, "child counts don't match: ");
6742 printf("%d != %d\n", l1, l2);
6743 if (0 == (VERIFY_REFLOW_ALL & gVerifyReflowFlags)) {
6744 break;
6748 nsRect r1, r2;
6749 nsIView* v1, *v2;
6750 for (;;) {
6751 if (((nsnull == k1) && (nsnull != k2)) ||
6752 ((nsnull != k1) && (nsnull == k2))) {
6753 ok = PR_FALSE;
6754 LogVerifyMessage(k1, k2, "child lists are different\n");
6755 break;
6757 else if (nsnull != k1) {
6758 // Verify that the frames are the same size
6759 if (k1->GetRect() != k2->GetRect()) {
6760 ok = PR_FALSE;
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.
6768 v1 = k1->GetView();
6769 v2 = k2->GetView();
6770 if (((nsnull == v1) && (nsnull != v2)) ||
6771 ((nsnull != v1) && (nsnull == v2))) {
6772 ok = PR_FALSE;
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))) {
6784 ok = PR_FALSE;
6785 LogVerifyMessage(k1, k2, "child widgets are not matched\n");
6787 else if (nsnull != w1) {
6788 w1->GetBounds(r1);
6789 w2->GetBounds(r2);
6790 if (r1 != r2) {
6791 LogVerifyMessage(k1, k2, "(widget rects)", r1, r2);
6795 if (!ok && (0 == (VERIFY_REFLOW_ALL & gVerifyReflowFlags))) {
6796 break;
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
6811 ok = PR_FALSE;
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);
6847 ok = PR_FALSE;
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));
6857 if (!match)
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);
6872 ok = PR_FALSE;
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));
6882 if (!match)
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)) {
6898 ok = PR_FALSE;
6899 if (0 == (VERIFY_REFLOW_ALL & gVerifyReflowFlags)) {
6900 break;
6904 // Advance to next sibling
6905 k1 = k1->GetNextSibling();
6906 k2 = k2->GetNextSibling();
6908 else {
6909 break;
6912 if (!ok && (0 == (VERIFY_REFLOW_ALL & gVerifyReflowFlags))) {
6913 break;
6916 nsIAtom* listName1 = aFirstFrame->GetAdditionalChildListName(listIndex);
6917 nsIAtom* listName2 = aSecondFrame->GetAdditionalChildListName(listIndex);
6918 listIndex++;
6919 if (listName1 != listName2) {
6920 if (0 == (VERIFY_REFLOW_ALL & gVerifyReflowFlags)) {
6921 ok = PR_FALSE;
6923 LogVerifyMessage(k1, k2, "child list names are not matched: ");
6924 nsAutoString tmp;
6925 if (nsnull != listName1) {
6926 listName1->ToString(tmp);
6927 fputs(NS_LossyConvertUTF16toASCII(tmp).get(), stdout);
6929 else
6930 fputs("(null)", stdout);
6931 printf(" != ");
6932 if (nsnull != listName2) {
6933 listName2->ToString(tmp);
6934 fputs(NS_LossyConvertUTF16toASCII(tmp).get(), stdout);
6936 else
6937 fputs("(null)", stdout);
6938 printf("\n");
6939 break;
6941 listName = listName1;
6942 } while (ok && (listName != nsnull));
6944 return ok;
6946 #endif
6948 #if 0
6949 static nsIFrame*
6950 FindTopFrame(nsIFrame* aRoot)
6952 if (aRoot) {
6953 nsIContent* content = aRoot->GetContent();
6954 if (content) {
6955 nsIAtom* tag;
6956 content->GetTag(tag);
6957 if (nsnull != tag) {
6958 NS_RELEASE(tag);
6959 return aRoot;
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) {
6968 return result;
6970 kid = kid->GetNextSibling();
6973 return nsnull;
6975 #endif
6978 #ifdef DEBUG
6980 nsresult
6981 PresShell::CloneStyleSet(nsStyleSet* aSet, nsStyleSet** aResult)
6983 nsStyleSet *clone = new nsStyleSet();
6984 if (!clone) {
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);
6991 if (ss)
6992 clone->AppendStyleSheet(nsStyleSet::eOverrideSheet, ss);
6995 // The document expects to insert document stylesheets itself
6996 #if 0
6997 n = aSet->SheetCount(nsStyleSet::eDocSheet);
6998 for (i = 0; i < n; i++) {
6999 nsIStyleSheet* ss = aSet->StyleSheetAt(nsStyleSet::eDocSheet, i);
7000 if (ss)
7001 clone->AddDocStyleSheet(ss, mDocument);
7003 #endif
7005 n = aSet->SheetCount(nsStyleSet::eUserSheet);
7006 for (i = 0; i < n; i++) {
7007 nsIStyleSheet* ss = aSet->StyleSheetAt(nsStyleSet::eUserSheet, i);
7008 if (ss)
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);
7015 if (ss)
7016 clone->AppendStyleSheet(nsStyleSet::eAgentSheet, ss);
7018 *aResult = clone;
7019 return NS_OK;
7022 #ifdef DEBUG_Eli
7023 static nsresult
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);
7062 PRUint32 length;
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);
7077 return NS_OK;
7079 #endif
7081 // After an incremental reflow, we verify the correctness by doing a
7082 // full reflow into a fresh frame tree.
7083 PRBool
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
7102 nsIView* rootView;
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);
7109 rv = vm->Init(dc);
7110 NS_ENSURE_SUCCESS(rv, PR_FALSE);
7112 // Create a child window of the parent that is our "root view/window"
7113 // Create a view
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);
7138 newSet.forget();
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);
7174 #ifdef DEBUG_Eli
7175 // Sample code for dumping page to png
7176 // XXX Needs to be made more flexible
7177 if (!ok) {
7178 nsString stra;
7179 static int num = 0;
7180 stra.AppendLiteral("C:\\mozilla\\mozilla\\debug\\filea");
7181 stra.AppendInt(num);
7182 stra.AppendLiteral(".png");
7183 DumpToPNG(sh, stra);
7184 nsString strb;
7185 strb.AppendLiteral("C:\\mozilla\\mozilla\\debug\\fileb");
7186 strb.AppendInt(num);
7187 strb.AppendLiteral(".png");
7188 DumpToPNG(this, strb);
7189 ++num;
7191 #endif
7193 sh->EndObservingDocument();
7194 sh->Destroy();
7195 if (VERIFY_REFLOW_NOISY & gVerifyReflowFlags) {
7196 printf("Finished Verifying Reflow...\n");
7199 return ok;
7202 // Layout debugging hooks
7203 void
7204 PresShell::ListStyleContexts(nsIFrame *aRootFrame, FILE *out, PRInt32 aIndent)
7206 nsStyleContext *sc = aRootFrame->GetStyleContext();
7207 if (sc)
7208 sc->List(out, aIndent);
7211 void
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);
7217 fputs("\n", out);
7221 void
7222 PresShell::VerifyStyleTree()
7224 VERIFY_STYLE_TREE;
7226 #endif
7228 //=============================================================
7229 //=============================================================
7230 //-- Debug Reflow Counts
7231 //=============================================================
7232 //=============================================================
7233 #ifdef MOZ_REFLOW_PERF
7234 //-------------------------------------------------------------
7235 NS_IMETHODIMP
7236 PresShell::DumpReflows()
7238 if (mReflowCountMgr) {
7239 nsCAutoString uriStr;
7240 if (mDocument) {
7241 nsIURI *uri = mDocument->GetDocumentURI();
7242 if (uri) {
7243 uri->GetPath(uriStr);
7246 mReflowCountMgr->DisplayTotals(uriStr.get());
7247 mReflowCountMgr->DisplayHTMLTotals(uriStr.get());
7248 mReflowCountMgr->DisplayDiffsInTotals("Differences");
7250 return NS_OK;
7253 //-------------------------------------------------------------
7254 NS_IMETHODIMP
7255 PresShell::CountReflows(const char * aName, nsIFrame * aFrame)
7257 if (mReflowCountMgr) {
7258 mReflowCountMgr->Add(aName, aFrame);
7261 return NS_OK;
7264 //-------------------------------------------------------------
7265 NS_IMETHODIMP
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);
7271 return NS_OK;
7274 //-------------------------------------------------------------
7275 NS_IMETHODIMP
7276 PresShell::SetPaintFrameCount(PRBool aPaintFrameCounts)
7278 if (mReflowCountMgr) {
7279 mReflowCountMgr->SetPaintFrameCounts(aPaintFrameCounts);
7281 return NS_OK;
7284 //------------------------------------------------------------------
7285 //-- Reflow Counter Classes Impls
7286 //------------------------------------------------------------------
7288 //------------------------------------------------------------------
7289 ReflowCounter::ReflowCounter(ReflowCountMgr * aMgr) :
7290 mMgr(aMgr)
7292 ClearTotals();
7293 SetTotalsCache();
7296 //------------------------------------------------------------------
7297 ReflowCounter::~ReflowCounter()
7302 //------------------------------------------------------------------
7303 void ReflowCounter::ClearTotals()
7305 mTotal = 0;
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)
7341 // figure total
7342 if (aTotal == 0) {
7343 return;
7345 ReflowCounter * gTots = (ReflowCounter *)mMgr->LookUp(kGrandTotalsStr);
7347 printf("%25s\t", aTitle);
7348 printf("%d\t", aTotal);
7349 if (gTots != this && aTotal > 0) {
7350 gTots->Add(aTotal);
7354 //------------------------------------------------------------------
7355 void ReflowCounter::DisplayHTMLTotals(PRUint32 aTotal, const char * aTitle)
7357 if (aTotal == 0) {
7358 return;
7361 ReflowCounter * gTots = (ReflowCounter *)mMgr->LookUp(kGrandTotalsStr);
7362 FILE * fd = mMgr->GetOutFile();
7363 if (!fd) {
7364 return;
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) {
7371 gTots->Add(aTotal);
7375 //------------------------------------------------------------------
7376 //-- ReflowCountMgr
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()
7393 CleanUp();
7396 //------------------------------------------------------------------
7397 ReflowCounter * ReflowCountMgr::LookUp(const char * aName)
7399 if (nsnull != mCounts) {
7400 ReflowCounter * counter = (ReflowCounter *)PL_HashTableLookup(mCounts, aName);
7401 return counter;
7403 return nsnull;
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);
7421 counter->Add();
7424 if ((mDumpFrameByFrameCounts || mPaintFrameByFrameCounts) &&
7425 nsnull != mIndiFrameCounts &&
7426 aFrame != nsnull) {
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)) {
7439 counter->mCount++;
7440 counter->mCounter.Add(1);
7445 //------------------------------------------------------------------
7446 void ReflowCountMgr::PaintCount(const char * aName,
7447 nsIRenderingContext* aRenderingContext,
7448 nsPresContext* aPresContext,
7449 nsIFrame* aFrame,
7450 PRUint32 aColor)
7452 if (mPaintFrameByFrameCounts &&
7453 nsnull != mIndiFrameCounts &&
7454 aFrame != nsnull) {
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);
7466 char buf[16];
7467 sprintf(buf, "%d", counter->mCount);
7468 nscoord x = 0, y;
7469 nscoord width, height;
7470 aRenderingContext->SetTextRunRTL(PR_FALSE);
7471 aRenderingContext->GetWidth((char*)buf, width);
7472 fm->GetHeight(height);
7473 fm->GetMaxAscent(y);
7475 PRUint32 color;
7476 PRUint32 color2;
7477 if (aColor != 0) {
7478 color = aColor;
7479 color2 = NS_RGB(0,0,0);
7480 } else {
7481 PRUint8 rc = 0, gc = 0, bc = 0;
7482 if (counter->mCount < 5) {
7483 rc = 255;
7484 gc = 255;
7485 } else if ( counter->mCount < 11) {
7486 gc = 255;
7487 } else {
7488 rc = 255;
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;
7512 delete counter;
7513 NS_Free(str);
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;
7523 delete counter;
7524 NS_Free(str);
7526 return HT_ENUMERATE_REMOVE;
7529 //------------------------------------------------------------------
7530 void ReflowCountMgr::CleanUp()
7532 if (nsnull != mCounts) {
7533 PL_HashTableEnumerateEntries(mCounts, RemoveItems, nsnull);
7534 PL_HashTableDestroy(mCounts);
7535 mCounts = nsnull;
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);
7564 } else {
7565 gTots->ClearTotals();
7568 printf("\t\t\t\tTotal\n");
7569 for (PRUint32 i=0;i<78;i++) {
7570 printf("-");
7572 printf("\n");
7573 PL_HashTableEnumerateEntries(mCounts, DoSingleTotal, this);
7577 static void RecurseIndiTotals(nsPresContext* aPresContext,
7578 PLHashTable * aHT,
7579 nsIFrame * aParentFrame,
7580 PRInt32 aLevel)
7582 if (aParentFrame == nsnull) {
7583 return;
7586 char key[16];
7587 sprintf(key, "%p", (void*)aParentFrame);
7588 IndiReflowCounter * counter = (IndiReflowCounter *)PL_HashTableLookup(aHT, key);
7589 if (counter) {
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());
7595 printf("]\n");
7596 nsMemory::Free(name);
7599 nsIFrame* child = aParentFrame->GetFirstChild(nsnull);
7600 while (child) {
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());
7615 printf("]\n");
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");
7629 if (mPresShell) {
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);
7659 } else {
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)
7676 #ifdef DEBUG_rods
7677 printf("%s\n", aStr?aStr:"No name");
7678 #endif
7679 if (mDumpFrameCounts) {
7680 DoGrandTotals();
7682 if (mDumpFrameByFrameCounts) {
7683 DoIndiTotalsTree();
7687 //------------------------------------
7688 void ReflowCountMgr::DisplayHTMLTotals(const char * aStr)
7690 #ifdef WIN32x // XXX NOT XP!
7691 char name[1024];
7693 char * sptr = strrchr(aStr, '/');
7694 if (sptr) {
7695 sptr++;
7696 strcpy(name, sptr);
7697 char * eptr = strrchr(name, '.');
7698 if (eptr) {
7699 *eptr = 0;
7701 strcat(name, "_stats.html");
7703 mFD = fopen(name, "w");
7704 if (mFD) {
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");
7711 fclose(mFD);
7712 mFD = nsnull;
7714 #endif // not XP!
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);
7740 } else {
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;
7755 if (cycledOnce) {
7756 counter->CalcDiffInTotals();
7757 counter->DisplayDiffTotals(str);
7759 counter->SetTotalsCache();
7761 return HT_ENUMERATE_NEXT;
7764 //------------------------------------------------------------------
7765 void ReflowCountMgr::DisplayDiffsInTotals(const char * aStr)
7767 if (mCycledOnce) {
7768 printf("Differences\n");
7769 for (PRInt32 i=0;i<78;i++) {
7770 printf("-");
7772 printf("\n");
7773 ClearGrandTotals();
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)
7785 char buf[8];
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);