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
5 : *
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/
10 : *
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.
15 : *
16 : * The Original Code is mozilla.org code.
17 : *
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.
22 : *
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 <matspal@gmail.com>
29 : * Mihai Sucan <mihai.sucan@gmail.com>
30 : *
31 : * Alternatively, the contents of this file may be used under the terms of
32 : * either of the GNU General Public License Version 2 or later (the "GPL"),
33 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
34 : * in which case the provisions of the GPL or the LGPL are applicable instead
35 : * of those above. If you wish to allow use of your version of this file only
36 : * under the terms of either the GPL or the LGPL, and not to allow others to
37 : * use your version of this file under the terms of the MPL, indicate your
38 : * decision by deleting the provisions above and replace them with the notice
39 : * and other provisions required by the GPL or the LGPL. If you do not delete
40 : * the provisions above, a recipient may use your version of this file under
41 : * the terms of any one of the MPL, the GPL or the LGPL.
42 : *
43 : * ***** END LICENSE BLOCK *****
44 : *
45 : * This Original Code has been modified by IBM Corporation.
46 : * Modifications made by IBM described herein are
47 : * Copyright (c) International Business Machines
48 : * Corporation, 2000
49 : *
50 : * Modifications to Mozilla code or documentation
51 : * identified per MPL Section 3.3
52 : *
53 : * Date Modified by Description of modification
54 : * 05/03/2000 IBM Corp. Observer events for reflow states
55 : */
56 :
57 : /* a presentation of a document, part 2 */
58 :
59 : #include "mozilla/dom/PBrowserChild.h"
60 : #include "mozilla/dom/TabChild.h"
61 : #include "mozilla/Util.h"
62 :
63 : #ifdef XP_WIN
64 : #include "winuser.h"
65 : #endif
66 :
67 : #include "nsPresShell.h"
68 : #include "nsPresContext.h"
69 : #include "nsIContent.h"
70 : #include "mozilla/dom/Element.h"
71 : #include "nsIDocument.h"
72 : #include "nsIDOMXULDocument.h"
73 : #include "nsCSSStyleSheet.h" // XXX for UA sheet loading hack, can this go away please?
74 : #include "nsIDOMCSSStyleSheet.h" // for Pref-related rule management (bugs 22963,20760,31816)
75 : #include "nsAnimationManager.h"
76 : #include "nsINameSpaceManager.h" // for Pref-related rule management (bugs 22963,20760,31816)
77 : #include "nsIServiceManager.h"
78 : #include "nsFrame.h"
79 : #include "nsViewManager.h"
80 : #include "nsView.h"
81 : #include "nsCRTGlue.h"
82 : #include "prlog.h"
83 : #include "prmem.h"
84 : #include "prprf.h"
85 : #include "prinrval.h"
86 : #include "nsTArray.h"
87 : #include "nsCOMArray.h"
88 : #include "nsHashtable.h"
89 : #include "nsContainerFrame.h"
90 : #include "nsDOMEvent.h"
91 : #include "nsHTMLParts.h"
92 : #include "nsISelection.h"
93 : #include "nsISelectionPrivate.h"
94 : #include "nsLayoutCID.h"
95 : #include "nsGkAtoms.h"
96 : #include "nsIDOMRange.h"
97 : #include "nsIDOMDocument.h"
98 : #include "nsIDOMNode.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 "nsIPageSequenceFrame.h"
108 : #include "nsCaret.h"
109 : #include "nsIDOMHTMLDocument.h"
110 : #include "nsIDOMXMLDocument.h"
111 : #include "nsIParser.h"
112 : #include "nsParserCIID.h"
113 : #include "nsViewsCID.h"
114 : #include "nsFrameManager.h"
115 : #include "nsEventStateManager.h"
116 : #include "nsXPCOM.h"
117 : #include "nsISupportsPrimitives.h"
118 : #include "nsILayoutHistoryState.h"
119 : #include "nsILineIterator.h" // for ScrollContentIntoView
120 : #include "nsWeakPtr.h"
121 : #include "pldhash.h"
122 : #include "nsDOMTouchEvent.h"
123 : #include "nsIObserverService.h"
124 : #include "nsIDocShell.h" // for reflow observation
125 : #include "nsIBaseWindow.h"
126 : #include "nsLayoutErrors.h"
127 : #include "nsLayoutUtils.h"
128 : #include "nsCSSRendering.h"
129 : // for |#ifdef DEBUG| code
130 : #include "prenv.h"
131 : #include "nsAlgorithm.h"
132 : #include "nsIAttribute.h"
133 : #include "nsIGlobalHistory2.h"
134 : #include "nsDisplayList.h"
135 : #include "nsRegion.h"
136 : #include "nsRenderingContext.h"
137 : #include "nsAutoLayoutPhase.h"
138 : #ifdef MOZ_REFLOW_PERF
139 : #include "nsFontMetrics.h"
140 : #endif
141 :
142 : #include "nsIReflowCallback.h"
143 :
144 : #include "nsPIDOMWindow.h"
145 : #include "nsFocusManager.h"
146 : #include "nsNPAPIPluginInstance.h"
147 : #include "nsIObjectFrame.h"
148 : #include "nsIObjectLoadingContent.h"
149 : #include "nsNetUtil.h"
150 : #include "nsEventDispatcher.h"
151 : #include "nsThreadUtils.h"
152 : #include "nsStyleSheetService.h"
153 : #include "gfxImageSurface.h"
154 : #include "gfxContext.h"
155 : #ifdef MOZ_MEDIA
156 : #include "nsHTMLMediaElement.h"
157 : #endif
158 : #include "nsSMILAnimationController.h"
159 :
160 : #include "nsRefreshDriver.h"
161 :
162 : // Drag & Drop, Clipboard
163 : #include "nsWidgetsCID.h"
164 : #include "nsIClipboard.h"
165 : #include "nsIClipboardHelper.h"
166 : #include "nsIDocShellTreeItem.h"
167 : #include "nsIURI.h"
168 : #include "nsIScrollableFrame.h"
169 : #include "prtime.h"
170 : #include "prlong.h"
171 : #include "nsIDragService.h"
172 : #include "nsCopySupport.h"
173 : #include "nsIDOMHTMLAnchorElement.h"
174 : #include "nsIDOMHTMLAreaElement.h"
175 : #include "nsIDOMHTMLLinkElement.h"
176 : #include "nsITimer.h"
177 : #ifdef ACCESSIBILITY
178 : #include "nsAccessibilityService.h"
179 : #endif
180 :
181 : // For style data reconstruction
182 : #include "nsStyleChangeList.h"
183 : #include "nsCSSFrameConstructor.h"
184 : #ifdef MOZ_XUL
185 : #include "nsMenuFrame.h"
186 : #include "nsTreeBodyFrame.h"
187 : #include "nsIBoxObject.h"
188 : #include "nsITreeBoxObject.h"
189 : #include "nsMenuPopupFrame.h"
190 : #include "nsITreeColumns.h"
191 : #include "nsIDOMXULMultSelectCntrlEl.h"
192 : #include "nsIDOMXULSelectCntrlItemEl.h"
193 : #include "nsIDOMXULMenuListElement.h"
194 :
195 : #endif
196 : #include "nsPlaceholderFrame.h"
197 : #include "nsCanvasFrame.h"
198 :
199 : // Content viewer interfaces
200 : #include "nsIContentViewer.h"
201 : #include "imgIEncoder.h"
202 : #include "gfxPlatform.h"
203 :
204 : #include "mozilla/FunctionTimer.h"
205 : #include "mozilla/Preferences.h"
206 : #include "mozilla/Telemetry.h"
207 : #include "sampler.h"
208 :
209 : #include "Layers.h"
210 : #include "nsAsyncDOMEvent.h"
211 :
212 : #ifdef NS_FUNCTION_TIMER
213 : #define NS_TIME_FUNCTION_DECLARE_DOCURL \
214 : nsCAutoString docURL__("N/A"); \
215 : nsIURI *uri__ = mDocument->GetDocumentURI(); \
216 : if (uri__) uri__->GetSpec(docURL__);
217 : #define NS_TIME_FUNCTION_WITH_DOCURL \
218 : NS_TIME_FUNCTION_DECLARE_DOCURL \
219 : NS_TIME_FUNCTION_MIN_FMT(1.0, \
220 : "%s (line %d) (document: %s)", MOZ_FUNCTION_NAME, \
221 : __LINE__, docURL__.get())
222 : #else
223 : #define NS_TIME_FUNCTION_WITH_DOCURL do{} while(0)
224 : #endif
225 :
226 : #define ANCHOR_SCROLL_FLAGS (SCROLL_OVERFLOW_HIDDEN | SCROLL_NO_PARENT_FRAMES)
227 :
228 : using namespace mozilla;
229 : using namespace mozilla::dom;
230 : using namespace mozilla::layers;
231 :
232 : CapturingContentInfo nsIPresShell::gCaptureInfo =
233 : { false /* mAllowed */, false /* mRetargetToElement */,
234 : false /* mPreventDrag */, nsnull /* mContent */ };
235 : nsIContent* nsIPresShell::gKeyDownTarget;
236 1464 : nsInterfaceHashtable<nsUint32HashKey, nsIDOMTouch> nsIPresShell::gCaptureTouchList;
237 : bool nsIPresShell::gPreventMouseEvents = false;
238 :
239 : static PRUint32
240 0 : ChangeFlag(PRUint32 aFlags, bool aOnOff, PRUint32 aFlag)
241 : {
242 : PRUint32 flags;
243 0 : if (aOnOff) {
244 0 : flags = (aFlags | aFlag);
245 : } else {
246 0 : flags = (aFlag & ~aFlag);
247 : }
248 0 : return flags;
249 : }
250 :
251 : // convert a color value to a string, in the CSS format #RRGGBB
252 : // * - initially created for bugs 31816, 20760, 22963
253 : static void ColorToString(nscolor aColor, nsAutoString &aString);
254 :
255 : // RangePaintInfo is used to paint ranges to offscreen buffers
256 : struct RangePaintInfo {
257 : nsRefPtr<nsRange> mRange;
258 : nsDisplayListBuilder mBuilder;
259 : nsDisplayList mList;
260 :
261 : // offset of builder's reference frame to the root frame
262 : nsPoint mRootOffset;
263 :
264 0 : RangePaintInfo(nsRange* aRange, nsIFrame* aFrame)
265 0 : : mRange(aRange), mBuilder(aFrame, nsDisplayListBuilder::PAINTING, false)
266 : {
267 0 : MOZ_COUNT_CTOR(RangePaintInfo);
268 0 : }
269 :
270 0 : ~RangePaintInfo()
271 0 : {
272 0 : mList.DeleteAll();
273 0 : MOZ_COUNT_DTOR(RangePaintInfo);
274 0 : }
275 : };
276 :
277 : #undef NOISY
278 :
279 : // ----------------------------------------------------------------------
280 :
281 : #ifdef NS_DEBUG
282 : // Set the environment variable GECKO_VERIFY_REFLOW_FLAGS to one or
283 : // more of the following flags (comma separated) for handy debug
284 : // output.
285 : static PRUint32 gVerifyReflowFlags;
286 :
287 : struct VerifyReflowFlags {
288 : const char* name;
289 : PRUint32 bit;
290 : };
291 :
292 : static const VerifyReflowFlags gFlags[] = {
293 : { "verify", VERIFY_REFLOW_ON },
294 : { "reflow", VERIFY_REFLOW_NOISY },
295 : { "all", VERIFY_REFLOW_ALL },
296 : { "list-commands", VERIFY_REFLOW_DUMP_COMMANDS },
297 : { "noisy-commands", VERIFY_REFLOW_NOISY_RC },
298 : { "really-noisy-commands", VERIFY_REFLOW_REALLY_NOISY_RC },
299 : { "resize", VERIFY_REFLOW_DURING_RESIZE_REFLOW },
300 : };
301 :
302 : #define NUM_VERIFY_REFLOW_FLAGS (sizeof(gFlags) / sizeof(gFlags[0]))
303 :
304 : static void
305 0 : ShowVerifyReflowFlags()
306 : {
307 0 : printf("Here are the available GECKO_VERIFY_REFLOW_FLAGS:\n");
308 0 : const VerifyReflowFlags* flag = gFlags;
309 0 : const VerifyReflowFlags* limit = gFlags + NUM_VERIFY_REFLOW_FLAGS;
310 0 : while (flag < limit) {
311 0 : printf(" %s\n", flag->name);
312 0 : ++flag;
313 : }
314 0 : printf("Note: GECKO_VERIFY_REFLOW_FLAGS is a comma separated list of flag\n");
315 0 : printf("names (no whitespace)\n");
316 0 : }
317 : #endif
318 :
319 : //========================================================================
320 : //========================================================================
321 : //========================================================================
322 : #ifdef MOZ_REFLOW_PERF
323 : class ReflowCountMgr;
324 :
325 : static const char kGrandTotalsStr[] = "Grand Totals";
326 :
327 : // Counting Class
328 : class ReflowCounter {
329 : public:
330 : ReflowCounter(ReflowCountMgr * aMgr = nsnull);
331 : ~ReflowCounter();
332 :
333 : void ClearTotals();
334 : void DisplayTotals(const char * aStr);
335 : void DisplayDiffTotals(const char * aStr);
336 : void DisplayHTMLTotals(const char * aStr);
337 :
338 0 : void Add() { mTotal++; }
339 0 : void Add(PRUint32 aTotal) { mTotal += aTotal; }
340 :
341 : void CalcDiffInTotals();
342 : void SetTotalsCache();
343 :
344 : void SetMgr(ReflowCountMgr * aMgr) { mMgr = aMgr; }
345 :
346 0 : PRUint32 GetTotal() { return mTotal; }
347 :
348 : protected:
349 : void DisplayTotals(PRUint32 aTotal, const char * aTitle);
350 : void DisplayHTMLTotals(PRUint32 aTotal, const char * aTitle);
351 :
352 : PRUint32 mTotal;
353 : PRUint32 mCacheTotal;
354 :
355 : ReflowCountMgr * mMgr; // weak reference (don't delete)
356 : };
357 :
358 : // Counting Class
359 : class IndiReflowCounter {
360 : public:
361 0 : IndiReflowCounter(ReflowCountMgr * aMgr = nsnull)
362 : : mFrame(nsnull),
363 : mCount(0),
364 : mMgr(aMgr),
365 : mCounter(aMgr),
366 0 : mHasBeenOutput(false)
367 0 : {}
368 0 : virtual ~IndiReflowCounter() {}
369 :
370 : nsAutoString mName;
371 : nsIFrame * mFrame; // weak reference (don't delete)
372 : PRInt32 mCount;
373 :
374 : ReflowCountMgr * mMgr; // weak reference (don't delete)
375 :
376 : ReflowCounter mCounter;
377 : bool mHasBeenOutput;
378 :
379 : };
380 :
381 : //--------------------
382 : // Manager Class
383 : //--------------------
384 : class ReflowCountMgr {
385 : public:
386 : ReflowCountMgr();
387 : virtual ~ReflowCountMgr();
388 :
389 : void ClearTotals();
390 : void ClearGrandTotals();
391 : void DisplayTotals(const char * aStr);
392 : void DisplayHTMLTotals(const char * aStr);
393 : void DisplayDiffsInTotals(const char * aStr);
394 :
395 : void Add(const char * aName, nsIFrame * aFrame);
396 : ReflowCounter * LookUp(const char * aName);
397 :
398 : void PaintCount(const char *aName, nsRenderingContext* aRenderingContext,
399 : nsPresContext *aPresContext, nsIFrame *aFrame,
400 : const nsPoint &aOffset, PRUint32 aColor);
401 :
402 0 : FILE * GetOutFile() { return mFD; }
403 :
404 : PLHashTable * GetIndiFrameHT() { return mIndiFrameCounts; }
405 :
406 0 : void SetPresContext(nsPresContext * aPresContext) { mPresContext = aPresContext; } // weak reference
407 0 : void SetPresShell(nsIPresShell* aPresShell) { mPresShell= aPresShell; } // weak reference
408 :
409 0 : void SetDumpFrameCounts(bool aVal) { mDumpFrameCounts = aVal; }
410 0 : void SetDumpFrameByFrameCounts(bool aVal) { mDumpFrameByFrameCounts = aVal; }
411 0 : void SetPaintFrameCounts(bool aVal) { mPaintFrameByFrameCounts = aVal; }
412 :
413 0 : bool IsPaintingFrameCounts() { return mPaintFrameByFrameCounts; }
414 :
415 : protected:
416 : void DisplayTotals(PRUint32 aTotal, PRUint32 * aDupArray, char * aTitle);
417 : void DisplayHTMLTotals(PRUint32 aTotal, PRUint32 * aDupArray, char * aTitle);
418 :
419 : static PRIntn RemoveItems(PLHashEntry *he, PRIntn i, void *arg);
420 : static PRIntn RemoveIndiItems(PLHashEntry *he, PRIntn i, void *arg);
421 : void CleanUp();
422 :
423 : // stdout Output Methods
424 : static PRIntn DoSingleTotal(PLHashEntry *he, PRIntn i, void *arg);
425 : static PRIntn DoSingleIndi(PLHashEntry *he, PRIntn i, void *arg);
426 :
427 : void DoGrandTotals();
428 : void DoIndiTotalsTree();
429 :
430 : // HTML Output Methods
431 : static PRIntn DoSingleHTMLTotal(PLHashEntry *he, PRIntn i, void *arg);
432 : void DoGrandHTMLTotals();
433 :
434 : // Zero Out the Totals
435 : static PRIntn DoClearTotals(PLHashEntry *he, PRIntn i, void *arg);
436 :
437 : // Displays the Diff Totals
438 : static PRIntn DoDisplayDiffTotals(PLHashEntry *he, PRIntn i, void *arg);
439 :
440 : PLHashTable * mCounts;
441 : PLHashTable * mIndiFrameCounts;
442 : FILE * mFD;
443 :
444 : bool mDumpFrameCounts;
445 : bool mDumpFrameByFrameCounts;
446 : bool mPaintFrameByFrameCounts;
447 :
448 : bool mCycledOnce;
449 :
450 : // Root Frame for Individual Tracking
451 : nsPresContext * mPresContext;
452 : nsIPresShell* mPresShell;
453 :
454 : // ReflowCountMgr gReflowCountMgr;
455 : };
456 : #endif
457 : //========================================================================
458 :
459 : // comment out to hide caret
460 : #define SHOW_CARET
461 :
462 : // The upper bound on the amount of time to spend reflowing, in
463 : // microseconds. When this bound is exceeded and reflow commands are
464 : // still queued up, a reflow event is posted. The idea is for reflow
465 : // to not hog the processor beyond the time specifed in
466 : // gMaxRCProcessingTime. This data member is initialized from the
467 : // layout.reflow.timeslice pref.
468 : #define NS_MAX_REFLOW_TIME 1000000
469 : static PRInt32 gMaxRCProcessingTime = -1;
470 :
471 0 : StackArena::StackArena()
472 : {
473 0 : mMarkLength = 0;
474 0 : mMarks = nsnull;
475 :
476 : // allocate our stack memory
477 0 : mBlocks = new StackBlock();
478 0 : mCurBlock = mBlocks;
479 :
480 0 : mStackTop = 0;
481 0 : mPos = 0;
482 0 : }
483 :
484 0 : StackArena::~StackArena()
485 : {
486 : // free up our data
487 0 : delete[] mMarks;
488 0 : while(mBlocks)
489 : {
490 0 : StackBlock* toDelete = mBlocks;
491 0 : mBlocks = mBlocks->mNext;
492 0 : delete toDelete;
493 : }
494 0 : }
495 :
496 : void
497 0 : StackArena::Push()
498 : {
499 : // Resize the mark array if we overrun it. Failure to allocate the
500 : // mark array is not fatal; we just won't free to that mark. This
501 : // allows callers not to worry about error checking.
502 0 : if (mStackTop >= mMarkLength)
503 : {
504 0 : PRUint32 newLength = mStackTop + STACK_ARENA_MARK_INCREMENT;
505 0 : StackMark* newMarks = new StackMark[newLength];
506 0 : if (newMarks) {
507 0 : if (mMarkLength)
508 0 : memcpy(newMarks, mMarks, sizeof(StackMark)*mMarkLength);
509 : // Fill in any marks that we couldn't allocate during a prior call
510 : // to Push().
511 0 : for (; mMarkLength < mStackTop; ++mMarkLength) {
512 0 : NS_NOTREACHED("should only hit this on out-of-memory");
513 0 : newMarks[mMarkLength].mBlock = mCurBlock;
514 0 : newMarks[mMarkLength].mPos = mPos;
515 : }
516 0 : delete [] mMarks;
517 0 : mMarks = newMarks;
518 0 : mMarkLength = newLength;
519 : }
520 : }
521 :
522 : // set a mark at the top (if we can)
523 0 : NS_ASSERTION(mStackTop < mMarkLength, "out of memory");
524 0 : if (mStackTop < mMarkLength) {
525 0 : mMarks[mStackTop].mBlock = mCurBlock;
526 0 : mMarks[mStackTop].mPos = mPos;
527 : }
528 :
529 0 : mStackTop++;
530 0 : }
531 :
532 : void*
533 0 : StackArena::Allocate(size_t aSize)
534 : {
535 0 : NS_ASSERTION(mStackTop > 0, "Allocate called without Push");
536 :
537 : // make sure we are aligned. Beard said 8 was safer then 4.
538 : // Round size to multiple of 8
539 0 : aSize = NS_ROUNDUP<size_t>(aSize, 8);
540 :
541 : // if the size makes the stack overflow. Grab another block for the stack
542 0 : if (mPos + aSize >= STACK_ARENA_BLOCK_INCREMENT)
543 : {
544 0 : NS_ASSERTION(aSize <= STACK_ARENA_BLOCK_INCREMENT,
545 : "Requested memory is greater that our block size!!");
546 0 : if (mCurBlock->mNext == nsnull)
547 0 : mCurBlock->mNext = new StackBlock();
548 :
549 0 : mCurBlock = mCurBlock->mNext;
550 0 : mPos = 0;
551 : }
552 :
553 : // return the chunk they need.
554 0 : void *result = mCurBlock->mBlock + mPos;
555 0 : mPos += aSize;
556 :
557 0 : return result;
558 : }
559 :
560 : void
561 0 : StackArena::Pop()
562 : {
563 : // pop off the mark
564 0 : NS_ASSERTION(mStackTop > 0, "unmatched pop");
565 0 : mStackTop--;
566 :
567 0 : if (mStackTop >= mMarkLength) {
568 : // We couldn't allocate the marks array at the time of the push, so
569 : // we don't know where we're freeing to.
570 0 : NS_NOTREACHED("out of memory");
571 0 : if (mStackTop == 0) {
572 : // But we do know if we've completely pushed the stack.
573 0 : mCurBlock = mBlocks;
574 0 : mPos = 0;
575 : }
576 0 : return;
577 : }
578 :
579 : #ifdef DEBUG
580 : // Mark the "freed" memory with 0xdd to help with debugging of memory
581 : // allocation problems.
582 : {
583 0 : StackBlock *block = mMarks[mStackTop].mBlock, *block_end = mCurBlock;
584 0 : size_t pos = mMarks[mStackTop].mPos;
585 0 : for (; block != block_end; block = block->mNext, pos = 0) {
586 0 : memset(block->mBlock + pos, 0xdd, sizeof(block->mBlock) - pos);
587 : }
588 0 : memset(block->mBlock + pos, 0xdd, mPos - pos);
589 : }
590 : #endif
591 :
592 0 : mCurBlock = mMarks[mStackTop].mBlock;
593 0 : mPos = mMarks[mStackTop].mPos;
594 : }
595 :
596 : struct nsCallbackEventRequest
597 : {
598 : nsIReflowCallback* callback;
599 : nsCallbackEventRequest* next;
600 : };
601 :
602 : // ----------------------------------------------------------------------------
603 : #define ASSERT_REFLOW_SCHEDULED_STATE() \
604 : NS_ASSERTION(mReflowScheduled == \
605 : GetPresContext()->RefreshDriver()-> \
606 : IsLayoutFlushObserver(this), "Unexpected state")
607 :
608 : class nsAutoCauseReflowNotifier
609 : {
610 : public:
611 0 : nsAutoCauseReflowNotifier(PresShell* aShell)
612 0 : : mShell(aShell)
613 : {
614 0 : mShell->WillCauseReflow();
615 0 : }
616 0 : ~nsAutoCauseReflowNotifier()
617 : {
618 : // This check should not be needed. Currently the only place that seem
619 : // to need it is the code that deals with bug 337586.
620 0 : if (!mShell->mHaveShutDown) {
621 0 : mShell->DidCauseReflow();
622 : }
623 : else {
624 0 : nsContentUtils::RemoveScriptBlocker();
625 : }
626 0 : }
627 :
628 : PresShell* mShell;
629 : };
630 :
631 : class NS_STACK_CLASS nsPresShellEventCB : public nsDispatchingCallback
632 0 : {
633 : public:
634 0 : nsPresShellEventCB(PresShell* aPresShell) : mPresShell(aPresShell) {}
635 :
636 0 : virtual void HandleEvent(nsEventChainPostVisitor& aVisitor)
637 : {
638 0 : if (aVisitor.mPresContext && aVisitor.mEvent->eventStructType != NS_EVENT) {
639 0 : nsIFrame* frame = mPresShell->GetCurrentEventFrame();
640 0 : if (frame) {
641 : frame->HandleEvent(aVisitor.mPresContext,
642 : (nsGUIEvent*) aVisitor.mEvent,
643 0 : &aVisitor.mEventStatus);
644 : }
645 : }
646 0 : }
647 :
648 : nsRefPtr<PresShell> mPresShell;
649 : };
650 :
651 : bool PresShell::sDisableNonTestMouseEvents = false;
652 :
653 : #ifdef PR_LOGGING
654 : PRLogModuleInfo* PresShell::gLog;
655 : #endif
656 :
657 : #ifdef NS_DEBUG
658 : static void
659 0 : VerifyStyleTree(nsPresContext* aPresContext, nsFrameManager* aFrameManager)
660 : {
661 0 : if (nsFrame::GetVerifyStyleTreeEnable()) {
662 0 : nsIFrame* rootFrame = aFrameManager->GetRootFrame();
663 0 : aFrameManager->DebugVerifyStyleTree(rootFrame);
664 : }
665 0 : }
666 : #define VERIFY_STYLE_TREE ::VerifyStyleTree(mPresContext, mFrameConstructor)
667 : #else
668 : #define VERIFY_STYLE_TREE
669 : #endif
670 :
671 : static bool gVerifyReflowEnabled;
672 :
673 : bool
674 0 : nsIPresShell::GetVerifyReflowEnable()
675 : {
676 : #ifdef NS_DEBUG
677 : static bool firstTime = true;
678 0 : if (firstTime) {
679 0 : firstTime = false;
680 0 : char* flags = PR_GetEnv("GECKO_VERIFY_REFLOW_FLAGS");
681 0 : if (flags) {
682 0 : bool error = false;
683 :
684 0 : for (;;) {
685 0 : char* comma = PL_strchr(flags, ',');
686 0 : if (comma)
687 0 : *comma = '\0';
688 :
689 0 : bool found = false;
690 0 : const VerifyReflowFlags* flag = gFlags;
691 0 : const VerifyReflowFlags* limit = gFlags + NUM_VERIFY_REFLOW_FLAGS;
692 0 : while (flag < limit) {
693 0 : if (PL_strcasecmp(flag->name, flags) == 0) {
694 0 : gVerifyReflowFlags |= flag->bit;
695 0 : found = true;
696 0 : break;
697 : }
698 0 : ++flag;
699 : }
700 :
701 0 : if (! found)
702 0 : error = true;
703 :
704 0 : if (! comma)
705 : break;
706 :
707 0 : *comma = ',';
708 0 : flags = comma + 1;
709 : }
710 :
711 0 : if (error)
712 0 : ShowVerifyReflowFlags();
713 : }
714 :
715 0 : if (VERIFY_REFLOW_ON & gVerifyReflowFlags) {
716 0 : gVerifyReflowEnabled = true;
717 :
718 0 : printf("Note: verifyreflow is enabled");
719 0 : if (VERIFY_REFLOW_NOISY & gVerifyReflowFlags) {
720 0 : printf(" (noisy)");
721 : }
722 0 : if (VERIFY_REFLOW_ALL & gVerifyReflowFlags) {
723 0 : printf(" (all)");
724 : }
725 0 : if (VERIFY_REFLOW_DUMP_COMMANDS & gVerifyReflowFlags) {
726 0 : printf(" (show reflow commands)");
727 : }
728 0 : if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) {
729 0 : printf(" (noisy reflow commands)");
730 0 : if (VERIFY_REFLOW_REALLY_NOISY_RC & gVerifyReflowFlags) {
731 0 : printf(" (REALLY noisy reflow commands)");
732 : }
733 : }
734 0 : printf("\n");
735 : }
736 : }
737 : #endif
738 0 : return gVerifyReflowEnabled;
739 : }
740 :
741 : void
742 0 : nsIPresShell::SetVerifyReflowEnable(bool aEnabled)
743 : {
744 0 : gVerifyReflowEnabled = aEnabled;
745 0 : }
746 :
747 : /* virtual */ void
748 0 : nsIPresShell::AddWeakFrameExternal(nsWeakFrame* aWeakFrame)
749 : {
750 0 : AddWeakFrameInternal(aWeakFrame);
751 0 : }
752 :
753 : void
754 0 : nsIPresShell::AddWeakFrameInternal(nsWeakFrame* aWeakFrame)
755 : {
756 0 : if (aWeakFrame->GetFrame()) {
757 0 : aWeakFrame->GetFrame()->AddStateBits(NS_FRAME_EXTERNAL_REFERENCE);
758 : }
759 0 : aWeakFrame->SetPreviousWeakFrame(mWeakFrames);
760 0 : mWeakFrames = aWeakFrame;
761 0 : }
762 :
763 : /* virtual */ void
764 0 : nsIPresShell::RemoveWeakFrameExternal(nsWeakFrame* aWeakFrame)
765 : {
766 0 : RemoveWeakFrameInternal(aWeakFrame);
767 0 : }
768 :
769 : void
770 0 : nsIPresShell::RemoveWeakFrameInternal(nsWeakFrame* aWeakFrame)
771 : {
772 0 : if (mWeakFrames == aWeakFrame) {
773 0 : mWeakFrames = aWeakFrame->GetPreviousWeakFrame();
774 0 : return;
775 : }
776 0 : nsWeakFrame* nextWeak = mWeakFrames;
777 0 : while (nextWeak && nextWeak->GetPreviousWeakFrame() != aWeakFrame) {
778 0 : nextWeak = nextWeak->GetPreviousWeakFrame();
779 : }
780 0 : if (nextWeak) {
781 0 : nextWeak->SetPreviousWeakFrame(aWeakFrame->GetPreviousWeakFrame());
782 : }
783 : }
784 :
785 : already_AddRefed<nsFrameSelection>
786 0 : nsIPresShell::FrameSelection()
787 : {
788 0 : NS_IF_ADDREF(mSelection);
789 0 : return mSelection;
790 : }
791 :
792 : //----------------------------------------------------------------------
793 :
794 : nsresult
795 0 : NS_NewPresShell(nsIPresShell** aInstancePtrResult)
796 : {
797 0 : NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr");
798 :
799 0 : if (!aInstancePtrResult)
800 0 : return NS_ERROR_NULL_POINTER;
801 :
802 0 : *aInstancePtrResult = new PresShell();
803 :
804 0 : NS_ADDREF(*aInstancePtrResult);
805 0 : return NS_OK;
806 : }
807 :
808 : static bool sSynthMouseMove = true;
809 :
810 0 : PresShell::PresShell()
811 0 : : mMouseLocation(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE)
812 : {
813 0 : mSelection = nsnull;
814 : #ifdef MOZ_REFLOW_PERF
815 0 : mReflowCountMgr = new ReflowCountMgr();
816 0 : mReflowCountMgr->SetPresContext(mPresContext);
817 0 : mReflowCountMgr->SetPresShell(this);
818 : #endif
819 : #ifdef PR_LOGGING
820 0 : if (! gLog)
821 0 : gLog = PR_NewLogModule("PresShell");
822 : #endif
823 0 : mSelectionFlags = nsISelectionDisplay::DISPLAY_TEXT | nsISelectionDisplay::DISPLAY_IMAGES;
824 0 : mIsThemeSupportDisabled = false;
825 0 : mIsActive = true;
826 0 : mFrozen = false;
827 : #ifdef DEBUG
828 0 : mPresArenaAllocCount = 0;
829 : #endif
830 0 : mRenderFlags = 0;
831 0 : mXResolution = 1.0;
832 0 : mYResolution = 1.0;
833 0 : mViewportOverridden = false;
834 :
835 : static bool addedSynthMouseMove = false;
836 0 : if (!addedSynthMouseMove) {
837 : Preferences::AddBoolVarCache(&sSynthMouseMove,
838 0 : "layout.reflow.synthMouseMove", true);
839 0 : addedSynthMouseMove = true;
840 : }
841 0 : }
842 :
843 0 : NS_IMPL_ISUPPORTS7(PresShell, nsIPresShell, nsIDocumentObserver,
844 : nsISelectionController,
845 : nsISelectionDisplay, nsIObserver, nsISupportsWeakReference,
846 : nsIMutationObserver)
847 :
848 0 : PresShell::~PresShell()
849 : {
850 0 : if (!mHaveShutDown) {
851 0 : NS_NOTREACHED("Someone did not call nsIPresShell::destroy");
852 0 : Destroy();
853 : }
854 :
855 0 : NS_ASSERTION(mCurrentEventContentStack.Count() == 0,
856 : "Huh, event content left on the stack in pres shell dtor!");
857 0 : NS_ASSERTION(mFirstCallbackEventRequest == nsnull &&
858 : mLastCallbackEventRequest == nsnull,
859 : "post-reflow queues not empty. This means we're leaking");
860 :
861 : #ifdef DEBUG
862 0 : MOZ_ASSERT(mPresArenaAllocCount == 0,
863 0 : "Some pres arena objects were not freed");
864 : #endif
865 :
866 0 : delete mStyleSet;
867 0 : delete mFrameConstructor;
868 :
869 0 : mCurrentEventContent = nsnull;
870 :
871 0 : NS_IF_RELEASE(mPresContext);
872 0 : NS_IF_RELEASE(mDocument);
873 0 : NS_IF_RELEASE(mSelection);
874 0 : }
875 :
876 : /**
877 : * Initialize the presentation shell. Create view manager and style
878 : * manager.
879 : */
880 : nsresult
881 0 : PresShell::Init(nsIDocument* aDocument,
882 : nsPresContext* aPresContext,
883 : nsIViewManager* aViewManager,
884 : nsStyleSet* aStyleSet,
885 : nsCompatibility aCompatMode)
886 : {
887 : NS_TIME_FUNCTION_MIN(1.0);
888 :
889 0 : NS_PRECONDITION(nsnull != aDocument, "null ptr");
890 0 : NS_PRECONDITION(nsnull != aPresContext, "null ptr");
891 0 : NS_PRECONDITION(nsnull != aViewManager, "null ptr");
892 : nsresult result;
893 :
894 0 : if ((nsnull == aDocument) || (nsnull == aPresContext) ||
895 : (nsnull == aViewManager)) {
896 0 : return NS_ERROR_NULL_POINTER;
897 : }
898 0 : if (mDocument) {
899 0 : NS_WARNING("PresShell double init'ed");
900 0 : return NS_ERROR_ALREADY_INITIALIZED;
901 : }
902 0 : result = mStackArena.Init();
903 0 : NS_ENSURE_SUCCESS(result, result);
904 :
905 0 : if (!mFramesToDirty.Init()) {
906 0 : return NS_ERROR_OUT_OF_MEMORY;
907 : }
908 :
909 0 : mDocument = aDocument;
910 0 : NS_ADDREF(mDocument);
911 0 : mViewManager = aViewManager;
912 :
913 : // Create our frame constructor.
914 0 : mFrameConstructor = new nsCSSFrameConstructor(mDocument, this);
915 :
916 0 : mFrameManager = mFrameConstructor;
917 :
918 : // The document viewer owns both view manager and pres shell.
919 0 : mViewManager->SetPresShell(this);
920 :
921 : // Bind the context to the presentation shell.
922 0 : mPresContext = aPresContext;
923 0 : NS_ADDREF(mPresContext);
924 0 : aPresContext->SetShell(this);
925 :
926 : // Now we can initialize the style set.
927 0 : result = aStyleSet->Init(aPresContext);
928 0 : NS_ENSURE_SUCCESS(result, result);
929 :
930 : // From this point on, any time we return an error we need to make
931 : // sure to null out mStyleSet first, since an error return from this
932 : // method will cause the caller to delete the style set, so we don't
933 : // want to delete it in our destructor.
934 0 : mStyleSet = aStyleSet;
935 :
936 : // Notify our prescontext that it now has a compatibility mode. Note that
937 : // this MUST happen after we set up our style set but before we create any
938 : // frames.
939 0 : mPresContext->CompatibilityModeChanged();
940 :
941 : // setup the preference style rules (no forced reflow), and do it
942 : // before creating any frames.
943 0 : SetPreferenceStyleRules(false);
944 :
945 0 : NS_ADDREF(mSelection = new nsFrameSelection());
946 :
947 : // Create and initialize the frame manager
948 : // XXXjwatt it would be better if we did this right after creating
949 : // mFrameConstructor, since the frame constructor and frame manager
950 : // are now the same object.
951 0 : result = mFrameConstructor->Init(mStyleSet);
952 0 : if (NS_FAILED(result)) {
953 0 : NS_WARNING("Frame manager initialization failed");
954 0 : mStyleSet = nsnull;
955 0 : return result;
956 : }
957 :
958 0 : mSelection->Init(this, nsnull);
959 :
960 : // Important: this has to happen after the selection has been set up
961 : #ifdef SHOW_CARET
962 : // make the caret
963 0 : mCaret = new nsCaret();
964 0 : mCaret->Init(this);
965 0 : mOriginalCaret = mCaret;
966 :
967 : //SetCaretEnabled(true); // make it show in browser windows
968 : #endif
969 : //set up selection to be displayed in document
970 : // Don't enable selection for print media
971 0 : nsPresContext::nsPresContextType type = aPresContext->Type();
972 0 : if (type != nsPresContext::eContext_PrintPreview &&
973 : type != nsPresContext::eContext_Print)
974 0 : SetDisplaySelection(nsISelectionController::SELECTION_DISABLED);
975 :
976 0 : if (gMaxRCProcessingTime == -1) {
977 : gMaxRCProcessingTime =
978 0 : Preferences::GetInt("layout.reflow.timeslice", NS_MAX_REFLOW_TIME);
979 : }
980 :
981 : {
982 0 : nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
983 0 : if (os) {
984 0 : os->AddObserver(this, "agent-sheet-added", false);
985 0 : os->AddObserver(this, "user-sheet-added", false);
986 0 : os->AddObserver(this, "agent-sheet-removed", false);
987 0 : os->AddObserver(this, "user-sheet-removed", false);
988 : #ifdef MOZ_XUL
989 0 : os->AddObserver(this, "chrome-flush-skin-caches", false);
990 : #endif
991 : }
992 : }
993 :
994 : // cache the drag service so we can check it during reflows
995 0 : mDragService = do_GetService("@mozilla.org/widget/dragservice;1");
996 :
997 : #ifdef MOZ_REFLOW_PERF
998 0 : if (mReflowCountMgr) {
999 : bool paintFrameCounts =
1000 0 : Preferences::GetBool("layout.reflow.showframecounts");
1001 :
1002 : bool dumpFrameCounts =
1003 0 : Preferences::GetBool("layout.reflow.dumpframecounts");
1004 :
1005 : bool dumpFrameByFrameCounts =
1006 0 : Preferences::GetBool("layout.reflow.dumpframebyframecounts");
1007 :
1008 0 : mReflowCountMgr->SetDumpFrameCounts(dumpFrameCounts);
1009 0 : mReflowCountMgr->SetDumpFrameByFrameCounts(dumpFrameByFrameCounts);
1010 0 : mReflowCountMgr->SetPaintFrameCounts(paintFrameCounts);
1011 : }
1012 : #endif
1013 :
1014 0 : if (mDocument->HasAnimationController()) {
1015 0 : nsSMILAnimationController* animCtrl = mDocument->GetAnimationController();
1016 0 : animCtrl->NotifyRefreshDriverCreated(GetPresContext()->RefreshDriver());
1017 : }
1018 :
1019 : // Get our activeness from the docShell.
1020 0 : QueryIsActive();
1021 :
1022 0 : return NS_OK;
1023 : }
1024 :
1025 : void
1026 0 : PresShell::Destroy()
1027 : {
1028 : NS_TIME_FUNCTION_MIN(1.0);
1029 :
1030 0 : NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
1031 : "destroy called on presshell while scripts not blocked");
1032 :
1033 : #ifdef MOZ_REFLOW_PERF
1034 0 : DumpReflows();
1035 0 : if (mReflowCountMgr) {
1036 0 : delete mReflowCountMgr;
1037 0 : mReflowCountMgr = nsnull;
1038 : }
1039 : #endif
1040 :
1041 0 : if (mHaveShutDown)
1042 0 : return;
1043 :
1044 : #ifdef ACCESSIBILITY
1045 0 : nsAccessibilityService* accService = AccService();
1046 0 : if (accService) {
1047 0 : accService->PresShellDestroyed(this);
1048 : }
1049 : #endif // ACCESSIBILITY
1050 :
1051 0 : MaybeReleaseCapturingContent();
1052 :
1053 0 : if (gKeyDownTarget && gKeyDownTarget->OwnerDoc() == mDocument) {
1054 0 : NS_RELEASE(gKeyDownTarget);
1055 : }
1056 :
1057 0 : mContentToScrollTo = nsnull;
1058 :
1059 0 : if (mPresContext) {
1060 : // We need to notify the destroying the nsPresContext to ESM for
1061 : // suppressing to use from ESM.
1062 0 : mPresContext->EventStateManager()->NotifyDestroyPresContext(mPresContext);
1063 : }
1064 :
1065 : {
1066 0 : nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
1067 0 : if (os) {
1068 0 : os->RemoveObserver(this, "agent-sheet-added");
1069 0 : os->RemoveObserver(this, "user-sheet-added");
1070 0 : os->RemoveObserver(this, "agent-sheet-removed");
1071 0 : os->RemoveObserver(this, "user-sheet-removed");
1072 : #ifdef MOZ_XUL
1073 0 : os->RemoveObserver(this, "chrome-flush-skin-caches");
1074 : #endif
1075 : }
1076 : }
1077 :
1078 : // If our paint suppression timer is still active, kill it.
1079 0 : if (mPaintSuppressionTimer) {
1080 0 : mPaintSuppressionTimer->Cancel();
1081 0 : mPaintSuppressionTimer = nsnull;
1082 : }
1083 :
1084 : // Same for our reflow continuation timer
1085 0 : if (mReflowContinueTimer) {
1086 0 : mReflowContinueTimer->Cancel();
1087 0 : mReflowContinueTimer = nsnull;
1088 : }
1089 :
1090 0 : mSynthMouseMoveEvent.Revoke();
1091 :
1092 0 : if (mCaret) {
1093 0 : mCaret->Terminate();
1094 0 : mCaret = nsnull;
1095 : }
1096 :
1097 0 : if (mSelection) {
1098 0 : mSelection->DisconnectFromPresShell();
1099 : }
1100 :
1101 : // release our pref style sheet, if we have one still
1102 0 : ClearPreferenceStyleRules();
1103 :
1104 0 : mIsDestroying = true;
1105 :
1106 : // We can't release all the event content in
1107 : // mCurrentEventContentStack here since there might be code on the
1108 : // stack that will release the event content too. Double release
1109 : // bad!
1110 :
1111 : // The frames will be torn down, so remove them from the current
1112 : // event frame stack (since they'd be dangling references if we'd
1113 : // leave them in) and null out the mCurrentEventFrame pointer as
1114 : // well.
1115 :
1116 0 : mCurrentEventFrame = nsnull;
1117 :
1118 0 : PRInt32 i, count = mCurrentEventFrameStack.Length();
1119 0 : for (i = 0; i < count; i++) {
1120 0 : mCurrentEventFrameStack[i] = nsnull;
1121 : }
1122 :
1123 0 : mFramesToDirty.Clear();
1124 :
1125 0 : if (mViewManager) {
1126 : // Clear the view manager's weak pointer back to |this| in case it
1127 : // was leaked.
1128 0 : mViewManager->SetPresShell(nsnull);
1129 0 : mViewManager = nsnull;
1130 : }
1131 :
1132 0 : mStyleSet->BeginShutdown(mPresContext);
1133 0 : nsRefreshDriver* rd = GetPresContext()->RefreshDriver();
1134 :
1135 : // This shell must be removed from the document before the frame
1136 : // hierarchy is torn down to avoid finding deleted frames through
1137 : // this presshell while the frames are being torn down
1138 0 : if (mDocument) {
1139 0 : NS_ASSERTION(mDocument->GetShell() == this, "Wrong shell?");
1140 0 : mDocument->DeleteShell();
1141 :
1142 0 : if (mDocument->HasAnimationController()) {
1143 0 : mDocument->GetAnimationController()->NotifyRefreshDriverDestroying(rd);
1144 : }
1145 : }
1146 :
1147 : // Revoke any pending events. We need to do this and cancel pending reflows
1148 : // before we destroy the frame manager, since apparently frame destruction
1149 : // sometimes spins the event queue when plug-ins are involved(!).
1150 0 : rd->RemoveLayoutFlushObserver(this);
1151 0 : rd->RevokeViewManagerFlush();
1152 :
1153 0 : mResizeEvent.Revoke();
1154 0 : if (mAsyncResizeTimerIsActive) {
1155 0 : mAsyncResizeEventTimer->Cancel();
1156 0 : mAsyncResizeTimerIsActive = false;
1157 : }
1158 :
1159 0 : CancelAllPendingReflows();
1160 0 : CancelPostedReflowCallbacks();
1161 :
1162 : // Destroy the frame manager. This will destroy the frame hierarchy
1163 0 : mFrameConstructor->WillDestroyFrameTree();
1164 :
1165 : // Destroy all frame properties (whose destruction was suppressed
1166 : // while destroying the frame tree, but which might contain more
1167 : // frames within the properties.
1168 0 : if (mPresContext) {
1169 : // Clear out the prescontext's property table -- since our frame tree is
1170 : // now dead, we shouldn't be looking up any more properties in that table.
1171 : // We want to do this before we call SetShell() on the prescontext, so
1172 : // property destructors can usefully call GetPresShell() on the
1173 : // prescontext.
1174 0 : mPresContext->PropertyTable()->DeleteAll();
1175 : }
1176 :
1177 :
1178 0 : NS_WARN_IF_FALSE(!mWeakFrames, "Weak frames alive after destroying FrameManager");
1179 0 : while (mWeakFrames) {
1180 0 : mWeakFrames->Clear(this);
1181 : }
1182 :
1183 : // Let the style set do its cleanup.
1184 0 : mStyleSet->Shutdown(mPresContext);
1185 :
1186 0 : if (mPresContext) {
1187 : // We hold a reference to the pres context, and it holds a weak link back
1188 : // to us. To avoid the pres context having a dangling reference, set its
1189 : // pres shell to NULL
1190 0 : mPresContext->SetShell(nsnull);
1191 :
1192 : // Clear the link handler (weak reference) as well
1193 0 : mPresContext->SetLinkHandler(nsnull);
1194 : }
1195 :
1196 0 : mHaveShutDown = true;
1197 : }
1198 :
1199 : // Dynamic stack memory allocation
1200 : /* virtual */ void
1201 0 : PresShell::PushStackMemory()
1202 : {
1203 0 : mStackArena.Push();
1204 0 : }
1205 :
1206 : /* virtual */ void
1207 0 : PresShell::PopStackMemory()
1208 : {
1209 0 : mStackArena.Pop();
1210 0 : }
1211 :
1212 : /* virtual */ void*
1213 0 : PresShell::AllocateStackMemory(size_t aSize)
1214 : {
1215 0 : return mStackArena.Allocate(aSize);
1216 : }
1217 :
1218 : void
1219 0 : PresShell::FreeFrame(nsQueryFrame::FrameIID aCode, void* aPtr)
1220 : {
1221 : #ifdef DEBUG
1222 0 : mPresArenaAllocCount--;
1223 : #endif
1224 0 : if (PRESARENA_MUST_FREE_DURING_DESTROY || !mIsDestroying)
1225 0 : mFrameArena.FreeByCode(aCode, aPtr);
1226 0 : }
1227 :
1228 : void*
1229 0 : PresShell::AllocateFrame(nsQueryFrame::FrameIID aCode, size_t aSize)
1230 : {
1231 : #ifdef DEBUG
1232 0 : mPresArenaAllocCount++;
1233 : #endif
1234 0 : void* result = mFrameArena.AllocateByCode(aCode, aSize);
1235 :
1236 0 : if (result) {
1237 0 : memset(result, 0, aSize);
1238 : }
1239 0 : return result;
1240 : }
1241 :
1242 : void
1243 0 : PresShell::FreeMisc(size_t aSize, void* aPtr)
1244 : {
1245 : #ifdef DEBUG
1246 0 : mPresArenaAllocCount--;
1247 : #endif
1248 0 : if (PRESARENA_MUST_FREE_DURING_DESTROY || !mIsDestroying)
1249 0 : mFrameArena.FreeBySize(aSize, aPtr);
1250 0 : }
1251 :
1252 : void*
1253 0 : PresShell::AllocateMisc(size_t aSize)
1254 : {
1255 : #ifdef DEBUG
1256 0 : mPresArenaAllocCount++;
1257 : #endif
1258 0 : return mFrameArena.AllocateBySize(aSize);
1259 : }
1260 :
1261 : void
1262 0 : nsIPresShell::SetAuthorStyleDisabled(bool aStyleDisabled)
1263 : {
1264 0 : if (aStyleDisabled != mStyleSet->GetAuthorStyleDisabled()) {
1265 0 : mStyleSet->SetAuthorStyleDisabled(aStyleDisabled);
1266 0 : ReconstructStyleData();
1267 : }
1268 0 : }
1269 :
1270 : bool
1271 0 : nsIPresShell::GetAuthorStyleDisabled() const
1272 : {
1273 0 : return mStyleSet->GetAuthorStyleDisabled();
1274 : }
1275 :
1276 : nsresult
1277 0 : PresShell::SetPreferenceStyleRules(bool aForceReflow)
1278 : {
1279 : NS_TIME_FUNCTION_MIN(1.0);
1280 :
1281 0 : if (!mDocument) {
1282 0 : return NS_ERROR_NULL_POINTER;
1283 : }
1284 :
1285 0 : nsPIDOMWindow *window = mDocument->GetWindow();
1286 :
1287 : // If the document doesn't have a window there's no need to notify
1288 : // its presshell about changes to preferences since the document is
1289 : // in a state where it doesn't matter any more (see
1290 : // DocumentViewerImpl::Close()).
1291 :
1292 0 : if (!window) {
1293 0 : return NS_ERROR_NULL_POINTER;
1294 : }
1295 :
1296 0 : NS_PRECONDITION(mPresContext, "presContext cannot be null");
1297 0 : if (mPresContext) {
1298 : // first, make sure this is not a chrome shell
1299 0 : if (nsContentUtils::IsInChromeDocshell(mDocument)) {
1300 0 : return NS_OK;
1301 : }
1302 :
1303 : #ifdef DEBUG_attinasi
1304 : printf("Setting Preference Style Rules:\n");
1305 : #endif
1306 : // if here, we need to create rules for the prefs
1307 : // - this includes the background-color, the text-color,
1308 : // the link color, the visited link color and the link-underlining
1309 :
1310 : // first clear any exising rules
1311 0 : nsresult result = ClearPreferenceStyleRules();
1312 :
1313 : // now the link rules (must come after the color rules, or links will not be correct color!)
1314 : // XXX - when there is both an override and agent pref stylesheet this won't matter,
1315 : // as the color rules will be overrides and the links rules will be agent
1316 0 : if (NS_SUCCEEDED(result)) {
1317 0 : result = SetPrefLinkRules();
1318 : }
1319 0 : if (NS_SUCCEEDED(result)) {
1320 0 : result = SetPrefFocusRules();
1321 : }
1322 0 : if (NS_SUCCEEDED(result)) {
1323 0 : result = SetPrefNoScriptRule();
1324 : }
1325 0 : if (NS_SUCCEEDED(result)) {
1326 0 : result = SetPrefNoFramesRule();
1327 : }
1328 : #ifdef DEBUG_attinasi
1329 : printf( "Preference Style Rules set: error=%ld\n", (long)result);
1330 : #endif
1331 :
1332 : // Note that this method never needs to force any calculation; the caller
1333 : // will recalculate style if needed
1334 :
1335 0 : return result;
1336 : }
1337 :
1338 0 : return NS_ERROR_NULL_POINTER;
1339 : }
1340 :
1341 0 : nsresult PresShell::ClearPreferenceStyleRules(void)
1342 : {
1343 0 : nsresult result = NS_OK;
1344 0 : if (mPrefStyleSheet) {
1345 0 : NS_ASSERTION(mStyleSet, "null styleset entirely unexpected!");
1346 0 : if (mStyleSet) {
1347 : // remove the sheet from the styleset:
1348 : // - note that we have to check for success by comparing the count before and after...
1349 : #ifdef NS_DEBUG
1350 0 : PRInt32 numBefore = mStyleSet->SheetCount(nsStyleSet::eUserSheet);
1351 0 : NS_ASSERTION(numBefore > 0, "no user stylesheets in styleset, but we have one!");
1352 : #endif
1353 0 : mStyleSet->RemoveStyleSheet(nsStyleSet::eUserSheet, mPrefStyleSheet);
1354 :
1355 : #ifdef DEBUG_attinasi
1356 : NS_ASSERTION((numBefore - 1) == mStyleSet->GetNumberOfUserStyleSheets(),
1357 : "Pref stylesheet was not removed");
1358 : printf("PrefStyleSheet removed\n");
1359 : #endif
1360 : // clear the sheet pointer: it is strictly historical now
1361 0 : mPrefStyleSheet = nsnull;
1362 : }
1363 : }
1364 0 : return result;
1365 : }
1366 :
1367 0 : nsresult PresShell::CreatePreferenceStyleSheet(void)
1368 : {
1369 : NS_TIME_FUNCTION_MIN(1.0);
1370 :
1371 0 : NS_ASSERTION(!mPrefStyleSheet, "prefStyleSheet already exists");
1372 0 : nsresult result = NS_NewCSSStyleSheet(getter_AddRefs(mPrefStyleSheet));
1373 0 : if (NS_SUCCEEDED(result)) {
1374 0 : NS_ASSERTION(mPrefStyleSheet, "null but no error");
1375 0 : nsCOMPtr<nsIURI> uri;
1376 0 : result = NS_NewURI(getter_AddRefs(uri), "about:PreferenceStyleSheet", nsnull);
1377 0 : if (NS_SUCCEEDED(result)) {
1378 0 : NS_ASSERTION(uri, "null but no error");
1379 0 : mPrefStyleSheet->SetURIs(uri, uri, uri);
1380 0 : mPrefStyleSheet->SetComplete();
1381 : PRUint32 index;
1382 : result =
1383 0 : mPrefStyleSheet->InsertRuleInternal(NS_LITERAL_STRING("@namespace url(http://www.w3.org/1999/xhtml);"),
1384 0 : 0, &index);
1385 0 : if (NS_SUCCEEDED(result)) {
1386 0 : mStyleSet->AppendStyleSheet(nsStyleSet::eUserSheet, mPrefStyleSheet);
1387 : }
1388 : }
1389 : }
1390 :
1391 : #ifdef DEBUG_attinasi
1392 : printf("CreatePrefStyleSheet completed: error=%ld\n",(long)result);
1393 : #endif
1394 :
1395 0 : if (NS_FAILED(result)) {
1396 0 : mPrefStyleSheet = nsnull;
1397 : }
1398 :
1399 0 : return result;
1400 : }
1401 :
1402 : // XXX We want these after the @namespace rule. Does order matter
1403 : // for these rules, or can we call StyleRule::StyleRuleCount()
1404 : // and just "append"?
1405 : static PRUint32 sInsertPrefSheetRulesAt = 1;
1406 :
1407 : nsresult
1408 0 : PresShell::SetPrefNoScriptRule()
1409 : {
1410 : NS_TIME_FUNCTION_MIN(1.0);
1411 :
1412 0 : nsresult rv = NS_OK;
1413 :
1414 : // also handle the case where print is done from print preview
1415 : // see bug #342439 for more details
1416 0 : nsIDocument* doc = mDocument;
1417 0 : if (doc->IsStaticDocument()) {
1418 0 : doc = doc->GetOriginalDocument();
1419 : }
1420 :
1421 0 : bool scriptEnabled = doc->IsScriptEnabled();
1422 0 : if (scriptEnabled) {
1423 0 : if (!mPrefStyleSheet) {
1424 0 : rv = CreatePreferenceStyleSheet();
1425 0 : NS_ENSURE_SUCCESS(rv, rv);
1426 : }
1427 :
1428 0 : PRUint32 index = 0;
1429 : mPrefStyleSheet->
1430 0 : InsertRuleInternal(NS_LITERAL_STRING("noscript{display:none!important}"),
1431 0 : sInsertPrefSheetRulesAt, &index);
1432 : }
1433 :
1434 0 : return rv;
1435 : }
1436 :
1437 0 : nsresult PresShell::SetPrefNoFramesRule(void)
1438 : {
1439 : NS_TIME_FUNCTION_MIN(1.0);
1440 :
1441 0 : NS_ASSERTION(mPresContext,"null prescontext not allowed");
1442 0 : if (!mPresContext) {
1443 0 : return NS_ERROR_FAILURE;
1444 : }
1445 :
1446 0 : nsresult rv = NS_OK;
1447 :
1448 0 : if (!mPrefStyleSheet) {
1449 0 : rv = CreatePreferenceStyleSheet();
1450 0 : NS_ENSURE_SUCCESS(rv, rv);
1451 : }
1452 :
1453 0 : NS_ASSERTION(mPrefStyleSheet, "prefstylesheet should not be null");
1454 :
1455 0 : bool allowSubframes = true;
1456 0 : nsCOMPtr<nsISupports> container = mPresContext->GetContainer();
1457 0 : nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(container));
1458 0 : if (docShell) {
1459 0 : docShell->GetAllowSubframes(&allowSubframes);
1460 : }
1461 0 : if (!allowSubframes) {
1462 0 : PRUint32 index = 0;
1463 : rv = mPrefStyleSheet->
1464 0 : InsertRuleInternal(NS_LITERAL_STRING("noframes{display:block}"),
1465 0 : sInsertPrefSheetRulesAt, &index);
1466 0 : NS_ENSURE_SUCCESS(rv, rv);
1467 : rv = mPrefStyleSheet->
1468 0 : InsertRuleInternal(NS_LITERAL_STRING("frame, frameset, iframe {display:none!important}"),
1469 0 : sInsertPrefSheetRulesAt, &index);
1470 : }
1471 0 : return rv;
1472 : }
1473 :
1474 0 : nsresult PresShell::SetPrefLinkRules(void)
1475 : {
1476 : NS_TIME_FUNCTION_MIN(1.0);
1477 :
1478 0 : NS_ASSERTION(mPresContext,"null prescontext not allowed");
1479 0 : if (!mPresContext) {
1480 0 : return NS_ERROR_FAILURE;
1481 : }
1482 :
1483 0 : nsresult rv = NS_OK;
1484 :
1485 0 : if (!mPrefStyleSheet) {
1486 0 : rv = CreatePreferenceStyleSheet();
1487 0 : NS_ENSURE_SUCCESS(rv, rv);
1488 : }
1489 :
1490 0 : NS_ASSERTION(mPrefStyleSheet, "prefstylesheet should not be null");
1491 :
1492 : // support default link colors:
1493 : // this means the link colors need to be overridable,
1494 : // which they are if we put them in the agent stylesheet,
1495 : // though if using an override sheet this will cause authors grief still
1496 : // In the agent stylesheet, they are !important when we are ignoring document colors
1497 :
1498 0 : nscolor linkColor(mPresContext->DefaultLinkColor());
1499 0 : nscolor activeColor(mPresContext->DefaultActiveLinkColor());
1500 0 : nscolor visitedColor(mPresContext->DefaultVisitedLinkColor());
1501 :
1502 0 : NS_NAMED_LITERAL_STRING(ruleClose, "}");
1503 0 : PRUint32 index = 0;
1504 0 : nsAutoString strColor;
1505 :
1506 : // insert a rule to color links: '*|*:link {color: #RRGGBB [!important];}'
1507 0 : ColorToString(linkColor, strColor);
1508 : rv = mPrefStyleSheet->
1509 0 : InsertRuleInternal(NS_LITERAL_STRING("*|*:link{color:") +
1510 0 : strColor + ruleClose,
1511 0 : sInsertPrefSheetRulesAt, &index);
1512 0 : NS_ENSURE_SUCCESS(rv, rv);
1513 :
1514 : // - visited links: '*|*:visited {color: #RRGGBB [!important];}'
1515 0 : ColorToString(visitedColor, strColor);
1516 : rv = mPrefStyleSheet->
1517 0 : InsertRuleInternal(NS_LITERAL_STRING("*|*:visited{color:") +
1518 0 : strColor + ruleClose,
1519 0 : sInsertPrefSheetRulesAt, &index);
1520 0 : NS_ENSURE_SUCCESS(rv, rv);
1521 :
1522 : // - active links: '*|*:-moz-any-link:active {color: #RRGGBB [!important];}'
1523 0 : ColorToString(activeColor, strColor);
1524 : rv = mPrefStyleSheet->
1525 0 : InsertRuleInternal(NS_LITERAL_STRING("*|*:-moz-any-link:active{color:") +
1526 0 : strColor + ruleClose,
1527 0 : sInsertPrefSheetRulesAt, &index);
1528 0 : NS_ENSURE_SUCCESS(rv, rv);
1529 :
1530 : bool underlineLinks =
1531 0 : mPresContext->GetCachedBoolPref(kPresContext_UnderlineLinks);
1532 :
1533 0 : if (underlineLinks) {
1534 : // create a rule to make underlining happen
1535 : // '*|*:-moz-any-link {text-decoration:[underline|none];}'
1536 : // no need for important, we want these to be overridable
1537 : // NOTE: these must go in the agent stylesheet or they cannot be
1538 : // overridden by authors
1539 : rv = mPrefStyleSheet->
1540 0 : InsertRuleInternal(NS_LITERAL_STRING("*|*:-moz-any-link{text-decoration:underline}"),
1541 0 : sInsertPrefSheetRulesAt, &index);
1542 : } else {
1543 : rv = mPrefStyleSheet->
1544 0 : InsertRuleInternal(NS_LITERAL_STRING("*|*:-moz-any-link{text-decoration:none}"),
1545 0 : sInsertPrefSheetRulesAt, &index);
1546 : }
1547 :
1548 0 : return rv;
1549 : }
1550 :
1551 0 : nsresult PresShell::SetPrefFocusRules(void)
1552 : {
1553 : NS_TIME_FUNCTION_MIN(1.0);
1554 :
1555 0 : NS_ASSERTION(mPresContext,"null prescontext not allowed");
1556 0 : nsresult result = NS_OK;
1557 :
1558 0 : if (!mPresContext)
1559 0 : result = NS_ERROR_FAILURE;
1560 :
1561 0 : if (NS_SUCCEEDED(result) && !mPrefStyleSheet)
1562 0 : result = CreatePreferenceStyleSheet();
1563 :
1564 0 : if (NS_SUCCEEDED(result)) {
1565 0 : NS_ASSERTION(mPrefStyleSheet, "prefstylesheet should not be null");
1566 :
1567 0 : if (mPresContext->GetUseFocusColors()) {
1568 0 : nscolor focusBackground(mPresContext->FocusBackgroundColor());
1569 0 : nscolor focusText(mPresContext->FocusTextColor());
1570 :
1571 : // insert a rule to make focus the preferred color
1572 0 : PRUint32 index = 0;
1573 0 : nsAutoString strRule, strColor;
1574 :
1575 : ///////////////////////////////////////////////////////////////
1576 : // - focus: '*:focus
1577 0 : ColorToString(focusText,strColor);
1578 0 : strRule.AppendLiteral("*:focus,*:focus>font {color: ");
1579 0 : strRule.Append(strColor);
1580 0 : strRule.AppendLiteral(" !important; background-color: ");
1581 0 : ColorToString(focusBackground,strColor);
1582 0 : strRule.Append(strColor);
1583 0 : strRule.AppendLiteral(" !important; } ");
1584 : // insert the rules
1585 : result = mPrefStyleSheet->
1586 0 : InsertRuleInternal(strRule, sInsertPrefSheetRulesAt, &index);
1587 : }
1588 0 : PRUint8 focusRingWidth = mPresContext->FocusRingWidth();
1589 0 : bool focusRingOnAnything = mPresContext->GetFocusRingOnAnything();
1590 0 : PRUint8 focusRingStyle = mPresContext->GetFocusRingStyle();
1591 :
1592 0 : if ((NS_SUCCEEDED(result) && focusRingWidth != 1 && focusRingWidth <= 4 ) || focusRingOnAnything) {
1593 0 : PRUint32 index = 0;
1594 0 : nsAutoString strRule;
1595 0 : if (!focusRingOnAnything)
1596 0 : strRule.AppendLiteral("*|*:link:focus, *|*:visited"); // If we only want focus rings on the normal things like links
1597 0 : strRule.AppendLiteral(":focus {outline: "); // For example 3px dotted WindowText (maximum 4)
1598 0 : strRule.AppendInt(focusRingWidth);
1599 0 : if (focusRingStyle == 0) // solid
1600 0 : strRule.AppendLiteral("px solid -moz-mac-focusring !important; -moz-outline-radius: 3px; outline-offset: 1px; } ");
1601 : else // dotted
1602 0 : strRule.AppendLiteral("px dotted WindowText !important; } ");
1603 : // insert the rules
1604 : result = mPrefStyleSheet->
1605 0 : InsertRuleInternal(strRule, sInsertPrefSheetRulesAt, &index);
1606 0 : NS_ENSURE_SUCCESS(result, result);
1607 0 : if (focusRingWidth != 1) {
1608 : // If the focus ring width is different from the default, fix buttons with rings
1609 0 : strRule.AssignLiteral("button::-moz-focus-inner, input[type=\"reset\"]::-moz-focus-inner,");
1610 0 : strRule.AppendLiteral("input[type=\"button\"]::-moz-focus-inner, ");
1611 0 : strRule.AppendLiteral("input[type=\"submit\"]::-moz-focus-inner { padding: 1px 2px 1px 2px; border: ");
1612 0 : strRule.AppendInt(focusRingWidth);
1613 0 : if (focusRingStyle == 0) // solid
1614 0 : strRule.AppendLiteral("px solid transparent !important; } ");
1615 : else
1616 0 : strRule.AppendLiteral("px dotted transparent !important; } ");
1617 : result = mPrefStyleSheet->
1618 0 : InsertRuleInternal(strRule, sInsertPrefSheetRulesAt, &index);
1619 0 : NS_ENSURE_SUCCESS(result, result);
1620 :
1621 0 : strRule.AssignLiteral("button:focus::-moz-focus-inner, input[type=\"reset\"]:focus::-moz-focus-inner,");
1622 0 : strRule.AppendLiteral("input[type=\"button\"]:focus::-moz-focus-inner, input[type=\"submit\"]:focus::-moz-focus-inner {");
1623 0 : strRule.AppendLiteral("border-color: ButtonText !important; }");
1624 : result = mPrefStyleSheet->
1625 0 : InsertRuleInternal(strRule, sInsertPrefSheetRulesAt, &index);
1626 : }
1627 : }
1628 : }
1629 0 : return result;
1630 : }
1631 :
1632 : void
1633 0 : PresShell::AddUserSheet(nsISupports* aSheet)
1634 : {
1635 : // Make sure this does what DocumentViewerImpl::CreateStyleSet does wrt
1636 : // ordering. We want this new sheet to come after all the existing stylesheet
1637 : // service sheets, but before other user sheets; see nsIStyleSheetService.idl
1638 : // for the ordering. Just remove and readd all the nsStyleSheetService
1639 : // sheets.
1640 : nsCOMPtr<nsIStyleSheetService> dummy =
1641 0 : do_GetService(NS_STYLESHEETSERVICE_CONTRACTID);
1642 :
1643 0 : mStyleSet->BeginUpdate();
1644 :
1645 0 : nsStyleSheetService *sheetService = nsStyleSheetService::gInstance;
1646 0 : nsCOMArray<nsIStyleSheet> & userSheets = *sheetService->UserStyleSheets();
1647 : PRInt32 i;
1648 : // Iterate forwards when removing so the searches for RemoveStyleSheet are as
1649 : // short as possible.
1650 0 : for (i = 0; i < userSheets.Count(); ++i) {
1651 0 : mStyleSet->RemoveStyleSheet(nsStyleSet::eUserSheet, userSheets[i]);
1652 : }
1653 :
1654 : // Now iterate backwards, so that the order of userSheets will be the same as
1655 : // the order of sheets from it in the style set.
1656 0 : for (i = userSheets.Count() - 1; i >= 0; --i) {
1657 0 : mStyleSet->PrependStyleSheet(nsStyleSet::eUserSheet, userSheets[i]);
1658 : }
1659 :
1660 0 : mStyleSet->EndUpdate();
1661 :
1662 0 : ReconstructStyleData();
1663 0 : }
1664 :
1665 : void
1666 0 : PresShell::AddAgentSheet(nsISupports* aSheet)
1667 : {
1668 : // Make sure this does what DocumentViewerImpl::CreateStyleSet does
1669 : // wrt ordering.
1670 0 : nsCOMPtr<nsIStyleSheet> sheet = do_QueryInterface(aSheet);
1671 0 : if (!sheet) {
1672 : return;
1673 : }
1674 :
1675 0 : mStyleSet->AppendStyleSheet(nsStyleSet::eAgentSheet, sheet);
1676 0 : ReconstructStyleData();
1677 : }
1678 :
1679 : void
1680 0 : PresShell::RemoveSheet(nsStyleSet::sheetType aType, nsISupports* aSheet)
1681 : {
1682 0 : nsCOMPtr<nsIStyleSheet> sheet = do_QueryInterface(aSheet);
1683 0 : if (!sheet) {
1684 : return;
1685 : }
1686 :
1687 0 : mStyleSet->RemoveStyleSheet(aType, sheet);
1688 0 : ReconstructStyleData();
1689 : }
1690 :
1691 : NS_IMETHODIMP
1692 0 : PresShell::SetDisplaySelection(PRInt16 aToggle)
1693 : {
1694 0 : mSelection->SetDisplaySelection(aToggle);
1695 0 : return NS_OK;
1696 : }
1697 :
1698 : NS_IMETHODIMP
1699 0 : PresShell::GetDisplaySelection(PRInt16 *aToggle)
1700 : {
1701 0 : *aToggle = mSelection->GetDisplaySelection();
1702 0 : return NS_OK;
1703 : }
1704 :
1705 : NS_IMETHODIMP
1706 0 : PresShell::GetSelection(SelectionType aType, nsISelection **aSelection)
1707 : {
1708 0 : if (!aSelection || !mSelection)
1709 0 : return NS_ERROR_NULL_POINTER;
1710 :
1711 0 : *aSelection = mSelection->GetSelection(aType);
1712 :
1713 0 : if (!(*aSelection))
1714 0 : return NS_ERROR_INVALID_ARG;
1715 :
1716 0 : NS_ADDREF(*aSelection);
1717 :
1718 0 : return NS_OK;
1719 : }
1720 :
1721 : nsISelection*
1722 0 : PresShell::GetCurrentSelection(SelectionType aType)
1723 : {
1724 0 : if (!mSelection)
1725 0 : return nsnull;
1726 :
1727 0 : return mSelection->GetSelection(aType);
1728 : }
1729 :
1730 : NS_IMETHODIMP
1731 0 : PresShell::ScrollSelectionIntoView(SelectionType aType, SelectionRegion aRegion,
1732 : PRInt16 aFlags)
1733 : {
1734 0 : if (!mSelection)
1735 0 : return NS_ERROR_NULL_POINTER;
1736 :
1737 0 : return mSelection->ScrollSelectionIntoView(aType, aRegion, aFlags);
1738 : }
1739 :
1740 : NS_IMETHODIMP
1741 0 : PresShell::RepaintSelection(SelectionType aType)
1742 : {
1743 0 : if (!mSelection)
1744 0 : return NS_ERROR_NULL_POINTER;
1745 :
1746 0 : return mSelection->RepaintSelection(aType);
1747 : }
1748 :
1749 : // Make shell be a document observer
1750 : void
1751 0 : PresShell::BeginObservingDocument()
1752 : {
1753 0 : if (mDocument && !mIsDestroying) {
1754 0 : mDocument->AddObserver(this);
1755 0 : if (mIsDocumentGone) {
1756 : NS_WARNING("Adding a presshell that was disconnected from the document "
1757 0 : "as a document observer? Sounds wrong...");
1758 0 : mIsDocumentGone = false;
1759 : }
1760 : }
1761 0 : }
1762 :
1763 : // Make shell stop being a document observer
1764 : void
1765 0 : PresShell::EndObservingDocument()
1766 : {
1767 : // XXXbz do we need to tell the frame constructor that the document
1768 : // is gone, perhaps? Except for printing it's NOT gone, sometimes.
1769 0 : mIsDocumentGone = true;
1770 0 : if (mDocument) {
1771 0 : mDocument->RemoveObserver(this);
1772 : }
1773 0 : }
1774 :
1775 : #ifdef DEBUG_kipp
1776 : char* nsPresShell_ReflowStackPointerTop;
1777 : #endif
1778 :
1779 : nsresult
1780 0 : PresShell::InitialReflow(nscoord aWidth, nscoord aHeight)
1781 : {
1782 0 : if (mIsDestroying) {
1783 0 : return NS_OK;
1784 : }
1785 :
1786 0 : if (!mDocument) {
1787 : // Nothing to do
1788 0 : return NS_OK;
1789 : }
1790 :
1791 : NS_TIME_FUNCTION_WITH_DOCURL;
1792 0 : mozilla::TimeStamp timerStart = mozilla::TimeStamp::Now();
1793 :
1794 0 : NS_ASSERTION(!mDidInitialReflow, "Why are we being called?");
1795 :
1796 0 : nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
1797 0 : mDidInitialReflow = true;
1798 :
1799 : #ifdef NS_DEBUG
1800 0 : if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) {
1801 0 : if (mDocument) {
1802 0 : nsIURI *uri = mDocument->GetDocumentURI();
1803 0 : if (uri) {
1804 0 : nsCAutoString url;
1805 0 : uri->GetSpec(url);
1806 0 : printf("*** PresShell::InitialReflow (this=%p, url='%s')\n", (void*)this, url.get());
1807 : }
1808 : }
1809 : }
1810 : #endif
1811 :
1812 0 : if (mCaret)
1813 0 : mCaret->EraseCaret();
1814 :
1815 : // XXX Do a full invalidate at the beginning so that invalidates along
1816 : // the way don't have region accumulation issues?
1817 :
1818 0 : mPresContext->SetVisibleArea(nsRect(0, 0, aWidth, aHeight));
1819 :
1820 : // Get the root frame from the frame manager
1821 : // XXXbz it would be nice to move this somewhere else... like frame manager
1822 : // Init(), say. But we need to make sure our views are all set up by the
1823 : // time we do this!
1824 0 : nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
1825 0 : NS_ASSERTION(!rootFrame, "How did that happen, exactly?");
1826 0 : if (!rootFrame) {
1827 0 : nsAutoScriptBlocker scriptBlocker;
1828 0 : mFrameConstructor->BeginUpdate();
1829 0 : mFrameConstructor->ConstructRootFrame(&rootFrame);
1830 0 : mFrameConstructor->SetRootFrame(rootFrame);
1831 0 : mFrameConstructor->EndUpdate();
1832 : }
1833 :
1834 0 : NS_ENSURE_STATE(!mHaveShutDown);
1835 :
1836 0 : if (!rootFrame) {
1837 0 : return NS_ERROR_OUT_OF_MEMORY;
1838 : }
1839 :
1840 0 : Element *root = mDocument->GetRootElement();
1841 :
1842 0 : if (root) {
1843 : {
1844 0 : nsAutoCauseReflowNotifier reflowNotifier(this);
1845 0 : mFrameConstructor->BeginUpdate();
1846 :
1847 : // Have the style sheet processor construct frame for the root
1848 : // content object down
1849 0 : mFrameConstructor->ContentInserted(nsnull, root, nsnull, false);
1850 0 : VERIFY_STYLE_TREE;
1851 :
1852 : // Something in mFrameConstructor->ContentInserted may have caused
1853 : // Destroy() to get called, bug 337586.
1854 0 : NS_ENSURE_STATE(!mHaveShutDown);
1855 :
1856 0 : mFrameConstructor->EndUpdate();
1857 : }
1858 :
1859 : // nsAutoScriptBlocker going out of scope may have killed us too
1860 0 : NS_ENSURE_STATE(!mHaveShutDown);
1861 :
1862 : // Run the XBL binding constructors for any new frames we've constructed
1863 0 : mDocument->BindingManager()->ProcessAttachedQueue();
1864 :
1865 : NS_TIME_FUNCTION_MARK("XBL binding constructors fired");
1866 :
1867 : // Constructors may have killed us too
1868 0 : NS_ENSURE_STATE(!mHaveShutDown);
1869 :
1870 : // Now flush out pending restyles before we actually reflow, in
1871 : // case XBL constructors changed styles somewhere.
1872 : {
1873 0 : nsAutoScriptBlocker scriptBlocker;
1874 0 : mFrameConstructor->CreateNeededFrames();
1875 0 : mFrameConstructor->ProcessPendingRestyles();
1876 : }
1877 :
1878 : // And that might have run _more_ XBL constructors
1879 0 : NS_ENSURE_STATE(!mHaveShutDown);
1880 : }
1881 :
1882 0 : NS_ASSERTION(rootFrame, "How did that happen?");
1883 :
1884 : // Note: when the frame was created above it had the NS_FRAME_IS_DIRTY bit
1885 : // set, but XBL processing could have caused a reflow which clears it.
1886 0 : if (NS_LIKELY(rootFrame->GetStateBits() & NS_FRAME_IS_DIRTY)) {
1887 : // Unset the DIRTY bits so that FrameNeedsReflow() will work right.
1888 : rootFrame->RemoveStateBits(NS_FRAME_IS_DIRTY |
1889 0 : NS_FRAME_HAS_DIRTY_CHILDREN);
1890 0 : NS_ASSERTION(!mDirtyRoots.Contains(rootFrame),
1891 : "Why is the root in mDirtyRoots already?");
1892 0 : FrameNeedsReflow(rootFrame, eResize, NS_FRAME_IS_DIRTY);
1893 0 : NS_ASSERTION(mDirtyRoots.Contains(rootFrame),
1894 : "Should be in mDirtyRoots now");
1895 0 : NS_ASSERTION(mReflowScheduled, "Why no reflow scheduled?");
1896 : }
1897 :
1898 : // Restore our root scroll position now if we're getting here after EndLoad
1899 : // got called, since this is our one chance to do it. Note that we need not
1900 : // have reflowed for this to work; when the scrollframe is finally reflowed
1901 : // it'll pick up the position we store in it here.
1902 0 : if (!mDocumentLoading) {
1903 0 : RestoreRootScrollPosition();
1904 : }
1905 :
1906 : // For printing, we just immediately unsuppress.
1907 0 : if (!mPresContext->IsPaginated()) {
1908 : // Kick off a one-shot timer based off our pref value. When this timer
1909 : // fires, if painting is still locked down, then we will go ahead and
1910 : // trigger a full invalidate and allow painting to proceed normally.
1911 0 : mPaintingSuppressed = true;
1912 : // Don't suppress painting if the document isn't loading.
1913 0 : nsIDocument::ReadyState readyState = mDocument->GetReadyStateEnum();
1914 0 : if (readyState != nsIDocument::READYSTATE_COMPLETE) {
1915 0 : mPaintSuppressionTimer = do_CreateInstance("@mozilla.org/timer;1");
1916 : }
1917 0 : if (!mPaintSuppressionTimer) {
1918 0 : mPaintingSuppressed = false;
1919 : } else {
1920 : // Initialize the timer.
1921 :
1922 : // Default to PAINTLOCK_EVENT_DELAY if we can't get the pref value.
1923 : PRInt32 delay =
1924 : Preferences::GetInt("nglayout.initialpaint.delay",
1925 0 : PAINTLOCK_EVENT_DELAY);
1926 :
1927 0 : mPaintSuppressionTimer->InitWithFuncCallback(sPaintSuppressionCallback,
1928 : this, delay,
1929 0 : nsITimer::TYPE_ONE_SHOT);
1930 : }
1931 : }
1932 :
1933 0 : if (root && root->IsXUL()) {
1934 : mozilla::Telemetry::AccumulateTimeDelta(Telemetry::XUL_INITIAL_FRAME_CONSTRUCTION,
1935 0 : timerStart);
1936 : }
1937 :
1938 0 : return NS_OK; //XXX this needs to be real. MMP
1939 : }
1940 :
1941 : void
1942 0 : PresShell::sPaintSuppressionCallback(nsITimer *aTimer, void* aPresShell)
1943 : {
1944 0 : nsRefPtr<PresShell> self = static_cast<PresShell*>(aPresShell);
1945 0 : if (self)
1946 0 : self->UnsuppressPainting();
1947 0 : }
1948 :
1949 : void
1950 0 : PresShell::AsyncResizeEventCallback(nsITimer* aTimer, void* aPresShell)
1951 : {
1952 0 : static_cast<PresShell*>(aPresShell)->FireResizeEvent();
1953 0 : }
1954 :
1955 : nsresult
1956 0 : PresShell::ResizeReflowOverride(nscoord aWidth, nscoord aHeight)
1957 : {
1958 0 : mViewportOverridden = true;
1959 0 : return ResizeReflowIgnoreOverride(aWidth, aHeight);
1960 : }
1961 :
1962 : nsresult
1963 0 : PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight)
1964 : {
1965 0 : if (mViewportOverridden) {
1966 : // The viewport has been overridden, and this reflow request
1967 : // didn't ask to ignore the override. Pretend it didn't happen.
1968 0 : return NS_OK;
1969 : }
1970 0 : return ResizeReflowIgnoreOverride(aWidth, aHeight);
1971 : }
1972 :
1973 : nsresult
1974 0 : PresShell::ResizeReflowIgnoreOverride(nscoord aWidth, nscoord aHeight)
1975 : {
1976 0 : NS_PRECONDITION(!mIsReflowing, "Shouldn't be in reflow here!");
1977 0 : NS_PRECONDITION(aWidth != NS_UNCONSTRAINEDSIZE,
1978 : "shouldn't use unconstrained widths anymore");
1979 :
1980 : // If we don't have a root frame yet, that means we haven't had our initial
1981 : // reflow... If that's the case, and aWidth or aHeight is unconstrained,
1982 : // ignore them altogether.
1983 0 : nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
1984 :
1985 0 : if (!rootFrame && aHeight == NS_UNCONSTRAINEDSIZE) {
1986 : // We can't do the work needed for SizeToContent without a root
1987 : // frame, and we want to return before setting the visible area.
1988 0 : return NS_ERROR_NOT_AVAILABLE;
1989 : }
1990 :
1991 0 : nsCOMPtr<nsIViewManager> viewManagerDeathGrip = mViewManager;
1992 : // Take this ref after viewManager so it'll make sure to go away first
1993 0 : nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
1994 :
1995 0 : if (!mIsDestroying && !mResizeEvent.IsPending() &&
1996 0 : !mAsyncResizeTimerIsActive) {
1997 0 : FireBeforeResizeEvent();
1998 : }
1999 :
2000 0 : mPresContext->SetVisibleArea(nsRect(0, 0, aWidth, aHeight));
2001 :
2002 : // There isn't anything useful we can do if the initial reflow hasn't happened
2003 0 : rootFrame = mFrameConstructor->GetRootFrame();
2004 0 : if (!rootFrame)
2005 0 : return NS_OK;
2006 :
2007 0 : if (!GetPresContext()->SupressingResizeReflow())
2008 : {
2009 : // Have to make sure that the content notifications are flushed before we
2010 : // start messing with the frame model; otherwise we can get content doubling.
2011 0 : mDocument->FlushPendingNotifications(Flush_ContentAndNotify);
2012 :
2013 : // Make sure style is up to date
2014 : {
2015 0 : nsAutoScriptBlocker scriptBlocker;
2016 0 : mFrameConstructor->CreateNeededFrames();
2017 0 : mFrameConstructor->ProcessPendingRestyles();
2018 : }
2019 :
2020 0 : rootFrame = mFrameConstructor->GetRootFrame();
2021 0 : if (!mIsDestroying && rootFrame) {
2022 : // XXX Do a full invalidate at the beginning so that invalidates along
2023 : // the way don't have region accumulation issues?
2024 :
2025 : {
2026 0 : nsAutoCauseReflowNotifier crNotifier(this);
2027 0 : WillDoReflow();
2028 :
2029 : // Kick off a top-down reflow
2030 0 : AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Reflow);
2031 0 : nsIViewManager::AutoDisableRefresh refreshBlocker(mViewManager);
2032 :
2033 0 : mDirtyRoots.RemoveElement(rootFrame);
2034 0 : DoReflow(rootFrame, true);
2035 : }
2036 :
2037 0 : DidDoReflow(true);
2038 : }
2039 : }
2040 :
2041 0 : rootFrame = mFrameConstructor->GetRootFrame();
2042 0 : if (aHeight == NS_UNCONSTRAINEDSIZE && rootFrame) {
2043 : mPresContext->SetVisibleArea(
2044 0 : nsRect(0, 0, aWidth, rootFrame->GetRect().height));
2045 : }
2046 :
2047 0 : if (!mIsDestroying && !mResizeEvent.IsPending() &&
2048 0 : !mAsyncResizeTimerIsActive) {
2049 0 : if (mInResize) {
2050 0 : if (!mAsyncResizeEventTimer) {
2051 0 : mAsyncResizeEventTimer = do_CreateInstance("@mozilla.org/timer;1");
2052 : }
2053 0 : if (mAsyncResizeEventTimer) {
2054 0 : mAsyncResizeTimerIsActive = true;
2055 0 : mAsyncResizeEventTimer->InitWithFuncCallback(AsyncResizeEventCallback,
2056 : this, 15,
2057 0 : nsITimer::TYPE_ONE_SHOT);
2058 : }
2059 : } else {
2060 : nsRefPtr<nsRunnableMethod<PresShell> > resizeEvent =
2061 0 : NS_NewRunnableMethod(this, &PresShell::FireResizeEvent);
2062 0 : if (NS_SUCCEEDED(NS_DispatchToCurrentThread(resizeEvent))) {
2063 0 : mResizeEvent = resizeEvent;
2064 0 : mDocument->SetNeedStyleFlush();
2065 : }
2066 : }
2067 : }
2068 :
2069 0 : return NS_OK; //XXX this needs to be real. MMP
2070 : }
2071 :
2072 : void
2073 0 : PresShell::FireBeforeResizeEvent()
2074 : {
2075 0 : if (mIsDocumentGone)
2076 0 : return;
2077 :
2078 : // Send beforeresize event from here.
2079 0 : nsEvent event(true, NS_BEFORERESIZE_EVENT);
2080 :
2081 0 : nsPIDOMWindow *window = mDocument->GetWindow();
2082 0 : if (window) {
2083 0 : nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
2084 0 : nsEventDispatcher::Dispatch(window, mPresContext, &event);
2085 : }
2086 : }
2087 :
2088 : void
2089 0 : PresShell::FireResizeEvent()
2090 : {
2091 0 : if (mAsyncResizeTimerIsActive) {
2092 0 : mAsyncResizeTimerIsActive = false;
2093 0 : mAsyncResizeEventTimer->Cancel();
2094 : }
2095 0 : mResizeEvent.Revoke();
2096 :
2097 0 : if (mIsDocumentGone)
2098 0 : return;
2099 :
2100 : //Send resize event from here.
2101 0 : nsEvent event(true, NS_RESIZE_EVENT);
2102 0 : nsEventStatus status = nsEventStatus_eIgnore;
2103 :
2104 0 : nsPIDOMWindow *window = mDocument->GetWindow();
2105 0 : if (window) {
2106 0 : nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
2107 0 : mInResize = true;
2108 0 : nsEventDispatcher::Dispatch(window, mPresContext, &event, nsnull, &status);
2109 0 : mInResize = false;
2110 : }
2111 : }
2112 :
2113 : void
2114 0 : PresShell::SetIgnoreFrameDestruction(bool aIgnore)
2115 : {
2116 0 : if (mPresContext) {
2117 : // We need to destroy the image loaders first, as they won't be
2118 : // notified when frames are destroyed once this setting takes effect.
2119 : // (See bug 673984)
2120 0 : mPresContext->DestroyImageLoaders();
2121 : }
2122 0 : mIgnoreFrameDestruction = aIgnore;
2123 0 : }
2124 :
2125 : void
2126 0 : PresShell::NotifyDestroyingFrame(nsIFrame* aFrame)
2127 : {
2128 : NS_TIME_FUNCTION_MIN(1.0);
2129 :
2130 0 : mPresContext->ForgetUpdatePluginGeometryFrame(aFrame);
2131 :
2132 0 : if (!mIgnoreFrameDestruction) {
2133 0 : mPresContext->StopImagesFor(aFrame);
2134 :
2135 0 : mFrameConstructor->NotifyDestroyingFrame(aFrame);
2136 :
2137 0 : for (PRInt32 idx = mDirtyRoots.Length(); idx; ) {
2138 0 : --idx;
2139 0 : if (mDirtyRoots[idx] == aFrame) {
2140 0 : mDirtyRoots.RemoveElementAt(idx);
2141 : }
2142 : }
2143 :
2144 : // Remove frame properties
2145 0 : mPresContext->NotifyDestroyingFrame(aFrame);
2146 :
2147 0 : if (aFrame == mCurrentEventFrame) {
2148 0 : mCurrentEventContent = aFrame->GetContent();
2149 0 : mCurrentEventFrame = nsnull;
2150 : }
2151 :
2152 : #ifdef NS_DEBUG
2153 0 : if (aFrame == mDrawEventTargetFrame) {
2154 0 : mDrawEventTargetFrame = nsnull;
2155 : }
2156 : #endif
2157 :
2158 0 : for (unsigned int i=0; i < mCurrentEventFrameStack.Length(); i++) {
2159 0 : if (aFrame == mCurrentEventFrameStack.ElementAt(i)) {
2160 : //One of our stack frames was deleted. Get its content so that when we
2161 : //pop it we can still get its new frame from its content
2162 0 : nsIContent *currentEventContent = aFrame->GetContent();
2163 0 : mCurrentEventContentStack.ReplaceObjectAt(currentEventContent, i);
2164 0 : mCurrentEventFrameStack[i] = nsnull;
2165 : }
2166 : }
2167 :
2168 0 : mFramesToDirty.RemoveEntry(aFrame);
2169 : }
2170 0 : }
2171 :
2172 0 : already_AddRefed<nsCaret> PresShell::GetCaret() const
2173 : {
2174 0 : nsCaret* caret = mCaret;
2175 0 : NS_IF_ADDREF(caret);
2176 0 : return caret;
2177 : }
2178 :
2179 0 : void PresShell::MaybeInvalidateCaretPosition()
2180 : {
2181 0 : if (mCaret) {
2182 0 : mCaret->InvalidateOutsideCaret();
2183 : }
2184 0 : }
2185 :
2186 0 : void PresShell::SetCaret(nsCaret *aNewCaret)
2187 : {
2188 0 : mCaret = aNewCaret;
2189 0 : }
2190 :
2191 0 : void PresShell::RestoreCaret()
2192 : {
2193 0 : mCaret = mOriginalCaret;
2194 0 : }
2195 :
2196 0 : NS_IMETHODIMP PresShell::SetCaretEnabled(bool aInEnable)
2197 : {
2198 0 : bool oldEnabled = mCaretEnabled;
2199 :
2200 0 : mCaretEnabled = aInEnable;
2201 :
2202 0 : if (mCaret && (mCaretEnabled != oldEnabled))
2203 : {
2204 : /* Don't change the caret's selection here! This was an evil side-effect of SetCaretEnabled()
2205 : nsCOMPtr<nsIDOMSelection> domSel;
2206 : if (NS_SUCCEEDED(GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(domSel))) && domSel)
2207 : mCaret->SetCaretDOMSelection(domSel);
2208 : */
2209 0 : mCaret->SetCaretVisible(mCaretEnabled);
2210 : }
2211 :
2212 0 : return NS_OK;
2213 : }
2214 :
2215 0 : NS_IMETHODIMP PresShell::SetCaretReadOnly(bool aReadOnly)
2216 : {
2217 0 : if (mCaret)
2218 0 : mCaret->SetCaretReadOnly(aReadOnly);
2219 0 : return NS_OK;
2220 : }
2221 :
2222 0 : NS_IMETHODIMP PresShell::GetCaretEnabled(bool *aOutEnabled)
2223 : {
2224 0 : NS_ENSURE_ARG_POINTER(aOutEnabled);
2225 0 : *aOutEnabled = mCaretEnabled;
2226 0 : return NS_OK;
2227 : }
2228 :
2229 0 : NS_IMETHODIMP PresShell::SetCaretVisibilityDuringSelection(bool aVisibility)
2230 : {
2231 0 : if (mCaret)
2232 0 : mCaret->SetVisibilityDuringSelection(aVisibility);
2233 0 : return NS_OK;
2234 : }
2235 :
2236 0 : NS_IMETHODIMP PresShell::GetCaretVisible(bool *aOutIsVisible)
2237 : {
2238 0 : *aOutIsVisible = false;
2239 0 : if (mCaret) {
2240 0 : nsresult rv = mCaret->GetCaretVisible(aOutIsVisible);
2241 0 : NS_ENSURE_SUCCESS(rv,rv);
2242 : }
2243 0 : return NS_OK;
2244 : }
2245 :
2246 0 : NS_IMETHODIMP PresShell::SetSelectionFlags(PRInt16 aInEnable)
2247 : {
2248 0 : mSelectionFlags = aInEnable;
2249 0 : return NS_OK;
2250 : }
2251 :
2252 0 : NS_IMETHODIMP PresShell::GetSelectionFlags(PRInt16 *aOutEnable)
2253 : {
2254 0 : if (!aOutEnable)
2255 0 : return NS_ERROR_INVALID_ARG;
2256 0 : *aOutEnable = mSelectionFlags;
2257 0 : return NS_OK;
2258 : }
2259 :
2260 : //implementation of nsISelectionController
2261 :
2262 : NS_IMETHODIMP
2263 0 : PresShell::CharacterMove(bool aForward, bool aExtend)
2264 : {
2265 0 : return mSelection->CharacterMove(aForward, aExtend);
2266 : }
2267 :
2268 : NS_IMETHODIMP
2269 0 : PresShell::CharacterExtendForDelete()
2270 : {
2271 0 : return mSelection->CharacterExtendForDelete();
2272 : }
2273 :
2274 : NS_IMETHODIMP
2275 0 : PresShell::CharacterExtendForBackspace()
2276 : {
2277 0 : return mSelection->CharacterExtendForBackspace();
2278 : }
2279 :
2280 : NS_IMETHODIMP
2281 0 : PresShell::WordMove(bool aForward, bool aExtend)
2282 : {
2283 0 : nsresult result = mSelection->WordMove(aForward, aExtend);
2284 : // if we can't go down/up any more we must then move caret completely to
2285 : // end/beginning respectively.
2286 0 : if (NS_FAILED(result))
2287 0 : result = CompleteMove(aForward, aExtend);
2288 0 : return result;
2289 : }
2290 :
2291 : NS_IMETHODIMP
2292 0 : PresShell::WordExtendForDelete(bool aForward)
2293 : {
2294 0 : return mSelection->WordExtendForDelete(aForward);
2295 : }
2296 :
2297 : NS_IMETHODIMP
2298 0 : PresShell::LineMove(bool aForward, bool aExtend)
2299 : {
2300 0 : nsresult result = mSelection->LineMove(aForward, aExtend);
2301 : // if we can't go down/up any more we must then move caret completely to
2302 : // end/beginning respectively.
2303 0 : if (NS_FAILED(result))
2304 0 : result = CompleteMove(aForward,aExtend);
2305 0 : return result;
2306 : }
2307 :
2308 : NS_IMETHODIMP
2309 0 : PresShell::IntraLineMove(bool aForward, bool aExtend)
2310 : {
2311 0 : return mSelection->IntraLineMove(aForward, aExtend);
2312 : }
2313 :
2314 :
2315 :
2316 : NS_IMETHODIMP
2317 0 : PresShell::PageMove(bool aForward, bool aExtend)
2318 : {
2319 : nsIScrollableFrame *scrollableFrame =
2320 0 : GetFrameToScrollAsScrollable(nsIPresShell::eVertical);
2321 0 : if (!scrollableFrame)
2322 0 : return NS_OK;
2323 :
2324 0 : mSelection->CommonPageMove(aForward, aExtend, scrollableFrame);
2325 : // After ScrollSelectionIntoView(), the pending notifications might be
2326 : // flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
2327 : return ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL,
2328 : nsISelectionController::SELECTION_FOCUS_REGION,
2329 0 : nsISelectionController::SCROLL_SYNCHRONOUS);
2330 : }
2331 :
2332 :
2333 :
2334 : NS_IMETHODIMP
2335 0 : PresShell::ScrollPage(bool aForward)
2336 : {
2337 : nsIScrollableFrame* scrollFrame =
2338 0 : GetFrameToScrollAsScrollable(nsIPresShell::eVertical);
2339 0 : if (scrollFrame) {
2340 : scrollFrame->ScrollBy(nsIntPoint(0, aForward ? 1 : -1),
2341 : nsIScrollableFrame::PAGES,
2342 0 : nsIScrollableFrame::SMOOTH);
2343 : }
2344 0 : return NS_OK;
2345 : }
2346 :
2347 : NS_IMETHODIMP
2348 0 : PresShell::ScrollLine(bool aForward)
2349 : {
2350 : nsIScrollableFrame* scrollFrame =
2351 0 : GetFrameToScrollAsScrollable(nsIPresShell::eVertical);
2352 0 : if (scrollFrame) {
2353 : PRInt32 lineCount = Preferences::GetInt("toolkit.scrollbox.verticalScrollDistance",
2354 0 : NS_DEFAULT_VERTICAL_SCROLL_DISTANCE);
2355 : scrollFrame->ScrollBy(nsIntPoint(0, aForward ? lineCount : -lineCount),
2356 : nsIScrollableFrame::LINES,
2357 0 : nsIScrollableFrame::SMOOTH);
2358 : }
2359 0 : return NS_OK;
2360 : }
2361 :
2362 : NS_IMETHODIMP
2363 0 : PresShell::ScrollCharacter(bool aRight)
2364 : {
2365 : nsIScrollableFrame* scrollFrame =
2366 0 : GetFrameToScrollAsScrollable(nsIPresShell::eHorizontal);
2367 0 : if (scrollFrame) {
2368 : scrollFrame->ScrollBy(nsIntPoint(aRight ? 1 : -1, 0),
2369 : nsIScrollableFrame::LINES,
2370 0 : nsIScrollableFrame::SMOOTH);
2371 : }
2372 0 : return NS_OK;
2373 : }
2374 :
2375 : NS_IMETHODIMP
2376 0 : PresShell::CompleteScroll(bool aForward)
2377 : {
2378 : nsIScrollableFrame* scrollFrame =
2379 0 : GetFrameToScrollAsScrollable(nsIPresShell::eVertical);
2380 0 : if (scrollFrame) {
2381 : scrollFrame->ScrollBy(nsIntPoint(0, aForward ? 1 : -1),
2382 : nsIScrollableFrame::WHOLE,
2383 0 : nsIScrollableFrame::INSTANT);
2384 : }
2385 0 : return NS_OK;
2386 : }
2387 :
2388 : NS_IMETHODIMP
2389 0 : PresShell::CompleteMove(bool aForward, bool aExtend)
2390 : {
2391 : // Beware! This may flush notifications via synchronous
2392 : // ScrollSelectionIntoView.
2393 0 : nsIContent* limiter = mSelection->GetAncestorLimiter();
2394 : nsIFrame* frame = limiter ? limiter->GetPrimaryFrame()
2395 0 : : FrameConstructor()->GetRootElementFrame();
2396 0 : if (!frame)
2397 0 : return NS_ERROR_FAILURE;
2398 0 : nsPeekOffsetStruct pos = frame->GetExtremeCaretPosition(!aForward);
2399 : mSelection->HandleClick(pos.mResultContent, pos.mContentOffset,
2400 0 : pos.mContentOffset, aExtend, false, aForward);
2401 0 : if (limiter) {
2402 : // HandleClick resets ancestorLimiter, so set it again.
2403 0 : mSelection->SetAncestorLimiter(limiter);
2404 : }
2405 :
2406 : // After ScrollSelectionIntoView(), the pending notifications might be
2407 : // flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
2408 : return ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL,
2409 : nsISelectionController::SELECTION_FOCUS_REGION,
2410 0 : nsISelectionController::SCROLL_SYNCHRONOUS);
2411 : }
2412 :
2413 : NS_IMETHODIMP
2414 0 : PresShell::SelectAll()
2415 : {
2416 0 : return mSelection->SelectAll();
2417 : }
2418 :
2419 : static void
2420 0 : DoCheckVisibility(nsPresContext* aPresContext,
2421 : nsIContent* aNode,
2422 : PRInt16 aStartOffset,
2423 : PRInt16 aEndOffset,
2424 : bool* aRetval)
2425 : {
2426 0 : nsIFrame* frame = aNode->GetPrimaryFrame();
2427 0 : if (!frame) {
2428 : // No frame to look at so it must not be visible.
2429 0 : return;
2430 : }
2431 :
2432 : // Start process now to go through all frames to find startOffset. Then check
2433 : // chars after that to see if anything until EndOffset is visible.
2434 0 : bool finished = false;
2435 : frame->CheckVisibility(aPresContext, aStartOffset, aEndOffset, true,
2436 0 : &finished, aRetval);
2437 : // Don't worry about other return value.
2438 : }
2439 :
2440 : NS_IMETHODIMP
2441 0 : PresShell::CheckVisibility(nsIDOMNode *node, PRInt16 startOffset, PRInt16 EndOffset, bool *_retval)
2442 : {
2443 0 : if (!node || startOffset>EndOffset || !_retval || startOffset<0 || EndOffset<0)
2444 0 : return NS_ERROR_INVALID_ARG;
2445 0 : *_retval = false; //initialize return parameter
2446 0 : nsCOMPtr<nsIContent> content(do_QueryInterface(node));
2447 0 : if (!content)
2448 0 : return NS_ERROR_FAILURE;
2449 :
2450 0 : DoCheckVisibility(mPresContext, content, startOffset, EndOffset, _retval);
2451 0 : return NS_OK;
2452 : }
2453 :
2454 : nsresult
2455 0 : PresShell::CheckVisibilityContent(nsIContent* aNode, PRInt16 aStartOffset,
2456 : PRInt16 aEndOffset, bool* aRetval)
2457 : {
2458 0 : if (!aNode || aStartOffset > aEndOffset || !aRetval ||
2459 : aStartOffset < 0 || aEndOffset < 0) {
2460 0 : return NS_ERROR_INVALID_ARG;
2461 : }
2462 :
2463 0 : *aRetval = false;
2464 0 : DoCheckVisibility(mPresContext, aNode, aStartOffset, aEndOffset, aRetval);
2465 0 : return NS_OK;
2466 : }
2467 :
2468 : //end implementations nsISelectionController
2469 :
2470 :
2471 : void
2472 0 : PresShell::StyleChangeReflow()
2473 : {
2474 0 : nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
2475 : // At the moment at least, we don't have a root frame before the initial
2476 : // reflow; it's safe to just ignore the request in that case
2477 0 : if (!rootFrame)
2478 0 : return;
2479 :
2480 0 : FrameNeedsReflow(rootFrame, eStyleChange, NS_FRAME_IS_DIRTY);
2481 : }
2482 :
2483 : nsIFrame*
2484 0 : nsIPresShell::GetRootFrameExternal() const
2485 : {
2486 0 : return mFrameConstructor->GetRootFrame();
2487 : }
2488 :
2489 : nsIFrame*
2490 0 : nsIPresShell::GetRootScrollFrame() const
2491 : {
2492 0 : nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
2493 : // Ensure root frame is a viewport frame
2494 0 : if (!rootFrame || nsGkAtoms::viewportFrame != rootFrame->GetType())
2495 0 : return nsnull;
2496 0 : nsIFrame* theFrame = rootFrame->GetFirstPrincipalChild();
2497 0 : if (!theFrame || nsGkAtoms::scrollFrame != theFrame->GetType())
2498 0 : return nsnull;
2499 0 : return theFrame;
2500 : }
2501 :
2502 : nsIScrollableFrame*
2503 0 : nsIPresShell::GetRootScrollFrameAsScrollable() const
2504 : {
2505 0 : nsIFrame* frame = GetRootScrollFrame();
2506 0 : if (!frame)
2507 0 : return nsnull;
2508 0 : nsIScrollableFrame* scrollableFrame = do_QueryFrame(frame);
2509 0 : NS_ASSERTION(scrollableFrame,
2510 : "All scroll frames must implement nsIScrollableFrame");
2511 0 : return scrollableFrame;
2512 : }
2513 :
2514 : nsIScrollableFrame*
2515 0 : nsIPresShell::GetRootScrollFrameAsScrollableExternal() const
2516 : {
2517 0 : return GetRootScrollFrameAsScrollable();
2518 : }
2519 :
2520 : nsIPageSequenceFrame*
2521 0 : PresShell::GetPageSequenceFrame() const
2522 : {
2523 0 : nsIFrame* frame = mFrameConstructor->GetPageSequenceFrame();
2524 0 : return do_QueryFrame(frame);
2525 : }
2526 :
2527 : nsIFrame*
2528 0 : PresShell::GetFrameForPoint(nsIFrame* aFrame, nsPoint aPt)
2529 : {
2530 0 : return nsLayoutUtils::GetFrameForPoint(aFrame, aPt);
2531 : }
2532 :
2533 : void
2534 0 : PresShell::BeginUpdate(nsIDocument *aDocument, nsUpdateType aUpdateType)
2535 : {
2536 : #ifdef DEBUG
2537 0 : mUpdateCount++;
2538 : #endif
2539 0 : mFrameConstructor->BeginUpdate();
2540 :
2541 0 : if (aUpdateType & UPDATE_STYLE)
2542 0 : mStyleSet->BeginUpdate();
2543 0 : }
2544 :
2545 : void
2546 0 : PresShell::EndUpdate(nsIDocument *aDocument, nsUpdateType aUpdateType)
2547 : {
2548 : #ifdef DEBUG
2549 0 : NS_PRECONDITION(0 != mUpdateCount, "too many EndUpdate's");
2550 0 : --mUpdateCount;
2551 : #endif
2552 :
2553 0 : if (aUpdateType & UPDATE_STYLE) {
2554 0 : mStyleSet->EndUpdate();
2555 0 : if (mStylesHaveChanged)
2556 0 : ReconstructStyleData();
2557 : }
2558 :
2559 0 : mFrameConstructor->EndUpdate();
2560 0 : }
2561 :
2562 : void
2563 0 : PresShell::RestoreRootScrollPosition()
2564 : {
2565 : // Restore frame state for the root scroll frame
2566 : nsCOMPtr<nsILayoutHistoryState> historyState =
2567 0 : mDocument->GetLayoutHistoryState();
2568 : // Make sure we don't reenter reflow via the sync paint that happens while
2569 : // we're scrolling to our restored position. Entering reflow for the
2570 : // scrollable frame will cause it to reenter ScrollToRestoredPosition(), and
2571 : // it'll get all confused.
2572 0 : nsAutoScriptBlocker scriptBlocker;
2573 0 : ++mChangeNestCount;
2574 :
2575 0 : if (historyState) {
2576 0 : nsIFrame* scrollFrame = GetRootScrollFrame();
2577 0 : if (scrollFrame) {
2578 0 : nsIScrollableFrame* scrollableFrame = do_QueryFrame(scrollFrame);
2579 0 : if (scrollableFrame) {
2580 : mFrameConstructor->RestoreFrameStateFor(scrollFrame, historyState,
2581 0 : nsIStatefulFrame::eDocumentScrollState);
2582 0 : scrollableFrame->ScrollToRestoredPosition();
2583 : }
2584 : }
2585 : }
2586 :
2587 0 : --mChangeNestCount;
2588 0 : }
2589 :
2590 : void
2591 0 : PresShell::BeginLoad(nsIDocument *aDocument)
2592 : {
2593 0 : mDocumentLoading = true;
2594 0 : }
2595 :
2596 : void
2597 0 : PresShell::EndLoad(nsIDocument *aDocument)
2598 : {
2599 0 : NS_PRECONDITION(aDocument == mDocument, "Wrong document");
2600 :
2601 0 : RestoreRootScrollPosition();
2602 :
2603 0 : mDocumentLoading = false;
2604 0 : }
2605 :
2606 : #ifdef DEBUG
2607 : void
2608 0 : PresShell::VerifyHasDirtyRootAncestor(nsIFrame* aFrame)
2609 : {
2610 : // XXXbz due to bug 372769, can't actually assert anything here...
2611 : return;
2612 :
2613 : // XXXbz shouldn't need this part; remove it once FrameNeedsReflow
2614 : // handles the root frame correctly.
2615 : if (!aFrame->GetParent()) {
2616 : return;
2617 : }
2618 :
2619 : // Make sure that there is a reflow root ancestor of |aFrame| that's
2620 : // in mDirtyRoots already.
2621 : while (aFrame && (aFrame->GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN)) {
2622 : if (((aFrame->GetStateBits() & NS_FRAME_REFLOW_ROOT) ||
2623 : !aFrame->GetParent()) &&
2624 : mDirtyRoots.Contains(aFrame)) {
2625 : return;
2626 : }
2627 :
2628 : aFrame = aFrame->GetParent();
2629 : }
2630 : NS_NOTREACHED("Frame has dirty bits set but isn't scheduled to be "
2631 : "reflowed?");
2632 : }
2633 : #endif
2634 :
2635 : void
2636 0 : PresShell::FrameNeedsReflow(nsIFrame *aFrame, IntrinsicDirty aIntrinsicDirty,
2637 : nsFrameState aBitToAdd)
2638 : {
2639 : #ifdef NS_FUNCTION_TIMER
2640 : NS_TIME_FUNCTION_DECLARE_DOCURL;
2641 : nsCAutoString frameType__("N/A");
2642 : nsIAtom *atomType__ = aFrame ? aFrame->GetType() : nsnull;
2643 : if (atomType__) atomType__->ToUTF8String(frameType__);
2644 : NS_TIME_FUNCTION_MIN_FMT(1.0, "%s (line %d) (document: %s, frame type: %s)", MOZ_FUNCTION_NAME,
2645 : __LINE__, docURL__.get(), frameType__.get());
2646 : #endif
2647 :
2648 0 : NS_PRECONDITION(aBitToAdd == NS_FRAME_IS_DIRTY ||
2649 : aBitToAdd == NS_FRAME_HAS_DIRTY_CHILDREN,
2650 : "Unexpected bits being added");
2651 0 : NS_PRECONDITION(aIntrinsicDirty != eStyleChange ||
2652 : aBitToAdd == NS_FRAME_IS_DIRTY,
2653 : "bits don't correspond to style change reason");
2654 :
2655 0 : NS_ASSERTION(!mIsReflowing, "can't mark frame dirty during reflow");
2656 :
2657 : // If we've not yet done the initial reflow, then don't bother
2658 : // enqueuing a reflow command yet.
2659 0 : if (! mDidInitialReflow)
2660 0 : return;
2661 :
2662 : // If we're already destroying, don't bother with this either.
2663 0 : if (mIsDestroying)
2664 0 : return;
2665 :
2666 : #ifdef DEBUG
2667 : //printf("gShellCounter: %d\n", gShellCounter++);
2668 0 : if (mInVerifyReflow)
2669 0 : return;
2670 :
2671 0 : if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) {
2672 0 : printf("\nPresShell@%p: frame %p needs reflow\n", (void*)this, (void*)aFrame);
2673 0 : if (VERIFY_REFLOW_REALLY_NOISY_RC & gVerifyReflowFlags) {
2674 0 : printf("Current content model:\n");
2675 0 : Element *rootElement = mDocument->GetRootElement();
2676 0 : if (rootElement) {
2677 0 : rootElement->List(stdout, 0);
2678 : }
2679 : }
2680 : }
2681 : #endif
2682 :
2683 0 : nsAutoTArray<nsIFrame*, 4> subtrees;
2684 0 : subtrees.AppendElement(aFrame);
2685 :
2686 0 : do {
2687 0 : nsIFrame *subtreeRoot = subtrees.ElementAt(subtrees.Length() - 1);
2688 0 : subtrees.RemoveElementAt(subtrees.Length() - 1);
2689 :
2690 : // Grab |wasDirty| now so we can go ahead and update the bits on
2691 : // subtreeRoot.
2692 0 : bool wasDirty = NS_SUBTREE_DIRTY(subtreeRoot);
2693 0 : subtreeRoot->AddStateBits(aBitToAdd);
2694 :
2695 : // Now if subtreeRoot is a reflow root we can cut off this reflow at it if
2696 : // the bit being added is NS_FRAME_HAS_DIRTY_CHILDREN.
2697 0 : bool targetFrameDirty = (aBitToAdd == NS_FRAME_IS_DIRTY);
2698 :
2699 : #define FRAME_IS_REFLOW_ROOT(_f) \
2700 : ((_f->GetStateBits() & NS_FRAME_REFLOW_ROOT) && \
2701 : (_f != subtreeRoot || !targetFrameDirty))
2702 :
2703 :
2704 : // Mark the intrinsic widths as dirty on the frame, all of its ancestors,
2705 : // and all of its descendants, if needed:
2706 :
2707 0 : if (aIntrinsicDirty != eResize) {
2708 : // Mark argument and all ancestors dirty. (Unless we hit a reflow
2709 : // root that should contain the reflow. That root could be
2710 : // subtreeRoot itself if it's not dirty, or it could be some
2711 : // ancestor of subtreeRoot.)
2712 0 : for (nsIFrame *a = subtreeRoot;
2713 0 : a && !FRAME_IS_REFLOW_ROOT(a);
2714 : a = a->GetParent())
2715 0 : a->MarkIntrinsicWidthsDirty();
2716 : }
2717 :
2718 0 : if (aIntrinsicDirty == eStyleChange) {
2719 : // Mark all descendants dirty (using an nsTArray stack rather than
2720 : // recursion).
2721 0 : nsAutoTArray<nsIFrame*, 32> stack;
2722 0 : stack.AppendElement(subtreeRoot);
2723 :
2724 0 : do {
2725 0 : nsIFrame *f = stack.ElementAt(stack.Length() - 1);
2726 0 : stack.RemoveElementAt(stack.Length() - 1);
2727 :
2728 0 : if (f->GetType() == nsGkAtoms::placeholderFrame) {
2729 0 : nsIFrame *oof = nsPlaceholderFrame::GetRealFrameForPlaceholder(f);
2730 0 : if (!nsLayoutUtils::IsProperAncestorFrame(subtreeRoot, oof)) {
2731 : // We have another distinct subtree we need to mark.
2732 0 : subtrees.AppendElement(oof);
2733 : }
2734 : }
2735 :
2736 0 : nsIFrame::ChildListIterator lists(f);
2737 0 : for (; !lists.IsDone(); lists.Next()) {
2738 0 : nsFrameList::Enumerator childFrames(lists.CurrentList());
2739 0 : for (; !childFrames.AtEnd(); childFrames.Next()) {
2740 0 : nsIFrame* kid = childFrames.get();
2741 0 : kid->MarkIntrinsicWidthsDirty();
2742 0 : stack.AppendElement(kid);
2743 : }
2744 : }
2745 0 : } while (stack.Length() != 0);
2746 : }
2747 :
2748 : // Set NS_FRAME_HAS_DIRTY_CHILDREN bits (via nsIFrame::ChildIsDirty)
2749 : // up the tree until we reach either a frame that's already dirty or
2750 : // a reflow root.
2751 0 : nsIFrame *f = subtreeRoot;
2752 0 : for (;;) {
2753 0 : if (FRAME_IS_REFLOW_ROOT(f) || !f->GetParent()) {
2754 : // we've hit a reflow root or the root frame
2755 0 : if (!wasDirty) {
2756 0 : mDirtyRoots.AppendElement(f);
2757 0 : mDocument->SetNeedLayoutFlush();
2758 : }
2759 : #ifdef DEBUG
2760 : else {
2761 0 : VerifyHasDirtyRootAncestor(f);
2762 : }
2763 : #endif
2764 :
2765 0 : break;
2766 : }
2767 :
2768 0 : nsIFrame *child = f;
2769 0 : f = f->GetParent();
2770 0 : wasDirty = NS_SUBTREE_DIRTY(f);
2771 0 : f->ChildIsDirty(child);
2772 0 : NS_ASSERTION(f->GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN,
2773 : "ChildIsDirty didn't do its job");
2774 0 : if (wasDirty) {
2775 : // This frame was already marked dirty.
2776 : #ifdef DEBUG
2777 0 : VerifyHasDirtyRootAncestor(f);
2778 : #endif
2779 0 : break;
2780 : }
2781 : }
2782 0 : } while (subtrees.Length() != 0);
2783 :
2784 0 : MaybeScheduleReflow();
2785 : }
2786 :
2787 : void
2788 0 : PresShell::FrameNeedsToContinueReflow(nsIFrame *aFrame)
2789 : {
2790 0 : NS_ASSERTION(mIsReflowing, "Must be in reflow when marking path dirty.");
2791 0 : NS_PRECONDITION(mCurrentReflowRoot, "Must have a current reflow root here");
2792 0 : NS_ASSERTION(aFrame == mCurrentReflowRoot ||
2793 : nsLayoutUtils::IsProperAncestorFrame(mCurrentReflowRoot, aFrame),
2794 : "Frame passed in is not the descendant of mCurrentReflowRoot");
2795 0 : NS_ASSERTION(aFrame->GetStateBits() & NS_FRAME_IN_REFLOW,
2796 : "Frame passed in not in reflow?");
2797 :
2798 0 : mFramesToDirty.PutEntry(aFrame);
2799 0 : }
2800 :
2801 : nsIScrollableFrame*
2802 0 : nsIPresShell::GetFrameToScrollAsScrollable(
2803 : nsIPresShell::ScrollDirection aDirection)
2804 : {
2805 0 : nsIScrollableFrame* scrollFrame = nsnull;
2806 :
2807 0 : nsCOMPtr<nsIContent> focusedContent;
2808 0 : nsIFocusManager* fm = nsFocusManager::GetFocusManager();
2809 0 : if (fm && mDocument) {
2810 0 : nsCOMPtr<nsIDOMWindow> window = do_QueryInterface(mDocument->GetWindow());
2811 :
2812 0 : nsCOMPtr<nsIDOMElement> focusedElement;
2813 0 : fm->GetFocusedElementForWindow(window, false, nsnull, getter_AddRefs(focusedElement));
2814 0 : focusedContent = do_QueryInterface(focusedElement);
2815 : }
2816 0 : if (!focusedContent && mSelection) {
2817 : nsISelection* domSelection = mSelection->
2818 0 : GetSelection(nsISelectionController::SELECTION_NORMAL);
2819 0 : if (domSelection) {
2820 0 : nsCOMPtr<nsIDOMNode> focusedNode;
2821 0 : domSelection->GetFocusNode(getter_AddRefs(focusedNode));
2822 0 : focusedContent = do_QueryInterface(focusedNode);
2823 : }
2824 : }
2825 0 : if (focusedContent) {
2826 0 : nsIFrame* startFrame = focusedContent->GetPrimaryFrame();
2827 0 : if (startFrame) {
2828 0 : scrollFrame = startFrame->GetScrollTargetFrame();
2829 0 : if (scrollFrame) {
2830 0 : startFrame = scrollFrame->GetScrolledFrame();
2831 : }
2832 0 : if (aDirection == nsIPresShell::eEither) {
2833 : scrollFrame =
2834 0 : nsLayoutUtils::GetNearestScrollableFrame(startFrame);
2835 : } else {
2836 : scrollFrame =
2837 : nsLayoutUtils::GetNearestScrollableFrameForDirection(startFrame,
2838 : aDirection == eVertical ? nsLayoutUtils::eVertical :
2839 0 : nsLayoutUtils::eHorizontal);
2840 : }
2841 : }
2842 : }
2843 0 : if (!scrollFrame) {
2844 0 : scrollFrame = GetRootScrollFrameAsScrollable();
2845 : }
2846 0 : return scrollFrame;
2847 : }
2848 :
2849 : void
2850 0 : PresShell::CancelAllPendingReflows()
2851 : {
2852 0 : mDirtyRoots.Clear();
2853 :
2854 0 : if (mReflowScheduled) {
2855 0 : GetPresContext()->RefreshDriver()->RemoveLayoutFlushObserver(this);
2856 0 : mReflowScheduled = false;
2857 : }
2858 :
2859 0 : ASSERT_REFLOW_SCHEDULED_STATE();
2860 0 : }
2861 :
2862 : nsresult
2863 0 : PresShell::RecreateFramesFor(nsIContent* aContent)
2864 : {
2865 : NS_TIME_FUNCTION_MIN(1.0);
2866 :
2867 0 : NS_ENSURE_TRUE(mPresContext, NS_ERROR_FAILURE);
2868 0 : if (!mDidInitialReflow) {
2869 : // Nothing to do here. In fact, if we proceed and aContent is the
2870 : // root we will crash.
2871 0 : return NS_OK;
2872 : }
2873 :
2874 : // Don't call RecreateFramesForContent since that is not exported and we want
2875 : // to keep the number of entrypoints down.
2876 :
2877 0 : NS_ASSERTION(mViewManager, "Should have view manager");
2878 :
2879 : // Have to make sure that the content notifications are flushed before we
2880 : // start messing with the frame model; otherwise we can get content doubling.
2881 0 : mDocument->FlushPendingNotifications(Flush_ContentAndNotify);
2882 :
2883 0 : nsAutoScriptBlocker scriptBlocker;
2884 :
2885 0 : nsStyleChangeList changeList;
2886 0 : changeList.AppendChange(nsnull, aContent, nsChangeHint_ReconstructFrame);
2887 :
2888 : // Mark ourselves as not safe to flush while we're doing frame construction.
2889 0 : ++mChangeNestCount;
2890 0 : nsresult rv = mFrameConstructor->ProcessRestyledFrames(changeList);
2891 0 : --mChangeNestCount;
2892 :
2893 0 : return rv;
2894 : }
2895 :
2896 : void
2897 0 : nsIPresShell::PostRecreateFramesFor(Element* aElement)
2898 : {
2899 : FrameConstructor()->PostRestyleEvent(aElement, nsRestyleHint(0),
2900 0 : nsChangeHint_ReconstructFrame);
2901 0 : }
2902 :
2903 : void
2904 0 : nsIPresShell::RestyleForAnimation(Element* aElement, nsRestyleHint aHint)
2905 : {
2906 : FrameConstructor()->PostAnimationRestyleEvent(aElement, aHint,
2907 0 : NS_STYLE_HINT_NONE);
2908 0 : }
2909 :
2910 : void
2911 0 : PresShell::ClearFrameRefs(nsIFrame* aFrame)
2912 : {
2913 0 : mPresContext->EventStateManager()->ClearFrameRefs(aFrame);
2914 :
2915 0 : nsWeakFrame* weakFrame = mWeakFrames;
2916 0 : while (weakFrame) {
2917 0 : nsWeakFrame* prev = weakFrame->GetPreviousWeakFrame();
2918 0 : if (weakFrame->GetFrame() == aFrame) {
2919 : // This removes weakFrame from mWeakFrames.
2920 0 : weakFrame->Clear(this);
2921 : }
2922 0 : weakFrame = prev;
2923 : }
2924 0 : }
2925 :
2926 : already_AddRefed<nsRenderingContext>
2927 0 : PresShell::GetReferenceRenderingContext()
2928 : {
2929 : NS_TIME_FUNCTION_MIN(1.0);
2930 :
2931 0 : nsDeviceContext* devCtx = mPresContext->DeviceContext();
2932 0 : nsRefPtr<nsRenderingContext> rc;
2933 0 : if (mPresContext->IsScreen()) {
2934 0 : rc = new nsRenderingContext();
2935 0 : rc->Init(devCtx, gfxPlatform::GetPlatform()->ScreenReferenceSurface());
2936 : } else {
2937 0 : devCtx->CreateRenderingContext(*getter_AddRefs(rc));
2938 : }
2939 0 : return rc.forget();
2940 : }
2941 :
2942 : nsresult
2943 0 : PresShell::GoToAnchor(const nsAString& aAnchorName, bool aScroll)
2944 : {
2945 0 : if (!mDocument) {
2946 0 : return NS_ERROR_FAILURE;
2947 : }
2948 :
2949 : // Hold a reference to the ESM in case event dispatch tears us down.
2950 0 : nsRefPtr<nsEventStateManager> esm = mPresContext->EventStateManager();
2951 :
2952 0 : if (aAnchorName.IsEmpty()) {
2953 0 : NS_ASSERTION(!aScroll, "can't scroll to empty anchor name");
2954 0 : esm->SetContentState(nsnull, NS_EVENT_STATE_URLTARGET);
2955 0 : return NS_OK;
2956 : }
2957 :
2958 0 : nsCOMPtr<nsIDOMHTMLDocument> htmlDoc = do_QueryInterface(mDocument);
2959 0 : nsresult rv = NS_OK;
2960 0 : nsCOMPtr<nsIContent> content;
2961 :
2962 : // Search for an element with a matching "id" attribute
2963 0 : if (mDocument) {
2964 0 : content = mDocument->GetElementById(aAnchorName);
2965 : }
2966 :
2967 : // Search for an anchor element with a matching "name" attribute
2968 0 : if (!content && htmlDoc) {
2969 0 : nsCOMPtr<nsIDOMNodeList> list;
2970 : // Find a matching list of named nodes
2971 0 : rv = htmlDoc->GetElementsByName(aAnchorName, getter_AddRefs(list));
2972 0 : if (NS_SUCCEEDED(rv) && list) {
2973 : PRUint32 i;
2974 : // Loop through the named nodes looking for the first anchor
2975 0 : for (i = 0; true; i++) {
2976 0 : nsCOMPtr<nsIDOMNode> node;
2977 0 : rv = list->Item(i, getter_AddRefs(node));
2978 0 : if (!node) { // End of list
2979 : break;
2980 : }
2981 : // Ensure it's an anchor element
2982 0 : content = do_QueryInterface(node);
2983 0 : if (content) {
2984 0 : if (content->Tag() == nsGkAtoms::a && content->IsHTML()) {
2985 : break;
2986 : }
2987 0 : content = nsnull;
2988 : }
2989 : }
2990 : }
2991 : }
2992 :
2993 : // Search for anchor in the HTML namespace with a matching name
2994 0 : if (!content && !htmlDoc)
2995 : {
2996 0 : nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(mDocument);
2997 0 : nsCOMPtr<nsIDOMNodeList> list;
2998 0 : NS_NAMED_LITERAL_STRING(nameSpace, "http://www.w3.org/1999/xhtml");
2999 : // Get the list of anchor elements
3000 0 : rv = doc->GetElementsByTagNameNS(nameSpace, NS_LITERAL_STRING("a"), getter_AddRefs(list));
3001 0 : if (NS_SUCCEEDED(rv) && list) {
3002 : PRUint32 i;
3003 : // Loop through the named nodes looking for the first anchor
3004 0 : for (i = 0; true; i++) {
3005 0 : nsCOMPtr<nsIDOMNode> node;
3006 0 : rv = list->Item(i, getter_AddRefs(node));
3007 0 : if (!node) { // End of list
3008 : break;
3009 : }
3010 : // Compare the name attribute
3011 0 : nsCOMPtr<nsIDOMElement> element = do_QueryInterface(node);
3012 0 : nsAutoString value;
3013 0 : if (element && NS_SUCCEEDED(element->GetAttribute(NS_LITERAL_STRING("name"), value))) {
3014 0 : if (value.Equals(aAnchorName)) {
3015 0 : content = do_QueryInterface(element);
3016 : break;
3017 : }
3018 : }
3019 : }
3020 : }
3021 : }
3022 :
3023 0 : esm->SetContentState(content, NS_EVENT_STATE_URLTARGET);
3024 :
3025 : #ifdef ACCESSIBILITY
3026 0 : nsIContent *anchorTarget = content;
3027 : #endif
3028 :
3029 0 : if (content) {
3030 0 : if (aScroll) {
3031 : rv = ScrollContentIntoView(content, NS_PRESSHELL_SCROLL_TOP,
3032 : NS_PRESSHELL_SCROLL_ANYWHERE,
3033 0 : ANCHOR_SCROLL_FLAGS);
3034 0 : NS_ENSURE_SUCCESS(rv, rv);
3035 :
3036 0 : nsIScrollableFrame* rootScroll = GetRootScrollFrameAsScrollable();
3037 0 : if (rootScroll) {
3038 0 : mLastAnchorScrolledTo = content;
3039 0 : mLastAnchorScrollPositionY = rootScroll->GetScrollPosition().y;
3040 : }
3041 : }
3042 :
3043 : // Should we select the target? This action is controlled by a
3044 : // preference: the default is to not select.
3045 0 : bool selectAnchor = Preferences::GetBool("layout.selectanchor");
3046 :
3047 : // Even if select anchor pref is false, we must still move the
3048 : // caret there. That way tabbing will start from the new
3049 : // location
3050 0 : nsRefPtr<nsIDOMRange> jumpToRange = new nsRange();
3051 0 : while (content && content->GetFirstChild()) {
3052 0 : content = content->GetFirstChild();
3053 : }
3054 0 : nsCOMPtr<nsIDOMNode> node(do_QueryInterface(content));
3055 0 : NS_ASSERTION(node, "No nsIDOMNode for descendant of anchor");
3056 0 : jumpToRange->SelectNodeContents(node);
3057 : // Select the anchor
3058 : nsISelection* sel = mSelection->
3059 0 : GetSelection(nsISelectionController::SELECTION_NORMAL);
3060 0 : if (sel) {
3061 0 : sel->RemoveAllRanges();
3062 0 : sel->AddRange(jumpToRange);
3063 0 : if (!selectAnchor) {
3064 : // Use a caret (collapsed selection) at the start of the anchor
3065 0 : sel->CollapseToStart();
3066 : }
3067 : }
3068 : // Selection is at anchor.
3069 : // Now focus the document itself if focus is on an element within it.
3070 0 : nsPIDOMWindow *win = mDocument->GetWindow();
3071 :
3072 0 : nsIFocusManager* fm = nsFocusManager::GetFocusManager();
3073 0 : if (fm && win) {
3074 0 : nsCOMPtr<nsIDOMWindow> focusedWindow;
3075 0 : fm->GetFocusedWindow(getter_AddRefs(focusedWindow));
3076 0 : if (SameCOMIdentity(win, focusedWindow)) {
3077 0 : fm->ClearFocus(focusedWindow);
3078 : }
3079 : }
3080 : } else {
3081 0 : rv = NS_ERROR_FAILURE;
3082 0 : NS_NAMED_LITERAL_STRING(top, "top");
3083 0 : if (nsContentUtils::EqualsIgnoreASCIICase(aAnchorName, top)) {
3084 : // Scroll to the top/left if aAnchorName is "top" and there is no element
3085 : // with such a name or id.
3086 0 : rv = NS_OK;
3087 0 : nsIScrollableFrame* sf = GetRootScrollFrameAsScrollable();
3088 : // Check |aScroll| after setting |rv| so we set |rv| to the same
3089 : // thing whether or not |aScroll| is true.
3090 0 : if (aScroll && sf) {
3091 : // Scroll to the top of the page
3092 0 : sf->ScrollTo(nsPoint(0, 0), nsIScrollableFrame::INSTANT);
3093 : }
3094 : }
3095 : }
3096 :
3097 : #ifdef ACCESSIBILITY
3098 0 : if (anchorTarget) {
3099 0 : nsAccessibilityService* accService = AccService();
3100 0 : if (accService)
3101 0 : accService->NotifyOfAnchorJumpTo(anchorTarget);
3102 : }
3103 : #endif
3104 :
3105 0 : return rv;
3106 : }
3107 :
3108 : nsresult
3109 0 : PresShell::ScrollToAnchor()
3110 : {
3111 0 : if (!mLastAnchorScrolledTo)
3112 0 : return NS_OK;
3113 :
3114 0 : NS_ASSERTION(mDidInitialReflow, "should have done initial reflow by now");
3115 :
3116 0 : nsIScrollableFrame* rootScroll = GetRootScrollFrameAsScrollable();
3117 0 : if (!rootScroll ||
3118 0 : mLastAnchorScrollPositionY != rootScroll->GetScrollPosition().y)
3119 0 : return NS_OK;
3120 :
3121 : nsresult rv = ScrollContentIntoView(mLastAnchorScrolledTo, NS_PRESSHELL_SCROLL_TOP,
3122 : NS_PRESSHELL_SCROLL_ANYWHERE,
3123 0 : ANCHOR_SCROLL_FLAGS);
3124 0 : mLastAnchorScrolledTo = nsnull;
3125 0 : return rv;
3126 : }
3127 :
3128 : /*
3129 : * Helper (per-continuation) for ScrollContentIntoView.
3130 : *
3131 : * @param aContainerFrame [in] the frame which aRect is relative to
3132 : * @param aFrame [in] Frame whose bounds should be unioned
3133 : * @param aUseWholeLineHeightForInlines [in] if true, then for inline frames
3134 : * we should include the top of the line in the added rectangle
3135 : * @param aRect [inout] rect into which its bounds should be unioned
3136 : * @param aHaveRect [inout] whether aRect contains data yet
3137 : * @param aPrevBlock [inout] the block aLines is a line iterator for
3138 : * @param aLines [inout] the line iterator we're using
3139 : * @param aCurLine [inout] the line to start looking from in this iterator
3140 : */
3141 : static void
3142 0 : AccumulateFrameBounds(nsIFrame* aContainerFrame,
3143 : nsIFrame* aFrame,
3144 : bool aUseWholeLineHeightForInlines,
3145 : nsRect& aRect,
3146 : bool& aHaveRect,
3147 : nsIFrame*& aPrevBlock,
3148 : nsAutoLineIterator& aLines,
3149 : PRInt32& aCurLine)
3150 : {
3151 0 : nsRect frameBounds = aFrame->GetRect() +
3152 0 : aFrame->GetParent()->GetOffsetTo(aContainerFrame);
3153 :
3154 : // If this is an inline frame and either the bounds height is 0 (quirks
3155 : // layout model) or aUseWholeLineHeightForInlines is set, we need to
3156 : // change the top of the bounds to include the whole line.
3157 0 : if (frameBounds.height == 0 || aUseWholeLineHeightForInlines) {
3158 0 : nsIAtom* frameType = NULL;
3159 0 : nsIFrame *prevFrame = aFrame;
3160 0 : nsIFrame *f = aFrame;
3161 :
3162 0 : while (f &&
3163 0 : (frameType = f->GetType()) == nsGkAtoms::inlineFrame) {
3164 0 : prevFrame = f;
3165 0 : f = prevFrame->GetParent();
3166 : }
3167 :
3168 0 : if (f != aFrame &&
3169 : f &&
3170 : frameType == nsGkAtoms::blockFrame) {
3171 : // find the line containing aFrame and increase the top of |offset|.
3172 0 : if (f != aPrevBlock) {
3173 0 : aLines = f->GetLineIterator();
3174 0 : aPrevBlock = f;
3175 0 : aCurLine = 0;
3176 : }
3177 0 : if (aLines) {
3178 0 : PRInt32 index = aLines->FindLineContaining(prevFrame, aCurLine);
3179 0 : if (index >= 0) {
3180 0 : aCurLine = index;
3181 : nsIFrame *trash1;
3182 : PRInt32 trash2;
3183 0 : nsRect lineBounds;
3184 : PRUint32 trash3;
3185 :
3186 0 : if (NS_SUCCEEDED(aLines->GetLine(index, &trash1, &trash2,
3187 : lineBounds, &trash3))) {
3188 0 : lineBounds += f->GetOffsetTo(aContainerFrame);
3189 0 : if (lineBounds.y < frameBounds.y) {
3190 0 : frameBounds.height = frameBounds.YMost() - lineBounds.y;
3191 0 : frameBounds.y = lineBounds.y;
3192 : }
3193 : }
3194 : }
3195 : }
3196 : }
3197 : }
3198 :
3199 0 : if (aHaveRect) {
3200 : // We can't use nsRect::UnionRect since it drops empty rects on
3201 : // the floor, and we need to include them. (Thus we need
3202 : // aHaveRect to know when to drop the initial value on the floor.)
3203 0 : aRect.UnionRectEdges(aRect, frameBounds);
3204 : } else {
3205 0 : aHaveRect = true;
3206 0 : aRect = frameBounds;
3207 : }
3208 0 : }
3209 :
3210 : /**
3211 : * This function takes a scrollable frame, a rect in the coordinate system
3212 : * of the scrolled frame, and a desired percentage-based scroll
3213 : * position and attempts to scroll the rect to that position in the
3214 : * scrollport.
3215 : *
3216 : * This needs to work even if aRect has a width or height of zero.
3217 : */
3218 0 : static void ScrollToShowRect(nsIScrollableFrame* aScrollFrame,
3219 : const nsRect& aRect,
3220 : PRIntn aVPercent,
3221 : PRIntn aHPercent,
3222 : PRUint32 aFlags)
3223 : {
3224 0 : nsPoint scrollPt = aScrollFrame->GetScrollPosition();
3225 0 : nsRect visibleRect(scrollPt, aScrollFrame->GetScrollPortRect().Size());
3226 0 : nsSize lineSize = aScrollFrame->GetLineScrollAmount();
3227 0 : nsPresContext::ScrollbarStyles ss = aScrollFrame->GetScrollbarStyles();
3228 :
3229 0 : if ((aFlags & nsIPresShell::SCROLL_OVERFLOW_HIDDEN) ||
3230 : ss.mVertical != NS_STYLE_OVERFLOW_HIDDEN) {
3231 : // See how the rect should be positioned vertically
3232 0 : if (NS_PRESSHELL_SCROLL_ANYWHERE == aVPercent ||
3233 : (NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE == aVPercent &&
3234 : aRect.height < lineSize.height)) {
3235 : // The caller doesn't care where the frame is positioned vertically,
3236 : // so long as it's fully visible
3237 0 : if (aRect.y < visibleRect.y) {
3238 : // Scroll up so the frame's top edge is visible
3239 0 : scrollPt.y = aRect.y;
3240 0 : } else if (aRect.YMost() > visibleRect.YMost()) {
3241 : // Scroll down so the frame's bottom edge is visible. Make sure the
3242 : // frame's top edge is still visible
3243 0 : scrollPt.y += aRect.YMost() - visibleRect.YMost();
3244 0 : if (scrollPt.y > aRect.y) {
3245 0 : scrollPt.y = aRect.y;
3246 : }
3247 : }
3248 0 : } else if (NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE == aVPercent) {
3249 : // Scroll only if no part of the frame is visible in this view
3250 0 : if (aRect.YMost() - lineSize.height < visibleRect.y) {
3251 : // Scroll up so the frame's top edge is visible
3252 0 : scrollPt.y = aRect.y;
3253 0 : } else if (aRect.y + lineSize.height > visibleRect.YMost()) {
3254 : // Scroll down so the frame's bottom edge is visible. Make sure the
3255 : // frame's top edge is still visible
3256 0 : scrollPt.y += aRect.YMost() - visibleRect.YMost();
3257 0 : if (scrollPt.y > aRect.y) {
3258 0 : scrollPt.y = aRect.y;
3259 : }
3260 : }
3261 : } else {
3262 : // Align the frame edge according to the specified percentage
3263 : nscoord frameAlignY =
3264 0 : NSToCoordRound(aRect.y + aRect.height * (aVPercent / 100.0f));
3265 : scrollPt.y =
3266 0 : NSToCoordRound(frameAlignY - visibleRect.height * (aVPercent / 100.0f));
3267 : }
3268 : }
3269 :
3270 0 : if ((aFlags & nsIPresShell::SCROLL_OVERFLOW_HIDDEN) ||
3271 : ss.mHorizontal != NS_STYLE_OVERFLOW_HIDDEN) {
3272 : // See how the frame should be positioned horizontally
3273 0 : if (NS_PRESSHELL_SCROLL_ANYWHERE == aHPercent ||
3274 : (NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE == aHPercent &&
3275 : aRect.width < lineSize.width)) {
3276 : // The caller doesn't care where the frame is positioned horizontally,
3277 : // so long as it's fully visible
3278 0 : if (aRect.x < visibleRect.x) {
3279 : // Scroll left so the frame's left edge is visible
3280 0 : scrollPt.x = aRect.x;
3281 0 : } else if (aRect.XMost() > visibleRect.XMost()) {
3282 : // Scroll right so the frame's right edge is visible. Make sure the
3283 : // frame's left edge is still visible
3284 0 : scrollPt.x += aRect.XMost() - visibleRect.XMost();
3285 0 : if (scrollPt.x > aRect.x) {
3286 0 : scrollPt.x = aRect.x;
3287 : }
3288 : }
3289 0 : } else if (NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE == aHPercent) {
3290 : // Scroll only if no part of the frame is visible in this view
3291 0 : if (aRect.XMost() - lineSize.width < visibleRect.x) {
3292 : // Scroll left so the frame's left edge is visible
3293 0 : scrollPt.x = aRect.x;
3294 0 : } else if (aRect.x + lineSize.width > visibleRect.XMost()) {
3295 : // Scroll right so the frame's right edge is visible. Make sure the
3296 : // frame's left edge is still visible
3297 0 : scrollPt.x += aRect.XMost() - visibleRect.XMost();
3298 0 : if (scrollPt.x > aRect.x) {
3299 0 : scrollPt.x = aRect.x;
3300 : }
3301 : }
3302 : } else {
3303 : // Align the frame edge according to the specified percentage
3304 : nscoord frameAlignX =
3305 0 : NSToCoordRound(aRect.x + (aRect.width) * (aHPercent / 100.0f));
3306 : scrollPt.x =
3307 0 : NSToCoordRound(frameAlignX - visibleRect.width * (aHPercent / 100.0f));
3308 : }
3309 : }
3310 :
3311 0 : aScrollFrame->ScrollTo(scrollPt, nsIScrollableFrame::INSTANT);
3312 0 : }
3313 :
3314 : nsresult
3315 0 : PresShell::ScrollContentIntoView(nsIContent* aContent,
3316 : PRIntn aVPercent,
3317 : PRIntn aHPercent,
3318 : PRUint32 aFlags)
3319 : {
3320 0 : nsCOMPtr<nsIContent> content = aContent; // Keep content alive while flushing.
3321 0 : NS_ENSURE_TRUE(content, NS_ERROR_NULL_POINTER);
3322 0 : nsCOMPtr<nsIDocument> currentDoc = content->GetCurrentDoc();
3323 0 : NS_ENSURE_STATE(currentDoc);
3324 :
3325 0 : NS_ASSERTION(mDidInitialReflow, "should have done initial reflow by now");
3326 :
3327 0 : mContentToScrollTo = aContent;
3328 0 : mContentScrollVPosition = aVPercent;
3329 0 : mContentScrollHPosition = aHPercent;
3330 0 : mContentToScrollToFlags = aFlags;
3331 :
3332 : // Flush layout and attempt to scroll in the process.
3333 0 : currentDoc->SetNeedLayoutFlush();
3334 0 : currentDoc->FlushPendingNotifications(Flush_InterruptibleLayout);
3335 :
3336 : // If mContentToScrollTo is non-null, that means we interrupted the reflow
3337 : // (or suppressed it altogether because we're suppressing interruptible
3338 : // flushes right now) and won't necessarily get the position correct, but do
3339 : // a best-effort scroll here. The other option would be to do this inside
3340 : // FlushPendingNotifications, but I'm not sure the repeated scrolling that
3341 : // could trigger if reflows keep getting interrupted would be more desirable
3342 : // than a single best-effort scroll followed by one final scroll on the first
3343 : // completed reflow.
3344 0 : if (mContentToScrollTo) {
3345 0 : DoScrollContentIntoView(content, aVPercent, aHPercent, aFlags);
3346 : }
3347 0 : return NS_OK;
3348 : }
3349 :
3350 : void
3351 0 : PresShell::DoScrollContentIntoView(nsIContent* aContent,
3352 : PRIntn aVPercent,
3353 : PRIntn aHPercent,
3354 : PRUint32 aFlags)
3355 : {
3356 0 : NS_ASSERTION(mDidInitialReflow, "should have done initial reflow by now");
3357 :
3358 0 : nsIFrame* frame = aContent->GetPrimaryFrame();
3359 0 : if (!frame) {
3360 0 : mContentToScrollTo = nsnull;
3361 0 : return;
3362 : }
3363 :
3364 0 : if (frame->GetStateBits() & NS_FRAME_FIRST_REFLOW) {
3365 : // The reflow flush before this scroll got interrupted, and this frame's
3366 : // coords and size are all zero, and it has no content showing anyway.
3367 : // Don't bother scrolling to it. We'll try again when we finish up layout.
3368 0 : return;
3369 : }
3370 :
3371 : nsIFrame* container =
3372 0 : nsLayoutUtils::GetClosestFrameOfType(frame, nsGkAtoms::scrollFrame);
3373 0 : if (!container) {
3374 : // nothing can be scrolled
3375 0 : return;
3376 : }
3377 :
3378 : // This is a two-step process.
3379 : // Step 1: Find the bounds of the rect we want to scroll into view. For
3380 : // example, for an inline frame we may want to scroll in the whole
3381 : // line, or we may want to scroll multiple lines into view.
3382 : // Step 2: Walk container frame and its ancestors and scroll them
3383 : // appropriately.
3384 : // frameBounds is relative to container. We're assuming
3385 : // that scrollframes don't split so every continuation of frame will
3386 : // be a descendant of container. (Things would still mostly work
3387 : // even if that assumption was false.)
3388 0 : nsRect frameBounds;
3389 0 : bool haveRect = false;
3390 0 : bool useWholeLineHeightForInlines = aVPercent != NS_PRESSHELL_SCROLL_ANYWHERE;
3391 : // Reuse the same line iterator across calls to AccumulateFrameBounds. We set
3392 : // it every time we detect a new block (stored in prevBlock).
3393 0 : nsIFrame* prevBlock = nsnull;
3394 0 : nsAutoLineIterator lines;
3395 : // The last line we found a continuation on in |lines|. We assume that later
3396 : // continuations cannot come on earlier lines.
3397 0 : PRInt32 curLine = 0;
3398 0 : do {
3399 : AccumulateFrameBounds(container, frame, useWholeLineHeightForInlines,
3400 0 : frameBounds, haveRect, prevBlock, lines, curLine);
3401 0 : } while ((frame = frame->GetNextContinuation()));
3402 :
3403 : ScrollFrameRectIntoView(container, frameBounds, aVPercent, aHPercent,
3404 0 : aFlags);
3405 : }
3406 :
3407 : bool
3408 0 : PresShell::ScrollFrameRectIntoView(nsIFrame* aFrame,
3409 : const nsRect& aRect,
3410 : PRIntn aVPercent,
3411 : PRIntn aHPercent,
3412 : PRUint32 aFlags)
3413 : {
3414 0 : bool didScroll = false;
3415 : // This function needs to work even if rect has a width or height of 0.
3416 0 : nsRect rect = aRect;
3417 0 : nsIFrame* container = aFrame;
3418 : // Walk up the frame hierarchy scrolling the rect into view and
3419 : // keeping rect relative to container
3420 0 : do {
3421 0 : nsIScrollableFrame* sf = do_QueryFrame(container);
3422 0 : if (sf) {
3423 0 : nsPoint oldPosition = sf->GetScrollPosition();
3424 0 : ScrollToShowRect(sf, rect - sf->GetScrolledFrame()->GetPosition(),
3425 0 : aVPercent, aHPercent, aFlags);
3426 0 : nsPoint newPosition = sf->GetScrollPosition();
3427 : // If the scroll position increased, that means our content moved up,
3428 : // so our rect's offset should decrease
3429 0 : rect += oldPosition - newPosition;
3430 :
3431 0 : if (oldPosition != newPosition) {
3432 0 : didScroll = true;
3433 : }
3434 :
3435 : // only scroll one container when this flag is set
3436 0 : if (aFlags & nsIPresShell::SCROLL_FIRST_ANCESTOR_ONLY) {
3437 0 : break;
3438 : }
3439 : }
3440 0 : rect += container->GetPosition();
3441 0 : nsIFrame* parent = container->GetParent();
3442 0 : if (!parent && !(aFlags & nsIPresShell::SCROLL_NO_PARENT_FRAMES)) {
3443 0 : nsPoint extraOffset(0,0);
3444 0 : parent = nsLayoutUtils::GetCrossDocParentFrame(container, &extraOffset);
3445 0 : if (parent) {
3446 0 : PRInt32 APD = container->PresContext()->AppUnitsPerDevPixel();
3447 0 : PRInt32 parentAPD = parent->PresContext()->AppUnitsPerDevPixel();
3448 0 : rect = rect.ConvertAppUnitsRoundOut(APD, parentAPD);
3449 0 : rect += extraOffset;
3450 : }
3451 : }
3452 0 : container = parent;
3453 : } while (container);
3454 :
3455 0 : return didScroll;
3456 : }
3457 :
3458 : nsRectVisibility
3459 0 : PresShell::GetRectVisibility(nsIFrame* aFrame,
3460 : const nsRect &aRect,
3461 : nscoord aMinTwips) const
3462 : {
3463 0 : NS_ASSERTION(aFrame->PresContext() == GetPresContext(),
3464 : "prescontext mismatch?");
3465 0 : nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
3466 0 : NS_ASSERTION(rootFrame,
3467 : "How can someone have a frame for this presshell when there's no root?");
3468 0 : nsIScrollableFrame* sf = GetRootScrollFrameAsScrollable();
3469 0 : nsRect scrollPortRect;
3470 0 : if (sf) {
3471 0 : scrollPortRect = sf->GetScrollPortRect();
3472 0 : nsIFrame* f = do_QueryFrame(sf);
3473 0 : scrollPortRect += f->GetOffsetTo(rootFrame);
3474 : } else {
3475 0 : scrollPortRect = nsRect(nsPoint(0,0), rootFrame->GetSize());
3476 : }
3477 :
3478 0 : nsRect r = aRect + aFrame->GetOffsetTo(rootFrame);
3479 : // If aRect is entirely visible then we don't need to ensure that
3480 : // at least aMinTwips of it is visible
3481 0 : if (scrollPortRect.Contains(r))
3482 0 : return nsRectVisibility_kVisible;
3483 :
3484 0 : nsRect insetRect = scrollPortRect;
3485 0 : insetRect.Deflate(aMinTwips, aMinTwips);
3486 0 : if (r.YMost() <= insetRect.y)
3487 0 : return nsRectVisibility_kAboveViewport;
3488 0 : if (r.y >= insetRect.YMost())
3489 0 : return nsRectVisibility_kBelowViewport;
3490 0 : if (r.XMost() <= insetRect.x)
3491 0 : return nsRectVisibility_kLeftOfViewport;
3492 0 : if (r.x >= insetRect.XMost())
3493 0 : return nsRectVisibility_kRightOfViewport;
3494 :
3495 0 : return nsRectVisibility_kVisible;
3496 : }
3497 :
3498 : // GetLinkLocation: copy link location to clipboard
3499 0 : nsresult PresShell::GetLinkLocation(nsIDOMNode* aNode, nsAString& aLocationString) const
3500 : {
3501 : #ifdef DEBUG_dr
3502 : printf("dr :: PresShell::GetLinkLocation\n");
3503 : #endif
3504 :
3505 0 : NS_ENSURE_ARG_POINTER(aNode);
3506 :
3507 0 : nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
3508 0 : if (content) {
3509 0 : nsCOMPtr<nsIURI> hrefURI = content->GetHrefURI();
3510 0 : if (hrefURI) {
3511 0 : nsCAutoString specUTF8;
3512 0 : nsresult rv = hrefURI->GetSpec(specUTF8);
3513 0 : NS_ENSURE_SUCCESS(rv, rv);
3514 :
3515 0 : nsAutoString anchorText;
3516 0 : CopyUTF8toUTF16(specUTF8, anchorText);
3517 :
3518 : // Remove all the '\t', '\r' and '\n' from 'anchorText'
3519 : static const char strippedChars[] = "\t\r\n";
3520 0 : anchorText.StripChars(strippedChars);
3521 0 : aLocationString = anchorText;
3522 0 : return NS_OK;
3523 : }
3524 : }
3525 :
3526 : // if no link, fail.
3527 0 : return NS_ERROR_FAILURE;
3528 : }
3529 :
3530 : void
3531 0 : PresShell::ScheduleViewManagerFlush()
3532 : {
3533 0 : nsPresContext* presContext = GetPresContext();
3534 0 : if (presContext) {
3535 0 : presContext->RefreshDriver()->ScheduleViewManagerFlush();
3536 : }
3537 0 : if (mDocument) {
3538 0 : mDocument->SetNeedLayoutFlush();
3539 : }
3540 0 : }
3541 :
3542 : void
3543 0 : PresShell::DispatchSynthMouseMove(nsGUIEvent *aEvent,
3544 : bool aFlushOnHoverChange)
3545 : {
3546 0 : PRUint32 hoverGenerationBefore = mFrameConstructor->GetHoverGeneration();
3547 : nsEventStatus status;
3548 0 : nsIView* targetView = nsIView::GetViewFor(aEvent->widget);
3549 0 : targetView->GetViewManager()->DispatchEvent(aEvent, targetView, &status);
3550 0 : if (aFlushOnHoverChange &&
3551 0 : hoverGenerationBefore != mFrameConstructor->GetHoverGeneration()) {
3552 : // Flush so that the resulting reflow happens now so that our caller
3553 : // can suppress any synthesized mouse moves caused by that reflow.
3554 0 : FlushPendingNotifications(Flush_Layout);
3555 : }
3556 0 : }
3557 :
3558 : void
3559 0 : PresShell::ClearMouseCaptureOnView(nsIView* aView)
3560 : {
3561 0 : if (gCaptureInfo.mContent) {
3562 0 : if (aView) {
3563 : // if a view was specified, ensure that the captured content is within
3564 : // this view.
3565 0 : nsIFrame* frame = gCaptureInfo.mContent->GetPrimaryFrame();
3566 0 : if (frame) {
3567 0 : nsIView* view = frame->GetClosestView();
3568 : // if there is no view, capturing won't be handled any more, so
3569 : // just release the capture.
3570 0 : if (view) {
3571 0 : do {
3572 0 : if (view == aView) {
3573 0 : NS_RELEASE(gCaptureInfo.mContent);
3574 : // the view containing the captured content likely disappeared so
3575 : // disable capture for now.
3576 0 : gCaptureInfo.mAllowed = false;
3577 0 : break;
3578 : }
3579 :
3580 0 : view = view->GetParent();
3581 : } while (view);
3582 : // return if the view wasn't found
3583 0 : return;
3584 : }
3585 : }
3586 : }
3587 :
3588 0 : NS_RELEASE(gCaptureInfo.mContent);
3589 : }
3590 :
3591 : // disable mouse capture until the next mousedown as a dialog has opened
3592 : // or a drag has started. Otherwise, someone could start capture during
3593 : // the modal dialog or drag.
3594 0 : gCaptureInfo.mAllowed = false;
3595 : }
3596 :
3597 : void
3598 0 : nsIPresShell::ClearMouseCapture(nsIFrame* aFrame)
3599 : {
3600 0 : if (!gCaptureInfo.mContent) {
3601 0 : gCaptureInfo.mAllowed = false;
3602 0 : return;
3603 : }
3604 :
3605 : // null frame argument means clear the capture
3606 0 : if (!aFrame) {
3607 0 : NS_RELEASE(gCaptureInfo.mContent);
3608 0 : gCaptureInfo.mAllowed = false;
3609 0 : return;
3610 : }
3611 :
3612 0 : nsIFrame* capturingFrame = gCaptureInfo.mContent->GetPrimaryFrame();
3613 0 : if (!capturingFrame) {
3614 0 : NS_RELEASE(gCaptureInfo.mContent);
3615 0 : gCaptureInfo.mAllowed = false;
3616 0 : return;
3617 : }
3618 :
3619 0 : if (nsLayoutUtils::IsAncestorFrameCrossDoc(aFrame, capturingFrame)) {
3620 0 : NS_RELEASE(gCaptureInfo.mContent);
3621 0 : gCaptureInfo.mAllowed = false;
3622 : }
3623 : }
3624 :
3625 : nsresult
3626 0 : PresShell::CaptureHistoryState(nsILayoutHistoryState** aState, bool aLeavingPage)
3627 : {
3628 : NS_TIME_FUNCTION_MIN(1.0);
3629 :
3630 0 : nsresult rv = NS_OK;
3631 :
3632 0 : NS_PRECONDITION(nsnull != aState, "null state pointer");
3633 :
3634 : // We actually have to mess with the docshell here, since we want to
3635 : // store the state back in it.
3636 : // XXXbz this isn't really right, since this is being called in the
3637 : // content viewer's Hide() method... by that point the docshell's
3638 : // state could be wrong. We should sort out a better ownership
3639 : // model for the layout history state.
3640 0 : nsCOMPtr<nsISupports> container = mPresContext->GetContainer();
3641 0 : if (!container)
3642 0 : return NS_ERROR_FAILURE;
3643 :
3644 0 : nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(container));
3645 0 : if (!docShell)
3646 0 : return NS_ERROR_FAILURE;
3647 :
3648 0 : nsCOMPtr<nsILayoutHistoryState> historyState;
3649 0 : docShell->GetLayoutHistoryState(getter_AddRefs(historyState));
3650 0 : if (!historyState) {
3651 : // Create the document state object
3652 0 : rv = NS_NewLayoutHistoryState(getter_AddRefs(historyState));
3653 :
3654 0 : if (NS_FAILED(rv)) {
3655 0 : *aState = nsnull;
3656 0 : return rv;
3657 : }
3658 :
3659 0 : docShell->SetLayoutHistoryState(historyState);
3660 : }
3661 :
3662 0 : *aState = historyState;
3663 0 : NS_IF_ADDREF(*aState);
3664 :
3665 : // Capture frame state for the entire frame hierarchy
3666 0 : nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
3667 0 : if (!rootFrame) return NS_OK;
3668 : // Capture frame state for the root scroll frame
3669 : // Don't capture state when first creating doc element hierarchy
3670 : // As the scroll position is 0 and this will cause us to lose
3671 : // our previously saved place!
3672 0 : if (aLeavingPage) {
3673 0 : nsIFrame* scrollFrame = GetRootScrollFrame();
3674 0 : if (scrollFrame) {
3675 : mFrameConstructor->CaptureFrameStateFor(scrollFrame, historyState,
3676 0 : nsIStatefulFrame::eDocumentScrollState);
3677 : }
3678 : }
3679 :
3680 0 : mFrameConstructor->CaptureFrameState(rootFrame, historyState);
3681 :
3682 0 : return NS_OK;
3683 : }
3684 :
3685 : void
3686 0 : PresShell::UnsuppressAndInvalidate()
3687 : {
3688 : // Note: We ignore the EnsureVisible check for resource documents, because
3689 : // they won't have a docshell, so they'll always fail EnsureVisible.
3690 0 : if ((!mDocument->IsResourceDoc() && !mPresContext->EnsureVisible()) ||
3691 : mHaveShutDown) {
3692 : // No point; we're about to be torn down anyway.
3693 0 : return;
3694 : }
3695 :
3696 0 : mPaintingSuppressed = false;
3697 0 : nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
3698 0 : if (rootFrame) {
3699 : // let's assume that outline on a root frame is not supported
3700 0 : nsRect rect(nsPoint(0, 0), rootFrame->GetSize());
3701 0 : rootFrame->Invalidate(rect);
3702 :
3703 0 : if (mCaretEnabled && mCaret) {
3704 0 : mCaret->CheckCaretDrawingState();
3705 : }
3706 :
3707 0 : nsRootPresContext* rootPC = mPresContext->GetRootPresContext();
3708 0 : if (rootPC) {
3709 0 : rootPC->RequestUpdatePluginGeometry(rootFrame);
3710 : }
3711 : }
3712 :
3713 : // now that painting is unsuppressed, focus may be set on the document
3714 0 : nsPIDOMWindow *win = mDocument->GetWindow();
3715 0 : if (win)
3716 0 : win->SetReadyForFocus();
3717 :
3718 0 : if (!mHaveShutDown)
3719 0 : SynthesizeMouseMove(false);
3720 : }
3721 :
3722 : void
3723 0 : PresShell::UnsuppressPainting()
3724 : {
3725 0 : if (mPaintSuppressionTimer) {
3726 0 : mPaintSuppressionTimer->Cancel();
3727 0 : mPaintSuppressionTimer = nsnull;
3728 : }
3729 :
3730 0 : if (mIsDocumentGone || !mPaintingSuppressed)
3731 0 : return;
3732 :
3733 : // If we have reflows pending, just wait until we process
3734 : // the reflows and get all the frames where we want them
3735 : // before actually unlocking the painting. Otherwise
3736 : // go ahead and unlock now.
3737 0 : if (!mDirtyRoots.IsEmpty())
3738 0 : mShouldUnsuppressPainting = true;
3739 : else
3740 0 : UnsuppressAndInvalidate();
3741 : }
3742 :
3743 : // Post a request to handle an arbitrary callback after reflow has finished.
3744 : nsresult
3745 0 : PresShell::PostReflowCallback(nsIReflowCallback* aCallback)
3746 : {
3747 0 : void* result = AllocateMisc(sizeof(nsCallbackEventRequest));
3748 0 : if (NS_UNLIKELY(!result)) {
3749 0 : return NS_ERROR_OUT_OF_MEMORY;
3750 : }
3751 0 : nsCallbackEventRequest* request = (nsCallbackEventRequest*)result;
3752 :
3753 0 : request->callback = aCallback;
3754 0 : request->next = nsnull;
3755 :
3756 0 : if (mLastCallbackEventRequest) {
3757 0 : mLastCallbackEventRequest = mLastCallbackEventRequest->next = request;
3758 : } else {
3759 0 : mFirstCallbackEventRequest = request;
3760 0 : mLastCallbackEventRequest = request;
3761 : }
3762 :
3763 0 : return NS_OK;
3764 : }
3765 :
3766 : void
3767 0 : PresShell::CancelReflowCallback(nsIReflowCallback* aCallback)
3768 : {
3769 0 : nsCallbackEventRequest* before = nsnull;
3770 0 : nsCallbackEventRequest* node = mFirstCallbackEventRequest;
3771 0 : while(node)
3772 : {
3773 0 : nsIReflowCallback* callback = node->callback;
3774 :
3775 0 : if (callback == aCallback)
3776 : {
3777 0 : nsCallbackEventRequest* toFree = node;
3778 0 : if (node == mFirstCallbackEventRequest) {
3779 0 : node = node->next;
3780 0 : mFirstCallbackEventRequest = node;
3781 0 : NS_ASSERTION(before == nsnull, "impossible");
3782 : } else {
3783 0 : node = node->next;
3784 0 : before->next = node;
3785 : }
3786 :
3787 0 : if (toFree == mLastCallbackEventRequest) {
3788 0 : mLastCallbackEventRequest = before;
3789 : }
3790 :
3791 0 : FreeMisc(sizeof(nsCallbackEventRequest), toFree);
3792 : } else {
3793 0 : before = node;
3794 0 : node = node->next;
3795 : }
3796 : }
3797 0 : }
3798 :
3799 : void
3800 0 : PresShell::CancelPostedReflowCallbacks()
3801 : {
3802 0 : while (mFirstCallbackEventRequest) {
3803 0 : nsCallbackEventRequest* node = mFirstCallbackEventRequest;
3804 0 : mFirstCallbackEventRequest = node->next;
3805 0 : if (!mFirstCallbackEventRequest) {
3806 0 : mLastCallbackEventRequest = nsnull;
3807 : }
3808 0 : nsIReflowCallback* callback = node->callback;
3809 0 : FreeMisc(sizeof(nsCallbackEventRequest), node);
3810 0 : if (callback) {
3811 0 : callback->ReflowCallbackCanceled();
3812 : }
3813 : }
3814 0 : }
3815 :
3816 : void
3817 0 : PresShell::HandlePostedReflowCallbacks(bool aInterruptible)
3818 : {
3819 0 : bool shouldFlush = false;
3820 :
3821 0 : while (mFirstCallbackEventRequest) {
3822 0 : nsCallbackEventRequest* node = mFirstCallbackEventRequest;
3823 0 : mFirstCallbackEventRequest = node->next;
3824 0 : if (!mFirstCallbackEventRequest) {
3825 0 : mLastCallbackEventRequest = nsnull;
3826 : }
3827 0 : nsIReflowCallback* callback = node->callback;
3828 0 : FreeMisc(sizeof(nsCallbackEventRequest), node);
3829 0 : if (callback) {
3830 0 : if (callback->ReflowFinished()) {
3831 0 : shouldFlush = true;
3832 : }
3833 : }
3834 : }
3835 :
3836 : mozFlushType flushType =
3837 0 : aInterruptible ? Flush_InterruptibleLayout : Flush_Layout;
3838 0 : if (shouldFlush)
3839 0 : FlushPendingNotifications(flushType);
3840 0 : }
3841 :
3842 : bool
3843 0 : PresShell::IsSafeToFlush() const
3844 : {
3845 : // Not safe if we are reflowing or in the middle of frame construction
3846 0 : bool isSafeToFlush = !mIsReflowing &&
3847 0 : !mChangeNestCount;
3848 :
3849 0 : if (isSafeToFlush) {
3850 : // Not safe if we are painting
3851 0 : nsIViewManager* viewManager = GetViewManager();
3852 0 : if (viewManager) {
3853 0 : bool isPainting = false;
3854 0 : viewManager->IsPainting(isPainting);
3855 0 : if (isPainting) {
3856 0 : isSafeToFlush = false;
3857 : }
3858 : }
3859 : }
3860 :
3861 0 : return isSafeToFlush;
3862 : }
3863 :
3864 :
3865 : void
3866 0 : PresShell::FlushPendingNotifications(mozFlushType aType)
3867 : {
3868 : /**
3869 : * VERY IMPORTANT: If you add some sort of new flushing to this
3870 : * method, make sure to add the relevant SetNeedLayoutFlush or
3871 : * SetNeedStyleFlush calls on the document.
3872 : */
3873 :
3874 : #ifdef NS_FUNCTION_TIMER
3875 : NS_TIME_FUNCTION_DECLARE_DOCURL;
3876 : static const char *flushTypeNames[] = {
3877 : "Flush_Content",
3878 : "Flush_ContentAndNotify",
3879 : "Flush_Styles",
3880 : "Flush_InterruptibleLayout",
3881 : "Flush_Layout",
3882 : "Flush_Display"
3883 : };
3884 : NS_TIME_FUNCTION_MIN_FMT(1.0, "%s (line %d) (document: %s, type: %s)", MOZ_FUNCTION_NAME,
3885 : __LINE__, docURL__.get(), flushTypeNames[aType - 1]);
3886 : #endif
3887 0 : SAMPLE_LABEL("layout", "FlushPendingNotifications");
3888 :
3889 : #ifdef ACCESSIBILITY
3890 : #ifdef DEBUG
3891 0 : nsAccessibilityService* accService = GetAccService();
3892 0 : if (accService) {
3893 0 : NS_ASSERTION(!accService->IsProcessingRefreshDriverNotification(),
3894 : "Flush during accessible tree update!");
3895 : }
3896 : #endif
3897 : #endif
3898 :
3899 0 : NS_ASSERTION(aType >= Flush_Frames, "Why did we get called?");
3900 :
3901 0 : bool isSafeToFlush = IsSafeToFlush();
3902 :
3903 : // If layout could possibly trigger scripts, then it's only safe to flush if
3904 : // it's safe to run script.
3905 : bool hasHadScriptObject;
3906 0 : if (mDocument->GetScriptHandlingObject(hasHadScriptObject) ||
3907 : hasHadScriptObject) {
3908 0 : isSafeToFlush = isSafeToFlush && nsContentUtils::IsSafeToRunScript();
3909 : }
3910 :
3911 0 : NS_ASSERTION(!isSafeToFlush || mViewManager, "Must have view manager");
3912 : // Make sure the view manager stays alive.
3913 0 : nsCOMPtr<nsIViewManager> viewManagerDeathGrip = mViewManager;
3914 0 : if (isSafeToFlush && mViewManager) {
3915 : // Processing pending notifications can kill us, and some callers only
3916 : // hold weak refs when calling FlushPendingNotifications(). :(
3917 0 : nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
3918 :
3919 0 : if (mResizeEvent.IsPending()) {
3920 0 : FireResizeEvent();
3921 0 : if (mIsDestroying) {
3922 : return;
3923 : }
3924 : }
3925 :
3926 : // We need to make sure external resource documents are flushed too (for
3927 : // example, svg filters that reference a filter in an external document
3928 : // need the frames in the external document to be constructed for the
3929 : // filter to work). We only need external resources to be flushed when the
3930 : // main document is flushing >= Flush_Frames, so we flush external
3931 : // resources here instead of nsDocument::FlushPendingNotifications.
3932 0 : mDocument->FlushExternalResources(aType);
3933 :
3934 : // Force flushing of any pending content notifications that might have
3935 : // queued up while our event was pending. That will ensure that we don't
3936 : // construct frames for content right now that's still waiting to be
3937 : // notified on,
3938 0 : mDocument->FlushPendingNotifications(Flush_ContentAndNotify);
3939 :
3940 : // Process pending restyles, since any flush of the presshell wants
3941 : // up-to-date style data.
3942 0 : if (!mIsDestroying) {
3943 0 : mViewManager->FlushDelayedResize(false);
3944 0 : mPresContext->FlushPendingMediaFeatureValuesChanged();
3945 :
3946 : // Flush any pending update of the user font set, since that could
3947 : // cause style changes (for updating ex/ch units, and to cause a
3948 : // reflow).
3949 0 : mPresContext->FlushUserFontSet();
3950 :
3951 : // Flush any requested SMIL samples.
3952 0 : if (mDocument->HasAnimationController()) {
3953 0 : mDocument->GetAnimationController()->FlushResampleRequests();
3954 : }
3955 :
3956 : // The FlushResampleRequests() above flushed style changes.
3957 0 : if (!mIsDestroying) {
3958 0 : nsAutoScriptBlocker scriptBlocker;
3959 0 : mFrameConstructor->CreateNeededFrames();
3960 0 : mFrameConstructor->ProcessPendingRestyles();
3961 : }
3962 : }
3963 :
3964 : // Dispatch any 'animationstart' events those (or earlier) restyles
3965 : // queued up.
3966 0 : if (!mIsDestroying) {
3967 0 : mPresContext->AnimationManager()->DispatchEvents();
3968 : }
3969 :
3970 : // Process whatever XBL constructors those restyles queued up. This
3971 : // ensures that onload doesn't fire too early and that we won't do extra
3972 : // reflows after those constructors run.
3973 0 : if (!mIsDestroying) {
3974 0 : mDocument->BindingManager()->ProcessAttachedQueue();
3975 : }
3976 :
3977 : // Now those constructors or events might have posted restyle
3978 : // events. At the same time, we still need up-to-date style data.
3979 : // In particular, reflow depends on style being completely up to
3980 : // date. If it's not, then style context reparenting, which can
3981 : // happen during reflow, might suddenly pick up the new rules and
3982 : // we'll end up with frames whose style doesn't match the frame
3983 : // type.
3984 0 : if (!mIsDestroying) {
3985 0 : nsAutoScriptBlocker scriptBlocker;
3986 0 : mFrameConstructor->CreateNeededFrames();
3987 0 : mFrameConstructor->ProcessPendingRestyles();
3988 : }
3989 :
3990 :
3991 : // There might be more pending constructors now, but we're not going to
3992 : // worry about them. They can't be triggered during reflow, so we should
3993 : // be good.
3994 :
3995 0 : if (aType >= (mSuppressInterruptibleReflows ? Flush_Layout : Flush_InterruptibleLayout) &&
3996 0 : !mIsDestroying) {
3997 0 : mFrameConstructor->RecalcQuotesAndCounters();
3998 0 : mViewManager->FlushDelayedResize(true);
3999 0 : if (ProcessReflowCommands(aType < Flush_Layout) && mContentToScrollTo) {
4000 : // We didn't get interrupted. Go ahead and scroll to our content
4001 : DoScrollContentIntoView(mContentToScrollTo, mContentScrollVPosition,
4002 : mContentScrollHPosition,
4003 0 : mContentToScrollToFlags);
4004 0 : mContentToScrollTo = nsnull;
4005 : }
4006 0 : } else if (!mIsDestroying && mSuppressInterruptibleReflows &&
4007 : aType == Flush_InterruptibleLayout) {
4008 : // We suppressed this flush, but the document thinks it doesn't
4009 : // need to flush anymore. Let it know what's really going on.
4010 0 : mDocument->SetNeedLayoutFlush();
4011 : }
4012 :
4013 0 : if (aType >= Flush_Layout) {
4014 : // Flush plugin geometry. Don't flush plugin geometry for
4015 : // interruptible layouts, since WillPaint does an interruptible
4016 : // layout.
4017 0 : nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext();
4018 0 : if (rootPresContext) {
4019 0 : rootPresContext->UpdatePluginGeometry();
4020 : }
4021 :
4022 0 : if (!mIsDestroying) {
4023 0 : mViewManager->UpdateWidgetGeometry();
4024 : }
4025 : }
4026 : }
4027 : }
4028 :
4029 : void
4030 0 : PresShell::CharacterDataChanged(nsIDocument *aDocument,
4031 : nsIContent* aContent,
4032 : CharacterDataChangeInfo* aInfo)
4033 : {
4034 0 : NS_PRECONDITION(!mIsDocumentGone, "Unexpected CharacterDataChanged");
4035 0 : NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
4036 :
4037 0 : nsAutoCauseReflowNotifier crNotifier(this);
4038 :
4039 0 : if (mCaret) {
4040 : // Invalidate the caret's current location before we call into the frame
4041 : // constructor. It is important to do this now, and not wait until the
4042 : // resulting reflow, because this call causes continuation frames of the
4043 : // text frame the caret is in to forget what part of the content they
4044 : // refer to, making it hard for them to return the correct continuation
4045 : // frame to the caret.
4046 0 : mCaret->InvalidateOutsideCaret();
4047 : }
4048 :
4049 : // Call this here so it only happens for real content mutations and
4050 : // not cases when the frame constructor calls its own methods to force
4051 : // frame reconstruction.
4052 0 : nsIContent *container = aContent->GetParent();
4053 : PRUint32 selectorFlags =
4054 0 : container ? (container->GetFlags() & NODE_ALL_SELECTOR_FLAGS) : 0;
4055 0 : if (selectorFlags != 0 && !aContent->IsRootOfAnonymousSubtree()) {
4056 0 : Element* element = container->AsElement();
4057 0 : if (aInfo->mAppend && !aContent->GetNextSibling())
4058 0 : mFrameConstructor->RestyleForAppend(element, aContent);
4059 : else
4060 0 : mFrameConstructor->RestyleForInsertOrChange(element, aContent);
4061 : }
4062 :
4063 0 : mFrameConstructor->CharacterDataChanged(aContent, aInfo);
4064 0 : VERIFY_STYLE_TREE;
4065 0 : }
4066 :
4067 : void
4068 0 : PresShell::ContentStateChanged(nsIDocument* aDocument,
4069 : nsIContent* aContent,
4070 : nsEventStates aStateMask)
4071 : {
4072 0 : NS_PRECONDITION(!mIsDocumentGone, "Unexpected ContentStateChanged");
4073 0 : NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
4074 :
4075 0 : if (mDidInitialReflow) {
4076 0 : nsAutoCauseReflowNotifier crNotifier(this);
4077 0 : mFrameConstructor->ContentStateChanged(aContent, aStateMask);
4078 0 : VERIFY_STYLE_TREE;
4079 : }
4080 0 : }
4081 :
4082 : void
4083 0 : PresShell::DocumentStatesChanged(nsIDocument* aDocument,
4084 : nsEventStates aStateMask)
4085 : {
4086 0 : NS_PRECONDITION(!mIsDocumentGone, "Unexpected DocumentStatesChanged");
4087 0 : NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
4088 :
4089 0 : if (mDidInitialReflow &&
4090 : mStyleSet->HasDocumentStateDependentStyle(mPresContext,
4091 0 : mDocument->GetRootElement(),
4092 0 : aStateMask)) {
4093 : mFrameConstructor->PostRestyleEvent(mDocument->GetRootElement(),
4094 0 : eRestyle_Subtree, NS_STYLE_HINT_NONE);
4095 0 : VERIFY_STYLE_TREE;
4096 : }
4097 :
4098 0 : if (aStateMask.HasState(NS_DOCUMENT_STATE_WINDOW_INACTIVE)) {
4099 0 : nsIFrame* root = mFrameConstructor->GetRootFrame();
4100 0 : if (root) {
4101 0 : root->InvalidateFrameSubtree();
4102 : }
4103 : }
4104 0 : }
4105 :
4106 : void
4107 0 : PresShell::AttributeWillChange(nsIDocument* aDocument,
4108 : Element* aElement,
4109 : PRInt32 aNameSpaceID,
4110 : nsIAtom* aAttribute,
4111 : PRInt32 aModType)
4112 : {
4113 0 : NS_PRECONDITION(!mIsDocumentGone, "Unexpected AttributeWillChange");
4114 0 : NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
4115 :
4116 : // XXXwaterson it might be more elegant to wait until after the
4117 : // initial reflow to begin observing the document. That would
4118 : // squelch any other inappropriate notifications as well.
4119 0 : if (mDidInitialReflow) {
4120 0 : nsAutoCauseReflowNotifier crNotifier(this);
4121 : mFrameConstructor->AttributeWillChange(aElement, aNameSpaceID,
4122 0 : aAttribute, aModType);
4123 0 : VERIFY_STYLE_TREE;
4124 : }
4125 0 : }
4126 :
4127 : void
4128 0 : PresShell::AttributeChanged(nsIDocument* aDocument,
4129 : Element* aElement,
4130 : PRInt32 aNameSpaceID,
4131 : nsIAtom* aAttribute,
4132 : PRInt32 aModType)
4133 : {
4134 0 : NS_PRECONDITION(!mIsDocumentGone, "Unexpected AttributeChanged");
4135 0 : NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
4136 :
4137 : // XXXwaterson it might be more elegant to wait until after the
4138 : // initial reflow to begin observing the document. That would
4139 : // squelch any other inappropriate notifications as well.
4140 0 : if (mDidInitialReflow) {
4141 0 : nsAutoCauseReflowNotifier crNotifier(this);
4142 : mFrameConstructor->AttributeChanged(aElement, aNameSpaceID,
4143 0 : aAttribute, aModType);
4144 0 : VERIFY_STYLE_TREE;
4145 : }
4146 0 : }
4147 :
4148 : void
4149 0 : PresShell::ContentAppended(nsIDocument *aDocument,
4150 : nsIContent* aContainer,
4151 : nsIContent* aFirstNewContent,
4152 : PRInt32 aNewIndexInContainer)
4153 : {
4154 0 : NS_PRECONDITION(!mIsDocumentGone, "Unexpected ContentAppended");
4155 0 : NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
4156 0 : NS_PRECONDITION(aContainer, "must have container");
4157 :
4158 0 : if (!mDidInitialReflow) {
4159 0 : return;
4160 : }
4161 :
4162 0 : nsAutoCauseReflowNotifier crNotifier(this);
4163 :
4164 : // Call this here so it only happens for real content mutations and
4165 : // not cases when the frame constructor calls its own methods to force
4166 : // frame reconstruction.
4167 0 : mFrameConstructor->RestyleForAppend(aContainer->AsElement(), aFirstNewContent);
4168 :
4169 0 : mFrameConstructor->ContentAppended(aContainer, aFirstNewContent, true);
4170 0 : VERIFY_STYLE_TREE;
4171 : }
4172 :
4173 : void
4174 0 : PresShell::ContentInserted(nsIDocument* aDocument,
4175 : nsIContent* aContainer,
4176 : nsIContent* aChild,
4177 : PRInt32 aIndexInContainer)
4178 : {
4179 0 : NS_PRECONDITION(!mIsDocumentGone, "Unexpected ContentInserted");
4180 0 : NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
4181 :
4182 0 : if (!mDidInitialReflow) {
4183 0 : return;
4184 : }
4185 :
4186 0 : nsAutoCauseReflowNotifier crNotifier(this);
4187 :
4188 : // Call this here so it only happens for real content mutations and
4189 : // not cases when the frame constructor calls its own methods to force
4190 : // frame reconstruction.
4191 0 : if (aContainer)
4192 0 : mFrameConstructor->RestyleForInsertOrChange(aContainer->AsElement(), aChild);
4193 :
4194 0 : mFrameConstructor->ContentInserted(aContainer, aChild, nsnull, true);
4195 0 : VERIFY_STYLE_TREE;
4196 : }
4197 :
4198 : void
4199 0 : PresShell::ContentRemoved(nsIDocument *aDocument,
4200 : nsIContent* aContainer,
4201 : nsIContent* aChild,
4202 : PRInt32 aIndexInContainer,
4203 : nsIContent* aPreviousSibling)
4204 : {
4205 0 : NS_PRECONDITION(!mIsDocumentGone, "Unexpected ContentRemoved");
4206 0 : NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
4207 :
4208 : // Make sure that the caret doesn't leave a turd where the child used to be.
4209 0 : if (mCaret) {
4210 0 : mCaret->InvalidateOutsideCaret();
4211 : }
4212 :
4213 : // Notify the ESM that the content has been removed, so that
4214 : // it can clean up any state related to the content.
4215 0 : mPresContext->EventStateManager()->ContentRemoved(aDocument, aChild);
4216 :
4217 0 : nsAutoCauseReflowNotifier crNotifier(this);
4218 :
4219 : // Call this here so it only happens for real content mutations and
4220 : // not cases when the frame constructor calls its own methods to force
4221 : // frame reconstruction.
4222 : nsIContent* oldNextSibling;
4223 0 : if (aContainer) {
4224 0 : oldNextSibling = aContainer->GetChildAt(aIndexInContainer);
4225 : } else {
4226 0 : oldNextSibling = nsnull;
4227 : }
4228 :
4229 0 : if (aContainer)
4230 : mFrameConstructor->RestyleForRemove(aContainer->AsElement(), aChild,
4231 0 : oldNextSibling);
4232 :
4233 : bool didReconstruct;
4234 : mFrameConstructor->ContentRemoved(aContainer, aChild, oldNextSibling,
4235 : nsCSSFrameConstructor::REMOVE_CONTENT,
4236 0 : &didReconstruct);
4237 :
4238 0 : VERIFY_STYLE_TREE;
4239 0 : }
4240 :
4241 : nsresult
4242 0 : PresShell::ReconstructFrames(void)
4243 : {
4244 0 : NS_PRECONDITION(!mFrameConstructor->GetRootFrame() || mDidInitialReflow,
4245 : "Must not have root frame before initial reflow");
4246 0 : if (!mDidInitialReflow) {
4247 : // Nothing to do here
4248 0 : return NS_OK;
4249 : }
4250 :
4251 0 : nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
4252 :
4253 : // Have to make sure that the content notifications are flushed before we
4254 : // start messing with the frame model; otherwise we can get content doubling.
4255 0 : mDocument->FlushPendingNotifications(Flush_ContentAndNotify);
4256 :
4257 0 : nsAutoCauseReflowNotifier crNotifier(this);
4258 0 : mFrameConstructor->BeginUpdate();
4259 0 : nsresult rv = mFrameConstructor->ReconstructDocElementHierarchy();
4260 0 : VERIFY_STYLE_TREE;
4261 0 : mFrameConstructor->EndUpdate();
4262 :
4263 0 : return rv;
4264 : }
4265 :
4266 : void
4267 0 : nsIPresShell::ReconstructStyleDataInternal()
4268 : {
4269 0 : mStylesHaveChanged = false;
4270 :
4271 0 : if (mIsDestroying) {
4272 : // We don't want to mess with restyles at this point
4273 0 : return;
4274 : }
4275 :
4276 0 : if (mPresContext) {
4277 0 : mPresContext->RebuildUserFontSet();
4278 0 : mPresContext->AnimationManager()->KeyframesListIsDirty();
4279 : }
4280 :
4281 0 : Element* root = mDocument->GetRootElement();
4282 0 : if (!mDidInitialReflow) {
4283 : // Nothing to do here, since we have no frames yet
4284 0 : return;
4285 : }
4286 :
4287 0 : if (!root) {
4288 : // No content to restyle
4289 0 : return;
4290 : }
4291 :
4292 0 : mFrameConstructor->PostRestyleEvent(root, eRestyle_Subtree, NS_STYLE_HINT_NONE);
4293 : }
4294 :
4295 : void
4296 0 : nsIPresShell::ReconstructStyleDataExternal()
4297 : {
4298 0 : ReconstructStyleDataInternal();
4299 0 : }
4300 :
4301 : void
4302 0 : PresShell::StyleSheetAdded(nsIDocument *aDocument,
4303 : nsIStyleSheet* aStyleSheet,
4304 : bool aDocumentSheet)
4305 : {
4306 : // We only care when enabled sheets are added
4307 0 : NS_PRECONDITION(aStyleSheet, "Must have a style sheet!");
4308 :
4309 0 : if (aStyleSheet->IsApplicable() && aStyleSheet->HasRules()) {
4310 0 : mStylesHaveChanged = true;
4311 : }
4312 0 : }
4313 :
4314 : void
4315 0 : PresShell::StyleSheetRemoved(nsIDocument *aDocument,
4316 : nsIStyleSheet* aStyleSheet,
4317 : bool aDocumentSheet)
4318 : {
4319 : // We only care when enabled sheets are removed
4320 0 : NS_PRECONDITION(aStyleSheet, "Must have a style sheet!");
4321 :
4322 0 : if (aStyleSheet->IsApplicable() && aStyleSheet->HasRules()) {
4323 0 : mStylesHaveChanged = true;
4324 : }
4325 0 : }
4326 :
4327 : void
4328 0 : PresShell::StyleSheetApplicableStateChanged(nsIDocument *aDocument,
4329 : nsIStyleSheet* aStyleSheet,
4330 : bool aApplicable)
4331 : {
4332 0 : if (aStyleSheet->HasRules()) {
4333 0 : mStylesHaveChanged = true;
4334 : }
4335 0 : }
4336 :
4337 : void
4338 0 : PresShell::StyleRuleChanged(nsIDocument *aDocument,
4339 : nsIStyleSheet* aStyleSheet,
4340 : nsIStyleRule* aOldStyleRule,
4341 : nsIStyleRule* aNewStyleRule)
4342 : {
4343 0 : mStylesHaveChanged = true;
4344 0 : }
4345 :
4346 : void
4347 0 : PresShell::StyleRuleAdded(nsIDocument *aDocument,
4348 : nsIStyleSheet* aStyleSheet,
4349 : nsIStyleRule* aStyleRule)
4350 : {
4351 0 : mStylesHaveChanged = true;
4352 0 : }
4353 :
4354 : void
4355 0 : PresShell::StyleRuleRemoved(nsIDocument *aDocument,
4356 : nsIStyleSheet* aStyleSheet,
4357 : nsIStyleRule* aStyleRule)
4358 : {
4359 0 : mStylesHaveChanged = true;
4360 0 : }
4361 :
4362 : nsIFrame*
4363 0 : PresShell::GetRealPrimaryFrameFor(nsIContent* aContent) const
4364 : {
4365 0 : if (aContent->GetDocument() != GetDocument()) {
4366 0 : return nsnull;
4367 : }
4368 0 : nsIFrame *primaryFrame = aContent->GetPrimaryFrame();
4369 0 : if (!primaryFrame)
4370 0 : return nsnull;
4371 0 : return nsPlaceholderFrame::GetRealFrameFor(primaryFrame);
4372 : }
4373 :
4374 : nsIFrame*
4375 0 : PresShell::GetPlaceholderFrameFor(nsIFrame* aFrame) const
4376 : {
4377 0 : return mFrameConstructor->GetPlaceholderFrameFor(aFrame);
4378 : }
4379 :
4380 : nsresult
4381 0 : PresShell::RenderDocument(const nsRect& aRect, PRUint32 aFlags,
4382 : nscolor aBackgroundColor,
4383 : gfxContext* aThebesContext)
4384 : {
4385 : NS_TIME_FUNCTION_WITH_DOCURL;
4386 :
4387 0 : NS_ENSURE_TRUE(!(aFlags & RENDER_IS_UNTRUSTED), NS_ERROR_NOT_IMPLEMENTED);
4388 :
4389 0 : nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext();
4390 0 : if (rootPresContext) {
4391 0 : rootPresContext->FlushWillPaintObservers();
4392 0 : if (mIsDestroying)
4393 0 : return NS_OK;
4394 : }
4395 :
4396 0 : nsAutoScriptBlocker blockScripts;
4397 :
4398 : // Set up the rectangle as the path in aThebesContext
4399 : gfxRect r(0, 0,
4400 0 : nsPresContext::AppUnitsToFloatCSSPixels(aRect.width),
4401 0 : nsPresContext::AppUnitsToFloatCSSPixels(aRect.height));
4402 0 : aThebesContext->NewPath();
4403 : #ifdef MOZ_GFX_OPTIMIZE_MOBILE
4404 : aThebesContext->Rectangle(r, true);
4405 : #else
4406 0 : aThebesContext->Rectangle(r);
4407 : #endif
4408 :
4409 0 : nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
4410 0 : if (!rootFrame) {
4411 : // Nothing to paint, just fill the rect
4412 0 : aThebesContext->SetColor(gfxRGBA(aBackgroundColor));
4413 0 : aThebesContext->Fill();
4414 0 : return NS_OK;
4415 : }
4416 :
4417 0 : gfxContextAutoSaveRestore save(aThebesContext);
4418 :
4419 0 : gfxContext::GraphicsOperator oldOperator = aThebesContext->CurrentOperator();
4420 0 : if (oldOperator == gfxContext::OPERATOR_OVER) {
4421 : // Clip to the destination rectangle before we push the group,
4422 : // to limit the size of the temporary surface
4423 0 : aThebesContext->Clip();
4424 : }
4425 :
4426 : // we want the window to be composited as a single image using
4427 : // whatever operator was set; set OPERATOR_OVER here, which is
4428 : // either already the case, or overrides the operator in a group.
4429 : // the original operator will be present when we PopGroup.
4430 : // we can avoid using a temporary surface if we're using OPERATOR_OVER
4431 : // and our background color has no alpha (so we'll be compositing on top
4432 : // of a fully opaque solid color region)
4433 : bool needsGroup = NS_GET_A(aBackgroundColor) < 0xff ||
4434 0 : oldOperator != gfxContext::OPERATOR_OVER;
4435 :
4436 0 : if (needsGroup) {
4437 : aThebesContext->PushGroup(NS_GET_A(aBackgroundColor) == 0xff ?
4438 : gfxASurface::CONTENT_COLOR :
4439 0 : gfxASurface::CONTENT_COLOR_ALPHA);
4440 0 : aThebesContext->Save();
4441 :
4442 0 : if (oldOperator != gfxContext::OPERATOR_OVER) {
4443 : // Clip now while we paint to the temporary surface. For
4444 : // non-source-bounded operators (e.g., SOURCE), we need to do clip
4445 : // here after we've pushed the group, so that eventually popping
4446 : // the group and painting it will be able to clear the entire
4447 : // destination surface.
4448 0 : aThebesContext->Clip();
4449 0 : aThebesContext->SetOperator(gfxContext::OPERATOR_OVER);
4450 : }
4451 : }
4452 :
4453 0 : aThebesContext->Translate(gfxPoint(-nsPresContext::AppUnitsToFloatCSSPixels(aRect.x),
4454 0 : -nsPresContext::AppUnitsToFloatCSSPixels(aRect.y)));
4455 :
4456 0 : nsDeviceContext* devCtx = mPresContext->DeviceContext();
4457 0 : gfxFloat scale = gfxFloat(devCtx->AppUnitsPerDevPixel())/nsPresContext::AppUnitsPerCSSPixel();
4458 0 : aThebesContext->Scale(scale, scale);
4459 :
4460 : // Since canvas APIs use floats to set up their matrices, we may have
4461 : // some slight inaccuracy here. Adjust matrix components that are
4462 : // integers up to the accuracy of floats to be those integers.
4463 0 : aThebesContext->NudgeCurrentMatrixToIntegers();
4464 :
4465 0 : AutoSaveRestoreRenderingState _(this);
4466 :
4467 0 : nsRefPtr<nsRenderingContext> rc = new nsRenderingContext();
4468 0 : rc->Init(devCtx, aThebesContext);
4469 :
4470 0 : bool wouldFlushRetainedLayers = false;
4471 0 : PRUint32 flags = nsLayoutUtils::PAINT_IGNORE_SUPPRESSION;
4472 0 : if (aThebesContext->CurrentMatrix().HasNonIntegerTranslation()) {
4473 0 : flags |= nsLayoutUtils::PAINT_IN_TRANSFORM;
4474 : }
4475 0 : if (!(aFlags & RENDER_ASYNC_DECODE_IMAGES)) {
4476 0 : flags |= nsLayoutUtils::PAINT_SYNC_DECODE_IMAGES;
4477 : }
4478 0 : if (aFlags & RENDER_USE_WIDGET_LAYERS) {
4479 : // We only support using widget layers on display root's with widgets.
4480 0 : nsIView* view = rootFrame->GetView();
4481 0 : if (view && view->GetWidget() &&
4482 0 : nsLayoutUtils::GetDisplayRootFrame(rootFrame) == rootFrame) {
4483 0 : flags |= nsLayoutUtils::PAINT_WIDGET_LAYERS;
4484 : }
4485 : }
4486 0 : if (!(aFlags & RENDER_CARET)) {
4487 0 : wouldFlushRetainedLayers = true;
4488 0 : flags |= nsLayoutUtils::PAINT_HIDE_CARET;
4489 : }
4490 0 : if (aFlags & RENDER_IGNORE_VIEWPORT_SCROLLING) {
4491 0 : wouldFlushRetainedLayers = !IgnoringViewportScrolling();
4492 0 : mRenderFlags = ChangeFlag(mRenderFlags, true, STATE_IGNORING_VIEWPORT_SCROLLING);
4493 : }
4494 0 : if (aFlags & RENDER_DOCUMENT_RELATIVE) {
4495 : // XXX be smarter about this ... drawWindow might want a rect
4496 : // that's "pretty close" to what our retained layer tree covers.
4497 : // In that case, it wouldn't disturb normal rendering too much,
4498 : // and we should allow it.
4499 0 : wouldFlushRetainedLayers = true;
4500 0 : flags |= nsLayoutUtils::PAINT_DOCUMENT_RELATIVE;
4501 : }
4502 :
4503 : // Don't let drawWindow blow away our retained layer tree
4504 0 : if ((flags & nsLayoutUtils::PAINT_WIDGET_LAYERS) && wouldFlushRetainedLayers) {
4505 0 : flags &= ~nsLayoutUtils::PAINT_WIDGET_LAYERS;
4506 : }
4507 :
4508 0 : nsLayoutUtils::PaintFrame(rc, rootFrame, nsRegion(aRect),
4509 0 : aBackgroundColor, flags);
4510 :
4511 : // if we had to use a group, paint it to the destination now
4512 0 : if (needsGroup) {
4513 0 : aThebesContext->Restore();
4514 0 : aThebesContext->PopGroupToSource();
4515 0 : aThebesContext->Paint();
4516 : }
4517 :
4518 0 : return NS_OK;
4519 : }
4520 :
4521 : /*
4522 : * Clip the display list aList to a range. Returns the clipped
4523 : * rectangle surrounding the range.
4524 : */
4525 : nsRect
4526 0 : PresShell::ClipListToRange(nsDisplayListBuilder *aBuilder,
4527 : nsDisplayList* aList,
4528 : nsRange* aRange)
4529 : {
4530 : NS_TIME_FUNCTION_WITH_DOCURL;
4531 :
4532 : // iterate though the display items and add up the bounding boxes of each.
4533 : // This will allow the total area of the frames within the range to be
4534 : // determined. To do this, remove an item from the bottom of the list, check
4535 : // whether it should be part of the range, and if so, append it to the top
4536 : // of the temporary list tmpList. If the item is a text frame at the end of
4537 : // the selection range, wrap it in an nsDisplayClip to clip the display to
4538 : // the portion of the text frame that is part of the selection. Then, append
4539 : // the wrapper to the top of the list. Otherwise, just delete the item and
4540 : // don't append it.
4541 0 : nsRect surfaceRect;
4542 0 : nsDisplayList tmpList;
4543 :
4544 : nsDisplayItem* i;
4545 0 : while ((i = aList->RemoveBottom())) {
4546 : // itemToInsert indiciates the item that should be inserted into the
4547 : // temporary list. If null, no item should be inserted.
4548 0 : nsDisplayItem* itemToInsert = nsnull;
4549 0 : nsIFrame* frame = i->GetUnderlyingFrame();
4550 0 : if (frame) {
4551 0 : nsIContent* content = frame->GetContent();
4552 0 : if (content) {
4553 0 : bool atStart = (content == aRange->GetStartParent());
4554 0 : bool atEnd = (content == aRange->GetEndParent());
4555 0 : if ((atStart || atEnd) && frame->GetType() == nsGkAtoms::textFrame) {
4556 : PRInt32 frameStartOffset, frameEndOffset;
4557 0 : frame->GetOffsets(frameStartOffset, frameEndOffset);
4558 :
4559 : PRInt32 hilightStart =
4560 0 : atStart ? NS_MAX(aRange->StartOffset(), frameStartOffset) : frameStartOffset;
4561 : PRInt32 hilightEnd =
4562 0 : atEnd ? NS_MIN(aRange->EndOffset(), frameEndOffset) : frameEndOffset;
4563 0 : if (hilightStart < hilightEnd) {
4564 : // determine the location of the start and end edges of the range.
4565 0 : nsPoint startPoint, endPoint;
4566 0 : frame->GetPointFromOffset(hilightStart, &startPoint);
4567 0 : frame->GetPointFromOffset(hilightEnd, &endPoint);
4568 :
4569 : // the clip rectangle is determined by taking the the start and
4570 : // end points of the range, offset from the reference frame.
4571 : // Because of rtl, the end point may be to the left of the
4572 : // start point, so x is set to the lowest value
4573 0 : nsRect textRect(aBuilder->ToReferenceFrame(frame), frame->GetSize());
4574 0 : nscoord x = NS_MIN(startPoint.x, endPoint.x);
4575 0 : textRect.x += x;
4576 0 : textRect.width = NS_MAX(startPoint.x, endPoint.x) - x;
4577 0 : surfaceRect.UnionRect(surfaceRect, textRect);
4578 :
4579 : // wrap the item in an nsDisplayClip so that it can be clipped to
4580 : // the selection. If the allocation fails, fall through and delete
4581 : // the item below.
4582 : itemToInsert = new (aBuilder)
4583 0 : nsDisplayClip(aBuilder, frame, i, textRect);
4584 : }
4585 : }
4586 : // Don't try to descend into subdocuments.
4587 : // If this ever changes we'd need to add handling for subdocuments with
4588 : // different zoom levels.
4589 0 : else if (content->GetCurrentDoc() ==
4590 0 : aRange->GetStartParent()->GetCurrentDoc()) {
4591 : // if the node is within the range, append it to the temporary list
4592 : bool before, after;
4593 : nsresult rv =
4594 0 : nsRange::CompareNodeToRange(content, aRange, &before, &after);
4595 0 : if (NS_SUCCEEDED(rv) && !before && !after) {
4596 0 : itemToInsert = i;
4597 0 : surfaceRect.UnionRect(surfaceRect, i->GetBounds(aBuilder));
4598 : }
4599 : }
4600 : }
4601 : }
4602 :
4603 : // insert the item into the list if necessary. If the item has a child
4604 : // list, insert that as well
4605 0 : nsDisplayList* sublist = i->GetList();
4606 0 : if (itemToInsert || sublist) {
4607 0 : tmpList.AppendToTop(itemToInsert ? itemToInsert : i);
4608 : // if the item is a list, iterate over it as well
4609 0 : if (sublist)
4610 : surfaceRect.UnionRect(surfaceRect,
4611 0 : ClipListToRange(aBuilder, sublist, aRange));
4612 : }
4613 : else {
4614 : // otherwise, just delete the item and don't readd it to the list
4615 0 : i->~nsDisplayItem();
4616 : }
4617 : }
4618 :
4619 : // now add all the items back onto the original list again
4620 0 : aList->AppendToTop(&tmpList);
4621 :
4622 : return surfaceRect;
4623 : }
4624 :
4625 : #ifdef DEBUG
4626 : #include <stdio.h>
4627 :
4628 : static bool gDumpRangePaintList = false;
4629 : #endif
4630 :
4631 : RangePaintInfo*
4632 0 : PresShell::CreateRangePaintInfo(nsIDOMRange* aRange,
4633 : nsRect& aSurfaceRect,
4634 : bool aForPrimarySelection)
4635 : {
4636 : NS_TIME_FUNCTION_WITH_DOCURL;
4637 :
4638 0 : RangePaintInfo* info = nsnull;
4639 :
4640 0 : nsRange* range = static_cast<nsRange*>(aRange);
4641 :
4642 : nsIFrame* ancestorFrame;
4643 0 : nsIFrame* rootFrame = GetRootFrame();
4644 :
4645 : // If the start or end of the range is the document, just use the root
4646 : // frame, otherwise get the common ancestor of the two endpoints of the
4647 : // range.
4648 0 : nsINode* startParent = range->GetStartParent();
4649 0 : nsINode* endParent = range->GetEndParent();
4650 0 : nsIDocument* doc = startParent->GetCurrentDoc();
4651 0 : if (startParent == doc || endParent == doc) {
4652 0 : ancestorFrame = rootFrame;
4653 : }
4654 : else {
4655 0 : nsINode* ancestor = nsContentUtils::GetCommonAncestor(startParent, endParent);
4656 0 : NS_ASSERTION(!ancestor || ancestor->IsNodeOfType(nsINode::eCONTENT),
4657 : "common ancestor is not content");
4658 0 : if (!ancestor || !ancestor->IsNodeOfType(nsINode::eCONTENT))
4659 0 : return nsnull;
4660 :
4661 0 : nsIContent* ancestorContent = static_cast<nsIContent*>(ancestor);
4662 0 : ancestorFrame = ancestorContent->GetPrimaryFrame();
4663 :
4664 : // use the nearest ancestor frame that includes all continuations as the
4665 : // root for building the display list
4666 0 : while (ancestorFrame &&
4667 0 : nsLayoutUtils::GetNextContinuationOrSpecialSibling(ancestorFrame))
4668 0 : ancestorFrame = ancestorFrame->GetParent();
4669 : }
4670 :
4671 0 : if (!ancestorFrame)
4672 0 : return nsnull;
4673 :
4674 0 : info = new RangePaintInfo(range, ancestorFrame);
4675 :
4676 0 : nsRect ancestorRect = ancestorFrame->GetVisualOverflowRect();
4677 :
4678 : // get a display list containing the range
4679 0 : info->mBuilder.SetIncludeAllOutOfFlows();
4680 0 : if (aForPrimarySelection) {
4681 0 : info->mBuilder.SetSelectedFramesOnly();
4682 : }
4683 0 : info->mBuilder.EnterPresShell(ancestorFrame, ancestorRect);
4684 : ancestorFrame->BuildDisplayListForStackingContext(&info->mBuilder,
4685 0 : ancestorRect, &info->mList);
4686 :
4687 : #ifdef DEBUG
4688 0 : if (gDumpRangePaintList) {
4689 0 : fprintf(stderr, "CreateRangePaintInfo --- before ClipListToRange:\n");
4690 0 : nsFrame::PrintDisplayList(&(info->mBuilder), info->mList);
4691 : }
4692 : #endif
4693 :
4694 0 : nsRect rangeRect = ClipListToRange(&info->mBuilder, &info->mList, range);
4695 :
4696 0 : info->mBuilder.LeavePresShell(ancestorFrame, ancestorRect);
4697 :
4698 : #ifdef DEBUG
4699 0 : if (gDumpRangePaintList) {
4700 0 : fprintf(stderr, "CreateRangePaintInfo --- after ClipListToRange:\n");
4701 0 : nsFrame::PrintDisplayList(&(info->mBuilder), info->mList);
4702 : }
4703 : #endif
4704 :
4705 : // determine the offset of the reference frame for the display list
4706 : // to the root frame. This will allow the coordinates used when painting
4707 : // to all be offset from the same point
4708 0 : info->mRootOffset = ancestorFrame->GetOffsetTo(rootFrame);
4709 0 : rangeRect.MoveBy(info->mRootOffset);
4710 0 : aSurfaceRect.UnionRect(aSurfaceRect, rangeRect);
4711 :
4712 0 : return info;
4713 : }
4714 :
4715 : already_AddRefed<gfxASurface>
4716 0 : PresShell::PaintRangePaintInfo(nsTArray<nsAutoPtr<RangePaintInfo> >* aItems,
4717 : nsISelection* aSelection,
4718 : nsIntRegion* aRegion,
4719 : nsRect aArea,
4720 : nsIntPoint& aPoint,
4721 : nsIntRect* aScreenRect)
4722 : {
4723 : NS_TIME_FUNCTION_WITH_DOCURL;
4724 :
4725 0 : nsPresContext* pc = GetPresContext();
4726 0 : if (!pc || aArea.width == 0 || aArea.height == 0)
4727 0 : return nsnull;
4728 :
4729 0 : nsDeviceContext* deviceContext = pc->DeviceContext();
4730 :
4731 : // use the rectangle to create the surface
4732 0 : nsIntRect pixelArea = aArea.ToOutsidePixels(pc->AppUnitsPerDevPixel());
4733 :
4734 : // if the area of the image is larger than the maximum area, scale it down
4735 0 : float scale = 0.0;
4736 : nsIntRect rootScreenRect =
4737 0 : GetRootFrame()->GetScreenRectInAppUnits().ToNearestPixels(
4738 0 : pc->AppUnitsPerDevPixel());
4739 :
4740 : // if the image is larger in one or both directions than half the size of
4741 : // the available screen area, scale the image down to that size.
4742 0 : nsRect maxSize;
4743 0 : deviceContext->GetClientRect(maxSize);
4744 0 : nscoord maxWidth = pc->AppUnitsToDevPixels(maxSize.width >> 1);
4745 0 : nscoord maxHeight = pc->AppUnitsToDevPixels(maxSize.height >> 1);
4746 0 : bool resize = (pixelArea.width > maxWidth || pixelArea.height > maxHeight);
4747 0 : if (resize) {
4748 0 : scale = 1.0;
4749 : // divide the maximum size by the image size in both directions. Whichever
4750 : // direction produces the smallest result determines how much should be
4751 : // scaled.
4752 0 : if (pixelArea.width > maxWidth)
4753 0 : scale = NS_MIN(scale, float(maxWidth) / pixelArea.width);
4754 0 : if (pixelArea.height > maxHeight)
4755 0 : scale = NS_MIN(scale, float(maxHeight) / pixelArea.height);
4756 :
4757 0 : pixelArea.width = NSToIntFloor(float(pixelArea.width) * scale);
4758 0 : pixelArea.height = NSToIntFloor(float(pixelArea.height) * scale);
4759 :
4760 : // adjust the screen position based on the rescaled size
4761 0 : nscoord left = rootScreenRect.x + pixelArea.x;
4762 0 : nscoord top = rootScreenRect.y + pixelArea.y;
4763 0 : aScreenRect->x = NSToIntFloor(aPoint.x - float(aPoint.x - left) * scale);
4764 0 : aScreenRect->y = NSToIntFloor(aPoint.y - float(aPoint.y - top) * scale);
4765 : }
4766 : else {
4767 : // move aScreenRect to the position of the surface in screen coordinates
4768 0 : aScreenRect->MoveTo(rootScreenRect.x + pixelArea.x, rootScreenRect.y + pixelArea.y);
4769 : }
4770 0 : aScreenRect->width = pixelArea.width;
4771 0 : aScreenRect->height = pixelArea.height;
4772 :
4773 : gfxImageSurface* surface =
4774 : new gfxImageSurface(gfxIntSize(pixelArea.width, pixelArea.height),
4775 0 : gfxImageSurface::ImageFormatARGB32);
4776 0 : if (surface->CairoStatus()) {
4777 0 : delete surface;
4778 0 : return nsnull;
4779 : }
4780 :
4781 : // clear the image
4782 0 : gfxContext context(surface);
4783 0 : context.SetOperator(gfxContext::OPERATOR_CLEAR);
4784 0 : context.Rectangle(gfxRect(0, 0, pixelArea.width, pixelArea.height));
4785 0 : context.Fill();
4786 :
4787 0 : nsRefPtr<nsRenderingContext> rc = new nsRenderingContext();
4788 0 : rc->Init(deviceContext, surface);
4789 :
4790 0 : if (aRegion) {
4791 : // Convert aRegion from CSS pixels to dev pixels
4792 : nsIntRegion region =
4793 0 : aRegion->ToAppUnits(nsPresContext::AppUnitsPerCSSPixel())
4794 0 : .ToOutsidePixels(pc->AppUnitsPerDevPixel());
4795 0 : rc->SetClip(region);
4796 : }
4797 :
4798 0 : if (resize)
4799 0 : rc->Scale(scale, scale);
4800 :
4801 : // translate so that points are relative to the surface area
4802 0 : rc->Translate(-aArea.TopLeft());
4803 :
4804 : // temporarily hide the selection so that text is drawn normally. If a
4805 : // selection is being rendered, use that, otherwise use the presshell's
4806 : // selection.
4807 0 : nsRefPtr<nsFrameSelection> frameSelection;
4808 0 : if (aSelection) {
4809 0 : nsCOMPtr<nsISelectionPrivate> selpriv = do_QueryInterface(aSelection);
4810 0 : selpriv->GetFrameSelection(getter_AddRefs(frameSelection));
4811 : }
4812 : else {
4813 0 : frameSelection = FrameSelection();
4814 : }
4815 0 : PRInt16 oldDisplaySelection = frameSelection->GetDisplaySelection();
4816 0 : frameSelection->SetDisplaySelection(nsISelectionController::SELECTION_HIDDEN);
4817 :
4818 : // next, paint each range in the selection
4819 0 : PRInt32 count = aItems->Length();
4820 0 : for (PRInt32 i = 0; i < count; i++) {
4821 0 : RangePaintInfo* rangeInfo = (*aItems)[i];
4822 : // the display lists paint relative to the offset from the reference
4823 : // frame, so translate the rendering context
4824 : nsRenderingContext::AutoPushTranslation
4825 0 : translate(rc, rangeInfo->mRootOffset);
4826 :
4827 0 : aArea.MoveBy(-rangeInfo->mRootOffset.x, -rangeInfo->mRootOffset.y);
4828 0 : nsRegion visible(aArea);
4829 0 : rangeInfo->mList.ComputeVisibilityForRoot(&rangeInfo->mBuilder, &visible);
4830 0 : rangeInfo->mList.PaintRoot(&rangeInfo->mBuilder, rc, nsDisplayList::PAINT_DEFAULT);
4831 0 : aArea.MoveBy(rangeInfo->mRootOffset.x, rangeInfo->mRootOffset.y);
4832 : }
4833 :
4834 : // restore the old selection display state
4835 0 : frameSelection->SetDisplaySelection(oldDisplaySelection);
4836 :
4837 0 : NS_ADDREF(surface);
4838 0 : return surface;
4839 : }
4840 :
4841 : already_AddRefed<gfxASurface>
4842 0 : PresShell::RenderNode(nsIDOMNode* aNode,
4843 : nsIntRegion* aRegion,
4844 : nsIntPoint& aPoint,
4845 : nsIntRect* aScreenRect)
4846 : {
4847 : // area will hold the size of the surface needed to draw the node, measured
4848 : // from the root frame.
4849 0 : nsRect area;
4850 0 : nsTArray<nsAutoPtr<RangePaintInfo> > rangeItems;
4851 :
4852 : // nothing to draw if the node isn't in a document
4853 0 : nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
4854 0 : if (!node->IsInDoc())
4855 0 : return nsnull;
4856 :
4857 0 : nsRefPtr<nsRange> range = new nsRange();
4858 0 : if (NS_FAILED(range->SelectNode(aNode)))
4859 0 : return nsnull;
4860 :
4861 0 : RangePaintInfo* info = CreateRangePaintInfo(range, area, false);
4862 0 : if (info && !rangeItems.AppendElement(info)) {
4863 0 : delete info;
4864 0 : return nsnull;
4865 : }
4866 :
4867 0 : if (aRegion) {
4868 : // combine the area with the supplied region
4869 0 : nsIntRect rrectPixels = aRegion->GetBounds();
4870 :
4871 0 : nsRect rrect = rrectPixels.ToAppUnits(nsPresContext::AppUnitsPerCSSPixel());
4872 0 : area.IntersectRect(area, rrect);
4873 :
4874 0 : nsPresContext* pc = GetPresContext();
4875 0 : if (!pc)
4876 0 : return nsnull;
4877 :
4878 : // move the region so that it is offset from the topleft corner of the surface
4879 0 : aRegion->MoveBy(-pc->AppUnitsToDevPixels(area.x),
4880 0 : -pc->AppUnitsToDevPixels(area.y));
4881 : }
4882 :
4883 : return PaintRangePaintInfo(&rangeItems, nsnull, aRegion, area, aPoint,
4884 0 : aScreenRect);
4885 : }
4886 :
4887 : already_AddRefed<gfxASurface>
4888 0 : PresShell::RenderSelection(nsISelection* aSelection,
4889 : nsIntPoint& aPoint,
4890 : nsIntRect* aScreenRect)
4891 : {
4892 : // area will hold the size of the surface needed to draw the selection,
4893 : // measured from the root frame.
4894 0 : nsRect area;
4895 0 : nsTArray<nsAutoPtr<RangePaintInfo> > rangeItems;
4896 :
4897 : // iterate over each range and collect them into the rangeItems array.
4898 : // This is done so that the size of selection can be determined so as
4899 : // to allocate a surface area
4900 : PRInt32 numRanges;
4901 0 : aSelection->GetRangeCount(&numRanges);
4902 0 : NS_ASSERTION(numRanges > 0, "RenderSelection called with no selection");
4903 :
4904 0 : for (PRInt32 r = 0; r < numRanges; r++)
4905 : {
4906 0 : nsCOMPtr<nsIDOMRange> range;
4907 0 : aSelection->GetRangeAt(r, getter_AddRefs(range));
4908 :
4909 0 : RangePaintInfo* info = CreateRangePaintInfo(range, area, true);
4910 0 : if (info && !rangeItems.AppendElement(info)) {
4911 0 : delete info;
4912 0 : return nsnull;
4913 : }
4914 : }
4915 :
4916 : return PaintRangePaintInfo(&rangeItems, aSelection, nsnull, area, aPoint,
4917 0 : aScreenRect);
4918 : }
4919 :
4920 : nsresult
4921 0 : PresShell::AddPrintPreviewBackgroundItem(nsDisplayListBuilder& aBuilder,
4922 : nsDisplayList& aList,
4923 : nsIFrame* aFrame,
4924 : const nsRect& aBounds)
4925 : {
4926 : return aList.AppendNewToBottom(new (&aBuilder)
4927 0 : nsDisplaySolidColor(&aBuilder, aFrame, aBounds, NS_RGB(115, 115, 115)));
4928 : }
4929 :
4930 : static bool
4931 0 : AddCanvasBackgroundColor(const nsDisplayList& aList, nsIFrame* aCanvasFrame,
4932 : nscolor aColor)
4933 : {
4934 0 : for (nsDisplayItem* i = aList.GetBottom(); i; i = i->GetAbove()) {
4935 0 : if (i->GetUnderlyingFrame() == aCanvasFrame &&
4936 0 : i->GetType() == nsDisplayItem::TYPE_CANVAS_BACKGROUND) {
4937 0 : nsDisplayCanvasBackground* bg = static_cast<nsDisplayCanvasBackground*>(i);
4938 0 : bg->SetExtraBackgroundColor(aColor);
4939 0 : return true;
4940 : }
4941 0 : nsDisplayList* sublist = i->GetList();
4942 0 : if (sublist && AddCanvasBackgroundColor(*sublist, aCanvasFrame, aColor))
4943 0 : return true;
4944 : }
4945 0 : return false;
4946 : }
4947 :
4948 0 : nsresult PresShell::AddCanvasBackgroundColorItem(nsDisplayListBuilder& aBuilder,
4949 : nsDisplayList& aList,
4950 : nsIFrame* aFrame,
4951 : const nsRect& aBounds,
4952 : nscolor aBackstopColor,
4953 : PRUint32 aFlags)
4954 : {
4955 0 : if (aBounds.IsEmpty()) {
4956 0 : return NS_OK;
4957 : }
4958 : // We don't want to add an item for the canvas background color if the frame
4959 : // (sub)tree we are painting doesn't include any canvas frames. There isn't
4960 : // an easy way to check this directly, but if we check if the root of the
4961 : // (sub)tree we are painting is a canvas frame that should cover us in all
4962 : // cases (it will usually be a viewport frame when we have a canvas frame in
4963 : // the (sub)tree).
4964 0 : if (!(aFlags & nsIPresShell::FORCE_DRAW) &&
4965 0 : !nsCSSRendering::IsCanvasFrame(aFrame)) {
4966 0 : return NS_OK;
4967 : }
4968 :
4969 0 : nscolor bgcolor = NS_ComposeColors(aBackstopColor, mCanvasBackgroundColor);
4970 0 : if (NS_GET_A(bgcolor) == 0)
4971 0 : return NS_OK;
4972 :
4973 : // To make layers work better, we want to avoid having a big non-scrolled
4974 : // color background behind a scrolled transparent background. Instead,
4975 : // we'll try to move the color background into the scrolled content
4976 : // by making nsDisplayCanvasBackground paint it.
4977 0 : if (!aFrame->GetParent()) {
4978 : nsIScrollableFrame* sf =
4979 0 : aFrame->PresContext()->PresShell()->GetRootScrollFrameAsScrollable();
4980 0 : if (sf) {
4981 0 : nsCanvasFrame* canvasFrame = do_QueryFrame(sf->GetScrolledFrame());
4982 0 : if (canvasFrame && canvasFrame->IsVisibleForPainting(&aBuilder)) {
4983 0 : if (AddCanvasBackgroundColor(aList, canvasFrame, bgcolor))
4984 0 : return NS_OK;
4985 : }
4986 : }
4987 : }
4988 :
4989 : return aList.AppendNewToBottom(
4990 0 : new (&aBuilder) nsDisplaySolidColor(&aBuilder, aFrame, aBounds, bgcolor));
4991 : }
4992 :
4993 0 : static bool IsTransparentContainerElement(nsPresContext* aPresContext)
4994 : {
4995 0 : nsCOMPtr<nsISupports> container = aPresContext->GetContainerInternal();
4996 0 : nsCOMPtr<nsIDocShellTreeItem> docShellItem = do_QueryInterface(container);
4997 0 : nsCOMPtr<nsPIDOMWindow> pwin(do_GetInterface(docShellItem));
4998 0 : if (!pwin)
4999 0 : return false;
5000 : nsCOMPtr<nsIContent> containerElement =
5001 0 : do_QueryInterface(pwin->GetFrameElementInternal());
5002 : return containerElement &&
5003 0 : containerElement->HasAttr(kNameSpaceID_None, nsGkAtoms::transparent);
5004 : }
5005 :
5006 0 : nscolor PresShell::GetDefaultBackgroundColorToDraw()
5007 : {
5008 0 : if (!mPresContext || !mPresContext->GetBackgroundColorDraw()) {
5009 0 : return NS_RGB(255,255,255);
5010 : }
5011 0 : return mPresContext->DefaultBackgroundColor();
5012 : }
5013 :
5014 0 : void PresShell::UpdateCanvasBackground()
5015 : {
5016 : // If we have a frame tree and it has style information that
5017 : // specifies the background color of the canvas, update our local
5018 : // cache of that color.
5019 0 : nsIFrame* rootStyleFrame = FrameConstructor()->GetRootElementStyleFrame();
5020 0 : if (rootStyleFrame) {
5021 : nsStyleContext* bgStyle =
5022 0 : nsCSSRendering::FindRootFrameBackground(rootStyleFrame);
5023 : // XXX We should really be passing the canvasframe, not the root element
5024 : // style frame but we don't have access to the canvasframe here. It isn't
5025 : // a problem because only a few frames can return something other than true
5026 : // and none of them would be a canvas frame or root element style frame.
5027 : mCanvasBackgroundColor =
5028 : nsCSSRendering::DetermineBackgroundColor(mPresContext, bgStyle,
5029 0 : rootStyleFrame);
5030 0 : if (GetPresContext()->IsRootContentDocument() &&
5031 0 : !IsTransparentContainerElement(mPresContext)) {
5032 : mCanvasBackgroundColor =
5033 0 : NS_ComposeColors(GetDefaultBackgroundColorToDraw(), mCanvasBackgroundColor);
5034 : }
5035 : }
5036 :
5037 : // If the root element of the document (ie html) has style 'display: none'
5038 : // then the document's background color does not get drawn; cache the
5039 : // color we actually draw.
5040 0 : if (!FrameConstructor()->GetRootElementFrame()) {
5041 0 : mCanvasBackgroundColor = GetDefaultBackgroundColorToDraw();
5042 : }
5043 0 : if (XRE_GetProcessType() == GeckoProcessType_Content) {
5044 0 : if (TabChild* tabChild = GetTabChildFrom(this)) {
5045 0 : tabChild->SetBackgroundColor(mCanvasBackgroundColor);
5046 : }
5047 : }
5048 0 : }
5049 :
5050 0 : nscolor PresShell::ComputeBackstopColor(nsIView* aDisplayRoot)
5051 : {
5052 0 : nsIWidget* widget = aDisplayRoot->GetWidget();
5053 0 : if (widget && widget->GetTransparencyMode() != eTransparencyOpaque) {
5054 : // Within a transparent widget, so the backstop color must be
5055 : // totally transparent.
5056 0 : return NS_RGBA(0,0,0,0);
5057 : }
5058 : // Within an opaque widget (or no widget at all), so the backstop
5059 : // color must be totally opaque. The user's default background
5060 : // as reported by the prescontext is guaranteed to be opaque.
5061 0 : return GetDefaultBackgroundColorToDraw();
5062 : }
5063 :
5064 : struct PaintParams {
5065 : nscolor mBackgroundColor;
5066 : };
5067 :
5068 0 : LayerManager* PresShell::GetLayerManager()
5069 : {
5070 0 : NS_ASSERTION(mViewManager, "Should have view manager");
5071 :
5072 0 : nsIView* rootView = mViewManager->GetRootView();
5073 0 : if (rootView) {
5074 0 : if (nsIWidget* widget = rootView->GetWidget()) {
5075 0 : return widget->GetLayerManager();
5076 : }
5077 : }
5078 0 : return nsnull;
5079 : }
5080 :
5081 0 : void PresShell::SetIgnoreViewportScrolling(bool aIgnore)
5082 : {
5083 0 : if (IgnoringViewportScrolling() == aIgnore) {
5084 0 : return;
5085 : }
5086 0 : RenderingState state(this);
5087 : state.mRenderFlags = ChangeFlag(state.mRenderFlags, aIgnore,
5088 0 : STATE_IGNORING_VIEWPORT_SCROLLING);
5089 0 : SetRenderingState(state);
5090 : }
5091 :
5092 0 : void PresShell::SetDisplayPort(const nsRect& aDisplayPort)
5093 : {
5094 0 : NS_ABORT_IF_FALSE(false, "SetDisplayPort is deprecated");
5095 0 : }
5096 :
5097 0 : nsresult PresShell::SetResolution(float aXResolution, float aYResolution)
5098 : {
5099 0 : if (!(aXResolution > 0.0 && aYResolution > 0.0)) {
5100 0 : return NS_ERROR_ILLEGAL_VALUE;
5101 : }
5102 0 : if (aXResolution == mXResolution && aYResolution == mYResolution) {
5103 0 : return NS_OK;
5104 : }
5105 0 : RenderingState state(this);
5106 0 : state.mXResolution = aXResolution;
5107 0 : state.mYResolution = aYResolution;
5108 0 : SetRenderingState(state);
5109 0 : return NS_OK;
5110 : }
5111 :
5112 0 : void PresShell::SetRenderingState(const RenderingState& aState)
5113 : {
5114 0 : if (mRenderFlags != aState.mRenderFlags) {
5115 : // Rendering state changed in a way that forces us to flush any
5116 : // retained layers we might already have.
5117 0 : LayerManager* manager = GetLayerManager();
5118 0 : if (manager) {
5119 0 : FrameLayerBuilder::InvalidateAllLayers(manager);
5120 : }
5121 : }
5122 :
5123 0 : mRenderFlags = aState.mRenderFlags;
5124 0 : mXResolution = aState.mXResolution;
5125 0 : mYResolution = aState.mYResolution;
5126 0 : }
5127 :
5128 0 : void PresShell::SynthesizeMouseMove(bool aFromScroll)
5129 : {
5130 0 : if (!sSynthMouseMove)
5131 0 : return;
5132 :
5133 0 : if (mPaintingSuppressed || !mIsActive || !mPresContext) {
5134 0 : return;
5135 : }
5136 :
5137 0 : if (!mPresContext->IsRoot()) {
5138 0 : nsIPresShell* rootPresShell = GetRootPresShell();
5139 0 : if (rootPresShell) {
5140 0 : rootPresShell->SynthesizeMouseMove(aFromScroll);
5141 : }
5142 0 : return;
5143 : }
5144 :
5145 0 : if (mMouseLocation == nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE))
5146 0 : return;
5147 :
5148 0 : if (!mSynthMouseMoveEvent.IsPending()) {
5149 : nsRefPtr<nsSynthMouseMoveEvent> ev =
5150 0 : new nsSynthMouseMoveEvent(this, aFromScroll);
5151 :
5152 0 : if (!GetPresContext()->RefreshDriver()->AddRefreshObserver(ev,
5153 0 : Flush_Display)) {
5154 0 : NS_WARNING("failed to dispatch nsSynthMouseMoveEvent");
5155 : return;
5156 : }
5157 :
5158 0 : mSynthMouseMoveEvent = ev;
5159 : }
5160 : }
5161 :
5162 : /**
5163 : * Find the first floating view with a widget in a postorder traversal of the
5164 : * view tree that contains the point. Thus more deeply nested floating views
5165 : * are preferred over their ancestors, and floating views earlier in the
5166 : * view hierarchy (i.e., added later) are preferred over their siblings.
5167 : * This is adequate for finding the "topmost" floating view under a point,
5168 : * given that floating views don't supporting having a specific z-index.
5169 : *
5170 : * We cannot exit early when aPt is outside the view bounds, because floating
5171 : * views aren't necessarily included in their parent's bounds, so this could
5172 : * traverse the entire view hierarchy --- use carefully.
5173 : */
5174 0 : static nsIView* FindFloatingViewContaining(nsIView* aView, nsPoint aPt)
5175 : {
5176 0 : if (aView->GetVisibility() == nsViewVisibility_kHide)
5177 : // No need to look into descendants.
5178 0 : return nsnull;
5179 :
5180 0 : nsIFrame* frame = aView->GetFrame();
5181 0 : if (frame) {
5182 0 : if (!frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) ||
5183 0 : !frame->PresContext()->PresShell()->IsActive()) {
5184 0 : return nsnull;
5185 : }
5186 : }
5187 :
5188 0 : for (nsIView* v = aView->GetFirstChild(); v; v = v->GetNextSibling()) {
5189 0 : nsIView* r = FindFloatingViewContaining(v, v->ConvertFromParentCoords(aPt));
5190 0 : if (r)
5191 0 : return r;
5192 : }
5193 :
5194 0 : if (aView->GetFloating() && aView->HasWidget() &&
5195 0 : aView->GetDimensions().Contains(aPt))
5196 0 : return aView;
5197 :
5198 0 : return nsnull;
5199 : }
5200 :
5201 : /*
5202 : * This finds the first view containing the given point in a postorder
5203 : * traversal of the view tree that contains the point, assuming that the
5204 : * point is not in a floating view. It assumes that only floating views
5205 : * extend outside the bounds of their parents.
5206 : *
5207 : * This methods should only be called if FindFloatingViewContaining
5208 : * returns null.
5209 : */
5210 0 : static nsIView* FindViewContaining(nsIView* aView, nsPoint aPt)
5211 : {
5212 0 : if (!aView->GetDimensions().Contains(aPt) ||
5213 0 : aView->GetVisibility() == nsViewVisibility_kHide) {
5214 0 : return nsnull;
5215 : }
5216 :
5217 0 : nsIFrame* frame = aView->GetFrame();
5218 0 : if (frame) {
5219 0 : if (!frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) ||
5220 0 : !frame->PresContext()->PresShell()->IsActive()) {
5221 0 : return nsnull;
5222 : }
5223 : }
5224 :
5225 0 : for (nsIView* v = aView->GetFirstChild(); v; v = v->GetNextSibling()) {
5226 0 : nsIView* r = FindViewContaining(v, v->ConvertFromParentCoords(aPt));
5227 0 : if (r)
5228 0 : return r;
5229 : }
5230 :
5231 0 : return aView;
5232 : }
5233 :
5234 : void
5235 0 : PresShell::ProcessSynthMouseMoveEvent(bool aFromScroll)
5236 : {
5237 : // If drag session has started, we shouldn't synthesize mousemove event.
5238 0 : nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
5239 0 : if (dragSession) {
5240 0 : mSynthMouseMoveEvent.Forget();
5241 : return;
5242 : }
5243 :
5244 : // allow new event to be posted while handling this one only if the
5245 : // source of the event is a scroll (to prevent infinite reflow loops)
5246 0 : if (aFromScroll) {
5247 0 : mSynthMouseMoveEvent.Forget();
5248 : }
5249 :
5250 0 : nsIView* rootView = mViewManager ? mViewManager->GetRootView() : nsnull;
5251 0 : if (mMouseLocation == nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE) ||
5252 0 : !rootView || !rootView->HasWidget() || !mPresContext) {
5253 0 : mSynthMouseMoveEvent.Forget();
5254 : return;
5255 : }
5256 :
5257 0 : NS_ASSERTION(mPresContext->IsRoot(), "Only a root pres shell should be here");
5258 :
5259 : // Hold a ref to ourselves so DispatchEvent won't destroy us (since
5260 : // we need to access members after we call DispatchEvent).
5261 0 : nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
5262 :
5263 : #ifdef DEBUG_MOUSE_LOCATION
5264 : printf("[ps=%p]synthesizing mouse move to (%d,%d)\n",
5265 : this, mMouseLocation.x, mMouseLocation.y);
5266 : #endif
5267 :
5268 0 : PRInt32 APD = mPresContext->AppUnitsPerDevPixel();
5269 :
5270 : // We need a widget to put in the event we are going to dispatch so we look
5271 : // for a view that has a widget and the mouse location is over. We first look
5272 : // for floating views, if there isn't one we use the root view. |view| holds
5273 : // that view.
5274 0 : nsIView* view = nsnull;
5275 :
5276 : // The appunits per devpixel ratio of |view|.
5277 : PRInt32 viewAPD;
5278 :
5279 : // refPoint will be mMouseLocation relative to the widget of |view|, the
5280 : // widget we will put in the event we dispatch, in viewAPD appunits
5281 0 : nsPoint refpoint(0, 0);
5282 :
5283 : // We always dispatch the event to the pres shell that contains the view that
5284 : // the mouse is over. pointVM is the VM of that pres shell.
5285 0 : nsIViewManager *pointVM = nsnull;
5286 :
5287 : // This could be a bit slow (traverses entire view hierarchy)
5288 : // but it's OK to do it once per synthetic mouse event
5289 0 : view = FindFloatingViewContaining(rootView, mMouseLocation);
5290 0 : if (!view) {
5291 0 : view = rootView;
5292 0 : nsIView *pointView = FindViewContaining(rootView, mMouseLocation);
5293 : // pointView can be null in situations related to mouse capture
5294 0 : pointVM = (pointView ? pointView : view)->GetViewManager();
5295 0 : refpoint = mMouseLocation + rootView->ViewToWidgetOffset();
5296 0 : viewAPD = APD;
5297 : } else {
5298 0 : pointVM = view->GetViewManager();
5299 0 : nsIFrame* frame = view->GetFrame();
5300 0 : NS_ASSERTION(frame, "floating views can't be anonymous");
5301 0 : viewAPD = frame->PresContext()->AppUnitsPerDevPixel();
5302 0 : refpoint = mMouseLocation.ConvertAppUnits(APD, viewAPD);
5303 0 : refpoint -= view->GetOffsetTo(rootView);
5304 0 : refpoint += view->ViewToWidgetOffset();
5305 : }
5306 0 : NS_ASSERTION(view->GetWidget(), "view should have a widget here");
5307 : nsMouseEvent event(true, NS_MOUSE_MOVE, view->GetWidget(),
5308 0 : nsMouseEvent::eSynthesized);
5309 0 : event.refPoint = refpoint.ToNearestPixels(viewAPD);
5310 0 : event.time = PR_IntervalNow();
5311 : // XXX set event.isShift, event.isControl, event.isAlt, event.isMeta ?
5312 :
5313 0 : nsCOMPtr<nsIPresShell> shell = pointVM->GetPresShell();
5314 0 : if (shell) {
5315 0 : shell->DispatchSynthMouseMove(&event, !aFromScroll);
5316 : }
5317 :
5318 0 : if (!aFromScroll) {
5319 0 : mSynthMouseMoveEvent.Forget();
5320 : }
5321 : }
5322 :
5323 : class nsAutoNotifyDidPaint
5324 : {
5325 : public:
5326 0 : nsAutoNotifyDidPaint(bool aWillSendDidPaint)
5327 0 : : mWillSendDidPaint(aWillSendDidPaint)
5328 : {
5329 0 : }
5330 0 : ~nsAutoNotifyDidPaint()
5331 : {
5332 0 : if (!mWillSendDidPaint && nsContentUtils::XPConnect()) {
5333 0 : nsContentUtils::XPConnect()->NotifyDidPaint();
5334 : }
5335 0 : }
5336 :
5337 : private:
5338 : bool mWillSendDidPaint;
5339 : };
5340 :
5341 : void
5342 0 : PresShell::Paint(nsIView* aViewToPaint,
5343 : nsIWidget* aWidgetToPaint,
5344 : const nsRegion& aDirtyRegion,
5345 : const nsIntRegion& aIntDirtyRegion,
5346 : bool aWillSendDidPaint)
5347 : {
5348 : #ifdef NS_FUNCTION_TIMER
5349 : NS_TIME_FUNCTION_DECLARE_DOCURL;
5350 : const nsRect& bounds__ = aDirtyRegion.GetBounds();
5351 : NS_TIME_FUNCTION_MIN_FMT(1.0, "%s (line %d) (document: %s, dirty rect: (<%f, %f>, <%f, %f>)",
5352 : MOZ_FUNCTION_NAME, __LINE__, docURL__.get(),
5353 : NSCoordToFloat(bounds__.x),
5354 : NSCoordToFloat(bounds__.y),
5355 : NSCoordToFloat(bounds__.XMost()),
5356 : NSCoordToFloat(bounds__.YMost()));
5357 : #endif
5358 :
5359 0 : SAMPLE_LABEL("Paint", "PresShell::Paint");
5360 0 : NS_ASSERTION(!mIsDestroying, "painting a destroyed PresShell");
5361 0 : NS_ASSERTION(aViewToPaint, "null view");
5362 0 : NS_ASSERTION(aWidgetToPaint, "Can't paint without a widget");
5363 :
5364 0 : nsAutoNotifyDidPaint notifyDidPaint(aWillSendDidPaint);
5365 :
5366 0 : nsPresContext* presContext = GetPresContext();
5367 0 : AUTO_LAYOUT_PHASE_ENTRY_POINT(presContext, Paint);
5368 :
5369 0 : nsIFrame* frame = aViewToPaint->GetFrame();
5370 :
5371 : bool isRetainingManager;
5372 : LayerManager* layerManager =
5373 0 : aWidgetToPaint->GetLayerManager(&isRetainingManager);
5374 0 : NS_ASSERTION(layerManager, "Must be in paint event");
5375 0 : layerManager->BeginTransaction();
5376 :
5377 0 : if (frame && isRetainingManager) {
5378 : // Try to do an empty transaction, if the frame tree does not
5379 : // need to be updated. Do not try to do an empty transaction on
5380 : // a non-retained layer manager (like the BasicLayerManager that
5381 : // draws the window title bar on Mac), because a) it won't work
5382 : // and b) below we don't want to clear NS_FRAME_UPDATE_LAYER_TREE,
5383 : // that will cause us to forget to update the real layer manager!
5384 0 : if (!(frame->GetStateBits() & NS_FRAME_UPDATE_LAYER_TREE)) {
5385 0 : if (layerManager->EndEmptyTransaction()) {
5386 0 : frame->UpdatePaintCountForPaintedPresShells();
5387 0 : presContext->NotifyDidPaintForSubtree();
5388 : return;
5389 : }
5390 : }
5391 :
5392 0 : frame->RemoveStateBits(NS_FRAME_UPDATE_LAYER_TREE);
5393 : }
5394 0 : if (frame) {
5395 0 : frame->ClearPresShellsFromLastPaint();
5396 : }
5397 :
5398 0 : nscolor bgcolor = ComputeBackstopColor(aViewToPaint);
5399 :
5400 0 : if (frame) {
5401 : // Defer invalidates that are triggered during painting, and discard
5402 : // invalidates of areas that are already being repainted.
5403 : // The layer system can trigger invalidates during painting
5404 : // (see FrameLayerBuilder).
5405 0 : frame->BeginDeferringInvalidatesForDisplayRoot(aDirtyRegion);
5406 :
5407 : // We can paint directly into the widget using its layer manager.
5408 : nsLayoutUtils::PaintFrame(nsnull, frame, aDirtyRegion, bgcolor,
5409 : nsLayoutUtils::PAINT_WIDGET_LAYERS |
5410 0 : nsLayoutUtils::PAINT_EXISTING_TRANSACTION);
5411 :
5412 0 : frame->EndDeferringInvalidatesForDisplayRoot();
5413 0 : presContext->NotifyDidPaintForSubtree();
5414 : return;
5415 : }
5416 :
5417 0 : nsRefPtr<ColorLayer> root = layerManager->CreateColorLayer();
5418 0 : if (root) {
5419 0 : nsPresContext* pc = GetPresContext();
5420 : nsIntRect bounds =
5421 0 : pc->GetVisibleArea().ToOutsidePixels(pc->AppUnitsPerDevPixel());
5422 0 : bgcolor = NS_ComposeColors(bgcolor, mCanvasBackgroundColor);
5423 0 : root->SetColor(bgcolor);
5424 0 : root->SetVisibleRegion(bounds);
5425 0 : layerManager->SetRoot(root);
5426 : }
5427 0 : layerManager->EndTransaction(NULL, NULL);
5428 :
5429 0 : presContext->NotifyDidPaintForSubtree();
5430 : }
5431 :
5432 : // static
5433 : void
5434 0 : nsIPresShell::SetCapturingContent(nsIContent* aContent, PRUint8 aFlags)
5435 : {
5436 0 : NS_IF_RELEASE(gCaptureInfo.mContent);
5437 :
5438 : // only set capturing content if allowed or the CAPTURE_IGNOREALLOWED flag
5439 : // is used
5440 0 : if ((aFlags & CAPTURE_IGNOREALLOWED) || gCaptureInfo.mAllowed) {
5441 0 : if (aContent) {
5442 0 : NS_ADDREF(gCaptureInfo.mContent = aContent);
5443 : }
5444 0 : gCaptureInfo.mRetargetToElement = (aFlags & CAPTURE_RETARGETTOELEMENT) != 0;
5445 0 : gCaptureInfo.mPreventDrag = (aFlags & CAPTURE_PREVENTDRAG) != 0;
5446 : }
5447 0 : }
5448 :
5449 : nsIFrame*
5450 0 : PresShell::GetCurrentEventFrame()
5451 : {
5452 0 : if (NS_UNLIKELY(mIsDestroying)) {
5453 0 : return nsnull;
5454 : }
5455 :
5456 0 : if (!mCurrentEventFrame && mCurrentEventContent) {
5457 : // Make sure the content still has a document reference. If not,
5458 : // then we assume it is no longer in the content tree and the
5459 : // frame shouldn't get an event, nor should we even assume its
5460 : // safe to try and find the frame.
5461 0 : if (mCurrentEventContent->GetDocument()) {
5462 0 : mCurrentEventFrame = mCurrentEventContent->GetPrimaryFrame();
5463 : }
5464 : }
5465 :
5466 0 : return mCurrentEventFrame;
5467 : }
5468 :
5469 : nsIFrame*
5470 0 : PresShell::GetEventTargetFrame()
5471 : {
5472 0 : return GetCurrentEventFrame();
5473 : }
5474 :
5475 : already_AddRefed<nsIContent>
5476 0 : PresShell::GetEventTargetContent(nsEvent* aEvent)
5477 : {
5478 0 : nsIContent* content = nsnull;
5479 :
5480 0 : if (mCurrentEventContent) {
5481 0 : content = mCurrentEventContent;
5482 0 : NS_IF_ADDREF(content);
5483 : } else {
5484 0 : nsIFrame* currentEventFrame = GetCurrentEventFrame();
5485 0 : if (currentEventFrame) {
5486 0 : currentEventFrame->GetContentForEvent(aEvent, &content);
5487 : } else {
5488 0 : content = nsnull;
5489 : }
5490 : }
5491 0 : return content;
5492 : }
5493 :
5494 : void
5495 0 : PresShell::PushCurrentEventInfo(nsIFrame* aFrame, nsIContent* aContent)
5496 : {
5497 0 : if (mCurrentEventFrame || mCurrentEventContent) {
5498 0 : mCurrentEventFrameStack.InsertElementAt(0, mCurrentEventFrame);
5499 0 : mCurrentEventContentStack.InsertObjectAt(mCurrentEventContent, 0);
5500 : }
5501 0 : mCurrentEventFrame = aFrame;
5502 0 : mCurrentEventContent = aContent;
5503 0 : }
5504 :
5505 : void
5506 0 : PresShell::PopCurrentEventInfo()
5507 : {
5508 0 : mCurrentEventFrame = nsnull;
5509 0 : mCurrentEventContent = nsnull;
5510 :
5511 0 : if (0 != mCurrentEventFrameStack.Length()) {
5512 0 : mCurrentEventFrame = mCurrentEventFrameStack.ElementAt(0);
5513 0 : mCurrentEventFrameStack.RemoveElementAt(0);
5514 0 : mCurrentEventContent = mCurrentEventContentStack.ObjectAt(0);
5515 0 : mCurrentEventContentStack.RemoveObjectAt(0);
5516 : }
5517 0 : }
5518 :
5519 0 : bool PresShell::InZombieDocument(nsIContent *aContent)
5520 : {
5521 : // If a content node points to a null document, or the document is not
5522 : // attached to a window, then it is possibly in a zombie document,
5523 : // about to be replaced by a newly loading document.
5524 : // Such documents cannot handle DOM events.
5525 : // It might actually be in a node not attached to any document,
5526 : // in which case there is not parent presshell to retarget it to.
5527 0 : nsIDocument *doc = aContent->GetDocument();
5528 0 : return !doc || !doc->GetWindow();
5529 : }
5530 :
5531 : already_AddRefed<nsPIDOMWindow>
5532 0 : PresShell::GetRootWindow()
5533 : {
5534 : nsCOMPtr<nsPIDOMWindow> window =
5535 0 : do_QueryInterface(mDocument->GetWindow());
5536 0 : if (window) {
5537 0 : nsCOMPtr<nsPIDOMWindow> rootWindow = window->GetPrivateRoot();
5538 0 : NS_ASSERTION(rootWindow, "nsPIDOMWindow::GetPrivateRoot() returns NULL");
5539 0 : return rootWindow.forget();
5540 : }
5541 :
5542 : // If we don't have DOM window, we're zombie, we should find the root window
5543 : // with our parent shell.
5544 0 : nsCOMPtr<nsIPresShell> parent = GetParentPresShell();
5545 0 : NS_ENSURE_TRUE(parent, nsnull);
5546 0 : return parent->GetRootWindow();
5547 : }
5548 :
5549 : already_AddRefed<nsIPresShell>
5550 0 : PresShell::GetParentPresShell()
5551 : {
5552 0 : NS_ENSURE_TRUE(mPresContext, nsnull);
5553 0 : nsCOMPtr<nsISupports> container = mPresContext->GetContainer();
5554 0 : if (!container) {
5555 0 : container = do_QueryReferent(mForwardingContainer);
5556 : }
5557 :
5558 : // Now, find the parent pres shell and send the event there
5559 0 : nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(container);
5560 : // Might have gone away, or never been around to start with
5561 0 : NS_ENSURE_TRUE(treeItem, nsnull);
5562 :
5563 0 : nsCOMPtr<nsIDocShellTreeItem> parentTreeItem;
5564 0 : treeItem->GetParent(getter_AddRefs(parentTreeItem));
5565 0 : nsCOMPtr<nsIDocShell> parentDocShell = do_QueryInterface(parentTreeItem);
5566 0 : NS_ENSURE_TRUE(parentDocShell && treeItem != parentTreeItem, nsnull);
5567 :
5568 0 : nsIPresShell* parentPresShell = nsnull;
5569 0 : parentDocShell->GetPresShell(&parentPresShell);
5570 0 : return parentPresShell;
5571 : }
5572 :
5573 : nsresult
5574 0 : PresShell::RetargetEventToParent(nsGUIEvent* aEvent,
5575 : nsEventStatus* aEventStatus)
5576 : {
5577 : // Send this events straight up to the parent pres shell.
5578 : // We do this for keystroke events in zombie documents or if either a frame
5579 : // or a root content is not present.
5580 : // That way at least the UI key bindings can work.
5581 :
5582 0 : nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
5583 0 : nsCOMPtr<nsIPresShell> parentPresShell = GetParentPresShell();
5584 0 : NS_ENSURE_TRUE(parentPresShell, NS_ERROR_FAILURE);
5585 :
5586 : // Fake the event as though it's from the parent pres shell's root frame.
5587 0 : return parentPresShell->HandleEvent(parentPresShell->GetRootFrame(), aEvent, true, aEventStatus);
5588 : }
5589 :
5590 : void
5591 0 : PresShell::DisableNonTestMouseEvents(bool aDisable)
5592 : {
5593 0 : sDisableNonTestMouseEvents = aDisable;
5594 0 : }
5595 :
5596 : already_AddRefed<nsPIDOMWindow>
5597 0 : PresShell::GetFocusedDOMWindowInOurWindow()
5598 : {
5599 0 : nsCOMPtr<nsPIDOMWindow> rootWindow = GetRootWindow();
5600 0 : NS_ENSURE_TRUE(rootWindow, nsnull);
5601 : nsPIDOMWindow* focusedWindow;
5602 0 : nsFocusManager::GetFocusedDescendant(rootWindow, true, &focusedWindow);
5603 0 : return focusedWindow;
5604 : }
5605 :
5606 : void
5607 0 : PresShell::RecordMouseLocation(nsGUIEvent* aEvent)
5608 : {
5609 0 : if (!mPresContext)
5610 0 : return;
5611 :
5612 0 : if (!mPresContext->IsRoot()) {
5613 0 : PresShell* rootPresShell = GetRootPresShell();
5614 0 : if (rootPresShell) {
5615 0 : rootPresShell->RecordMouseLocation(aEvent);
5616 : }
5617 0 : return;
5618 : }
5619 :
5620 0 : if ((aEvent->message == NS_MOUSE_MOVE &&
5621 : static_cast<nsMouseEvent*>(aEvent)->reason == nsMouseEvent::eReal) ||
5622 : aEvent->message == NS_MOUSE_ENTER ||
5623 : aEvent->message == NS_MOUSE_BUTTON_DOWN ||
5624 : aEvent->message == NS_MOUSE_BUTTON_UP) {
5625 0 : nsIFrame* rootFrame = GetRootFrame();
5626 0 : if (!rootFrame) {
5627 0 : nsIView* rootView = mViewManager->GetRootView();
5628 : mMouseLocation = nsLayoutUtils::TranslateWidgetToView(mPresContext,
5629 0 : aEvent->widget, aEvent->refPoint, rootView);
5630 : } else {
5631 : mMouseLocation =
5632 0 : nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, rootFrame);
5633 : }
5634 : #ifdef DEBUG_MOUSE_LOCATION
5635 : if (aEvent->message == NS_MOUSE_ENTER)
5636 : printf("[ps=%p]got mouse enter for %p\n",
5637 : this, aEvent->widget);
5638 : printf("[ps=%p]setting mouse location to (%d,%d)\n",
5639 : this, mMouseLocation.x, mMouseLocation.y);
5640 : #endif
5641 0 : if (aEvent->message == NS_MOUSE_ENTER)
5642 0 : SynthesizeMouseMove(false);
5643 0 : } else if (aEvent->message == NS_MOUSE_EXIT) {
5644 : // Although we only care about the mouse moving into an area for which this
5645 : // pres shell doesn't receive mouse move events, we don't check which widget
5646 : // the mouse exit was for since this seems to vary by platform. Hopefully
5647 : // this won't matter at all since we'll get the mouse move or enter after
5648 : // the mouse exit when the mouse moves from one of our widgets into another.
5649 0 : mMouseLocation = nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
5650 : #ifdef DEBUG_MOUSE_LOCATION
5651 : printf("[ps=%p]got mouse exit for %p\n",
5652 : this, aEvent->widget);
5653 : printf("[ps=%p]clearing mouse location\n",
5654 : this);
5655 : #endif
5656 : }
5657 : }
5658 :
5659 : #ifdef MOZ_TOUCH
5660 : static void
5661 : EvictTouchPoint(nsCOMPtr<nsIDOMTouch>& aTouch)
5662 : {
5663 : nsIWidget *widget = nsnull;
5664 : // is there an easier/better way to dig out the widget?
5665 : nsCOMPtr<nsINode> node(do_QueryInterface(aTouch->GetTarget()));
5666 : if (!node) {
5667 : return;
5668 : }
5669 : nsIDocument* doc = node->GetCurrentDoc();
5670 : if (!doc) {
5671 : return;
5672 : }
5673 : nsIPresShell *presShell = doc->GetShell();
5674 : if (!presShell) {
5675 : return;
5676 : }
5677 : nsIFrame* frame = presShell->GetRootFrame();
5678 : if (!frame) {
5679 : return;
5680 : }
5681 : nsPoint *pt = new nsPoint(aTouch->mRefPoint.x, aTouch->mRefPoint.y);
5682 : widget = frame->GetView()->GetNearestWidget(pt);
5683 : if (!widget) {
5684 : return;
5685 : }
5686 : nsTouchEvent event(true, NS_TOUCH_END, widget);
5687 : event.isShift = false;
5688 : event.isControl = false;
5689 : event.isAlt = false;
5690 : event.isMeta = false;
5691 : event.widget = widget;
5692 : event.time = PR_IntervalNow();
5693 : event.touches.AppendElement(aTouch);
5694 :
5695 : nsEventStatus status;
5696 : widget->DispatchEvent(&event, status);
5697 : }
5698 :
5699 : static PLDHashOperator
5700 : AppendToTouchList(const PRUint32& aKey, nsCOMPtr<nsIDOMTouch>& aData, void *aTouchList)
5701 : {
5702 : nsTArray<nsCOMPtr<nsIDOMTouch> > *touches = static_cast<nsTArray<nsCOMPtr<nsIDOMTouch> > *>(aTouchList);
5703 : aData->mChanged = false;
5704 : touches->AppendElement(aData);
5705 : return PL_DHASH_NEXT;
5706 : }
5707 : #endif // MOZ_TOUCH
5708 :
5709 : nsresult
5710 0 : PresShell::HandleEvent(nsIFrame *aFrame,
5711 : nsGUIEvent* aEvent,
5712 : bool aDontRetargetEvents,
5713 : nsEventStatus* aEventStatus)
5714 : {
5715 0 : NS_ASSERTION(aFrame, "null frame");
5716 :
5717 0 : if (mIsDestroying ||
5718 : (sDisableNonTestMouseEvents && NS_IS_MOUSE_EVENT(aEvent) &&
5719 0 : !(aEvent->flags & NS_EVENT_FLAG_SYNTHETIC_TEST_EVENT))) {
5720 0 : return NS_OK;
5721 : }
5722 :
5723 0 : RecordMouseLocation(aEvent);
5724 :
5725 : #ifdef ACCESSIBILITY
5726 0 : if (aEvent->eventStructType == NS_ACCESSIBLE_EVENT) {
5727 : NS_TIME_FUNCTION_MIN(1.0);
5728 :
5729 : // Accessibility events come through OS requests and not from scripts,
5730 : // so it is safe to handle here
5731 0 : return HandleEventInternal(aEvent, aEventStatus);
5732 : }
5733 : #endif
5734 :
5735 0 : if (!nsContentUtils::IsSafeToRunScript())
5736 0 : return NS_OK;
5737 :
5738 : NS_TIME_FUNCTION_MIN(1.0);
5739 :
5740 : nsIContent* capturingContent =
5741 0 : NS_IS_MOUSE_EVENT(aEvent) ? GetCapturingContent() : nsnull;
5742 :
5743 0 : nsCOMPtr<nsIDocument> retargetEventDoc;
5744 0 : if (!aDontRetargetEvents) {
5745 : // key and IME related events should not cross top level window boundary.
5746 : // Basically, such input events should be fired only on focused widget.
5747 : // However, some IMEs might need to clean up composition after focused
5748 : // window is deactivated. And also some tests on MozMill want to test key
5749 : // handling on deactivated window because MozMill window can be activated
5750 : // during tests. So, there is no merit the events should be redirected to
5751 : // active window. So, the events should be handled on the last focused
5752 : // content in the last focused DOM window in same top level window.
5753 : // Note, if no DOM window has been focused yet, we can discard the events.
5754 0 : if (NS_IsEventTargetedAtFocusedWindow(aEvent)) {
5755 0 : nsCOMPtr<nsPIDOMWindow> window = GetFocusedDOMWindowInOurWindow();
5756 : // No DOM window in same top level window has not been focused yet,
5757 : // discard the events.
5758 0 : if (!window) {
5759 0 : return NS_OK;
5760 : }
5761 :
5762 0 : retargetEventDoc = do_QueryInterface(window->GetExtantDocument());
5763 0 : if (!retargetEventDoc)
5764 0 : return NS_OK;
5765 0 : } else if (capturingContent) {
5766 : // if the mouse is being captured then retarget the mouse event at the
5767 : // document that is being captured.
5768 0 : retargetEventDoc = capturingContent->GetCurrentDoc();
5769 : }
5770 :
5771 0 : if (retargetEventDoc) {
5772 0 : nsCOMPtr<nsIPresShell> presShell = retargetEventDoc->GetShell();
5773 0 : if (!presShell)
5774 0 : return NS_OK;
5775 :
5776 0 : if (presShell != this) {
5777 0 : nsIFrame* frame = presShell->GetRootFrame();
5778 0 : if (!frame) {
5779 0 : if (aEvent->message == NS_QUERY_TEXT_CONTENT ||
5780 : NS_IS_CONTENT_COMMAND_EVENT(aEvent)) {
5781 0 : return NS_OK;
5782 : }
5783 :
5784 0 : nsIView* view = presShell->GetViewManager()->GetRootView();
5785 0 : while (view && !view->GetFrame()) {
5786 0 : view = view->GetParent();
5787 : }
5788 :
5789 0 : if (view) {
5790 0 : frame = view->GetFrame();
5791 : }
5792 : }
5793 :
5794 0 : if (!frame)
5795 0 : return NS_OK;
5796 :
5797 0 : nsCOMPtr<nsIPresShell> shell = frame->PresContext()->GetPresShell();
5798 0 : return shell->HandleEvent(frame, aEvent, true, aEventStatus);
5799 : }
5800 : }
5801 : }
5802 :
5803 : // Check for a theme change up front, since the frame type is irrelevant
5804 0 : if (aEvent->message == NS_THEMECHANGED && mPresContext) {
5805 0 : mPresContext->ThemeChanged();
5806 0 : return NS_OK;
5807 : }
5808 :
5809 0 : if (aEvent->message == NS_UISTATECHANGED && mDocument) {
5810 0 : nsPIDOMWindow* win = mDocument->GetWindow();
5811 0 : if (win) {
5812 0 : nsUIStateChangeEvent* event = (nsUIStateChangeEvent*)aEvent;
5813 0 : win->SetKeyboardIndicators(event->showAccelerators, event->showFocusRings);
5814 : }
5815 0 : return NS_OK;
5816 : }
5817 :
5818 : // Check for a system color change up front, since the frame type is
5819 : // irrelevant
5820 0 : if ((aEvent->message == NS_SYSCOLORCHANGED) && mPresContext &&
5821 0 : aFrame == mFrameConstructor->GetRootFrame()) {
5822 0 : *aEventStatus = nsEventStatus_eConsumeDoDefault;
5823 0 : mPresContext->SysColorChanged();
5824 0 : return NS_OK;
5825 : }
5826 :
5827 0 : if (aEvent->eventStructType == NS_KEY_EVENT &&
5828 0 : mDocument && mDocument->EventHandlingSuppressed()) {
5829 0 : if (aEvent->message == NS_KEY_DOWN) {
5830 0 : mNoDelayedKeyEvents = true;
5831 0 : } else if (!mNoDelayedKeyEvents) {
5832 : nsDelayedEvent* event =
5833 0 : new nsDelayedKeyEvent(static_cast<nsKeyEvent*>(aEvent));
5834 0 : if (!mDelayedEvents.AppendElement(event)) {
5835 0 : delete event;
5836 : }
5837 : }
5838 0 : return NS_OK;
5839 : }
5840 :
5841 0 : nsIFrame* frame = aFrame;
5842 0 : bool dispatchUsingCoordinates = NS_IsEventUsingCoordinates(aEvent);
5843 0 : if (dispatchUsingCoordinates) {
5844 0 : NS_WARN_IF_FALSE(frame, "Nothing to handle this event!");
5845 0 : if (!frame)
5846 0 : return NS_OK;
5847 :
5848 0 : nsPresContext* framePresContext = frame->PresContext();
5849 0 : nsPresContext* rootPresContext = framePresContext->GetRootPresContext();
5850 0 : NS_ASSERTION(rootPresContext == mPresContext->GetRootPresContext(),
5851 : "How did we end up outside the connected prescontext/viewmanager hierarchy?");
5852 : // If we aren't starting our event dispatch from the root frame of the root prescontext,
5853 : // then someone must be capturing the mouse. In that case we don't want to search the popup
5854 : // list.
5855 0 : if (framePresContext == rootPresContext &&
5856 0 : frame == mFrameConstructor->GetRootFrame()) {
5857 : nsIFrame* popupFrame =
5858 0 : nsLayoutUtils::GetPopupFrameForEventCoordinates(rootPresContext, aEvent);
5859 : // If the popupFrame is an ancestor of the 'frame', the frame should
5860 : // handle the event, otherwise, the popup should handle it.
5861 0 : if (popupFrame &&
5862 : !nsContentUtils::ContentIsCrossDocDescendantOf(
5863 0 : framePresContext->GetPresShell()->GetDocument(),
5864 0 : popupFrame->GetContent())) {
5865 0 : frame = popupFrame;
5866 : }
5867 : }
5868 :
5869 0 : bool captureRetarget = false;
5870 0 : if (capturingContent) {
5871 : // If a capture is active, determine if the docshell is visible. If not,
5872 : // clear the capture and target the mouse event normally instead. This
5873 : // would occur if the mouse button is held down while a tab change occurs.
5874 : // If the docshell is visible, look for a scrolling container.
5875 : bool vis;
5876 0 : nsCOMPtr<nsISupports> supports = mPresContext->GetContainer();
5877 0 : nsCOMPtr<nsIBaseWindow> baseWin(do_QueryInterface(supports));
5878 0 : if (baseWin && NS_SUCCEEDED(baseWin->GetVisibility(&vis)) && vis) {
5879 0 : captureRetarget = gCaptureInfo.mRetargetToElement;
5880 0 : if (!captureRetarget) {
5881 : // A check was already done above to ensure that capturingContent is
5882 : // in this presshell.
5883 0 : NS_ASSERTION(capturingContent->GetCurrentDoc() == GetDocument(),
5884 : "Unexpected document");
5885 0 : nsIFrame* captureFrame = capturingContent->GetPrimaryFrame();
5886 0 : if (captureFrame) {
5887 0 : if (capturingContent->Tag() == nsGkAtoms::select &&
5888 0 : capturingContent->IsHTML()) {
5889 : // a dropdown <select> has a child in its selectPopupList and we should
5890 : // capture on that instead.
5891 0 : nsIFrame* childFrame = captureFrame->GetChildList(nsIFrame::kSelectPopupList).FirstChild();
5892 0 : if (childFrame) {
5893 0 : captureFrame = childFrame;
5894 : }
5895 : }
5896 :
5897 : // scrollable frames should use the scrolling container as
5898 : // the root instead of the document
5899 0 : nsIScrollableFrame* scrollFrame = do_QueryFrame(captureFrame);
5900 0 : if (scrollFrame) {
5901 0 : frame = scrollFrame->GetScrolledFrame();
5902 : }
5903 : }
5904 : }
5905 : }
5906 : else {
5907 0 : ClearMouseCapture(nsnull);
5908 0 : capturingContent = nsnull;
5909 : }
5910 : }
5911 :
5912 : bool isWindowLevelMouseExit = (aEvent->message == NS_MOUSE_EXIT) &&
5913 0 : (static_cast<nsMouseEvent*>(aEvent)->exit == nsMouseEvent::eTopLevel);
5914 :
5915 : // Get the frame at the event point. However, don't do this if we're
5916 : // capturing and retargeting the event because the captured frame will
5917 : // be used instead below. Also keep using the root frame if we're dealing
5918 : // with a window-level mouse exit event since we want to start sending
5919 : // mouse out events at the root EventStateManager.
5920 0 : if (!captureRetarget && !isWindowLevelMouseExit) {
5921 : #ifdef MOZ_TOUCH
5922 : nsPoint eventPoint;
5923 : if (aEvent->message == NS_TOUCH_START) {
5924 : // Add any new touches to the queue
5925 : nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(aEvent);
5926 : // if there is only one touch in this touchstart event, assume that it is
5927 : // the start of a new touch session and evict any old touches in the
5928 : // queue
5929 : if (touchEvent->touches.Length() == 1) {
5930 : nsTArray<nsCOMPtr<nsIDOMTouch> > touches;
5931 : gCaptureTouchList.Enumerate(&AppendToTouchList, (void *)&touches);
5932 : for (PRUint32 i = 0; i < touches.Length(); ++i) {
5933 : EvictTouchPoint(touches[i]);
5934 : }
5935 : }
5936 : for (PRUint32 i = 0; i < touchEvent->touches.Length(); ++i) {
5937 : nsIDOMTouch *touch = touchEvent->touches[i];
5938 : nsDOMTouch *domtouch = static_cast<nsDOMTouch*>(touch);
5939 : touch->mMessage = aEvent->message;
5940 :
5941 : PRInt32 id = 0;
5942 : touch->GetIdentifier(&id);
5943 : if (!gCaptureTouchList.Get(id, nsnull)) {
5944 : // This event is a new touch. Mark it as a changedTouch and
5945 : // add it to the queue.
5946 : touch->mChanged = true;
5947 : gCaptureTouchList.Put(id, touch);
5948 :
5949 : eventPoint = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, touch->mRefPoint, frame);
5950 : } else {
5951 : // This touch is an old touch, we need to ensure that is not
5952 : // marked as changed and set its target correctly
5953 : touch->mChanged = false;
5954 : PRInt32 id;
5955 : touch->GetIdentifier(&id);
5956 :
5957 : nsCOMPtr<nsIDOMTouch> oldTouch;
5958 : gCaptureTouchList.Get(id, getter_AddRefs(oldTouch));
5959 : if (oldTouch) {
5960 : nsCOMPtr<nsPIDOMEventTarget> targetPtr;
5961 : oldTouch->GetTarget(getter_AddRefs(targetPtr));
5962 : domtouch->SetTarget(targetPtr);
5963 : gCaptureTouchList.Put(id, touch);
5964 : }
5965 : }
5966 : }
5967 : } else {
5968 : eventPoint = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, frame);
5969 : }
5970 : #else
5971 : nsPoint eventPoint
5972 0 : = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, frame);
5973 : #endif
5974 : {
5975 0 : bool ignoreRootScrollFrame = false;
5976 0 : if (aEvent->eventStructType == NS_MOUSE_EVENT) {
5977 0 : ignoreRootScrollFrame = static_cast<nsMouseEvent*>(aEvent)->ignoreRootScrollFrame;
5978 : }
5979 : nsIFrame* target = nsLayoutUtils::GetFrameForPoint(frame, eventPoint,
5980 0 : false, ignoreRootScrollFrame);
5981 0 : if (target) {
5982 0 : frame = target;
5983 : }
5984 : }
5985 : }
5986 :
5987 : // if a node is capturing the mouse, check if the event needs to be
5988 : // retargeted at the capturing content instead. This will be the case when
5989 : // capture retargeting is being used, no frame was found or the frame's
5990 : // content is not a descendant of the capturing content.
5991 0 : if (capturingContent &&
5992 0 : (gCaptureInfo.mRetargetToElement || !frame->GetContent() ||
5993 0 : !nsContentUtils::ContentIsCrossDocDescendantOf(frame->GetContent(),
5994 0 : capturingContent))) {
5995 : // A check was already done above to ensure that capturingContent is
5996 : // in this presshell.
5997 0 : NS_ASSERTION(capturingContent->GetCurrentDoc() == GetDocument(),
5998 : "Unexpected document");
5999 0 : nsIFrame* capturingFrame = capturingContent->GetPrimaryFrame();
6000 0 : if (capturingFrame) {
6001 0 : frame = capturingFrame;
6002 : }
6003 : }
6004 :
6005 : // Suppress mouse event if it's being targeted at an element inside
6006 : // a document which needs events suppressed
6007 0 : if (aEvent->eventStructType == NS_MOUSE_EVENT &&
6008 0 : frame->PresContext()->Document()->EventHandlingSuppressed()) {
6009 0 : if (aEvent->message == NS_MOUSE_BUTTON_DOWN) {
6010 0 : mNoDelayedMouseEvents = true;
6011 0 : } else if (!mNoDelayedMouseEvents && aEvent->message == NS_MOUSE_BUTTON_UP) {
6012 : nsDelayedEvent* event =
6013 0 : new nsDelayedMouseEvent(static_cast<nsMouseEvent*>(aEvent));
6014 0 : if (!mDelayedEvents.AppendElement(event)) {
6015 0 : delete event;
6016 : }
6017 : }
6018 :
6019 0 : return NS_OK;
6020 : }
6021 :
6022 : PresShell* shell =
6023 0 : static_cast<PresShell*>(frame->PresContext()->PresShell());
6024 :
6025 : // Check if we have an active EventStateManager which isn't the
6026 : // EventStateManager of the current PresContext.
6027 : // If that is the case, and mouse is over some ancestor document,
6028 : // forward event handling to the active document.
6029 : // This way content can get mouse events even when
6030 : // mouse is over the chrome or outside the window.
6031 : //
6032 : // Note, currently for backwards compatibility we don't forward mouse events
6033 : // to the active document when mouse is over some subdocument.
6034 : nsEventStateManager* activeESM =
6035 0 : nsEventStateManager::GetActiveEventStateManager();
6036 0 : if (activeESM && NS_IS_MOUSE_EVENT(aEvent) &&
6037 0 : activeESM != shell->GetPresContext()->EventStateManager() &&
6038 0 : static_cast<nsEventStateManager*>(activeESM)->GetPresContext()) {
6039 : nsIPresShell* activeShell =
6040 0 : static_cast<nsEventStateManager*>(activeESM)->GetPresContext()->GetPresShell();
6041 0 : if (activeShell &&
6042 0 : nsContentUtils::ContentIsCrossDocDescendantOf(activeShell->GetDocument(),
6043 0 : shell->GetDocument())) {
6044 0 : shell = static_cast<PresShell*>(activeShell);
6045 0 : frame = shell->GetRootFrame();
6046 : }
6047 : }
6048 :
6049 0 : if (shell != this) {
6050 : // Handle the event in the correct shell.
6051 : // Prevent deletion until we're done with event handling (bug 336582).
6052 0 : nsCOMPtr<nsIPresShell> kungFuDeathGrip(shell);
6053 : // We pass the subshell's root frame as the frame to start from. This is
6054 : // the only correct alternative; if the event was captured then it
6055 : // must have been captured by us or some ancestor shell and we
6056 : // now ask the subshell to dispatch it normally.
6057 0 : return shell->HandlePositionedEvent(frame, aEvent, aEventStatus);
6058 : }
6059 :
6060 0 : return HandlePositionedEvent(frame, aEvent, aEventStatus);
6061 : }
6062 :
6063 0 : nsresult rv = NS_OK;
6064 :
6065 0 : if (frame) {
6066 0 : PushCurrentEventInfo(nsnull, nsnull);
6067 :
6068 : // key and IME related events go to the focused frame in this DOM window.
6069 0 : if (NS_IsEventTargetedAtFocusedContent(aEvent)) {
6070 0 : mCurrentEventContent = nsnull;
6071 :
6072 : nsCOMPtr<nsPIDOMWindow> window =
6073 0 : do_QueryInterface(mDocument->GetWindow());
6074 0 : nsCOMPtr<nsPIDOMWindow> focusedWindow;
6075 : nsCOMPtr<nsIContent> eventTarget =
6076 : nsFocusManager::GetFocusedDescendant(window, false,
6077 0 : getter_AddRefs(focusedWindow));
6078 :
6079 : // otherwise, if there is no focused content or the focused content has
6080 : // no frame, just use the root content. This ensures that key events
6081 : // still get sent to the window properly if nothing is focused or if a
6082 : // frame goes away while it is focused.
6083 0 : if (!eventTarget || !eventTarget->GetPrimaryFrame()) {
6084 0 : nsCOMPtr<nsIDOMHTMLDocument> htmlDoc = do_QueryInterface(mDocument);
6085 0 : if (htmlDoc) {
6086 0 : nsCOMPtr<nsIDOMHTMLElement> body;
6087 0 : htmlDoc->GetBody(getter_AddRefs(body));
6088 0 : eventTarget = do_QueryInterface(body);
6089 0 : if (!eventTarget) {
6090 0 : eventTarget = mDocument->GetRootElement();
6091 : }
6092 : } else {
6093 0 : eventTarget = mDocument->GetRootElement();
6094 : }
6095 : }
6096 :
6097 0 : if (aEvent->message == NS_KEY_DOWN) {
6098 0 : NS_IF_RELEASE(gKeyDownTarget);
6099 0 : NS_IF_ADDREF(gKeyDownTarget = eventTarget);
6100 : }
6101 0 : else if ((aEvent->message == NS_KEY_PRESS || aEvent->message == NS_KEY_UP) &&
6102 : gKeyDownTarget) {
6103 : // If a different element is now focused for the keypress/keyup event
6104 : // than what was focused during the keydown event, check if the new
6105 : // focused element is not in a chrome document any more, and if so,
6106 : // retarget the event back at the keydown target. This prevents a
6107 : // content area from grabbing the focus from chrome in-between key
6108 : // events.
6109 0 : if (eventTarget &&
6110 0 : nsContentUtils::IsChromeDoc(gKeyDownTarget->GetCurrentDoc()) !=
6111 0 : nsContentUtils::IsChromeDoc(eventTarget->GetCurrentDoc())) {
6112 0 : eventTarget = gKeyDownTarget;
6113 : }
6114 :
6115 0 : if (aEvent->message == NS_KEY_UP) {
6116 0 : NS_RELEASE(gKeyDownTarget);
6117 : }
6118 : }
6119 :
6120 0 : mCurrentEventFrame = nsnull;
6121 0 : nsIDocument* targetDoc = eventTarget ? eventTarget->OwnerDoc() : nsnull;
6122 0 : if (targetDoc && targetDoc != mDocument) {
6123 0 : PopCurrentEventInfo();
6124 0 : nsCOMPtr<nsIPresShell> shell = targetDoc->GetShell();
6125 0 : if (shell) {
6126 0 : rv = static_cast<PresShell*>(shell.get())->
6127 0 : HandleRetargetedEvent(aEvent, aEventStatus, eventTarget);
6128 : }
6129 0 : return rv;
6130 : } else {
6131 0 : mCurrentEventContent = eventTarget;
6132 : }
6133 :
6134 0 : if (!mCurrentEventContent || !GetCurrentEventFrame() ||
6135 0 : InZombieDocument(mCurrentEventContent)) {
6136 0 : rv = RetargetEventToParent(aEvent, aEventStatus);
6137 0 : PopCurrentEventInfo();
6138 0 : return rv;
6139 : }
6140 : } else {
6141 0 : mCurrentEventFrame = frame;
6142 : }
6143 0 : if (GetCurrentEventFrame()) {
6144 0 : rv = HandleEventInternal(aEvent, aEventStatus);
6145 : }
6146 :
6147 : #ifdef NS_DEBUG
6148 0 : ShowEventTargetDebug();
6149 : #endif
6150 0 : PopCurrentEventInfo();
6151 : } else {
6152 : // Activation events need to be dispatched even if no frame was found, since
6153 : // we don't want the focus to be out of sync.
6154 :
6155 0 : if (!NS_EVENT_NEEDS_FRAME(aEvent)) {
6156 0 : mCurrentEventFrame = nsnull;
6157 0 : return HandleEventInternal(aEvent, aEventStatus);
6158 : }
6159 0 : else if (NS_IS_KEY_EVENT(aEvent)) {
6160 : // Keypress events in new blank tabs should not be completely thrown away.
6161 : // Retarget them -- the parent chrome shell might make use of them.
6162 0 : return RetargetEventToParent(aEvent, aEventStatus);
6163 : }
6164 : }
6165 :
6166 0 : return rv;
6167 : }
6168 :
6169 : #ifdef NS_DEBUG
6170 : void
6171 0 : PresShell::ShowEventTargetDebug()
6172 : {
6173 0 : if (nsFrame::GetShowEventTargetFrameBorder() &&
6174 0 : GetCurrentEventFrame()) {
6175 0 : if (mDrawEventTargetFrame) {
6176 : mDrawEventTargetFrame->Invalidate(
6177 0 : nsRect(nsPoint(0, 0), mDrawEventTargetFrame->GetSize()));
6178 : }
6179 :
6180 0 : mDrawEventTargetFrame = mCurrentEventFrame;
6181 : mDrawEventTargetFrame->Invalidate(
6182 0 : nsRect(nsPoint(0, 0), mDrawEventTargetFrame->GetSize()));
6183 : }
6184 0 : }
6185 : #endif
6186 :
6187 : nsresult
6188 0 : PresShell::HandlePositionedEvent(nsIFrame* aTargetFrame,
6189 : nsGUIEvent* aEvent,
6190 : nsEventStatus* aEventStatus)
6191 : {
6192 0 : nsresult rv = NS_OK;
6193 :
6194 0 : PushCurrentEventInfo(nsnull, nsnull);
6195 :
6196 0 : mCurrentEventFrame = aTargetFrame;
6197 :
6198 0 : if (mCurrentEventFrame) {
6199 0 : nsCOMPtr<nsIContent> targetElement;
6200 : mCurrentEventFrame->GetContentForEvent(aEvent,
6201 0 : getter_AddRefs(targetElement));
6202 :
6203 : // If there is no content for this frame, target it anyway. Some
6204 : // frames can be targeted but do not have content, particularly
6205 : // windows with scrolling off.
6206 0 : if (targetElement) {
6207 : // Bug 103055, bug 185889: mouse events apply to *elements*, not all
6208 : // nodes. Thus we get the nearest element parent here.
6209 : // XXX we leave the frame the same even if we find an element
6210 : // parent, so that the text frame will receive the event (selection
6211 : // and friends are the ones who care about that anyway)
6212 : //
6213 : // We use weak pointers because during this tight loop, the node
6214 : // will *not* go away. And this happens on every mousemove.
6215 0 : while (targetElement && !targetElement->IsElement()) {
6216 0 : targetElement = targetElement->GetParent();
6217 : }
6218 :
6219 : // If we found an element, target it. Otherwise, target *nothing*.
6220 0 : if (!targetElement) {
6221 0 : mCurrentEventContent = nsnull;
6222 0 : mCurrentEventFrame = nsnull;
6223 0 : } else if (targetElement != mCurrentEventContent) {
6224 0 : mCurrentEventContent = targetElement;
6225 : }
6226 : }
6227 : }
6228 :
6229 0 : if (GetCurrentEventFrame()) {
6230 0 : rv = HandleEventInternal(aEvent, aEventStatus);
6231 : }
6232 :
6233 : #ifdef NS_DEBUG
6234 0 : ShowEventTargetDebug();
6235 : #endif
6236 0 : PopCurrentEventInfo();
6237 0 : return rv;
6238 : }
6239 :
6240 : nsresult
6241 0 : PresShell::HandleEventWithTarget(nsEvent* aEvent, nsIFrame* aFrame,
6242 : nsIContent* aContent, nsEventStatus* aStatus)
6243 : {
6244 0 : PushCurrentEventInfo(aFrame, aContent);
6245 0 : nsresult rv = HandleEventInternal(aEvent, aStatus);
6246 0 : PopCurrentEventInfo();
6247 0 : return rv;
6248 : }
6249 :
6250 : static inline bool
6251 0 : IsSynthesizedMouseEvent(nsEvent* aEvent)
6252 : {
6253 : return aEvent->eventStructType == NS_MOUSE_EVENT &&
6254 0 : static_cast<nsMouseEvent*>(aEvent)->reason != nsMouseEvent::eReal;
6255 : }
6256 :
6257 0 : static bool CanHandleContextMenuEvent(nsMouseEvent* aMouseEvent,
6258 : nsIFrame* aFrame)
6259 : {
6260 : #if defined(XP_MACOSX) && defined(MOZ_XUL)
6261 : nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
6262 : if (pm) {
6263 : nsIFrame* popupFrame = pm->GetTopPopup(ePopupTypeMenu);
6264 : if (popupFrame) {
6265 : // context menus should not be opened while another menu is open on Mac,
6266 : // so return false so that the event is not fired.
6267 : if (aMouseEvent->context == nsMouseEvent::eContextMenuKey) {
6268 : return false;
6269 : } else if (aMouseEvent->widget) {
6270 : nsWindowType windowType;
6271 : aMouseEvent->widget->GetWindowType(windowType);
6272 : if (windowType == eWindowType_popup) {
6273 : for (nsIFrame* current = aFrame; current;
6274 : current = nsLayoutUtils::GetCrossDocParentFrame(current)) {
6275 : if (current->GetType() == nsGkAtoms::menuPopupFrame) {
6276 : return false;
6277 : }
6278 : }
6279 : }
6280 : }
6281 : }
6282 : }
6283 : #endif
6284 0 : return true;
6285 : }
6286 :
6287 : static bool
6288 0 : IsFullScreenAndRestrictedKeyEvent(nsIContent* aTarget, const nsEvent* aEvent)
6289 : {
6290 0 : NS_ABORT_IF_FALSE(aEvent, "Must have an event to check.");
6291 :
6292 : // Bail out if the event is not a key event, or the target's document is
6293 : // not in DOM full screen mode, or full-screen key input is not restricted.
6294 0 : nsIDocument *root = nsnull;
6295 0 : if (!aTarget ||
6296 : (aEvent->message != NS_KEY_DOWN &&
6297 : aEvent->message != NS_KEY_UP &&
6298 : aEvent->message != NS_KEY_PRESS) ||
6299 0 : !(root = nsContentUtils::GetRootDocument(aTarget->OwnerDoc())) ||
6300 0 : !root->IsFullScreenDoc() ||
6301 0 : !nsContentUtils::IsFullScreenKeyInputRestricted()) {
6302 0 : return false;
6303 : }
6304 :
6305 : // We're in full-screen mode. We whitelist key codes, and we will
6306 : // show a warning when keys not in this list are pressed.
6307 0 : const nsKeyEvent* keyEvent = static_cast<const nsKeyEvent*>(aEvent);
6308 0 : int key = keyEvent->keyCode ? keyEvent->keyCode : keyEvent->charCode;
6309 0 : switch (key) {
6310 : case NS_VK_TAB:
6311 : case NS_VK_SPACE:
6312 : case NS_VK_PAGE_UP:
6313 : case NS_VK_PAGE_DOWN:
6314 : case NS_VK_END:
6315 : case NS_VK_HOME:
6316 : case NS_VK_LEFT:
6317 : case NS_VK_UP:
6318 : case NS_VK_RIGHT:
6319 : case NS_VK_DOWN:
6320 : case NS_VK_SHIFT:
6321 : case NS_VK_CONTROL:
6322 : case NS_VK_ALT:
6323 : case NS_VK_META:
6324 : #ifdef XP_WIN
6325 : case VK_VOLUME_MUTE:
6326 : case VK_VOLUME_DOWN:
6327 : case VK_VOLUME_UP:
6328 : #endif
6329 : // Unrestricted key code.
6330 0 : return false;
6331 : default:
6332 : // Otherwise, fullscreen is enabled, key input is restricted, and the key
6333 : // code is not an allowed key code.
6334 0 : return true;
6335 : }
6336 : }
6337 :
6338 : nsresult
6339 0 : PresShell::HandleEventInternal(nsEvent* aEvent, nsEventStatus* aStatus)
6340 : {
6341 : NS_TIME_FUNCTION_MIN(1.0);
6342 :
6343 : #ifdef ACCESSIBILITY
6344 0 : if (aEvent->eventStructType == NS_ACCESSIBLE_EVENT)
6345 : {
6346 0 : nsAccessibleEvent *accEvent = static_cast<nsAccessibleEvent*>(aEvent);
6347 0 : accEvent->mAccessible = nsnull;
6348 :
6349 : nsCOMPtr<nsIAccessibilityService> accService =
6350 0 : do_GetService("@mozilla.org/accessibilityService;1");
6351 0 : if (accService) {
6352 0 : nsCOMPtr<nsISupports> container = mPresContext->GetContainer();
6353 0 : if (!container) {
6354 : // This presshell is not active. This often happens when a
6355 : // preshell is being held onto for fastback.
6356 0 : return NS_OK;
6357 : }
6358 :
6359 : // Accessible creation might be not safe so we make sure it's not created
6360 : // at unsafe times.
6361 : accEvent->mAccessible =
6362 0 : accService->GetRootDocumentAccessible(this, nsContentUtils::IsSafeToRunScript());
6363 :
6364 0 : return NS_OK;
6365 : }
6366 : }
6367 : #endif
6368 :
6369 0 : nsRefPtr<nsEventStateManager> manager = mPresContext->EventStateManager();
6370 0 : nsresult rv = NS_OK;
6371 :
6372 0 : if (!NS_EVENT_NEEDS_FRAME(aEvent) || GetCurrentEventFrame()) {
6373 : #ifdef MOZ_TOUCH
6374 : bool touchIsNew = false;
6375 : #endif
6376 0 : bool isHandlingUserInput = false;
6377 :
6378 : // XXX How about IME events and input events for plugins?
6379 0 : if (NS_IS_TRUSTED_EVENT(aEvent)) {
6380 0 : switch (aEvent->message) {
6381 : case NS_KEY_PRESS:
6382 : case NS_KEY_DOWN:
6383 : case NS_KEY_UP: {
6384 : nsIDocument *doc = mCurrentEventContent ?
6385 0 : mCurrentEventContent->OwnerDoc() : nsnull;
6386 0 : nsIDocument* root = nsnull;
6387 0 : if (static_cast<const nsKeyEvent*>(aEvent)->keyCode == NS_VK_ESCAPE &&
6388 : (root = nsContentUtils::GetRootDocument(doc)) &&
6389 0 : root->IsFullScreenDoc()) {
6390 : // Prevent default action on ESC key press when exiting
6391 : // DOM full-screen mode. This prevents the browser ESC key
6392 : // handler from stopping all loads in the document, which
6393 : // would cause <video> loads to stop.
6394 : aEvent->flags |= (NS_EVENT_FLAG_NO_DEFAULT |
6395 0 : NS_EVENT_FLAG_ONLY_CHROME_DISPATCH);
6396 :
6397 0 : if (aEvent->message == NS_KEY_UP) {
6398 : // ESC key released while in DOM full-screen mode.
6399 : // Exit full-screen mode.
6400 0 : nsIDocument::ExitFullScreen(true);
6401 : }
6402 0 : } else if (IsFullScreenAndRestrictedKeyEvent(mCurrentEventContent, aEvent)) {
6403 : // Restricted key press while in DOM full-screen mode. Dispatch
6404 : // an event to chrome so it knows to show a warning message
6405 : // informing the user how to exit full-screen.
6406 : nsRefPtr<nsAsyncDOMEvent> e =
6407 0 : new nsAsyncDOMEvent(doc, NS_LITERAL_STRING("MozShowFullScreenWarning"),
6408 0 : true, true);
6409 0 : e->PostDOMEvent();
6410 : }
6411 : // Else not full-screen mode or key code is unrestricted, fall
6412 : // through to normal handling.
6413 : }
6414 : case NS_MOUSE_BUTTON_DOWN:
6415 : case NS_MOUSE_BUTTON_UP:
6416 0 : isHandlingUserInput = true;
6417 0 : break;
6418 : #ifdef MOZ_TOUCH
6419 : case NS_TOUCH_CANCEL:
6420 : case NS_TOUCH_END: {
6421 : // Remove the changed touches
6422 : // need to make sure we only remove touches that are ending here
6423 : nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(aEvent);
6424 : nsTArray<nsCOMPtr<nsIDOMTouch> > &touches = touchEvent->touches;
6425 : for (PRUint32 i = 0; i < touches.Length(); ++i) {
6426 : nsIDOMTouch *touch = touches[i];
6427 : nsDOMTouch *domtouch = static_cast<nsDOMTouch*>(touch);
6428 : if (!touch) {
6429 : continue;
6430 : }
6431 : touch->mMessage = aEvent->message;
6432 : touch->mChanged = true;
6433 : nsCOMPtr<nsIDOMTouch> oldTouch;
6434 :
6435 : PRInt32 id;
6436 : touch->GetIdentifier(&id);
6437 :
6438 : gCaptureTouchList.Get(id, getter_AddRefs(oldTouch));
6439 : if (!oldTouch) {
6440 : continue;
6441 : }
6442 : nsCOMPtr<nsPIDOMEventTarget> targetPtr;
6443 : oldTouch->GetTarget(getter_AddRefs(targetPtr));
6444 :
6445 : mCurrentEventContent = do_QueryInterface(targetPtr);
6446 : domtouch->SetTarget(targetPtr);
6447 : gCaptureTouchList.Remove(id);
6448 : }
6449 : // add any touches left in the touch list, but ensure changed=false
6450 : gCaptureTouchList.Enumerate(&AppendToTouchList, (void *)&touches);
6451 : break;
6452 : }
6453 : case NS_TOUCH_MOVE: {
6454 : // Check for touches that changed. Mark them add to queue
6455 : nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(aEvent);
6456 : nsTArray<nsCOMPtr<nsIDOMTouch> > touches = touchEvent->touches;
6457 : bool haveChanged = false;
6458 : for (PRUint32 i = 0; i < touches.Length(); ++i) {
6459 : nsIDOMTouch *touch = touches[i];
6460 : nsDOMTouch *domtouch = static_cast<nsDOMTouch*>(touch);
6461 : if (!touch) {
6462 : continue;
6463 : }
6464 : PRInt32 id;
6465 : touch->GetIdentifier(&id);
6466 : touch->mMessage = aEvent->message;
6467 :
6468 : nsCOMPtr<nsIDOMTouch> oldTouch;
6469 : gCaptureTouchList.Get(id, getter_AddRefs(oldTouch));
6470 : if (!oldTouch) {
6471 : continue;
6472 : }
6473 : if(domtouch->Equals(oldTouch)) {
6474 : touch->mChanged = true;
6475 : haveChanged = true;
6476 : }
6477 :
6478 : nsCOMPtr<nsPIDOMEventTarget> targetPtr;
6479 : oldTouch->GetTarget(getter_AddRefs(targetPtr));
6480 : domtouch->SetTarget(targetPtr);
6481 :
6482 : gCaptureTouchList.Put(id, touch);
6483 : // if we're moving from touchstart to touchmove for this touch
6484 : // we allow preventDefault to prevent mouse events
6485 : if (oldTouch->mMessage != touch->mMessage) {
6486 : touchIsNew = true;
6487 : }
6488 : }
6489 : // is nothing has changed, we should just return
6490 : if (!haveChanged) {
6491 : if (gPreventMouseEvents) {
6492 : *aStatus = nsEventStatus_eConsumeNoDefault;
6493 : }
6494 : return NS_OK;
6495 : }
6496 : break;
6497 : }
6498 : #endif
6499 : case NS_DRAGDROP_DROP:
6500 0 : nsCOMPtr<nsIDragSession> session = nsContentUtils::GetDragSession();
6501 0 : if (session) {
6502 0 : bool onlyChromeDrop = false;
6503 0 : session->GetOnlyChromeDrop(&onlyChromeDrop);
6504 0 : if (onlyChromeDrop) {
6505 0 : aEvent->flags |= NS_EVENT_FLAG_ONLY_CHROME_DISPATCH;
6506 : }
6507 : }
6508 : break;
6509 : }
6510 : }
6511 :
6512 0 : if (aEvent->message == NS_CONTEXTMENU) {
6513 0 : nsMouseEvent* me = static_cast<nsMouseEvent*>(aEvent);
6514 0 : if (!CanHandleContextMenuEvent(me, GetCurrentEventFrame())) {
6515 0 : return NS_OK;
6516 : }
6517 0 : if (me->context == nsMouseEvent::eContextMenuKey &&
6518 0 : !AdjustContextMenuKeyEvent(me)) {
6519 0 : return NS_OK;
6520 : }
6521 0 : if (me->isShift)
6522 : aEvent->flags |= NS_EVENT_FLAG_ONLY_CHROME_DISPATCH |
6523 0 : NS_EVENT_RETARGET_TO_NON_NATIVE_ANONYMOUS;
6524 : }
6525 :
6526 : nsAutoHandlingUserInputStatePusher userInpStatePusher(isHandlingUserInput,
6527 0 : aEvent, mDocument);
6528 :
6529 0 : if (NS_IS_TRUSTED_EVENT(aEvent) && aEvent->message == NS_MOUSE_MOVE) {
6530 : nsIPresShell::AllowMouseCapture(
6531 0 : nsEventStateManager::GetActiveEventStateManager() == manager);
6532 : }
6533 :
6534 0 : nsAutoPopupStatePusher popupStatePusher(nsDOMEvent::GetEventPopupControlState(aEvent));
6535 :
6536 : // FIXME. If the event was reused, we need to clear the old target,
6537 : // bug 329430
6538 0 : aEvent->target = nsnull;
6539 :
6540 : // 1. Give event to event manager for pre event state changes and
6541 : // generation of synthetic events.
6542 0 : rv = manager->PreHandleEvent(mPresContext, aEvent, mCurrentEventFrame, aStatus);
6543 :
6544 : // 2. Give event to the DOM for third party and JS use.
6545 0 : if (GetCurrentEventFrame() && NS_SUCCEEDED(rv)) {
6546 : bool wasHandlingKeyBoardEvent =
6547 0 : nsContentUtils::IsHandlingKeyBoardEvent();
6548 0 : if (aEvent->eventStructType == NS_KEY_EVENT) {
6549 0 : nsContentUtils::SetIsHandlingKeyBoardEvent(true);
6550 : }
6551 : // We want synthesized mouse moves to cause mouseover and mouseout
6552 : // DOM events (PreHandleEvent above), but not mousemove DOM events.
6553 : // Synthesized button up events also do not cause DOM events
6554 : // because they do not have a reliable refPoint.
6555 0 : if (!IsSynthesizedMouseEvent(aEvent)) {
6556 0 : nsPresShellEventCB eventCB(this);
6557 : #ifdef MOZ_TOUCH
6558 : if (aEvent->eventStructType == NS_TOUCH_EVENT) {
6559 : DispatchTouchEvent(aEvent, aStatus, &eventCB, touchIsNew);
6560 : }
6561 : else if (mCurrentEventContent) {
6562 : #else
6563 0 : if (mCurrentEventContent) {
6564 : #endif
6565 : nsEventDispatcher::Dispatch(mCurrentEventContent, mPresContext,
6566 0 : aEvent, nsnull, aStatus, &eventCB);
6567 : }
6568 : else {
6569 0 : nsCOMPtr<nsIContent> targetContent;
6570 : rv = mCurrentEventFrame->GetContentForEvent(aEvent,
6571 0 : getter_AddRefs(targetContent));
6572 0 : if (NS_SUCCEEDED(rv) && targetContent) {
6573 : nsEventDispatcher::Dispatch(targetContent, mPresContext, aEvent,
6574 0 : nsnull, aStatus, &eventCB);
6575 0 : } else if (mDocument) {
6576 : nsEventDispatcher::Dispatch(mDocument, mPresContext, aEvent,
6577 0 : nsnull, aStatus, nsnull);
6578 : }
6579 : }
6580 : }
6581 :
6582 0 : nsContentUtils::SetIsHandlingKeyBoardEvent(wasHandlingKeyBoardEvent);
6583 :
6584 : // 3. Give event to event manager for post event state changes and
6585 : // generation of synthetic events.
6586 0 : if (!mIsDestroying && NS_SUCCEEDED(rv)) {
6587 : rv = manager->PostHandleEvent(mPresContext, aEvent,
6588 0 : GetCurrentEventFrame(), aStatus);
6589 : }
6590 : }
6591 :
6592 0 : if (aEvent->message == NS_MOUSE_BUTTON_UP) {
6593 : // reset the capturing content now that the mouse button is up
6594 0 : SetCapturingContent(nsnull, 0);
6595 0 : } else if (aEvent->message == NS_MOUSE_MOVE) {
6596 0 : nsIPresShell::AllowMouseCapture(false);
6597 : }
6598 : }
6599 0 : return rv;
6600 : }
6601 :
6602 : void
6603 0 : PresShell::DispatchTouchEvent(nsEvent *aEvent,
6604 : nsEventStatus* aStatus,
6605 : nsPresShellEventCB* aEventCB,
6606 : bool aTouchIsNew)
6607 : {
6608 0 : nsresult rv = NS_OK;
6609 : // calling preventDefault on touchstart or the first touchmove for a
6610 : // point prevents mouse events
6611 : bool canPrevent = aEvent->message == NS_TOUCH_START ||
6612 0 : (aEvent->message == NS_TOUCH_MOVE && aTouchIsNew);
6613 0 : bool preventDefault = false;
6614 0 : nsEventStatus tmpStatus = nsEventStatus_eIgnore;
6615 0 : nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(aEvent);
6616 : // touch events should fire on all targets
6617 0 : if (aEvent->message != NS_TOUCH_START) {
6618 0 : nsTArray<nsCOMPtr<nsIDOMTouch> > touches = touchEvent->touches;
6619 0 : for (PRUint32 i = 0; i < touches.Length(); ++i) {
6620 0 : nsIDOMTouch *touch = touches[i];
6621 0 : if (!touch || !touch->mChanged) {
6622 0 : continue;
6623 : }
6624 : // copy the event
6625 0 : nsCOMPtr<nsPIDOMEventTarget> targetPtr;
6626 0 : touch->GetTarget(getter_AddRefs(targetPtr));
6627 0 : if (!targetPtr) {
6628 0 : continue;
6629 : }
6630 :
6631 0 : nsTouchEvent newEvent(touchEvent);
6632 0 : newEvent.target = targetPtr;
6633 :
6634 0 : nsCOMPtr<nsIContent> content(do_QueryInterface(targetPtr));
6635 0 : nsPresContext *context = nsContentUtils::GetContextForContent(content);
6636 0 : if (!context) {
6637 0 : context = mPresContext;
6638 : }
6639 0 : tmpStatus = nsEventStatus_eIgnore;
6640 : nsEventDispatcher::Dispatch(targetPtr, context,
6641 0 : &newEvent, nsnull, &tmpStatus, aEventCB);
6642 0 : if (nsEventStatus_eConsumeNoDefault == tmpStatus) {
6643 0 : preventDefault = true;
6644 : }
6645 : }
6646 : } else {
6647 : // touchevents need to have the target attribute set on each touch
6648 0 : nsTArray<nsCOMPtr<nsIDOMTouch> > touches = touchEvent->touches;
6649 0 : for (PRUint32 i = 0; i < touches.Length(); ++i) {
6650 0 : nsIDOMTouch *touch = touches[i];
6651 0 : if (touch->mChanged) {
6652 0 : touch->SetTarget(mCurrentEventContent);
6653 : }
6654 : }
6655 :
6656 0 : if (mCurrentEventContent) {
6657 : nsEventDispatcher::Dispatch(mCurrentEventContent, mPresContext,
6658 0 : aEvent, nsnull, &tmpStatus, aEventCB);
6659 : } else {
6660 0 : nsCOMPtr<nsIContent> targetContent;
6661 : rv = mCurrentEventFrame->GetContentForEvent(aEvent,
6662 0 : getter_AddRefs(targetContent));
6663 0 : if (NS_SUCCEEDED(rv) && targetContent) {
6664 : nsEventDispatcher::Dispatch(targetContent, mPresContext, aEvent,
6665 0 : nsnull, &tmpStatus, aEventCB);
6666 0 : } else if (mDocument) {
6667 : nsEventDispatcher::Dispatch(mDocument, mPresContext, aEvent,
6668 0 : nsnull, &tmpStatus, nsnull);
6669 : }
6670 : }
6671 0 : if (nsEventStatus_eConsumeNoDefault == tmpStatus) {
6672 0 : preventDefault = true;
6673 : }
6674 :
6675 0 : if (touchEvent->touches.Length() == 1) {
6676 0 : gPreventMouseEvents = false;
6677 : }
6678 : }
6679 :
6680 : // if preventDefault was called on any of the events dispatched
6681 : // and this is touchstart, or the first touchmove, widget should consume
6682 : // other events that would be associated with this touch session
6683 0 : if (preventDefault && canPrevent) {
6684 0 : gPreventMouseEvents = true;
6685 : }
6686 :
6687 0 : if (gPreventMouseEvents) {
6688 0 : *aStatus = nsEventStatus_eConsumeNoDefault;
6689 : } else {
6690 0 : *aStatus = nsEventStatus_eIgnore;
6691 : }
6692 0 : }
6693 :
6694 : // Dispatch event to content only (NOT full processing)
6695 : // See also HandleEventWithTarget which does full event processing.
6696 : nsresult
6697 0 : PresShell::HandleDOMEventWithTarget(nsIContent* aTargetContent, nsEvent* aEvent,
6698 : nsEventStatus* aStatus)
6699 : {
6700 0 : nsresult rv = NS_OK;
6701 :
6702 0 : PushCurrentEventInfo(nsnull, aTargetContent);
6703 :
6704 : // Bug 41013: Check if the event should be dispatched to content.
6705 : // It's possible that we are in the middle of destroying the window
6706 : // and the js context is out of date. This check detects the case
6707 : // that caused a crash in bug 41013, but there may be a better way
6708 : // to handle this situation!
6709 0 : nsCOMPtr<nsISupports> container = mPresContext->GetContainer();
6710 0 : if (container) {
6711 :
6712 : // Dispatch event to content
6713 : rv = nsEventDispatcher::Dispatch(aTargetContent, mPresContext, aEvent, nsnull,
6714 0 : aStatus);
6715 : }
6716 :
6717 0 : PopCurrentEventInfo();
6718 0 : return rv;
6719 : }
6720 :
6721 : // See the method above.
6722 : nsresult
6723 0 : PresShell::HandleDOMEventWithTarget(nsIContent* aTargetContent,
6724 : nsIDOMEvent* aEvent,
6725 : nsEventStatus* aStatus)
6726 : {
6727 0 : nsresult rv = NS_OK;
6728 :
6729 0 : PushCurrentEventInfo(nsnull, aTargetContent);
6730 0 : nsCOMPtr<nsISupports> container = mPresContext->GetContainer();
6731 0 : if (container) {
6732 : rv = nsEventDispatcher::DispatchDOMEvent(aTargetContent, nsnull, aEvent,
6733 0 : mPresContext, aStatus);
6734 : }
6735 :
6736 0 : PopCurrentEventInfo();
6737 0 : return rv;
6738 : }
6739 :
6740 : bool
6741 0 : PresShell::AdjustContextMenuKeyEvent(nsMouseEvent* aEvent)
6742 : {
6743 : #ifdef MOZ_XUL
6744 : // if a menu is open, open the context menu relative to the active item on the menu.
6745 0 : nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
6746 0 : if (pm) {
6747 0 : nsIFrame* popupFrame = pm->GetTopPopup(ePopupTypeMenu);
6748 0 : if (popupFrame) {
6749 : nsIFrame* itemFrame =
6750 0 : (static_cast<nsMenuPopupFrame *>(popupFrame))->GetCurrentMenuItem();
6751 0 : if (!itemFrame)
6752 0 : itemFrame = popupFrame;
6753 :
6754 0 : nsCOMPtr<nsIWidget> widget = popupFrame->GetNearestWidget();
6755 0 : aEvent->widget = widget;
6756 0 : nsIntPoint widgetPoint = widget->WidgetToScreenOffset();
6757 0 : aEvent->refPoint = itemFrame->GetScreenRect().BottomLeft() - widgetPoint;
6758 :
6759 0 : mCurrentEventContent = itemFrame->GetContent();
6760 0 : mCurrentEventFrame = itemFrame;
6761 :
6762 0 : return true;
6763 : }
6764 : }
6765 : #endif
6766 :
6767 : // If we're here because of the key-equiv for showing context menus, we
6768 : // have to twiddle with the NS event to make sure the context menu comes
6769 : // up in the upper left of the relevant content area before we create
6770 : // the DOM event. Since we never call InitMouseEvent() on the event,
6771 : // the client X/Y will be 0,0. We can make use of that if the widget is null.
6772 : // Use the root view manager's widget since it's most likely to have one,
6773 : // and the coordinates returned by GetCurrentItemAndPositionForElement
6774 : // are relative to the widget of the root of the root view manager.
6775 0 : nsRootPresContext* rootPC = mPresContext->GetRootPresContext();
6776 0 : aEvent->refPoint.x = 0;
6777 0 : aEvent->refPoint.y = 0;
6778 0 : if (rootPC) {
6779 0 : rootPC->PresShell()->GetViewManager()->
6780 0 : GetRootWidget(getter_AddRefs(aEvent->widget));
6781 :
6782 0 : if (aEvent->widget) {
6783 : // default the refpoint to the topleft of our document
6784 0 : nsPoint offset(0, 0);
6785 0 : nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
6786 0 : if (rootFrame) {
6787 0 : nsIView* view = rootFrame->GetClosestView(&offset);
6788 0 : offset += view->GetOffsetToWidget(aEvent->widget);
6789 : aEvent->refPoint =
6790 0 : offset.ToNearestPixels(mPresContext->AppUnitsPerDevPixel());
6791 : }
6792 : }
6793 : } else {
6794 0 : aEvent->widget = nsnull;
6795 : }
6796 :
6797 : // see if we should use the caret position for the popup
6798 0 : nsIntPoint caretPoint;
6799 : // Beware! This may flush notifications via synchronous
6800 : // ScrollSelectionIntoView.
6801 0 : if (PrepareToUseCaretPosition(aEvent->widget, caretPoint)) {
6802 : // caret position is good
6803 0 : aEvent->refPoint = caretPoint;
6804 0 : return true;
6805 : }
6806 :
6807 : // If we're here because of the key-equiv for showing context menus, we
6808 : // have to reset the event target to the currently focused element. Get it
6809 : // from the focus controller.
6810 0 : nsCOMPtr<nsIDOMElement> currentFocus;
6811 0 : nsIFocusManager* fm = nsFocusManager::GetFocusManager();
6812 0 : if (fm)
6813 0 : fm->GetFocusedElement(getter_AddRefs(currentFocus));
6814 :
6815 : // Reset event coordinates relative to focused frame in view
6816 0 : if (currentFocus) {
6817 0 : nsCOMPtr<nsIContent> currentPointElement;
6818 : GetCurrentItemAndPositionForElement(currentFocus,
6819 0 : getter_AddRefs(currentPointElement),
6820 : aEvent->refPoint,
6821 0 : aEvent->widget);
6822 0 : if (currentPointElement) {
6823 0 : mCurrentEventContent = currentPointElement;
6824 0 : mCurrentEventFrame = nsnull;
6825 0 : GetCurrentEventFrame();
6826 : }
6827 : }
6828 :
6829 0 : return true;
6830 : }
6831 :
6832 : // PresShell::PrepareToUseCaretPosition
6833 : //
6834 : // This checks to see if we should use the caret position for popup context
6835 : // menus. Returns true if the caret position should be used, and the
6836 : // coordinates of that position is returned in aTargetPt. This function
6837 : // will also scroll the window as needed to make the caret visible.
6838 : //
6839 : // The event widget should be the widget that generated the event, and
6840 : // whose coordinate system the resulting event's refPoint should be
6841 : // relative to. The returned point is in device pixels realtive to the
6842 : // widget passed in.
6843 : bool
6844 0 : PresShell::PrepareToUseCaretPosition(nsIWidget* aEventWidget, nsIntPoint& aTargetPt)
6845 : {
6846 : nsresult rv;
6847 :
6848 : // check caret visibility
6849 0 : nsRefPtr<nsCaret> caret = GetCaret();
6850 0 : NS_ENSURE_TRUE(caret, false);
6851 :
6852 0 : bool caretVisible = false;
6853 0 : rv = caret->GetCaretVisible(&caretVisible);
6854 0 : if (NS_FAILED(rv) || ! caretVisible)
6855 0 : return false;
6856 :
6857 : // caret selection, this is a temporary weak reference, so no refcounting is
6858 : // needed
6859 0 : nsISelection* domSelection = caret->GetCaretDOMSelection();
6860 0 : NS_ENSURE_TRUE(domSelection, false);
6861 :
6862 : // since the match could be an anonymous textnode inside a
6863 : // <textarea> or text <input>, we need to get the outer frame
6864 : // note: frames are not refcounted
6865 0 : nsIFrame* frame = nsnull; // may be NULL
6866 0 : nsCOMPtr<nsIDOMNode> node;
6867 0 : rv = domSelection->GetFocusNode(getter_AddRefs(node));
6868 0 : NS_ENSURE_SUCCESS(rv, false);
6869 0 : NS_ENSURE_TRUE(node, false);
6870 0 : nsCOMPtr<nsIContent> content(do_QueryInterface(node));
6871 0 : if (content) {
6872 0 : nsIContent* nonNative = content->FindFirstNonNativeAnonymous();
6873 0 : content = nonNative;
6874 : }
6875 :
6876 0 : if (content) {
6877 : // It seems like ScrollSelectionIntoView should be enough, but it's
6878 : // not. The problem is that scrolling the selection into view when it is
6879 : // below the current viewport will align the top line of the frame exactly
6880 : // with the bottom of the window. This is fine, BUT, the popup event causes
6881 : // the control to be re-focused which does this exact call to
6882 : // ScrollContentIntoView, which has a one-pixel disagreement of whether the
6883 : // frame is actually in view. The result is that the frame is aligned with
6884 : // the top of the window, but the menu is still at the bottom.
6885 : //
6886 : // Doing this call first forces the frame to be in view, eliminating the
6887 : // problem. The only difference in the result is that if your cursor is in
6888 : // an edit box below the current view, you'll get the edit box aligned with
6889 : // the top of the window. This is arguably better behavior anyway.
6890 : rv = ScrollContentIntoView(content, NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE,
6891 : NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE,
6892 0 : SCROLL_OVERFLOW_HIDDEN);
6893 0 : NS_ENSURE_SUCCESS(rv, false);
6894 0 : frame = content->GetPrimaryFrame();
6895 0 : NS_WARN_IF_FALSE(frame, "No frame for focused content?");
6896 : }
6897 :
6898 : // Actually scroll the selection (ie caret) into view. Note that this must
6899 : // be synchronous since we will be checking the caret position on the screen.
6900 : //
6901 : // Be easy about errors, and just don't scroll in those cases. Better to have
6902 : // the correct menu at a weird place than the wrong menu.
6903 : // After ScrollSelectionIntoView(), the pending notifications might be
6904 : // flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
6905 0 : nsCOMPtr<nsISelectionController> selCon;
6906 0 : if (frame)
6907 0 : frame->GetSelectionController(GetPresContext(), getter_AddRefs(selCon));
6908 : else
6909 0 : selCon = static_cast<nsISelectionController *>(this);
6910 0 : if (selCon) {
6911 0 : rv = selCon->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL,
6912 : nsISelectionController::SELECTION_FOCUS_REGION,
6913 0 : nsISelectionController::SCROLL_SYNCHRONOUS);
6914 0 : NS_ENSURE_SUCCESS(rv, false);
6915 : }
6916 :
6917 0 : nsPresContext* presContext = GetPresContext();
6918 :
6919 : // get caret position relative to the closest view
6920 0 : nsRect caretCoords;
6921 0 : nsIFrame* caretFrame = caret->GetGeometry(domSelection, &caretCoords);
6922 0 : if (!caretFrame)
6923 0 : return false;
6924 0 : nsPoint viewOffset;
6925 0 : nsIView* view = caretFrame->GetClosestView(&viewOffset);
6926 0 : if (!view)
6927 0 : return false;
6928 : // and then get the caret coords relative to the event widget
6929 0 : if (aEventWidget) {
6930 0 : viewOffset += view->GetOffsetToWidget(aEventWidget);
6931 : }
6932 0 : caretCoords.MoveBy(viewOffset);
6933 :
6934 : // caret coordinates are in app units, convert to pixels
6935 : aTargetPt.x =
6936 0 : presContext->AppUnitsToDevPixels(caretCoords.x + caretCoords.width);
6937 : aTargetPt.y =
6938 0 : presContext->AppUnitsToDevPixels(caretCoords.y + caretCoords.height);
6939 :
6940 : // make sure rounding doesn't return a pixel which is outside the caret
6941 : // (e.g. one line lower)
6942 0 : aTargetPt.y -= 1;
6943 :
6944 0 : return true;
6945 : }
6946 :
6947 : void
6948 0 : PresShell::GetCurrentItemAndPositionForElement(nsIDOMElement *aCurrentEl,
6949 : nsIContent** aTargetToUse,
6950 : nsIntPoint& aTargetPt,
6951 : nsIWidget *aRootWidget)
6952 : {
6953 0 : nsCOMPtr<nsIContent> focusedContent(do_QueryInterface(aCurrentEl));
6954 : ScrollContentIntoView(focusedContent, NS_PRESSHELL_SCROLL_ANYWHERE,
6955 : NS_PRESSHELL_SCROLL_ANYWHERE,
6956 0 : SCROLL_OVERFLOW_HIDDEN);
6957 :
6958 0 : nsPresContext* presContext = GetPresContext();
6959 :
6960 0 : bool istree = false, checkLineHeight = true;
6961 0 : nscoord extraTreeY = 0;
6962 :
6963 : #ifdef MOZ_XUL
6964 : // Set the position to just underneath the current item for multi-select
6965 : // lists or just underneath the selected item for single-select lists. If
6966 : // the element is not a list, or there is no selection, leave the position
6967 : // as is.
6968 0 : nsCOMPtr<nsIDOMXULSelectControlItemElement> item;
6969 : nsCOMPtr<nsIDOMXULMultiSelectControlElement> multiSelect =
6970 0 : do_QueryInterface(aCurrentEl);
6971 0 : if (multiSelect) {
6972 0 : checkLineHeight = false;
6973 :
6974 : PRInt32 currentIndex;
6975 0 : multiSelect->GetCurrentIndex(¤tIndex);
6976 0 : if (currentIndex >= 0) {
6977 0 : nsCOMPtr<nsIDOMXULElement> xulElement(do_QueryInterface(aCurrentEl));
6978 0 : if (xulElement) {
6979 0 : nsCOMPtr<nsIBoxObject> box;
6980 0 : xulElement->GetBoxObject(getter_AddRefs(box));
6981 0 : nsCOMPtr<nsITreeBoxObject> treeBox(do_QueryInterface(box));
6982 : // Tree view special case (tree items have no frames)
6983 : // Get the focused row and add its coordinates, which are already in pixels
6984 : // XXX Boris, should we create a new interface so that this doesn't
6985 : // need to know about trees? Something like nsINodelessChildCreator which
6986 : // could provide the current focus coordinates?
6987 0 : if (treeBox) {
6988 0 : treeBox->EnsureRowIsVisible(currentIndex);
6989 : PRInt32 firstVisibleRow, rowHeight;
6990 0 : treeBox->GetFirstVisibleRow(&firstVisibleRow);
6991 0 : treeBox->GetRowHeight(&rowHeight);
6992 :
6993 : extraTreeY += presContext->CSSPixelsToAppUnits(
6994 0 : (currentIndex - firstVisibleRow + 1) * rowHeight);
6995 0 : istree = true;
6996 :
6997 0 : nsCOMPtr<nsITreeColumns> cols;
6998 0 : treeBox->GetColumns(getter_AddRefs(cols));
6999 0 : if (cols) {
7000 0 : nsCOMPtr<nsITreeColumn> col;
7001 0 : cols->GetFirstColumn(getter_AddRefs(col));
7002 0 : if (col) {
7003 0 : nsCOMPtr<nsIDOMElement> colElement;
7004 0 : col->GetElement(getter_AddRefs(colElement));
7005 0 : nsCOMPtr<nsIContent> colContent(do_QueryInterface(colElement));
7006 0 : if (colContent) {
7007 0 : nsIFrame* frame = colContent->GetPrimaryFrame();
7008 0 : if (frame) {
7009 0 : extraTreeY += frame->GetSize().height;
7010 : }
7011 : }
7012 : }
7013 : }
7014 : }
7015 : else {
7016 0 : multiSelect->GetCurrentItem(getter_AddRefs(item));
7017 : }
7018 : }
7019 : }
7020 : }
7021 : else {
7022 : // don't check menulists as the selected item will be inside a popup.
7023 0 : nsCOMPtr<nsIDOMXULMenuListElement> menulist = do_QueryInterface(aCurrentEl);
7024 0 : if (!menulist) {
7025 : nsCOMPtr<nsIDOMXULSelectControlElement> select =
7026 0 : do_QueryInterface(aCurrentEl);
7027 0 : if (select) {
7028 0 : checkLineHeight = false;
7029 0 : select->GetSelectedItem(getter_AddRefs(item));
7030 : }
7031 : }
7032 : }
7033 :
7034 0 : if (item)
7035 0 : focusedContent = do_QueryInterface(item);
7036 : #endif
7037 :
7038 0 : nsIFrame *frame = focusedContent->GetPrimaryFrame();
7039 0 : if (frame) {
7040 0 : NS_ASSERTION(frame->PresContext() == GetPresContext(),
7041 : "handling event for focused content that is not in our document?");
7042 :
7043 0 : nsPoint frameOrigin(0, 0);
7044 :
7045 : // Get the frame's origin within its view
7046 0 : nsIView *view = frame->GetClosestView(&frameOrigin);
7047 0 : NS_ASSERTION(view, "No view for frame");
7048 :
7049 : // View's origin relative the widget
7050 0 : if (aRootWidget) {
7051 0 : frameOrigin += view->GetOffsetToWidget(aRootWidget);
7052 : }
7053 :
7054 : // Start context menu down and to the right from top left of frame
7055 : // use the lineheight. This is a good distance to move the context
7056 : // menu away from the top left corner of the frame. If we always
7057 : // used the frame height, the context menu could end up far away,
7058 : // for example when we're focused on linked images.
7059 : // On the other hand, we want to use the frame height if it's less
7060 : // than the current line height, so that the context menu appears
7061 : // associated with the correct frame.
7062 0 : nscoord extra = 0;
7063 0 : if (!istree) {
7064 0 : extra = frame->GetSize().height;
7065 0 : if (checkLineHeight) {
7066 : nsIScrollableFrame *scrollFrame =
7067 0 : nsLayoutUtils::GetNearestScrollableFrame(frame);
7068 0 : if (scrollFrame) {
7069 0 : nsSize scrollAmount = scrollFrame->GetLineScrollAmount();
7070 0 : nsIFrame* f = do_QueryFrame(scrollFrame);
7071 0 : PRInt32 APD = presContext->AppUnitsPerDevPixel();
7072 0 : PRInt32 scrollAPD = f->PresContext()->AppUnitsPerDevPixel();
7073 0 : scrollAmount = scrollAmount.ConvertAppUnits(scrollAPD, APD);
7074 0 : if (extra > scrollAmount.height) {
7075 0 : extra = scrollAmount.height;
7076 : }
7077 : }
7078 : }
7079 : }
7080 :
7081 0 : aTargetPt.x = presContext->AppUnitsToDevPixels(frameOrigin.x);
7082 : aTargetPt.y = presContext->AppUnitsToDevPixels(
7083 0 : frameOrigin.y + extra + extraTreeY);
7084 : }
7085 :
7086 0 : NS_IF_ADDREF(*aTargetToUse = focusedContent);
7087 0 : }
7088 :
7089 : bool
7090 0 : PresShell::ShouldIgnoreInvalidation()
7091 : {
7092 0 : return mPaintingSuppressed || !mIsActive;
7093 : }
7094 :
7095 : void
7096 0 : PresShell::WillPaint(bool aWillSendDidPaint)
7097 : {
7098 : // Don't bother doing anything if some viewmanager in our tree is painting
7099 : // while we still have painting suppressed or we are not active.
7100 0 : if (mPaintingSuppressed || !mIsActive || !IsVisible()) {
7101 0 : return;
7102 : }
7103 :
7104 0 : nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext();
7105 0 : if (!rootPresContext) {
7106 0 : return;
7107 : }
7108 :
7109 0 : if (!aWillSendDidPaint && rootPresContext == mPresContext) {
7110 0 : rootPresContext->UpdatePluginGeometry();
7111 : }
7112 0 : rootPresContext->FlushWillPaintObservers();
7113 0 : if (mIsDestroying)
7114 0 : return;
7115 :
7116 : // Process reflows, if we have them, to reduce flicker due to invalidates and
7117 : // reflow being interspersed. Note that we _do_ allow this to be
7118 : // interruptible; if we can't do all the reflows it's better to flicker a bit
7119 : // than to freeze up.
7120 0 : FlushPendingNotifications(Flush_InterruptibleLayout);
7121 : }
7122 :
7123 : void
7124 0 : PresShell::DidPaint()
7125 : {
7126 0 : if (mPaintingSuppressed || !mIsActive || !IsVisible()) {
7127 0 : return;
7128 : }
7129 :
7130 0 : NS_ASSERTION(mPresContext->IsRoot(), "Should only call DidPaint on root presshells");
7131 :
7132 0 : nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext();
7133 : // This should only be called on root presshells, but maybe if a document
7134 : // tree is torn down we might not be a root presshell...
7135 0 : if (rootPresContext == mPresContext) {
7136 0 : rootPresContext->UpdatePluginGeometry();
7137 : }
7138 :
7139 0 : if (nsContentUtils::XPConnect()) {
7140 0 : nsContentUtils::XPConnect()->NotifyDidPaint();
7141 : }
7142 : }
7143 :
7144 : bool
7145 0 : PresShell::IsVisible()
7146 : {
7147 0 : if (!mViewManager)
7148 0 : return false;
7149 :
7150 0 : nsIView* view = mViewManager->GetRootView();
7151 0 : if (!view)
7152 0 : return true;
7153 :
7154 : // inner view of subdoc frame
7155 0 : view = view->GetParent();
7156 0 : if (!view)
7157 0 : return true;
7158 :
7159 : // subdoc view
7160 0 : view = view->GetParent();
7161 0 : if (!view)
7162 0 : return true;
7163 :
7164 0 : nsIFrame* frame = view->GetFrame();
7165 0 : if (!frame)
7166 0 : return true;
7167 :
7168 0 : return frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY);
7169 : }
7170 :
7171 : nsresult
7172 0 : PresShell::GetAgentStyleSheets(nsCOMArray<nsIStyleSheet>& aSheets)
7173 : {
7174 0 : aSheets.Clear();
7175 0 : PRInt32 sheetCount = mStyleSet->SheetCount(nsStyleSet::eAgentSheet);
7176 :
7177 0 : for (PRInt32 i = 0; i < sheetCount; ++i) {
7178 0 : nsIStyleSheet *sheet = mStyleSet->StyleSheetAt(nsStyleSet::eAgentSheet, i);
7179 0 : if (!aSheets.AppendObject(sheet))
7180 0 : return NS_ERROR_OUT_OF_MEMORY;
7181 : }
7182 :
7183 0 : return NS_OK;
7184 : }
7185 :
7186 : nsresult
7187 0 : PresShell::SetAgentStyleSheets(const nsCOMArray<nsIStyleSheet>& aSheets)
7188 : {
7189 0 : return mStyleSet->ReplaceSheets(nsStyleSet::eAgentSheet, aSheets);
7190 : }
7191 :
7192 : nsresult
7193 0 : PresShell::AddOverrideStyleSheet(nsIStyleSheet *aSheet)
7194 : {
7195 0 : return mStyleSet->PrependStyleSheet(nsStyleSet::eOverrideSheet, aSheet);
7196 : }
7197 :
7198 : nsresult
7199 0 : PresShell::RemoveOverrideStyleSheet(nsIStyleSheet *aSheet)
7200 : {
7201 0 : return mStyleSet->RemoveStyleSheet(nsStyleSet::eOverrideSheet, aSheet);
7202 : }
7203 :
7204 : static void
7205 0 : FreezeElement(nsIContent *aContent, void * /* unused */)
7206 : {
7207 0 : nsCOMPtr<nsIObjectLoadingContent> olc(do_QueryInterface(aContent));
7208 0 : if (olc) {
7209 0 : olc->StopPluginInstance();
7210 : }
7211 0 : }
7212 :
7213 : static bool
7214 0 : FreezeSubDocument(nsIDocument *aDocument, void *aData)
7215 : {
7216 0 : nsIPresShell *shell = aDocument->GetShell();
7217 0 : if (shell)
7218 0 : shell->Freeze();
7219 :
7220 0 : return true;
7221 : }
7222 :
7223 : void
7224 0 : PresShell::Freeze()
7225 : {
7226 0 : MaybeReleaseCapturingContent();
7227 :
7228 0 : mDocument->EnumerateFreezableElements(FreezeElement, nsnull);
7229 :
7230 0 : if (mCaret) {
7231 0 : mCaret->SetCaretVisible(false);
7232 : }
7233 :
7234 0 : mPaintingSuppressed = true;
7235 :
7236 0 : if (mDocument) {
7237 0 : mDocument->EnumerateSubDocuments(FreezeSubDocument, nsnull);
7238 : }
7239 :
7240 0 : nsPresContext* presContext = GetPresContext();
7241 0 : if (presContext &&
7242 0 : presContext->RefreshDriver()->PresContext() == presContext) {
7243 0 : presContext->RefreshDriver()->Freeze();
7244 : }
7245 :
7246 0 : if (presContext) {
7247 0 : nsRootPresContext* rootPresContext = presContext->GetRootPresContext();
7248 0 : if (rootPresContext) {
7249 : rootPresContext->
7250 0 : RootForgetUpdatePluginGeometryFrameForPresContext(mPresContext);
7251 : }
7252 : }
7253 :
7254 0 : mFrozen = true;
7255 0 : if (mDocument) {
7256 0 : UpdateImageLockingState();
7257 : }
7258 0 : }
7259 :
7260 : void
7261 0 : PresShell::FireOrClearDelayedEvents(bool aFireEvents)
7262 : {
7263 0 : mNoDelayedMouseEvents = false;
7264 0 : mNoDelayedKeyEvents = false;
7265 0 : if (!aFireEvents) {
7266 0 : mDelayedEvents.Clear();
7267 0 : return;
7268 : }
7269 :
7270 0 : if (mDocument) {
7271 0 : nsCOMPtr<nsIDocument> doc = mDocument;
7272 0 : while (!mIsDestroying && mDelayedEvents.Length() &&
7273 0 : !doc->EventHandlingSuppressed()) {
7274 0 : nsAutoPtr<nsDelayedEvent> ev(mDelayedEvents[0].forget());
7275 0 : mDelayedEvents.RemoveElementAt(0);
7276 0 : ev->Dispatch(this);
7277 : }
7278 0 : if (!doc->EventHandlingSuppressed()) {
7279 0 : mDelayedEvents.Clear();
7280 : }
7281 : }
7282 : }
7283 :
7284 : static void
7285 0 : ThawElement(nsIContent *aContent, void *aShell)
7286 : {
7287 0 : nsCOMPtr<nsIObjectLoadingContent> olc(do_QueryInterface(aContent));
7288 0 : if (olc) {
7289 0 : olc->AsyncStartPluginInstance();
7290 : }
7291 0 : }
7292 :
7293 : static bool
7294 0 : ThawSubDocument(nsIDocument *aDocument, void *aData)
7295 : {
7296 0 : nsIPresShell *shell = aDocument->GetShell();
7297 0 : if (shell)
7298 0 : shell->Thaw();
7299 :
7300 0 : return true;
7301 : }
7302 :
7303 : void
7304 0 : PresShell::Thaw()
7305 : {
7306 0 : nsPresContext* presContext = GetPresContext();
7307 0 : if (presContext &&
7308 0 : presContext->RefreshDriver()->PresContext() == presContext) {
7309 0 : presContext->RefreshDriver()->Thaw();
7310 : }
7311 :
7312 0 : mDocument->EnumerateFreezableElements(ThawElement, this);
7313 :
7314 0 : if (mDocument)
7315 0 : mDocument->EnumerateSubDocuments(ThawSubDocument, nsnull);
7316 :
7317 : // Get the activeness of our presshell, as this might have changed
7318 : // while we were in the bfcache
7319 0 : QueryIsActive();
7320 :
7321 : // We're now unfrozen
7322 0 : mFrozen = false;
7323 0 : UpdateImageLockingState();
7324 :
7325 0 : UnsuppressPainting();
7326 0 : }
7327 :
7328 : //--------------------------------------------------------
7329 : // Start of protected and private methods on the PresShell
7330 : //--------------------------------------------------------
7331 :
7332 : void
7333 0 : PresShell::MaybeScheduleReflow()
7334 : {
7335 0 : ASSERT_REFLOW_SCHEDULED_STATE();
7336 0 : if (mReflowScheduled || mIsDestroying || mIsReflowing ||
7337 0 : mDirtyRoots.Length() == 0)
7338 0 : return;
7339 :
7340 0 : if (!mPresContext->HasPendingInterrupt() || !ScheduleReflowOffTimer()) {
7341 0 : ScheduleReflow();
7342 : }
7343 :
7344 0 : ASSERT_REFLOW_SCHEDULED_STATE();
7345 : }
7346 :
7347 : void
7348 0 : PresShell::ScheduleReflow()
7349 : {
7350 0 : NS_PRECONDITION(!mReflowScheduled, "Why are we trying to schedule a reflow?");
7351 0 : ASSERT_REFLOW_SCHEDULED_STATE();
7352 :
7353 0 : if (GetPresContext()->RefreshDriver()->AddLayoutFlushObserver(this)) {
7354 0 : mReflowScheduled = true;
7355 : }
7356 :
7357 0 : ASSERT_REFLOW_SCHEDULED_STATE();
7358 0 : }
7359 :
7360 : nsresult
7361 0 : PresShell::DidCauseReflow()
7362 : {
7363 0 : NS_ASSERTION(mChangeNestCount != 0, "Unexpected call to DidCauseReflow()");
7364 0 : --mChangeNestCount;
7365 0 : nsContentUtils::RemoveScriptBlocker();
7366 :
7367 0 : return NS_OK;
7368 : }
7369 :
7370 : void
7371 0 : PresShell::WillDoReflow()
7372 : {
7373 : // We just reflowed, tell the caret that its frame might have moved.
7374 : // XXXbz that comment makes no sense
7375 0 : if (mCaret) {
7376 0 : mCaret->InvalidateOutsideCaret();
7377 : }
7378 :
7379 0 : mPresContext->FlushUserFontSet();
7380 :
7381 0 : mFrameConstructor->BeginUpdate();
7382 0 : }
7383 :
7384 : void
7385 0 : PresShell::DidDoReflow(bool aInterruptible)
7386 : {
7387 0 : mFrameConstructor->EndUpdate();
7388 :
7389 0 : HandlePostedReflowCallbacks(aInterruptible);
7390 0 : if (sSynthMouseMove) {
7391 0 : SynthesizeMouseMove(false);
7392 : }
7393 0 : if (mCaret) {
7394 : // Update the caret's position now to account for any changes created by
7395 : // the reflow.
7396 0 : mCaret->InvalidateOutsideCaret();
7397 0 : mCaret->UpdateCaretPosition();
7398 : }
7399 0 : }
7400 :
7401 : static PLDHashOperator
7402 0 : MarkFramesDirtyToRoot(nsPtrHashKey<nsIFrame>* p, void* closure)
7403 : {
7404 0 : nsIFrame* target = static_cast<nsIFrame*>(closure);
7405 0 : for (nsIFrame* f = p->GetKey(); f && !NS_SUBTREE_DIRTY(f);
7406 : f = f->GetParent()) {
7407 0 : f->AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
7408 :
7409 0 : if (f == target) {
7410 0 : break;
7411 : }
7412 : }
7413 :
7414 0 : return PL_DHASH_NEXT;
7415 : }
7416 :
7417 : void
7418 0 : PresShell::sReflowContinueCallback(nsITimer* aTimer, void* aPresShell)
7419 : {
7420 0 : nsRefPtr<PresShell> self = static_cast<PresShell*>(aPresShell);
7421 :
7422 0 : NS_PRECONDITION(aTimer == self->mReflowContinueTimer, "Unexpected timer");
7423 0 : self->mReflowContinueTimer = nsnull;
7424 0 : self->ScheduleReflow();
7425 0 : }
7426 :
7427 : bool
7428 0 : PresShell::ScheduleReflowOffTimer()
7429 : {
7430 0 : NS_PRECONDITION(!mReflowScheduled, "Shouldn't get here");
7431 0 : ASSERT_REFLOW_SCHEDULED_STATE();
7432 :
7433 0 : if (!mReflowContinueTimer) {
7434 0 : mReflowContinueTimer = do_CreateInstance("@mozilla.org/timer;1");
7435 0 : if (!mReflowContinueTimer ||
7436 0 : NS_FAILED(mReflowContinueTimer->
7437 : InitWithFuncCallback(sReflowContinueCallback, this, 30,
7438 : nsITimer::TYPE_ONE_SHOT))) {
7439 0 : return false;
7440 : }
7441 : }
7442 0 : return true;
7443 : }
7444 :
7445 : bool
7446 0 : PresShell::DoReflow(nsIFrame* target, bool aInterruptible)
7447 : {
7448 : NS_TIME_FUNCTION_WITH_DOCURL;
7449 0 : SAMPLE_LABEL("layout", "DoReflow");
7450 :
7451 0 : if (mReflowContinueTimer) {
7452 0 : mReflowContinueTimer->Cancel();
7453 0 : mReflowContinueTimer = nsnull;
7454 : }
7455 :
7456 0 : nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
7457 :
7458 0 : nsRefPtr<nsRenderingContext> rcx = GetReferenceRenderingContext();
7459 0 : if (!rcx) {
7460 0 : NS_NOTREACHED("CreateRenderingContext failure");
7461 0 : return false;
7462 : }
7463 :
7464 0 : NS_ASSERTION(!mPresContext->mCurrentInflationContainer,
7465 : "current inflation container should be null");
7466 : AutoRestore<nsIFrame*> restoreInflationContainer(mPresContext->
7467 0 : mCurrentInflationContainer);
7468 0 : for (nsIFrame *f = target->GetParent(); f; f = f->GetParent()) {
7469 0 : if (nsLayoutUtils::IsContainerForFontSizeInflation(f)) {
7470 0 : NS_ASSERTION(!(f->GetStateBits() & NS_FRAME_IN_REFLOW),
7471 : "a frame outside should not be in reflow");
7472 0 : mPresContext->mCurrentInflationContainer = f;
7473 0 : mPresContext->mCurrentInflationContainerWidth = f->GetContentRect().width;
7474 0 : break;
7475 : }
7476 : }
7477 :
7478 : #ifdef DEBUG
7479 0 : mCurrentReflowRoot = target;
7480 : #endif
7481 :
7482 0 : target->WillReflow(mPresContext);
7483 :
7484 : // If the target frame is the root of the frame hierarchy, then
7485 : // use all the available space. If it's simply a `reflow root',
7486 : // then use the target frame's size as the available space.
7487 0 : nsSize size;
7488 0 : if (target == rootFrame) {
7489 0 : size = mPresContext->GetVisibleArea().Size();
7490 :
7491 : // target->GetRect() has the old size of the frame,
7492 : // mPresContext->GetVisibleArea() has the new size.
7493 0 : target->InvalidateRectDifference(mPresContext->GetVisibleArea(),
7494 0 : target->GetRect());
7495 : } else {
7496 0 : size = target->GetSize();
7497 : }
7498 :
7499 0 : NS_ASSERTION(!target->GetNextInFlow() && !target->GetPrevInFlow(),
7500 : "reflow roots should never split");
7501 :
7502 : // Don't pass size directly to the reflow state, since a
7503 : // constrained height implies page/column breaking.
7504 0 : nsSize reflowSize(size.width, NS_UNCONSTRAINEDSIZE);
7505 0 : nsHTMLReflowState reflowState(mPresContext, target, rcx, reflowSize);
7506 :
7507 0 : if (rootFrame == target) {
7508 : // When the root frame is being reflowed with unconstrained height
7509 : // (which happens when we're called from
7510 : // DocumentViewerImpl::SizeToContent), we're effectively doing a
7511 : // vertical resize, since it changes the meaning of percentage
7512 : // heights even if no heights actually changed. The same applies
7513 : // when we reflow again after that computation. This is an unusual
7514 : // case, and isn't caught by nsHTMLReflowState::InitResizeFlags.
7515 0 : bool hasUnconstrainedHeight = size.height == NS_UNCONSTRAINEDSIZE;
7516 :
7517 0 : if (hasUnconstrainedHeight || mLastRootReflowHadUnconstrainedHeight) {
7518 0 : reflowState.mFlags.mVResize = true;
7519 : }
7520 :
7521 0 : mLastRootReflowHadUnconstrainedHeight = hasUnconstrainedHeight;
7522 : }
7523 :
7524 : // fix the computed height
7525 0 : NS_ASSERTION(reflowState.mComputedMargin == nsMargin(0, 0, 0, 0),
7526 : "reflow state should not set margin for reflow roots");
7527 0 : if (size.height != NS_UNCONSTRAINEDSIZE) {
7528 : nscoord computedHeight =
7529 0 : size.height - reflowState.mComputedBorderPadding.TopBottom();
7530 0 : computedHeight = NS_MAX(computedHeight, 0);
7531 0 : reflowState.SetComputedHeight(computedHeight);
7532 : }
7533 0 : NS_ASSERTION(reflowState.ComputedWidth() ==
7534 : size.width -
7535 : reflowState.mComputedBorderPadding.LeftRight(),
7536 : "reflow state computed incorrect width");
7537 :
7538 0 : mPresContext->ReflowStarted(aInterruptible);
7539 0 : mIsReflowing = true;
7540 :
7541 : nsReflowStatus status;
7542 0 : nsHTMLReflowMetrics desiredSize;
7543 0 : target->Reflow(mPresContext, desiredSize, reflowState, status);
7544 :
7545 : // If an incremental reflow is initiated at a frame other than the
7546 : // root frame, then its desired size had better not change! If it's
7547 : // initiated at the root, then the size better not change unless its
7548 : // height was unconstrained to start with.
7549 0 : nsRect boundsRelativeToTarget = nsRect(0, 0, desiredSize.width, desiredSize.height);
7550 0 : NS_ASSERTION((target == rootFrame && size.height == NS_UNCONSTRAINEDSIZE) ||
7551 : (desiredSize.width == size.width &&
7552 : desiredSize.height == size.height),
7553 : "non-root frame's desired size changed during an "
7554 : "incremental reflow");
7555 0 : NS_ASSERTION(target == rootFrame ||
7556 : desiredSize.VisualOverflow().IsEqualInterior(boundsRelativeToTarget),
7557 : "non-root reflow roots must not have visible overflow");
7558 0 : NS_ASSERTION(target == rootFrame ||
7559 : desiredSize.ScrollableOverflow().IsEqualEdges(boundsRelativeToTarget),
7560 : "non-root reflow roots must not have scrollable overflow");
7561 0 : NS_ASSERTION(status == NS_FRAME_COMPLETE,
7562 : "reflow roots should never split");
7563 :
7564 0 : target->SetSize(boundsRelativeToTarget.Size());
7565 :
7566 : // Always use boundsRelativeToTarget here, not desiredSize.GetVisualOverflowArea(),
7567 : // because for root frames (where they could be different, since root frames
7568 : // are allowed to have overflow) the root view bounds need to match the
7569 : // viewport bounds; the view manager "window dimensions" code depends on it.
7570 : nsContainerFrame::SyncFrameViewAfterReflow(mPresContext, target,
7571 : target->GetView(),
7572 0 : boundsRelativeToTarget);
7573 : nsContainerFrame::SyncWindowProperties(mPresContext, target,
7574 0 : target->GetView());
7575 :
7576 0 : target->DidReflow(mPresContext, nsnull, NS_FRAME_REFLOW_FINISHED);
7577 0 : if (target == rootFrame && size.height == NS_UNCONSTRAINEDSIZE) {
7578 0 : mPresContext->SetVisibleArea(boundsRelativeToTarget);
7579 : }
7580 :
7581 : #ifdef DEBUG
7582 0 : mCurrentReflowRoot = nsnull;
7583 : #endif
7584 :
7585 0 : NS_ASSERTION(mPresContext->HasPendingInterrupt() ||
7586 : mFramesToDirty.Count() == 0,
7587 : "Why do we need to dirty anything if not interrupted?");
7588 :
7589 0 : mIsReflowing = false;
7590 0 : bool interrupted = mPresContext->HasPendingInterrupt();
7591 0 : if (interrupted) {
7592 : // Make sure target gets reflowed again.
7593 0 : mFramesToDirty.EnumerateEntries(&MarkFramesDirtyToRoot, target);
7594 0 : NS_ASSERTION(NS_SUBTREE_DIRTY(target), "Why is the target not dirty?");
7595 0 : mDirtyRoots.AppendElement(target);
7596 0 : mDocument->SetNeedLayoutFlush();
7597 :
7598 : // Clear mFramesToDirty after we've done the NS_SUBTREE_DIRTY(target)
7599 : // assertion so that if it fails it's easier to see what's going on.
7600 : #ifdef NOISY_INTERRUPTIBLE_REFLOW
7601 : printf("mFramesToDirty.Count() == %u\n", mFramesToDirty.Count());
7602 : #endif /* NOISY_INTERRUPTIBLE_REFLOW */
7603 0 : mFramesToDirty.Clear();
7604 :
7605 : // Any FlushPendingNotifications with interruptible reflows
7606 : // should be suppressed now. We don't want to do extra reflow work
7607 : // before our reflow event happens.
7608 0 : mSuppressInterruptibleReflows = true;
7609 0 : MaybeScheduleReflow();
7610 : }
7611 :
7612 0 : nsRootPresContext* rootPC = mPresContext->GetRootPresContext();
7613 0 : if (rootPC) {
7614 0 : rootPC->RequestUpdatePluginGeometry(target);
7615 : }
7616 :
7617 0 : return !interrupted;
7618 : }
7619 :
7620 : #ifdef DEBUG
7621 : void
7622 0 : PresShell::DoVerifyReflow()
7623 : {
7624 0 : if (GetVerifyReflowEnable()) {
7625 : // First synchronously render what we have so far so that we can
7626 : // see it.
7627 0 : nsIView* rootView = mViewManager->GetRootView();
7628 0 : mViewManager->InvalidateView(rootView);
7629 :
7630 0 : FlushPendingNotifications(Flush_Layout);
7631 0 : mInVerifyReflow = true;
7632 0 : bool ok = VerifyIncrementalReflow();
7633 0 : mInVerifyReflow = false;
7634 0 : if (VERIFY_REFLOW_ALL & gVerifyReflowFlags) {
7635 : printf("ProcessReflowCommands: finished (%s)\n",
7636 0 : ok ? "ok" : "failed");
7637 : }
7638 :
7639 0 : if (!mDirtyRoots.IsEmpty()) {
7640 0 : printf("XXX yikes! reflow commands queued during verify-reflow\n");
7641 : }
7642 : }
7643 0 : }
7644 : #endif
7645 :
7646 : bool
7647 0 : PresShell::ProcessReflowCommands(bool aInterruptible)
7648 : {
7649 0 : if (mDirtyRoots.IsEmpty() && !mShouldUnsuppressPainting) {
7650 : // Nothing to do; bail out
7651 0 : return true;
7652 : }
7653 :
7654 : NS_TIME_FUNCTION_WITH_DOCURL;
7655 0 : mozilla::TimeStamp timerStart = mozilla::TimeStamp::Now();
7656 0 : bool interrupted = false;
7657 0 : if (!mDirtyRoots.IsEmpty()) {
7658 :
7659 : #ifdef DEBUG
7660 0 : if (VERIFY_REFLOW_DUMP_COMMANDS & gVerifyReflowFlags) {
7661 0 : printf("ProcessReflowCommands: begin incremental reflow\n");
7662 : }
7663 : #endif
7664 :
7665 : // If reflow is interruptible, then make a note of our deadline.
7666 : const PRIntervalTime deadline = aInterruptible
7667 0 : ? PR_IntervalNow() + PR_MicrosecondsToInterval(gMaxRCProcessingTime)
7668 0 : : (PRIntervalTime)0;
7669 :
7670 : // Scope for the reflow entry point
7671 : {
7672 0 : nsAutoScriptBlocker scriptBlocker;
7673 0 : WillDoReflow();
7674 0 : AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Reflow);
7675 0 : nsIViewManager::AutoDisableRefresh refreshBlocker(mViewManager);
7676 :
7677 0 : do {
7678 : // Send an incremental reflow notification to the target frame.
7679 0 : PRInt32 idx = mDirtyRoots.Length() - 1;
7680 0 : nsIFrame *target = mDirtyRoots[idx];
7681 0 : mDirtyRoots.RemoveElementAt(idx);
7682 :
7683 0 : if (!NS_SUBTREE_DIRTY(target)) {
7684 : // It's not dirty anymore, which probably means the notification
7685 : // was posted in the middle of a reflow (perhaps with a reflow
7686 : // root in the middle). Don't do anything.
7687 0 : continue;
7688 : }
7689 :
7690 0 : interrupted = !DoReflow(target, aInterruptible);
7691 :
7692 : // Keep going until we're out of reflow commands, or we've run
7693 : // past our deadline, or we're interrupted.
7694 0 : } while (!interrupted && !mDirtyRoots.IsEmpty() &&
7695 0 : (!aInterruptible || PR_IntervalNow() < deadline));
7696 :
7697 0 : interrupted = !mDirtyRoots.IsEmpty();
7698 : }
7699 :
7700 : // Exiting the scriptblocker might have killed us
7701 0 : if (!mIsDestroying) {
7702 0 : DidDoReflow(aInterruptible);
7703 : }
7704 :
7705 : // DidDoReflow might have killed us
7706 0 : if (!mIsDestroying) {
7707 : #ifdef DEBUG
7708 0 : if (VERIFY_REFLOW_DUMP_COMMANDS & gVerifyReflowFlags) {
7709 : printf("\nPresShell::ProcessReflowCommands() finished: this=%p\n",
7710 0 : (void*)this);
7711 : }
7712 0 : DoVerifyReflow();
7713 : #endif
7714 :
7715 : // If any new reflow commands were enqueued during the reflow, schedule
7716 : // another reflow event to process them. Note that we want to do this
7717 : // after DidDoReflow(), since that method can change whether there are
7718 : // dirty roots around by flushing, and there's no point in posting a
7719 : // reflow event just to have the flush revoke it.
7720 0 : if (!mDirtyRoots.IsEmpty()) {
7721 0 : MaybeScheduleReflow();
7722 : // And tell our document that we might need flushing
7723 0 : mDocument->SetNeedLayoutFlush();
7724 : }
7725 : }
7726 : }
7727 :
7728 0 : if (!mIsDestroying && mShouldUnsuppressPainting &&
7729 0 : mDirtyRoots.IsEmpty()) {
7730 : // We only unlock if we're out of reflows. It's pointless
7731 : // to unlock if reflows are still pending, since reflows
7732 : // are just going to thrash the frames around some more. By
7733 : // waiting we avoid an overeager "jitter" effect.
7734 0 : mShouldUnsuppressPainting = false;
7735 0 : UnsuppressAndInvalidate();
7736 : }
7737 :
7738 0 : if (mDocument->GetRootElement()) {
7739 : Telemetry::ID id;
7740 0 : if (mDocument->GetRootElement()->IsXUL()) {
7741 : id = mIsActive
7742 : ? Telemetry::XUL_FOREGROUND_REFLOW_MS
7743 0 : : Telemetry::XUL_BACKGROUND_REFLOW_MS;
7744 : } else {
7745 : id = mIsActive
7746 : ? Telemetry::HTML_FOREGROUND_REFLOW_MS
7747 0 : : Telemetry::HTML_BACKGROUND_REFLOW_MS;
7748 : }
7749 0 : Telemetry::AccumulateTimeDelta(id, timerStart);
7750 : }
7751 :
7752 0 : return !interrupted;
7753 : }
7754 :
7755 : #ifdef MOZ_XUL
7756 : /*
7757 : * It's better to add stuff to the |DidSetStyleContext| method of the
7758 : * relevant frames than adding it here. These methods should (ideally,
7759 : * anyway) go away.
7760 : */
7761 :
7762 : // Return value says whether to walk children.
7763 : typedef bool (* frameWalkerFn)(nsIFrame *aFrame, void *aClosure);
7764 :
7765 : static bool
7766 0 : ReResolveMenusAndTrees(nsIFrame *aFrame, void *aClosure)
7767 : {
7768 : // Trees have a special style cache that needs to be flushed when
7769 : // the theme changes.
7770 0 : nsTreeBodyFrame *treeBody = do_QueryFrame(aFrame);
7771 0 : if (treeBody)
7772 0 : treeBody->ClearStyleAndImageCaches();
7773 :
7774 : // We deliberately don't re-resolve style on a menu's popup
7775 : // sub-content, since doing so slows menus to a crawl. That means we
7776 : // have to special-case them on a skin switch, and ensure that the
7777 : // popup frames just get destroyed completely.
7778 0 : if (aFrame && aFrame->GetType() == nsGkAtoms::menuFrame)
7779 0 : (static_cast<nsMenuFrame *>(aFrame))->CloseMenu(true);
7780 0 : return true;
7781 : }
7782 :
7783 : static bool
7784 0 : ReframeImageBoxes(nsIFrame *aFrame, void *aClosure)
7785 : {
7786 0 : nsStyleChangeList *list = static_cast<nsStyleChangeList*>(aClosure);
7787 0 : if (aFrame->GetType() == nsGkAtoms::imageBoxFrame) {
7788 : list->AppendChange(aFrame, aFrame->GetContent(),
7789 0 : NS_STYLE_HINT_FRAMECHANGE);
7790 0 : return false; // don't walk descendants
7791 : }
7792 0 : return true; // walk descendants
7793 : }
7794 :
7795 : static void
7796 0 : WalkFramesThroughPlaceholders(nsPresContext *aPresContext, nsIFrame *aFrame,
7797 : frameWalkerFn aFunc, void *aClosure)
7798 : {
7799 0 : bool walkChildren = (*aFunc)(aFrame, aClosure);
7800 0 : if (!walkChildren)
7801 0 : return;
7802 :
7803 0 : nsIFrame::ChildListIterator lists(aFrame);
7804 0 : for (; !lists.IsDone(); lists.Next()) {
7805 0 : nsFrameList::Enumerator childFrames(lists.CurrentList());
7806 0 : for (; !childFrames.AtEnd(); childFrames.Next()) {
7807 0 : nsIFrame* child = childFrames.get();
7808 0 : if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
7809 : // only do frames that are in flow, and recur through the
7810 : // out-of-flows of placeholders.
7811 : WalkFramesThroughPlaceholders(aPresContext,
7812 : nsPlaceholderFrame::GetRealFrameFor(child),
7813 0 : aFunc, aClosure);
7814 : }
7815 : }
7816 : }
7817 : }
7818 : #endif
7819 :
7820 : NS_IMETHODIMP
7821 0 : PresShell::Observe(nsISupports* aSubject,
7822 : const char* aTopic,
7823 : const PRUnichar* aData)
7824 : {
7825 : #ifdef MOZ_XUL
7826 0 : if (!nsCRT::strcmp(aTopic, "chrome-flush-skin-caches")) {
7827 0 : nsIFrame *rootFrame = mFrameConstructor->GetRootFrame();
7828 : // Need to null-check because "chrome-flush-skin-caches" can happen
7829 : // at interesting times during startup.
7830 0 : if (rootFrame) {
7831 0 : NS_ASSERTION(mViewManager, "View manager must exist");
7832 :
7833 0 : nsWeakFrame weakRoot(rootFrame);
7834 : // Have to make sure that the content notifications are flushed before we
7835 : // start messing with the frame model; otherwise we can get content doubling.
7836 0 : mDocument->FlushPendingNotifications(Flush_ContentAndNotify);
7837 :
7838 0 : if (weakRoot.IsAlive()) {
7839 : WalkFramesThroughPlaceholders(mPresContext, rootFrame,
7840 0 : &ReResolveMenusAndTrees, nsnull);
7841 :
7842 : // Because "chrome:" URL equality is messy, reframe image box
7843 : // frames (hack!).
7844 0 : nsStyleChangeList changeList;
7845 : WalkFramesThroughPlaceholders(mPresContext, rootFrame,
7846 0 : ReframeImageBoxes, &changeList);
7847 : // Mark ourselves as not safe to flush while we're doing frame
7848 : // construction.
7849 : {
7850 0 : nsAutoScriptBlocker scriptBlocker;
7851 0 : ++mChangeNestCount;
7852 0 : mFrameConstructor->ProcessRestyledFrames(changeList);
7853 0 : --mChangeNestCount;
7854 : }
7855 : }
7856 : }
7857 0 : return NS_OK;
7858 : }
7859 : #endif
7860 :
7861 0 : if (!nsCRT::strcmp(aTopic, "agent-sheet-added") && mStyleSet) {
7862 0 : AddAgentSheet(aSubject);
7863 0 : return NS_OK;
7864 : }
7865 :
7866 0 : if (!nsCRT::strcmp(aTopic, "user-sheet-added") && mStyleSet) {
7867 0 : AddUserSheet(aSubject);
7868 0 : return NS_OK;
7869 : }
7870 :
7871 0 : if (!nsCRT::strcmp(aTopic, "agent-sheet-removed") && mStyleSet) {
7872 0 : RemoveSheet(nsStyleSet::eAgentSheet, aSubject);
7873 0 : return NS_OK;
7874 : }
7875 :
7876 0 : if (!nsCRT::strcmp(aTopic, "user-sheet-removed") && mStyleSet) {
7877 0 : RemoveSheet(nsStyleSet::eUserSheet, aSubject);
7878 0 : return NS_OK;
7879 : }
7880 :
7881 0 : NS_WARNING("unrecognized topic in PresShell::Observe");
7882 0 : return NS_ERROR_FAILURE;
7883 : }
7884 :
7885 : bool
7886 0 : nsIPresShell::AddRefreshObserverInternal(nsARefreshObserver* aObserver,
7887 : mozFlushType aFlushType)
7888 : {
7889 0 : nsPresContext* presContext = GetPresContext();
7890 : return presContext ? presContext->RefreshDriver()->
7891 0 : AddRefreshObserver(aObserver, aFlushType) : false;
7892 : }
7893 :
7894 : /* virtual */ bool
7895 0 : nsIPresShell::AddRefreshObserverExternal(nsARefreshObserver* aObserver,
7896 : mozFlushType aFlushType)
7897 : {
7898 0 : return AddRefreshObserverInternal(aObserver, aFlushType);
7899 : }
7900 :
7901 : bool
7902 0 : nsIPresShell::RemoveRefreshObserverInternal(nsARefreshObserver* aObserver,
7903 : mozFlushType aFlushType)
7904 : {
7905 0 : nsPresContext* presContext = GetPresContext();
7906 : return presContext ? presContext->RefreshDriver()->
7907 0 : RemoveRefreshObserver(aObserver, aFlushType) : false;
7908 : }
7909 :
7910 : /* virtual */ bool
7911 0 : nsIPresShell::RemoveRefreshObserverExternal(nsARefreshObserver* aObserver,
7912 : mozFlushType aFlushType)
7913 : {
7914 0 : return RemoveRefreshObserverInternal(aObserver, aFlushType);
7915 : }
7916 :
7917 : //------------------------------------------------------
7918 : // End of protected and private methods on the PresShell
7919 : //------------------------------------------------------
7920 :
7921 : // Start of DEBUG only code
7922 :
7923 : #ifdef NS_DEBUG
7924 : #include "nsIURL.h"
7925 : #include "nsILinkHandler.h"
7926 :
7927 : static NS_DEFINE_CID(kViewManagerCID, NS_VIEW_MANAGER_CID);
7928 :
7929 : static void
7930 0 : LogVerifyMessage(nsIFrame* k1, nsIFrame* k2, const char* aMsg)
7931 : {
7932 0 : nsAutoString n1, n2;
7933 0 : if (k1) {
7934 0 : k1->GetFrameName(n1);
7935 : } else {
7936 0 : n1.Assign(NS_LITERAL_STRING("(null)"));
7937 : }
7938 :
7939 0 : if (k2) {
7940 0 : k2->GetFrameName(n2);
7941 : } else {
7942 0 : n2.Assign(NS_LITERAL_STRING("(null)"));
7943 : }
7944 :
7945 : printf("verifyreflow: %s %p != %s %p %s\n",
7946 0 : NS_LossyConvertUTF16toASCII(n1).get(), (void*)k1,
7947 0 : NS_LossyConvertUTF16toASCII(n2).get(), (void*)k2, aMsg);
7948 0 : }
7949 :
7950 : static void
7951 0 : LogVerifyMessage(nsIFrame* k1, nsIFrame* k2, const char* aMsg,
7952 : const nsRect& r1, const nsRect& r2)
7953 : {
7954 0 : printf("VerifyReflow Error:\n");
7955 0 : nsAutoString name;
7956 :
7957 0 : if (k1) {
7958 0 : k1->GetFrameName(name);
7959 0 : printf(" %s %p ", NS_LossyConvertUTF16toASCII(name).get(), (void*)k1);
7960 : }
7961 0 : printf("{%d, %d, %d, %d} != \n", r1.x, r1.y, r1.width, r1.height);
7962 :
7963 0 : if (k2) {
7964 0 : k2->GetFrameName(name);
7965 0 : printf(" %s %p ", NS_LossyConvertUTF16toASCII(name).get(), (void*)k2);
7966 : }
7967 : printf("{%d, %d, %d, %d}\n %s\n",
7968 0 : r2.x, r2.y, r2.width, r2.height, aMsg);
7969 0 : }
7970 :
7971 : static void
7972 0 : LogVerifyMessage(nsIFrame* k1, nsIFrame* k2, const char* aMsg,
7973 : const nsIntRect& r1, const nsIntRect& r2)
7974 : {
7975 0 : printf("VerifyReflow Error:\n");
7976 0 : nsAutoString name;
7977 :
7978 0 : if (k1) {
7979 0 : k1->GetFrameName(name);
7980 0 : printf(" %s %p ", NS_LossyConvertUTF16toASCII(name).get(), (void*)k1);
7981 : }
7982 0 : printf("{%d, %d, %d, %d} != \n", r1.x, r1.y, r1.width, r1.height);
7983 :
7984 0 : if (k2) {
7985 0 : k2->GetFrameName(name);
7986 0 : printf(" %s %p ", NS_LossyConvertUTF16toASCII(name).get(), (void*)k2);
7987 : }
7988 : printf("{%d, %d, %d, %d}\n %s\n",
7989 0 : r2.x, r2.y, r2.width, r2.height, aMsg);
7990 0 : }
7991 :
7992 : static bool
7993 0 : CompareTrees(nsPresContext* aFirstPresContext, nsIFrame* aFirstFrame,
7994 : nsPresContext* aSecondPresContext, nsIFrame* aSecondFrame)
7995 : {
7996 0 : if (!aFirstPresContext || !aFirstFrame || !aSecondPresContext || !aSecondFrame)
7997 0 : return true;
7998 : // XXX Evil hack to reduce false positives; I can't seem to figure
7999 : // out how to flush scrollbar changes correctly
8000 : //if (aFirstFrame->GetType() == nsGkAtoms::scrollbarFrame)
8001 : // return true;
8002 0 : bool ok = true;
8003 0 : nsIFrame::ChildListIterator lists1(aFirstFrame);
8004 0 : nsIFrame::ChildListIterator lists2(aSecondFrame);
8005 0 : do {
8006 0 : const nsFrameList& kids1 = !lists1.IsDone() ? lists1.CurrentList() : nsFrameList();
8007 0 : const nsFrameList& kids2 = !lists2.IsDone() ? lists2.CurrentList() : nsFrameList();
8008 0 : PRInt32 l1 = kids1.GetLength();
8009 0 : PRInt32 l2 = kids2.GetLength();;
8010 0 : if (l1 != l2) {
8011 0 : ok = false;
8012 : LogVerifyMessage(kids1.FirstChild(), kids2.FirstChild(),
8013 0 : "child counts don't match: ");
8014 0 : printf("%d != %d\n", l1, l2);
8015 0 : if (0 == (VERIFY_REFLOW_ALL & gVerifyReflowFlags)) {
8016 : break;
8017 : }
8018 : }
8019 :
8020 0 : nsIntRect r1, r2;
8021 : nsIView* v1, *v2;
8022 0 : for (nsFrameList::Enumerator e1(kids1), e2(kids2);
8023 : ;
8024 0 : e1.Next(), e2.Next()) {
8025 0 : nsIFrame* k1 = e1.get();
8026 0 : nsIFrame* k2 = e2.get();
8027 0 : if (((nsnull == k1) && (nsnull != k2)) ||
8028 : ((nsnull != k1) && (nsnull == k2))) {
8029 0 : ok = false;
8030 0 : LogVerifyMessage(k1, k2, "child lists are different\n");
8031 0 : break;
8032 : }
8033 0 : else if (nsnull != k1) {
8034 : // Verify that the frames are the same size
8035 0 : if (!k1->GetRect().IsEqualInterior(k2->GetRect())) {
8036 0 : ok = false;
8037 0 : LogVerifyMessage(k1, k2, "(frame rects)", k1->GetRect(), k2->GetRect());
8038 : }
8039 :
8040 : // Make sure either both have views or neither have views; if they
8041 : // do have views, make sure the views are the same size. If the
8042 : // views have widgets, make sure they both do or neither does. If
8043 : // they do, make sure the widgets are the same size.
8044 0 : v1 = k1->GetView();
8045 0 : v2 = k2->GetView();
8046 0 : if (((nsnull == v1) && (nsnull != v2)) ||
8047 : ((nsnull != v1) && (nsnull == v2))) {
8048 0 : ok = false;
8049 0 : LogVerifyMessage(k1, k2, "child views are not matched\n");
8050 : }
8051 0 : else if (nsnull != v1) {
8052 0 : if (!v1->GetBounds().IsEqualInterior(v2->GetBounds())) {
8053 0 : LogVerifyMessage(k1, k2, "(view rects)", v1->GetBounds(), v2->GetBounds());
8054 : }
8055 :
8056 0 : nsIWidget* w1 = v1->GetWidget();
8057 0 : nsIWidget* w2 = v2->GetWidget();
8058 0 : if (((nsnull == w1) && (nsnull != w2)) ||
8059 : ((nsnull != w1) && (nsnull == w2))) {
8060 0 : ok = false;
8061 0 : LogVerifyMessage(k1, k2, "child widgets are not matched\n");
8062 : }
8063 0 : else if (nsnull != w1) {
8064 0 : w1->GetBounds(r1);
8065 0 : w2->GetBounds(r2);
8066 0 : if (!r1.IsEqualEdges(r2)) {
8067 0 : LogVerifyMessage(k1, k2, "(widget rects)", r1, r2);
8068 : }
8069 : }
8070 : }
8071 0 : if (!ok && (0 == (VERIFY_REFLOW_ALL & gVerifyReflowFlags))) {
8072 0 : break;
8073 : }
8074 :
8075 : // XXX Should perhaps compare their float managers.
8076 :
8077 : // Compare the sub-trees too
8078 0 : if (!CompareTrees(aFirstPresContext, k1, aSecondPresContext, k2)) {
8079 0 : ok = false;
8080 0 : if (0 == (VERIFY_REFLOW_ALL & gVerifyReflowFlags)) {
8081 0 : break;
8082 : }
8083 : }
8084 : }
8085 : else {
8086 0 : break;
8087 : }
8088 : }
8089 0 : if (!ok && (0 == (VERIFY_REFLOW_ALL & gVerifyReflowFlags))) {
8090 : break;
8091 : }
8092 :
8093 0 : lists1.Next();
8094 0 : lists2.Next();
8095 0 : if (lists1.IsDone() != lists2.IsDone() ||
8096 0 : (!lists1.IsDone() && lists1.CurrentID() != lists2.CurrentID())) {
8097 0 : if (0 == (VERIFY_REFLOW_ALL & gVerifyReflowFlags)) {
8098 0 : ok = false;
8099 : }
8100 : LogVerifyMessage(kids1.FirstChild(), kids2.FirstChild(),
8101 0 : "child list names are not matched: ");
8102 : fprintf(stdout, "%s != %s\n",
8103 0 : !lists1.IsDone() ? mozilla::layout::ChildListName(lists1.CurrentID()) : "(null)",
8104 0 : !lists2.IsDone() ? mozilla::layout::ChildListName(lists2.CurrentID()) : "(null)");
8105 : break;
8106 : }
8107 0 : } while (ok && !lists1.IsDone());
8108 :
8109 0 : return ok;
8110 : }
8111 : #endif
8112 :
8113 : #if 0
8114 : static nsIFrame*
8115 : FindTopFrame(nsIFrame* aRoot)
8116 : {
8117 : if (aRoot) {
8118 : nsIContent* content = aRoot->GetContent();
8119 : if (content) {
8120 : nsIAtom* tag;
8121 : content->GetTag(tag);
8122 : if (nsnull != tag) {
8123 : NS_RELEASE(tag);
8124 : return aRoot;
8125 : }
8126 : }
8127 :
8128 : // Try one of the children
8129 : nsIFrame* kid = aRoot->GetFirstPrincipalChild();
8130 : while (nsnull != kid) {
8131 : nsIFrame* result = FindTopFrame(kid);
8132 : if (nsnull != result) {
8133 : return result;
8134 : }
8135 : kid = kid->GetNextSibling();
8136 : }
8137 : }
8138 : return nsnull;
8139 : }
8140 : #endif
8141 :
8142 :
8143 : #ifdef DEBUG
8144 :
8145 : nsStyleSet*
8146 0 : PresShell::CloneStyleSet(nsStyleSet* aSet)
8147 : {
8148 0 : nsStyleSet *clone = new nsStyleSet();
8149 :
8150 0 : PRInt32 i, n = aSet->SheetCount(nsStyleSet::eOverrideSheet);
8151 0 : for (i = 0; i < n; i++) {
8152 0 : nsIStyleSheet* ss = aSet->StyleSheetAt(nsStyleSet::eOverrideSheet, i);
8153 0 : if (ss)
8154 0 : clone->AppendStyleSheet(nsStyleSet::eOverrideSheet, ss);
8155 : }
8156 :
8157 : // The document expects to insert document stylesheets itself
8158 : #if 0
8159 : n = aSet->SheetCount(nsStyleSet::eDocSheet);
8160 : for (i = 0; i < n; i++) {
8161 : nsIStyleSheet* ss = aSet->StyleSheetAt(nsStyleSet::eDocSheet, i);
8162 : if (ss)
8163 : clone->AddDocStyleSheet(ss, mDocument);
8164 : }
8165 : #endif
8166 :
8167 0 : n = aSet->SheetCount(nsStyleSet::eUserSheet);
8168 0 : for (i = 0; i < n; i++) {
8169 0 : nsIStyleSheet* ss = aSet->StyleSheetAt(nsStyleSet::eUserSheet, i);
8170 0 : if (ss)
8171 0 : clone->AppendStyleSheet(nsStyleSet::eUserSheet, ss);
8172 : }
8173 :
8174 0 : n = aSet->SheetCount(nsStyleSet::eAgentSheet);
8175 0 : for (i = 0; i < n; i++) {
8176 0 : nsIStyleSheet* ss = aSet->StyleSheetAt(nsStyleSet::eAgentSheet, i);
8177 0 : if (ss)
8178 0 : clone->AppendStyleSheet(nsStyleSet::eAgentSheet, ss);
8179 : }
8180 0 : return clone;
8181 : }
8182 :
8183 : #ifdef DEBUG_Eli
8184 : static nsresult
8185 : DumpToPNG(nsIPresShell* shell, nsAString& name) {
8186 : PRInt32 width=1000, height=1000;
8187 : nsRect r(0, 0, shell->GetPresContext()->DevPixelsToAppUnits(width),
8188 : shell->GetPresContext()->DevPixelsToAppUnits(height));
8189 :
8190 : nsRefPtr<gfxImageSurface> imgSurface =
8191 : new gfxImageSurface(gfxIntSize(width, height),
8192 : gfxImageSurface::ImageFormatARGB32);
8193 :
8194 : nsRefPtr<gfxContext> imgContext = new gfxContext(imgSurface);
8195 :
8196 : nsRefPtr<gfxASurface> surface =
8197 : gfxPlatform::GetPlatform()->
8198 : CreateOffscreenSurface(gfxIntSize(width, height),
8199 : gfxASurface::ContentFromFormat(gfxASurface::ImageFormatARGB32));
8200 : NS_ENSURE_TRUE(surface, NS_ERROR_OUT_OF_MEMORY);
8201 :
8202 : nsRefPtr<gfxContext> context = new gfxContext(surface);
8203 :
8204 : shell->RenderDocument(r, 0, NS_RGB(255, 255, 0), context);
8205 :
8206 : imgContext->DrawSurface(surface, gfxSize(width, height));
8207 :
8208 : nsCOMPtr<imgIEncoder> encoder = do_CreateInstance("@mozilla.org/image/encoder;2?type=image/png");
8209 : NS_ENSURE_TRUE(encoder, NS_ERROR_FAILURE);
8210 : encoder->InitFromData(imgSurface->Data(), imgSurface->Stride() * height,
8211 : width, height, imgSurface->Stride(),
8212 : imgIEncoder::INPUT_FORMAT_HOSTARGB, EmptyString());
8213 :
8214 : // XXX not sure if this is the right way to write to a file
8215 : nsCOMPtr<nsILocalFile> file = do_CreateInstance("@mozilla.org/file/local;1");
8216 : NS_ENSURE_TRUE(file, NS_ERROR_FAILURE);
8217 : rv = file->InitWithPath(name);
8218 : NS_ENSURE_SUCCESS(rv, rv);
8219 :
8220 : PRUint32 length;
8221 : encoder->Available(&length);
8222 :
8223 : nsCOMPtr<nsIOutputStream> outputStream;
8224 : rv = NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), file);
8225 : NS_ENSURE_SUCCESS(rv, rv);
8226 :
8227 : nsCOMPtr<nsIOutputStream> bufferedOutputStream;
8228 : rv = NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream),
8229 : outputStream, length);
8230 :
8231 : PRUint32 numWritten;
8232 : rv = bufferedOutputStream->WriteFrom(encoder, length, &numWritten);
8233 : NS_ENSURE_SUCCESS(rv, rv);
8234 :
8235 : return NS_OK;
8236 : }
8237 : #endif
8238 :
8239 : // After an incremental reflow, we verify the correctness by doing a
8240 : // full reflow into a fresh frame tree.
8241 : bool
8242 0 : PresShell::VerifyIncrementalReflow()
8243 : {
8244 0 : if (VERIFY_REFLOW_NOISY & gVerifyReflowFlags) {
8245 0 : printf("Building Verification Tree...\n");
8246 : }
8247 :
8248 : // Create a presentation context to view the new frame tree
8249 : nsRefPtr<nsPresContext> cx =
8250 0 : new nsRootPresContext(mDocument, mPresContext->IsPaginated() ?
8251 : nsPresContext::eContext_PrintPreview :
8252 0 : nsPresContext::eContext_Galley);
8253 0 : NS_ENSURE_TRUE(cx, false);
8254 :
8255 0 : nsDeviceContext *dc = mPresContext->DeviceContext();
8256 0 : nsresult rv = cx->Init(dc);
8257 0 : NS_ENSURE_SUCCESS(rv, false);
8258 :
8259 : // Get our scrolling preference
8260 0 : nsIView* rootView = mViewManager->GetRootView();
8261 0 : NS_ENSURE_TRUE(rootView->HasWidget(), false);
8262 0 : nsIWidget* parentWidget = rootView->GetWidget();
8263 :
8264 : // Create a new view manager.
8265 0 : nsCOMPtr<nsIViewManager> vm = do_CreateInstance(kViewManagerCID);
8266 0 : NS_ENSURE_TRUE(vm, false);
8267 0 : rv = vm->Init(dc);
8268 0 : NS_ENSURE_SUCCESS(rv, false);
8269 :
8270 : // Create a child window of the parent that is our "root view/window"
8271 : // Create a view
8272 0 : nsRect tbounds = mPresContext->GetVisibleArea();
8273 0 : nsIView* view = vm->CreateView(tbounds, nsnull);
8274 0 : NS_ENSURE_TRUE(view, false);
8275 :
8276 : //now create the widget for the view
8277 0 : rv = view->CreateWidgetForParent(parentWidget, nsnull, true);
8278 0 : NS_ENSURE_SUCCESS(rv, false);
8279 :
8280 : // Setup hierarchical relationship in view manager
8281 0 : vm->SetRootView(view);
8282 :
8283 : // Make the new presentation context the same size as our
8284 : // presentation context.
8285 0 : nsRect r = mPresContext->GetVisibleArea();
8286 0 : cx->SetVisibleArea(r);
8287 :
8288 : // Create a new presentation shell to view the document. Use the
8289 : // exact same style information that this document has.
8290 0 : nsAutoPtr<nsStyleSet> newSet(CloneStyleSet(mStyleSet));
8291 0 : nsCOMPtr<nsIPresShell> sh;
8292 0 : rv = mDocument->CreateShell(cx, vm, newSet, getter_AddRefs(sh));
8293 0 : NS_ENSURE_SUCCESS(rv, false);
8294 0 : newSet.forget();
8295 : // Note that after we create the shell, we must make sure to destroy it
8296 0 : sh->SetVerifyReflowEnable(false); // turn off verify reflow while we're reflowing the test frame tree
8297 0 : vm->SetPresShell(sh);
8298 : {
8299 0 : nsAutoCauseReflowNotifier crNotifier(this);
8300 0 : sh->InitialReflow(r.width, r.height);
8301 : }
8302 0 : mDocument->BindingManager()->ProcessAttachedQueue();
8303 0 : sh->FlushPendingNotifications(Flush_Layout);
8304 0 : sh->SetVerifyReflowEnable(true); // turn on verify reflow again now that we're done reflowing the test frame tree
8305 : // Force the non-primary presshell to unsuppress; it doesn't want to normally
8306 : // because it thinks it's hidden
8307 0 : ((PresShell*)sh.get())->mPaintingSuppressed = false;
8308 0 : if (VERIFY_REFLOW_NOISY & gVerifyReflowFlags) {
8309 0 : printf("Verification Tree built, comparing...\n");
8310 : }
8311 :
8312 : // Now that the document has been reflowed, use its frame tree to
8313 : // compare against our frame tree.
8314 0 : nsIFrame* root1 = mFrameConstructor->GetRootFrame();
8315 0 : nsIFrame* root2 = sh->GetRootFrame();
8316 0 : bool ok = CompareTrees(mPresContext, root1, cx, root2);
8317 0 : if (!ok && (VERIFY_REFLOW_NOISY & gVerifyReflowFlags)) {
8318 0 : printf("Verify reflow failed, primary tree:\n");
8319 0 : root1->List(stdout, 0);
8320 0 : printf("Verification tree:\n");
8321 0 : root2->List(stdout, 0);
8322 : }
8323 :
8324 : #ifdef DEBUG_Eli
8325 : // Sample code for dumping page to png
8326 : // XXX Needs to be made more flexible
8327 : if (!ok) {
8328 : nsString stra;
8329 : static int num = 0;
8330 : stra.AppendLiteral("C:\\mozilla\\mozilla\\debug\\filea");
8331 : stra.AppendInt(num);
8332 : stra.AppendLiteral(".png");
8333 : DumpToPNG(sh, stra);
8334 : nsString strb;
8335 : strb.AppendLiteral("C:\\mozilla\\mozilla\\debug\\fileb");
8336 : strb.AppendInt(num);
8337 : strb.AppendLiteral(".png");
8338 : DumpToPNG(this, strb);
8339 : ++num;
8340 : }
8341 : #endif
8342 :
8343 0 : sh->EndObservingDocument();
8344 0 : sh->Destroy();
8345 0 : if (VERIFY_REFLOW_NOISY & gVerifyReflowFlags) {
8346 0 : printf("Finished Verifying Reflow...\n");
8347 : }
8348 :
8349 0 : return ok;
8350 : }
8351 :
8352 : // Layout debugging hooks
8353 : void
8354 0 : PresShell::ListStyleContexts(nsIFrame *aRootFrame, FILE *out, PRInt32 aIndent)
8355 : {
8356 0 : nsStyleContext *sc = aRootFrame->GetStyleContext();
8357 0 : if (sc)
8358 0 : sc->List(out, aIndent);
8359 0 : }
8360 :
8361 : void
8362 0 : PresShell::ListStyleSheets(FILE *out, PRInt32 aIndent)
8363 : {
8364 0 : PRInt32 sheetCount = mStyleSet->SheetCount(nsStyleSet::eDocSheet);
8365 0 : for (PRInt32 i = 0; i < sheetCount; ++i) {
8366 0 : mStyleSet->StyleSheetAt(nsStyleSet::eDocSheet, i)->List(out, aIndent);
8367 0 : fputs("\n", out);
8368 : }
8369 0 : }
8370 :
8371 : void
8372 0 : PresShell::VerifyStyleTree()
8373 : {
8374 0 : VERIFY_STYLE_TREE;
8375 0 : }
8376 : #endif
8377 :
8378 : //=============================================================
8379 : //=============================================================
8380 : //-- Debug Reflow Counts
8381 : //=============================================================
8382 : //=============================================================
8383 : #ifdef MOZ_REFLOW_PERF
8384 : //-------------------------------------------------------------
8385 : void
8386 0 : PresShell::DumpReflows()
8387 : {
8388 0 : if (mReflowCountMgr) {
8389 0 : nsCAutoString uriStr;
8390 0 : if (mDocument) {
8391 0 : nsIURI *uri = mDocument->GetDocumentURI();
8392 0 : if (uri) {
8393 0 : uri->GetPath(uriStr);
8394 : }
8395 : }
8396 0 : mReflowCountMgr->DisplayTotals(uriStr.get());
8397 0 : mReflowCountMgr->DisplayHTMLTotals(uriStr.get());
8398 0 : mReflowCountMgr->DisplayDiffsInTotals("Differences");
8399 : }
8400 0 : }
8401 :
8402 : //-------------------------------------------------------------
8403 : void
8404 0 : PresShell::CountReflows(const char * aName, nsIFrame * aFrame)
8405 : {
8406 0 : if (mReflowCountMgr) {
8407 0 : mReflowCountMgr->Add(aName, aFrame);
8408 : }
8409 0 : }
8410 :
8411 : //-------------------------------------------------------------
8412 : void
8413 0 : PresShell::PaintCount(const char * aName,
8414 : nsRenderingContext* aRenderingContext,
8415 : nsPresContext* aPresContext,
8416 : nsIFrame * aFrame,
8417 : const nsPoint& aOffset,
8418 : PRUint32 aColor)
8419 : {
8420 0 : if (mReflowCountMgr) {
8421 : mReflowCountMgr->PaintCount(aName, aRenderingContext, aPresContext,
8422 0 : aFrame, aOffset, aColor);
8423 : }
8424 0 : }
8425 :
8426 : //-------------------------------------------------------------
8427 : void
8428 0 : PresShell::SetPaintFrameCount(bool aPaintFrameCounts)
8429 : {
8430 0 : if (mReflowCountMgr) {
8431 0 : mReflowCountMgr->SetPaintFrameCounts(aPaintFrameCounts);
8432 : }
8433 0 : }
8434 :
8435 : bool
8436 0 : PresShell::IsPaintingFrameCounts()
8437 : {
8438 0 : if (mReflowCountMgr)
8439 0 : return mReflowCountMgr->IsPaintingFrameCounts();
8440 0 : return false;
8441 : }
8442 :
8443 : //------------------------------------------------------------------
8444 : //-- Reflow Counter Classes Impls
8445 : //------------------------------------------------------------------
8446 :
8447 : //------------------------------------------------------------------
8448 0 : ReflowCounter::ReflowCounter(ReflowCountMgr * aMgr) :
8449 0 : mMgr(aMgr)
8450 : {
8451 0 : ClearTotals();
8452 0 : SetTotalsCache();
8453 0 : }
8454 :
8455 : //------------------------------------------------------------------
8456 0 : ReflowCounter::~ReflowCounter()
8457 : {
8458 :
8459 0 : }
8460 :
8461 : //------------------------------------------------------------------
8462 0 : void ReflowCounter::ClearTotals()
8463 : {
8464 0 : mTotal = 0;
8465 0 : }
8466 :
8467 : //------------------------------------------------------------------
8468 0 : void ReflowCounter::SetTotalsCache()
8469 : {
8470 0 : mCacheTotal = mTotal;
8471 0 : }
8472 :
8473 : //------------------------------------------------------------------
8474 0 : void ReflowCounter::CalcDiffInTotals()
8475 : {
8476 0 : mCacheTotal = mTotal - mCacheTotal;
8477 0 : }
8478 :
8479 : //------------------------------------------------------------------
8480 0 : void ReflowCounter::DisplayTotals(const char * aStr)
8481 : {
8482 0 : DisplayTotals(mTotal, aStr?aStr:"Totals");
8483 0 : }
8484 :
8485 : //------------------------------------------------------------------
8486 0 : void ReflowCounter::DisplayDiffTotals(const char * aStr)
8487 : {
8488 0 : DisplayTotals(mCacheTotal, aStr?aStr:"Diff Totals");
8489 0 : }
8490 :
8491 : //------------------------------------------------------------------
8492 0 : void ReflowCounter::DisplayHTMLTotals(const char * aStr)
8493 : {
8494 0 : DisplayHTMLTotals(mTotal, aStr?aStr:"Totals");
8495 0 : }
8496 :
8497 : //------------------------------------------------------------------
8498 0 : void ReflowCounter::DisplayTotals(PRUint32 aTotal, const char * aTitle)
8499 : {
8500 : // figure total
8501 0 : if (aTotal == 0) {
8502 0 : return;
8503 : }
8504 0 : ReflowCounter * gTots = (ReflowCounter *)mMgr->LookUp(kGrandTotalsStr);
8505 :
8506 0 : printf("%25s\t", aTitle);
8507 0 : printf("%d\t", aTotal);
8508 0 : if (gTots != this && aTotal > 0) {
8509 0 : gTots->Add(aTotal);
8510 : }
8511 : }
8512 :
8513 : //------------------------------------------------------------------
8514 0 : void ReflowCounter::DisplayHTMLTotals(PRUint32 aTotal, const char * aTitle)
8515 : {
8516 0 : if (aTotal == 0) {
8517 0 : return;
8518 : }
8519 :
8520 0 : ReflowCounter * gTots = (ReflowCounter *)mMgr->LookUp(kGrandTotalsStr);
8521 0 : FILE * fd = mMgr->GetOutFile();
8522 0 : if (!fd) {
8523 0 : return;
8524 : }
8525 :
8526 0 : fprintf(fd, "<tr><td><center>%s</center></td>", aTitle);
8527 0 : fprintf(fd, "<td><center>%d</center></td></tr>\n", aTotal);
8528 :
8529 0 : if (gTots != this && aTotal > 0) {
8530 0 : gTots->Add(aTotal);
8531 : }
8532 : }
8533 :
8534 : //------------------------------------------------------------------
8535 : //-- ReflowCountMgr
8536 : //------------------------------------------------------------------
8537 0 : ReflowCountMgr::ReflowCountMgr()
8538 : {
8539 : mCounts = PL_NewHashTable(10, PL_HashString, PL_CompareStrings,
8540 0 : PL_CompareValues, nsnull, nsnull);
8541 : mIndiFrameCounts = PL_NewHashTable(10, PL_HashString, PL_CompareStrings,
8542 0 : PL_CompareValues, nsnull, nsnull);
8543 0 : mCycledOnce = false;
8544 0 : mDumpFrameCounts = false;
8545 0 : mDumpFrameByFrameCounts = false;
8546 0 : mPaintFrameByFrameCounts = false;
8547 0 : }
8548 :
8549 : //------------------------------------------------------------------
8550 0 : ReflowCountMgr::~ReflowCountMgr()
8551 : {
8552 0 : CleanUp();
8553 0 : }
8554 :
8555 : //------------------------------------------------------------------
8556 0 : ReflowCounter * ReflowCountMgr::LookUp(const char * aName)
8557 : {
8558 0 : if (nsnull != mCounts) {
8559 0 : ReflowCounter * counter = (ReflowCounter *)PL_HashTableLookup(mCounts, aName);
8560 0 : return counter;
8561 : }
8562 0 : return nsnull;
8563 :
8564 : }
8565 :
8566 : //------------------------------------------------------------------
8567 0 : void ReflowCountMgr::Add(const char * aName, nsIFrame * aFrame)
8568 : {
8569 0 : NS_ASSERTION(aName != nsnull, "Name shouldn't be null!");
8570 :
8571 0 : if (mDumpFrameCounts && nsnull != mCounts) {
8572 0 : ReflowCounter * counter = (ReflowCounter *)PL_HashTableLookup(mCounts, aName);
8573 0 : if (counter == nsnull) {
8574 0 : counter = new ReflowCounter(this);
8575 0 : char * name = NS_strdup(aName);
8576 0 : NS_ASSERTION(name != nsnull, "null ptr");
8577 0 : PL_HashTableAdd(mCounts, name, counter);
8578 : }
8579 0 : counter->Add();
8580 : }
8581 :
8582 0 : if ((mDumpFrameByFrameCounts || mPaintFrameByFrameCounts) &&
8583 : nsnull != mIndiFrameCounts &&
8584 : aFrame != nsnull) {
8585 0 : char * key = new char[16];
8586 0 : sprintf(key, "%p", (void*)aFrame);
8587 0 : IndiReflowCounter * counter = (IndiReflowCounter *)PL_HashTableLookup(mIndiFrameCounts, key);
8588 0 : if (counter == nsnull) {
8589 0 : counter = new IndiReflowCounter(this);
8590 0 : counter->mFrame = aFrame;
8591 0 : counter->mName.AssignASCII(aName);
8592 0 : PL_HashTableAdd(mIndiFrameCounts, key, counter);
8593 : }
8594 : // this eliminates extra counts from super classes
8595 0 : if (counter != nsnull && counter->mName.EqualsASCII(aName)) {
8596 0 : counter->mCount++;
8597 0 : counter->mCounter.Add(1);
8598 : }
8599 : }
8600 0 : }
8601 :
8602 : //------------------------------------------------------------------
8603 0 : void ReflowCountMgr::PaintCount(const char* aName,
8604 : nsRenderingContext* aRenderingContext,
8605 : nsPresContext* aPresContext,
8606 : nsIFrame* aFrame,
8607 : const nsPoint& aOffset,
8608 : PRUint32 aColor)
8609 : {
8610 0 : if (mPaintFrameByFrameCounts &&
8611 : nsnull != mIndiFrameCounts &&
8612 : aFrame != nsnull) {
8613 0 : char * key = new char[16];
8614 0 : sprintf(key, "%p", (void*)aFrame);
8615 : IndiReflowCounter * counter =
8616 0 : (IndiReflowCounter *)PL_HashTableLookup(mIndiFrameCounts, key);
8617 0 : if (counter != nsnull && counter->mName.EqualsASCII(aName)) {
8618 0 : aRenderingContext->PushState();
8619 0 : aRenderingContext->Translate(aOffset);
8620 : nsFont font("Times", NS_FONT_STYLE_NORMAL, NS_FONT_VARIANT_NORMAL,
8621 : NS_FONT_WEIGHT_NORMAL, NS_FONT_STRETCH_NORMAL, 0,
8622 0 : nsPresContext::CSSPixelsToAppUnits(11));
8623 :
8624 0 : nsRefPtr<nsFontMetrics> fm;
8625 : aPresContext->DeviceContext()->GetMetricsFor(font,
8626 : // We have one frame, therefore we must have a root...
8627 : aPresContext->GetPresShell()->GetRootFrame()->
8628 0 : GetStyleFont()->mLanguage,
8629 0 : aPresContext->GetUserFontSet(), *getter_AddRefs(fm));
8630 :
8631 0 : aRenderingContext->SetFont(fm);
8632 : char buf[16];
8633 0 : sprintf(buf, "%d", counter->mCount);
8634 0 : nscoord x = 0, y = fm->MaxAscent();
8635 0 : nscoord width, height = fm->MaxHeight();
8636 0 : aRenderingContext->SetTextRunRTL(false);
8637 0 : width = aRenderingContext->GetWidth(buf);
8638 :
8639 : PRUint32 color;
8640 : PRUint32 color2;
8641 0 : if (aColor != 0) {
8642 0 : color = aColor;
8643 0 : color2 = NS_RGB(0,0,0);
8644 : } else {
8645 0 : PRUint8 rc = 0, gc = 0, bc = 0;
8646 0 : if (counter->mCount < 5) {
8647 0 : rc = 255;
8648 0 : gc = 255;
8649 0 : } else if ( counter->mCount < 11) {
8650 0 : gc = 255;
8651 : } else {
8652 0 : rc = 255;
8653 : }
8654 0 : color = NS_RGB(rc,gc,bc);
8655 0 : color2 = NS_RGB(rc/2,gc/2,bc/2);
8656 : }
8657 :
8658 0 : nsRect rect(0,0, width+15, height+15);
8659 0 : aRenderingContext->SetColor(NS_RGB(0,0,0));
8660 0 : aRenderingContext->FillRect(rect);
8661 0 : aRenderingContext->SetColor(color2);
8662 0 : aRenderingContext->DrawString(buf, strlen(buf), x+15,y+15);
8663 0 : aRenderingContext->SetColor(color);
8664 0 : aRenderingContext->DrawString(buf, strlen(buf), x,y);
8665 :
8666 0 : aRenderingContext->PopState();
8667 : }
8668 : }
8669 0 : }
8670 :
8671 : //------------------------------------------------------------------
8672 0 : PRIntn ReflowCountMgr::RemoveItems(PLHashEntry *he, PRIntn i, void *arg)
8673 : {
8674 0 : char *str = (char *)he->key;
8675 0 : ReflowCounter * counter = (ReflowCounter *)he->value;
8676 0 : delete counter;
8677 0 : NS_Free(str);
8678 :
8679 0 : return HT_ENUMERATE_REMOVE;
8680 : }
8681 :
8682 : //------------------------------------------------------------------
8683 0 : PRIntn ReflowCountMgr::RemoveIndiItems(PLHashEntry *he, PRIntn i, void *arg)
8684 : {
8685 0 : char *str = (char *)he->key;
8686 0 : IndiReflowCounter * counter = (IndiReflowCounter *)he->value;
8687 0 : delete counter;
8688 0 : NS_Free(str);
8689 :
8690 0 : return HT_ENUMERATE_REMOVE;
8691 : }
8692 :
8693 : //------------------------------------------------------------------
8694 0 : void ReflowCountMgr::CleanUp()
8695 : {
8696 0 : if (nsnull != mCounts) {
8697 0 : PL_HashTableEnumerateEntries(mCounts, RemoveItems, nsnull);
8698 0 : PL_HashTableDestroy(mCounts);
8699 0 : mCounts = nsnull;
8700 : }
8701 :
8702 0 : if (nsnull != mIndiFrameCounts) {
8703 0 : PL_HashTableEnumerateEntries(mIndiFrameCounts, RemoveIndiItems, nsnull);
8704 0 : PL_HashTableDestroy(mIndiFrameCounts);
8705 0 : mIndiFrameCounts = nsnull;
8706 : }
8707 0 : }
8708 :
8709 : //------------------------------------------------------------------
8710 0 : PRIntn ReflowCountMgr::DoSingleTotal(PLHashEntry *he, PRIntn i, void *arg)
8711 : {
8712 0 : char *str = (char *)he->key;
8713 0 : ReflowCounter * counter = (ReflowCounter *)he->value;
8714 :
8715 0 : counter->DisplayTotals(str);
8716 :
8717 0 : return HT_ENUMERATE_NEXT;
8718 : }
8719 :
8720 : //------------------------------------------------------------------
8721 0 : void ReflowCountMgr::DoGrandTotals()
8722 : {
8723 0 : if (nsnull != mCounts) {
8724 0 : ReflowCounter * gTots = (ReflowCounter *)PL_HashTableLookup(mCounts, kGrandTotalsStr);
8725 0 : if (gTots == nsnull) {
8726 0 : gTots = new ReflowCounter(this);
8727 0 : PL_HashTableAdd(mCounts, NS_strdup(kGrandTotalsStr), gTots);
8728 : } else {
8729 0 : gTots->ClearTotals();
8730 : }
8731 :
8732 0 : printf("\t\t\t\tTotal\n");
8733 0 : for (PRUint32 i=0;i<78;i++) {
8734 0 : printf("-");
8735 : }
8736 0 : printf("\n");
8737 0 : PL_HashTableEnumerateEntries(mCounts, DoSingleTotal, this);
8738 : }
8739 0 : }
8740 :
8741 0 : static void RecurseIndiTotals(nsPresContext* aPresContext,
8742 : PLHashTable * aHT,
8743 : nsIFrame * aParentFrame,
8744 : PRInt32 aLevel)
8745 : {
8746 0 : if (aParentFrame == nsnull) {
8747 0 : return;
8748 : }
8749 :
8750 : char key[16];
8751 0 : sprintf(key, "%p", (void*)aParentFrame);
8752 0 : IndiReflowCounter * counter = (IndiReflowCounter *)PL_HashTableLookup(aHT, key);
8753 0 : if (counter) {
8754 0 : counter->mHasBeenOutput = true;
8755 0 : char * name = ToNewCString(counter->mName);
8756 0 : for (PRInt32 i=0;i<aLevel;i++) printf(" ");
8757 0 : printf("%s - %p [%d][", name, (void*)aParentFrame, counter->mCount);
8758 0 : printf("%d", counter->mCounter.GetTotal());
8759 0 : printf("]\n");
8760 0 : nsMemory::Free(name);
8761 : }
8762 :
8763 0 : nsIFrame* child = aParentFrame->GetFirstPrincipalChild();
8764 0 : while (child) {
8765 0 : RecurseIndiTotals(aPresContext, aHT, child, aLevel+1);
8766 0 : child = child->GetNextSibling();
8767 : }
8768 :
8769 : }
8770 :
8771 : //------------------------------------------------------------------
8772 0 : PRIntn ReflowCountMgr::DoSingleIndi(PLHashEntry *he, PRIntn i, void *arg)
8773 : {
8774 0 : IndiReflowCounter * counter = (IndiReflowCounter *)he->value;
8775 0 : if (counter && !counter->mHasBeenOutput) {
8776 0 : char * name = ToNewCString(counter->mName);
8777 0 : printf("%s - %p [%d][", name, (void*)counter->mFrame, counter->mCount);
8778 0 : printf("%d", counter->mCounter.GetTotal());
8779 0 : printf("]\n");
8780 0 : nsMemory::Free(name);
8781 : }
8782 0 : return HT_ENUMERATE_NEXT;
8783 : }
8784 :
8785 : //------------------------------------------------------------------
8786 0 : void ReflowCountMgr::DoIndiTotalsTree()
8787 : {
8788 0 : if (nsnull != mCounts) {
8789 0 : printf("\n------------------------------------------------\n");
8790 0 : printf("-- Individual Frame Counts\n");
8791 0 : printf("------------------------------------------------\n");
8792 :
8793 0 : if (mPresShell) {
8794 0 : nsIFrame * rootFrame = mPresShell->FrameManager()->GetRootFrame();
8795 0 : RecurseIndiTotals(mPresContext, mIndiFrameCounts, rootFrame, 0);
8796 0 : printf("------------------------------------------------\n");
8797 0 : printf("-- Individual Counts of Frames not in Root Tree\n");
8798 0 : printf("------------------------------------------------\n");
8799 0 : PL_HashTableEnumerateEntries(mIndiFrameCounts, DoSingleIndi, this);
8800 : }
8801 : }
8802 0 : }
8803 :
8804 : //------------------------------------------------------------------
8805 0 : PRIntn ReflowCountMgr::DoSingleHTMLTotal(PLHashEntry *he, PRIntn i, void *arg)
8806 : {
8807 0 : char *str = (char *)he->key;
8808 0 : ReflowCounter * counter = (ReflowCounter *)he->value;
8809 :
8810 0 : counter->DisplayHTMLTotals(str);
8811 :
8812 0 : return HT_ENUMERATE_NEXT;
8813 : }
8814 :
8815 : //------------------------------------------------------------------
8816 0 : void ReflowCountMgr::DoGrandHTMLTotals()
8817 : {
8818 0 : if (nsnull != mCounts) {
8819 0 : ReflowCounter * gTots = (ReflowCounter *)PL_HashTableLookup(mCounts, kGrandTotalsStr);
8820 0 : if (gTots == nsnull) {
8821 0 : gTots = new ReflowCounter(this);
8822 0 : PL_HashTableAdd(mCounts, NS_strdup(kGrandTotalsStr), gTots);
8823 : } else {
8824 0 : gTots->ClearTotals();
8825 : }
8826 :
8827 : static const char * title[] = {"Class", "Reflows"};
8828 0 : fprintf(mFD, "<tr>");
8829 0 : for (PRUint32 i=0; i < ArrayLength(title); i++) {
8830 0 : fprintf(mFD, "<td><center><b>%s<b></center></td>", title[i]);
8831 : }
8832 0 : fprintf(mFD, "</tr>\n");
8833 0 : PL_HashTableEnumerateEntries(mCounts, DoSingleHTMLTotal, this);
8834 : }
8835 0 : }
8836 :
8837 : //------------------------------------
8838 0 : void ReflowCountMgr::DisplayTotals(const char * aStr)
8839 : {
8840 : #ifdef DEBUG_rods
8841 : printf("%s\n", aStr?aStr:"No name");
8842 : #endif
8843 0 : if (mDumpFrameCounts) {
8844 0 : DoGrandTotals();
8845 : }
8846 0 : if (mDumpFrameByFrameCounts) {
8847 0 : DoIndiTotalsTree();
8848 : }
8849 :
8850 0 : }
8851 : //------------------------------------
8852 0 : void ReflowCountMgr::DisplayHTMLTotals(const char * aStr)
8853 : {
8854 : #ifdef WIN32x // XXX NOT XP!
8855 : char name[1024];
8856 :
8857 : char * sptr = strrchr(aStr, '/');
8858 : if (sptr) {
8859 : sptr++;
8860 : strcpy(name, sptr);
8861 : char * eptr = strrchr(name, '.');
8862 : if (eptr) {
8863 : *eptr = 0;
8864 : }
8865 : strcat(name, "_stats.html");
8866 : }
8867 : mFD = fopen(name, "w");
8868 : if (mFD) {
8869 : fprintf(mFD, "<html><head><title>Reflow Stats</title></head><body>\n");
8870 : const char * title = aStr?aStr:"No name";
8871 : fprintf(mFD, "<center><b>%s</b><br><table border=1 style=\"background-color:#e0e0e0\">", title);
8872 : DoGrandHTMLTotals();
8873 : fprintf(mFD, "</center></table>\n");
8874 : fprintf(mFD, "</body></html>\n");
8875 : fclose(mFD);
8876 : mFD = nsnull;
8877 : }
8878 : #endif // not XP!
8879 0 : }
8880 :
8881 : //------------------------------------------------------------------
8882 0 : PRIntn ReflowCountMgr::DoClearTotals(PLHashEntry *he, PRIntn i, void *arg)
8883 : {
8884 0 : ReflowCounter * counter = (ReflowCounter *)he->value;
8885 0 : counter->ClearTotals();
8886 :
8887 0 : return HT_ENUMERATE_NEXT;
8888 : }
8889 :
8890 : //------------------------------------------------------------------
8891 0 : void ReflowCountMgr::ClearTotals()
8892 : {
8893 0 : PL_HashTableEnumerateEntries(mCounts, DoClearTotals, this);
8894 0 : }
8895 :
8896 : //------------------------------------------------------------------
8897 0 : void ReflowCountMgr::ClearGrandTotals()
8898 : {
8899 0 : if (nsnull != mCounts) {
8900 0 : ReflowCounter * gTots = (ReflowCounter *)PL_HashTableLookup(mCounts, kGrandTotalsStr);
8901 0 : if (gTots == nsnull) {
8902 0 : gTots = new ReflowCounter(this);
8903 0 : PL_HashTableAdd(mCounts, NS_strdup(kGrandTotalsStr), gTots);
8904 : } else {
8905 0 : gTots->ClearTotals();
8906 0 : gTots->SetTotalsCache();
8907 : }
8908 : }
8909 0 : }
8910 :
8911 : //------------------------------------------------------------------
8912 0 : PRIntn ReflowCountMgr::DoDisplayDiffTotals(PLHashEntry *he, PRIntn i, void *arg)
8913 : {
8914 0 : bool cycledOnce = (arg != 0);
8915 :
8916 0 : char *str = (char *)he->key;
8917 0 : ReflowCounter * counter = (ReflowCounter *)he->value;
8918 :
8919 0 : if (cycledOnce) {
8920 0 : counter->CalcDiffInTotals();
8921 0 : counter->DisplayDiffTotals(str);
8922 : }
8923 0 : counter->SetTotalsCache();
8924 :
8925 0 : return HT_ENUMERATE_NEXT;
8926 : }
8927 :
8928 : //------------------------------------------------------------------
8929 0 : void ReflowCountMgr::DisplayDiffsInTotals(const char * aStr)
8930 : {
8931 0 : if (mCycledOnce) {
8932 0 : printf("Differences\n");
8933 0 : for (PRInt32 i=0;i<78;i++) {
8934 0 : printf("-");
8935 : }
8936 0 : printf("\n");
8937 0 : ClearGrandTotals();
8938 : }
8939 0 : PL_HashTableEnumerateEntries(mCounts, DoDisplayDiffTotals, (void *)mCycledOnce);
8940 :
8941 0 : mCycledOnce = true;
8942 0 : }
8943 :
8944 : #endif // MOZ_REFLOW_PERF
8945 :
8946 : // make a color string like #RRGGBB
8947 0 : void ColorToString(nscolor aColor, nsAutoString &aString)
8948 : {
8949 : char buf[8];
8950 :
8951 : PR_snprintf(buf, sizeof(buf), "#%02x%02x%02x",
8952 0 : NS_GET_R(aColor), NS_GET_G(aColor), NS_GET_B(aColor));
8953 0 : CopyASCIItoUTF16(buf, aString);
8954 0 : }
8955 :
8956 0 : nsIFrame* nsIPresShell::GetAbsoluteContainingBlock(nsIFrame *aFrame)
8957 : {
8958 0 : return FrameConstructor()->GetAbsoluteContainingBlock(aFrame);
8959 : }
8960 :
8961 : #ifdef ACCESSIBILITY
8962 : bool
8963 0 : nsIPresShell::IsAccessibilityActive()
8964 : {
8965 0 : return GetAccService() != nsnull;
8966 : }
8967 :
8968 : nsAccessibilityService*
8969 0 : nsIPresShell::AccService()
8970 : {
8971 0 : return GetAccService();
8972 : }
8973 : #endif
8974 :
8975 : static bool inited = false;
8976 :
8977 1404 : void nsIPresShell::InitializeStatics()
8978 : {
8979 1404 : NS_ASSERTION(!inited, "InitializeStatics called multiple times!");
8980 1404 : gCaptureTouchList.Init();
8981 1404 : inited = true;
8982 1404 : }
8983 :
8984 1403 : void nsIPresShell::ReleaseStatics()
8985 : {
8986 1403 : NS_ASSERTION(inited, "ReleaseStatics called without Initialize!");
8987 1403 : }
8988 :
8989 : // Asks our docshell whether we're active.
8990 0 : void PresShell::QueryIsActive()
8991 : {
8992 0 : nsCOMPtr<nsISupports> container = mPresContext->GetContainer();
8993 0 : if (mDocument) {
8994 0 : nsIDocument* displayDoc = mDocument->GetDisplayDocument();
8995 0 : if (displayDoc) {
8996 : // Ok, we're an external resource document -- we need to use our display
8997 : // document's docshell to determine "IsActive" status, since we lack
8998 : // a container.
8999 0 : NS_ABORT_IF_FALSE(!container,
9000 : "external resource doc shouldn't have "
9001 : "its own container");
9002 :
9003 0 : nsIPresShell* displayPresShell = displayDoc->GetShell();
9004 0 : if (displayPresShell) {
9005 0 : container = displayPresShell->GetPresContext()->GetContainer();
9006 : }
9007 : }
9008 : }
9009 :
9010 0 : nsCOMPtr<nsIDocShell> docshell(do_QueryInterface(container));
9011 0 : if (docshell) {
9012 : bool isActive;
9013 0 : nsresult rv = docshell->GetIsActive(&isActive);
9014 0 : if (NS_SUCCEEDED(rv))
9015 0 : SetIsActive(isActive);
9016 : }
9017 0 : }
9018 :
9019 : // Helper for propagating mIsActive changes to external resources
9020 : static bool
9021 0 : SetExternalResourceIsActive(nsIDocument* aDocument, void* aClosure)
9022 : {
9023 0 : nsIPresShell* shell = aDocument->GetShell();
9024 0 : if (shell) {
9025 0 : shell->SetIsActive(*static_cast<bool*>(aClosure));
9026 : }
9027 0 : return true;
9028 : }
9029 :
9030 : static void
9031 0 : SetPluginIsActive(nsIContent* aContent, void* aClosure)
9032 : {
9033 0 : nsIFrame *frame = aContent->GetPrimaryFrame();
9034 0 : nsIObjectFrame *objectFrame = do_QueryFrame(frame);
9035 0 : if (objectFrame) {
9036 0 : objectFrame->SetIsDocumentActive(*static_cast<bool*>(aClosure));
9037 : }
9038 0 : }
9039 :
9040 : nsresult
9041 0 : PresShell::SetIsActive(bool aIsActive)
9042 : {
9043 0 : NS_PRECONDITION(mDocument, "should only be called with a document");
9044 :
9045 0 : mIsActive = aIsActive;
9046 0 : nsPresContext* presContext = GetPresContext();
9047 0 : if (presContext &&
9048 0 : presContext->RefreshDriver()->PresContext() == presContext) {
9049 0 : presContext->RefreshDriver()->SetThrottled(!mIsActive);
9050 : }
9051 :
9052 : // Propagate state-change to my resource documents' PresShells
9053 : mDocument->EnumerateExternalResources(SetExternalResourceIsActive,
9054 0 : &aIsActive);
9055 : mDocument->EnumerateFreezableElements(SetPluginIsActive,
9056 0 : &aIsActive);
9057 0 : nsresult rv = UpdateImageLockingState();
9058 : #ifdef ACCESSIBILITY
9059 0 : if (aIsActive) {
9060 0 : nsAccessibilityService* accService = AccService();
9061 0 : if (accService) {
9062 0 : accService->PresShellActivated(this);
9063 : }
9064 : }
9065 : #endif
9066 0 : return rv;
9067 : }
9068 :
9069 : /*
9070 : * Determines the current image locking state. Called when one of the
9071 : * dependent factors changes.
9072 : */
9073 : nsresult
9074 0 : PresShell::UpdateImageLockingState()
9075 : {
9076 : // We're locked if we're both thawed and active.
9077 0 : return mDocument->SetImageLockingState(!mFrozen && mIsActive);
9078 : }
9079 :
9080 : PresShell*
9081 0 : PresShell::GetRootPresShell()
9082 : {
9083 0 : if (mPresContext) {
9084 0 : nsPresContext* rootPresContext = mPresContext->GetRootPresContext();
9085 0 : if (rootPresContext) {
9086 0 : return static_cast<PresShell*>(rootPresContext->PresShell());
9087 : }
9088 : }
9089 0 : return nsnull;
9090 : }
9091 :
9092 : void
9093 0 : PresShell::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
9094 : size_t *aArenasSize,
9095 : size_t *aStyleSetsSize,
9096 : size_t *aTextRunsSize) const
9097 : {
9098 0 : *aArenasSize = aMallocSizeOf(this);
9099 0 : *aArenasSize += mStackArena.SizeOfExcludingThis(aMallocSizeOf);
9100 0 : *aArenasSize += mFrameArena.SizeOfExcludingThis(aMallocSizeOf);
9101 :
9102 0 : *aStyleSetsSize = StyleSet()->SizeOfIncludingThis(aMallocSizeOf);
9103 :
9104 0 : *aTextRunsSize = SizeOfTextRuns(aMallocSizeOf);
9105 0 : }
9106 :
9107 : size_t
9108 0 : PresShell::SizeOfTextRuns(nsMallocSizeOfFun aMallocSizeOf) const
9109 : {
9110 0 : nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
9111 0 : if (!rootFrame) {
9112 0 : return 0;
9113 : }
9114 :
9115 : // clear the TEXT_RUN_MEMORY_ACCOUNTED flags
9116 : nsLayoutUtils::SizeOfTextRunsForFrames(rootFrame, nsnull,
9117 0 : /* clear = */true);
9118 :
9119 : // collect the total memory in use for textruns
9120 : return nsLayoutUtils::SizeOfTextRunsForFrames(rootFrame, aMallocSizeOf,
9121 0 : /* clear = */false);
9122 4392 : }
9123 :
|