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 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 * This Original Code has been modified by IBM Corporation.
8 * Modifications made by IBM described herein are
9 * Copyright (c) International Business Machines
12 * Modifications to Mozilla code or documentation
13 * identified per MPL Section 3.3
15 * Date Modified by Description of modification
16 * 05/03/2000 IBM Corp. Observer events for reflow states
19 /* a presentation of a document, part 2 */
22 #define FORCE_PR_LOG /* Allow logging in the release build */
26 #include "mozilla/ArrayUtils.h"
27 #include "mozilla/CSSStyleSheet.h"
28 #include "mozilla/EventDispatcher.h"
29 #include "mozilla/EventStateManager.h"
30 #include "mozilla/EventStates.h"
31 #include "mozilla/IMEStateManager.h"
32 #include "mozilla/MemoryReporting.h"
33 #include "mozilla/dom/TabChild.h"
34 #include "mozilla/Likely.h"
35 #include "mozilla/MouseEvents.h"
36 #include "mozilla/TextEvents.h"
37 #include "mozilla/TouchEvents.h"
38 #include "mozilla/UniquePtr.h"
45 #include "nsPresShell.h"
46 #include "nsPresContext.h"
47 #include "nsIContent.h"
48 #include "mozilla/dom/Element.h"
49 #include "mozilla/dom/Event.h" // for Event::GetEventPopupControlState()
50 #include "mozilla/dom/ShadowRoot.h"
51 #include "mozilla/dom/PointerEvent.h"
52 #include "nsIDocument.h"
53 #include "nsAnimationManager.h"
54 #include "nsNameSpaceManager.h" // for Pref-related rule management (bugs 22963,20760,31816)
56 #include "FrameLayerBuilder.h"
57 #include "nsViewManager.h"
59 #include "nsCRTGlue.h"
63 #include "nsCOMArray.h"
64 #include "nsContainerFrame.h"
65 #include "nsISelection.h"
66 #include "mozilla/dom/Selection.h"
67 #include "nsGkAtoms.h"
68 #include "nsIDOMRange.h"
69 #include "nsIDOMDocument.h"
70 #include "nsIDOMNode.h"
71 #include "nsIDOMNodeList.h"
72 #include "nsIDOMElement.h"
75 #include "nsAutoPtr.h"
76 #include "nsReadableUtils.h"
77 #include "nsIPageSequenceFrame.h"
79 #include "TouchCaret.h"
80 #include "SelectionCarets.h"
81 #include "nsIDOMHTMLDocument.h"
82 #include "nsFrameManager.h"
84 #include "nsILayoutHistoryState.h"
85 #include "nsILineIterator.h" // for ScrollContentIntoView
87 #include "mozilla/dom/Touch.h"
88 #include "mozilla/dom/PointerEventBinding.h"
89 #include "nsIObserverService.h"
90 #include "nsDocShell.h" // for reflow observation
91 #include "nsIBaseWindow.h"
93 #include "nsLayoutUtils.h"
94 #include "nsViewportInfo.h"
95 #include "nsCSSRendering.h"
96 // for |#ifdef DEBUG| code
98 #include "nsDisplayList.h"
100 #include "nsRenderingContext.h"
101 #include "nsAutoLayoutPhase.h"
102 #ifdef MOZ_REFLOW_PERF
103 #include "nsFontMetrics.h"
105 #include "PositionedEventTargeting.h"
107 #include "nsIReflowCallback.h"
109 #include "nsPIDOMWindow.h"
110 #include "nsFocusManager.h"
111 #include "nsIObjectFrame.h"
112 #include "nsIObjectLoadingContent.h"
113 #include "nsNetUtil.h"
114 #include "nsThreadUtils.h"
115 #include "nsStyleSheetService.h"
116 #include "gfxContext.h"
117 #include "gfxUtils.h"
118 #include "nsSMILAnimationController.h"
119 #include "SVGContentUtils.h"
120 #include "nsSVGEffects.h"
121 #include "SVGFragmentIdentifier.h"
122 #include "nsArenaMemoryStats.h"
123 #include "nsFrameSelection.h"
125 #include "nsPerformance.h"
126 #include "nsRefreshDriver.h"
127 #include "nsDOMNavigationTiming.h"
129 // Drag & Drop, Clipboard
130 #include "nsIDocShellTreeItem.h"
132 #include "nsIScrollableFrame.h"
133 #include "nsITimer.h"
135 #include "nsAccessibilityService.h"
136 #include "mozilla/a11y/DocAccessible.h"
138 #include "mozilla/a11y/Logging.h"
142 // For style data reconstruction
143 #include "nsStyleChangeList.h"
144 #include "nsCSSFrameConstructor.h"
146 #include "nsMenuFrame.h"
147 #include "nsTreeBodyFrame.h"
148 #include "nsIBoxObject.h"
149 #include "nsITreeBoxObject.h"
150 #include "nsMenuPopupFrame.h"
151 #include "nsITreeColumns.h"
152 #include "nsIDOMXULMultSelectCntrlEl.h"
153 #include "nsIDOMXULSelectCntrlItemEl.h"
154 #include "nsIDOMXULMenuListElement.h"
158 #include "GeckoProfiler.h"
159 #include "gfxPlatform.h"
161 #include "LayerTreeInvalidation.h"
162 #include "mozilla/css/ImageLoader.h"
163 #include "mozilla/Preferences.h"
164 #include "mozilla/Telemetry.h"
165 #include "nsCanvasFrame.h"
166 #include "nsIImageLoadingContent.h"
167 #include "nsIScreen.h"
168 #include "nsIScreenManager.h"
169 #include "nsPlaceholderFrame.h"
170 #include "nsTransitionManager.h"
171 #include "ChildIterator.h"
172 #include "RestyleManager.h"
173 #include "nsIDOMHTMLElement.h"
174 #include "nsIDragSession.h"
175 #include "nsIFrameInlines.h"
176 #include "mozilla/gfx/2D.h"
177 #include "nsSubDocumentFrame.h"
180 #include "nsIDocShellTreeOwner.h"
183 #ifdef MOZ_TASK_TRACER
184 #include "GeckoTaskTracer.h"
185 using namespace mozilla::tasktracer
;
188 #define ANCHOR_SCROLL_FLAGS \
189 (nsIPresShell::SCROLL_OVERFLOW_HIDDEN | nsIPresShell::SCROLL_NO_PARENT_FRAMES)
191 using namespace mozilla
;
192 using namespace mozilla::css
;
193 using namespace mozilla::dom
;
194 using namespace mozilla::gfx
;
195 using namespace mozilla::layers
;
196 using namespace mozilla::gfx
;
197 using namespace mozilla::layout
;
199 CapturingContentInfo
nsIPresShell::gCaptureInfo
=
200 { false /* mAllowed */, false /* mPointerLock */, false /* mRetargetToElement */,
201 false /* mPreventDrag */, nullptr /* mContent */ };
202 nsIContent
* nsIPresShell::gKeyDownTarget
;
203 nsRefPtrHashtable
<nsUint32HashKey
, dom::Touch
>* nsIPresShell::gCaptureTouchList
;
204 nsRefPtrHashtable
<nsUint32HashKey
, nsIContent
>* nsIPresShell::gPointerCaptureList
;
205 nsClassHashtable
<nsUint32HashKey
, nsIPresShell::PointerInfo
>* nsIPresShell::gActivePointersIds
;
206 bool nsIPresShell::gPreventMouseEvents
= false;
208 // convert a color value to a string, in the CSS format #RRGGBB
209 // * - initially created for bugs 31816, 20760, 22963
210 static void ColorToString(nscolor aColor
, nsAutoString
&aString
);
212 // RangePaintInfo is used to paint ranges to offscreen buffers
213 struct RangePaintInfo
{
214 nsRefPtr
<nsRange
> mRange
;
215 nsDisplayListBuilder mBuilder
;
218 // offset of builder's reference frame to the root frame
221 RangePaintInfo(nsRange
* aRange
, nsIFrame
* aFrame
)
222 : mRange(aRange
), mBuilder(aFrame
, nsDisplayListBuilder::PAINTING
, false)
224 MOZ_COUNT_CTOR(RangePaintInfo
);
230 MOZ_COUNT_DTOR(RangePaintInfo
);
236 // ----------------------------------------------------------------------
239 // Set the environment variable GECKO_VERIFY_REFLOW_FLAGS to one or
240 // more of the following flags (comma separated) for handy debug
242 static uint32_t gVerifyReflowFlags
;
244 struct VerifyReflowFlags
{
249 static const VerifyReflowFlags gFlags
[] = {
250 { "verify", VERIFY_REFLOW_ON
},
251 { "reflow", VERIFY_REFLOW_NOISY
},
252 { "all", VERIFY_REFLOW_ALL
},
253 { "list-commands", VERIFY_REFLOW_DUMP_COMMANDS
},
254 { "noisy-commands", VERIFY_REFLOW_NOISY_RC
},
255 { "really-noisy-commands", VERIFY_REFLOW_REALLY_NOISY_RC
},
256 { "resize", VERIFY_REFLOW_DURING_RESIZE_REFLOW
},
259 #define NUM_VERIFY_REFLOW_FLAGS (sizeof(gFlags) / sizeof(gFlags[0]))
262 ShowVerifyReflowFlags()
264 printf("Here are the available GECKO_VERIFY_REFLOW_FLAGS:\n");
265 const VerifyReflowFlags
* flag
= gFlags
;
266 const VerifyReflowFlags
* limit
= gFlags
+ NUM_VERIFY_REFLOW_FLAGS
;
267 while (flag
< limit
) {
268 printf(" %s\n", flag
->name
);
271 printf("Note: GECKO_VERIFY_REFLOW_FLAGS is a comma separated list of flag\n");
272 printf("names (no whitespace)\n");
276 //========================================================================
277 //========================================================================
278 //========================================================================
279 #ifdef MOZ_REFLOW_PERF
280 class ReflowCountMgr
;
282 static const char kGrandTotalsStr
[] = "Grand Totals";
285 class ReflowCounter
{
287 explicit ReflowCounter(ReflowCountMgr
* aMgr
= nullptr);
291 void DisplayTotals(const char * aStr
);
292 void DisplayDiffTotals(const char * aStr
);
293 void DisplayHTMLTotals(const char * aStr
);
295 void Add() { mTotal
++; }
296 void Add(uint32_t aTotal
) { mTotal
+= aTotal
; }
298 void CalcDiffInTotals();
299 void SetTotalsCache();
301 void SetMgr(ReflowCountMgr
* aMgr
) { mMgr
= aMgr
; }
303 uint32_t GetTotal() { return mTotal
; }
306 void DisplayTotals(uint32_t aTotal
, const char * aTitle
);
307 void DisplayHTMLTotals(uint32_t aTotal
, const char * aTitle
);
310 uint32_t mCacheTotal
;
312 ReflowCountMgr
* mMgr
; // weak reference (don't delete)
316 class IndiReflowCounter
{
318 explicit IndiReflowCounter(ReflowCountMgr
* aMgr
= nullptr)
323 mHasBeenOutput(false)
325 virtual ~IndiReflowCounter() {}
328 nsIFrame
* mFrame
; // weak reference (don't delete)
331 ReflowCountMgr
* mMgr
; // weak reference (don't delete)
333 ReflowCounter mCounter
;
338 //--------------------
340 //--------------------
341 class ReflowCountMgr
{
344 virtual ~ReflowCountMgr();
347 void ClearGrandTotals();
348 void DisplayTotals(const char * aStr
);
349 void DisplayHTMLTotals(const char * aStr
);
350 void DisplayDiffsInTotals(const char * aStr
);
352 void Add(const char * aName
, nsIFrame
* aFrame
);
353 ReflowCounter
* LookUp(const char * aName
);
355 void PaintCount(const char *aName
, nsRenderingContext
* aRenderingContext
,
356 nsPresContext
*aPresContext
, nsIFrame
*aFrame
,
357 const nsPoint
&aOffset
, uint32_t aColor
);
359 FILE * GetOutFile() { return mFD
; }
361 PLHashTable
* GetIndiFrameHT() { return mIndiFrameCounts
; }
363 void SetPresContext(nsPresContext
* aPresContext
) { mPresContext
= aPresContext
; } // weak reference
364 void SetPresShell(nsIPresShell
* aPresShell
) { mPresShell
= aPresShell
; } // weak reference
366 void SetDumpFrameCounts(bool aVal
) { mDumpFrameCounts
= aVal
; }
367 void SetDumpFrameByFrameCounts(bool aVal
) { mDumpFrameByFrameCounts
= aVal
; }
368 void SetPaintFrameCounts(bool aVal
) { mPaintFrameByFrameCounts
= aVal
; }
370 bool IsPaintingFrameCounts() { return mPaintFrameByFrameCounts
; }
373 void DisplayTotals(uint32_t aTotal
, uint32_t * aDupArray
, char * aTitle
);
374 void DisplayHTMLTotals(uint32_t aTotal
, uint32_t * aDupArray
, char * aTitle
);
376 static int RemoveItems(PLHashEntry
*he
, int i
, void *arg
);
377 static int RemoveIndiItems(PLHashEntry
*he
, int i
, void *arg
);
380 // stdout Output Methods
381 static int DoSingleTotal(PLHashEntry
*he
, int i
, void *arg
);
382 static int DoSingleIndi(PLHashEntry
*he
, int i
, void *arg
);
384 void DoGrandTotals();
385 void DoIndiTotalsTree();
387 // HTML Output Methods
388 static int DoSingleHTMLTotal(PLHashEntry
*he
, int i
, void *arg
);
389 void DoGrandHTMLTotals();
391 // Zero Out the Totals
392 static int DoClearTotals(PLHashEntry
*he
, int i
, void *arg
);
394 // Displays the Diff Totals
395 static int DoDisplayDiffTotals(PLHashEntry
*he
, int i
, void *arg
);
397 PLHashTable
* mCounts
;
398 PLHashTable
* mIndiFrameCounts
;
401 bool mDumpFrameCounts
;
402 bool mDumpFrameByFrameCounts
;
403 bool mPaintFrameByFrameCounts
;
407 // Root Frame for Individual Tracking
408 nsPresContext
* mPresContext
;
409 nsIPresShell
* mPresShell
;
411 // ReflowCountMgr gReflowCountMgr;
414 //========================================================================
416 // comment out to hide caret
419 // The upper bound on the amount of time to spend reflowing, in
420 // microseconds. When this bound is exceeded and reflow commands are
421 // still queued up, a reflow event is posted. The idea is for reflow
422 // to not hog the processor beyond the time specifed in
423 // gMaxRCProcessingTime. This data member is initialized from the
424 // layout.reflow.timeslice pref.
425 #define NS_MAX_REFLOW_TIME 1000000
426 static int32_t gMaxRCProcessingTime
= -1;
428 struct nsCallbackEventRequest
430 nsIReflowCallback
* callback
;
431 nsCallbackEventRequest
* next
;
434 // ----------------------------------------------------------------------------
435 #define ASSERT_REFLOW_SCHEDULED_STATE() \
436 NS_ASSERTION(mReflowScheduled == \
437 GetPresContext()->RefreshDriver()-> \
438 IsLayoutFlushObserver(this), "Unexpected state")
440 class nsAutoCauseReflowNotifier
443 explicit nsAutoCauseReflowNotifier(PresShell
* aShell
)
446 mShell
->WillCauseReflow();
448 ~nsAutoCauseReflowNotifier()
450 // This check should not be needed. Currently the only place that seem
451 // to need it is the code that deals with bug 337586.
452 if (!mShell
->mHaveShutDown
) {
453 mShell
->DidCauseReflow();
456 nsContentUtils::RemoveScriptBlocker();
463 class MOZ_STACK_CLASS nsPresShellEventCB
: public EventDispatchingCallback
466 explicit nsPresShellEventCB(PresShell
* aPresShell
) : mPresShell(aPresShell
) {}
468 virtual void HandleEvent(EventChainPostVisitor
& aVisitor
) MOZ_OVERRIDE
470 if (aVisitor
.mPresContext
&& aVisitor
.mEvent
->mClass
!= eBasicEventClass
) {
471 if (aVisitor
.mEvent
->message
== NS_MOUSE_BUTTON_DOWN
||
472 aVisitor
.mEvent
->message
== NS_MOUSE_BUTTON_UP
) {
473 // Mouse-up and mouse-down events call nsFrame::HandlePress/Release
474 // which call GetContentOffsetsFromPoint which requires up-to-date layout.
475 // Bring layout up-to-date now so that GetCurrentEventFrame() below
476 // will return a real frame and we don't have to worry about
477 // destroying it by flushing later.
478 mPresShell
->FlushPendingNotifications(Flush_Layout
);
479 } else if (aVisitor
.mEvent
->message
== NS_WHEEL_WHEEL
&&
480 aVisitor
.mEventStatus
!= nsEventStatus_eConsumeNoDefault
) {
481 nsIFrame
* frame
= mPresShell
->GetCurrentEventFrame();
483 // chrome (including addons) should be able to know if content
484 // handles both D3E "wheel" event and legacy mouse scroll events.
485 // We should dispatch legacy mouse events before dispatching the
486 // "wheel" event into system group.
487 nsRefPtr
<EventStateManager
> esm
=
488 aVisitor
.mPresContext
->EventStateManager();
489 esm
->DispatchLegacyMouseScrollEvents(frame
,
490 aVisitor
.mEvent
->AsWheelEvent(),
491 &aVisitor
.mEventStatus
);
494 nsIFrame
* frame
= mPresShell
->GetCurrentEventFrame();
496 (aVisitor
.mEvent
->message
== NS_MOUSE_BUTTON_UP
||
497 aVisitor
.mEvent
->message
== NS_TOUCH_END
)) {
498 // Redirect BUTTON_UP and TOUCH_END events to the root frame to ensure
499 // that capturing is released.
500 frame
= mPresShell
->GetRootFrame();
503 frame
->HandleEvent(aVisitor
.mPresContext
,
504 aVisitor
.mEvent
->AsGUIEvent(),
505 &aVisitor
.mEventStatus
);
510 nsRefPtr
<PresShell
> mPresShell
;
513 class nsBeforeFirstPaintDispatcher
: public nsRunnable
516 explicit nsBeforeFirstPaintDispatcher(nsIDocument
* aDocument
)
517 : mDocument(aDocument
) {}
519 // Fires the "before-first-paint" event so that interested parties (right now, the
520 // mobile browser) are aware of it.
521 NS_IMETHOD
Run() MOZ_OVERRIDE
523 nsCOMPtr
<nsIObserverService
> observerService
=
524 mozilla::services::GetObserverService();
525 if (observerService
) {
526 observerService
->NotifyObservers(mDocument
, "before-first-paint",
533 nsCOMPtr
<nsIDocument
> mDocument
;
536 bool PresShell::sDisableNonTestMouseEvents
= false;
539 PRLogModuleInfo
* PresShell::gLog
;
544 VerifyStyleTree(nsPresContext
* aPresContext
, nsFrameManager
* aFrameManager
)
546 if (nsFrame::GetVerifyStyleTreeEnable()) {
547 nsIFrame
* rootFrame
= aFrameManager
->GetRootFrame();
548 aPresContext
->RestyleManager()->DebugVerifyStyleTree(rootFrame
);
551 #define VERIFY_STYLE_TREE ::VerifyStyleTree(mPresContext, mFrameConstructor)
553 #define VERIFY_STYLE_TREE
556 static bool gVerifyReflowEnabled
;
559 nsIPresShell::GetVerifyReflowEnable()
562 static bool firstTime
= true;
565 char* flags
= PR_GetEnv("GECKO_VERIFY_REFLOW_FLAGS");
570 char* comma
= PL_strchr(flags
, ',');
575 const VerifyReflowFlags
* flag
= gFlags
;
576 const VerifyReflowFlags
* limit
= gFlags
+ NUM_VERIFY_REFLOW_FLAGS
;
577 while (flag
< limit
) {
578 if (PL_strcasecmp(flag
->name
, flags
) == 0) {
579 gVerifyReflowFlags
|= flag
->bit
;
597 ShowVerifyReflowFlags();
600 if (VERIFY_REFLOW_ON
& gVerifyReflowFlags
) {
601 gVerifyReflowEnabled
= true;
603 printf("Note: verifyreflow is enabled");
604 if (VERIFY_REFLOW_NOISY
& gVerifyReflowFlags
) {
607 if (VERIFY_REFLOW_ALL
& gVerifyReflowFlags
) {
610 if (VERIFY_REFLOW_DUMP_COMMANDS
& gVerifyReflowFlags
) {
611 printf(" (show reflow commands)");
613 if (VERIFY_REFLOW_NOISY_RC
& gVerifyReflowFlags
) {
614 printf(" (noisy reflow commands)");
615 if (VERIFY_REFLOW_REALLY_NOISY_RC
& gVerifyReflowFlags
) {
616 printf(" (REALLY noisy reflow commands)");
623 return gVerifyReflowEnabled
;
627 PresShell::AddInvalidateHiddenPresShellObserver(nsRefreshDriver
*aDriver
)
629 if (!mHiddenInvalidationObserverRefreshDriver
&& !mIsDestroying
&& !mHaveShutDown
) {
630 aDriver
->AddPresShellToInvalidateIfHidden(this);
631 mHiddenInvalidationObserverRefreshDriver
= aDriver
;
636 nsIPresShell::InvalidatePresShellIfHidden()
638 if (!IsVisible() && mPresContext
) {
639 mPresContext
->NotifyInvalidation(0);
641 mHiddenInvalidationObserverRefreshDriver
= nullptr;
645 nsIPresShell::CancelInvalidatePresShellIfHidden()
647 if (mHiddenInvalidationObserverRefreshDriver
) {
648 mHiddenInvalidationObserverRefreshDriver
->RemovePresShellToInvalidateIfHidden(this);
649 mHiddenInvalidationObserverRefreshDriver
= nullptr;
654 nsIPresShell::SetVerifyReflowEnable(bool aEnabled
)
656 gVerifyReflowEnabled
= aEnabled
;
660 nsIPresShell::AddWeakFrameExternal(nsWeakFrame
* aWeakFrame
)
662 AddWeakFrameInternal(aWeakFrame
);
666 nsIPresShell::AddWeakFrameInternal(nsWeakFrame
* aWeakFrame
)
668 if (aWeakFrame
->GetFrame()) {
669 aWeakFrame
->GetFrame()->AddStateBits(NS_FRAME_EXTERNAL_REFERENCE
);
671 aWeakFrame
->SetPreviousWeakFrame(mWeakFrames
);
672 mWeakFrames
= aWeakFrame
;
676 nsIPresShell::RemoveWeakFrameExternal(nsWeakFrame
* aWeakFrame
)
678 RemoveWeakFrameInternal(aWeakFrame
);
682 nsIPresShell::RemoveWeakFrameInternal(nsWeakFrame
* aWeakFrame
)
684 if (mWeakFrames
== aWeakFrame
) {
685 mWeakFrames
= aWeakFrame
->GetPreviousWeakFrame();
688 nsWeakFrame
* nextWeak
= mWeakFrames
;
689 while (nextWeak
&& nextWeak
->GetPreviousWeakFrame() != aWeakFrame
) {
690 nextWeak
= nextWeak
->GetPreviousWeakFrame();
693 nextWeak
->SetPreviousWeakFrame(aWeakFrame
->GetPreviousWeakFrame());
697 already_AddRefed
<nsFrameSelection
>
698 nsIPresShell::FrameSelection()
700 nsRefPtr
<nsFrameSelection
> ret
= mSelection
;
704 //----------------------------------------------------------------------
706 static bool sSynthMouseMove
= true;
707 static uint32_t sNextPresShellId
;
708 static bool sPointerEventEnabled
= true;
709 static bool sTouchCaretEnabled
= false;
710 static bool sSelectionCaretEnabled
= false;
713 PresShell::TouchCaretPrefEnabled()
715 static bool initialized
= false;
717 Preferences::AddBoolVarCache(&sTouchCaretEnabled
, "touchcaret.enabled");
720 return sTouchCaretEnabled
;
724 PresShell::SelectionCaretPrefEnabled()
726 static bool initialized
= false;
728 Preferences::AddBoolVarCache(&sSelectionCaretEnabled
, "selectioncaret.enabled");
731 return sSelectionCaretEnabled
;
734 PresShell::PresShell()
735 : mMouseLocation(NS_UNCONSTRAINEDSIZE
, NS_UNCONSTRAINEDSIZE
)
737 mSelection
= nullptr;
738 #ifdef MOZ_REFLOW_PERF
739 mReflowCountMgr
= new ReflowCountMgr();
740 mReflowCountMgr
->SetPresContext(mPresContext
);
741 mReflowCountMgr
->SetPresShell(this);
744 mLoadBegin
= TimeStamp::Now();
746 gLog
= PR_NewLogModule("PresShell");
749 mSelectionFlags
= nsISelectionDisplay::DISPLAY_TEXT
| nsISelectionDisplay::DISPLAY_IMAGES
;
750 mIsThemeSupportDisabled
= false;
752 // FIXME/bug 735029: find a better solution to this problem
753 #ifdef MOZ_WIDGET_ANDROID
754 // The java pan/zoom code uses this to mean approximately "request a
755 // reset of pan/zoom state" which doesn't necessarily correspond
756 // with the first paint of content.
757 mIsFirstPaint
= false;
759 mIsFirstPaint
= true;
761 mPresShellId
= sNextPresShellId
++;
764 mPresArenaAllocCount
= 0;
769 mViewportOverridden
= false;
771 mScrollPositionClampingScrollPortSizeSet
= false;
773 mMaxLineBoxWidth
= 0;
775 static bool addedSynthMouseMove
= false;
776 if (!addedSynthMouseMove
) {
777 Preferences::AddBoolVarCache(&sSynthMouseMove
,
778 "layout.reflow.synthMouseMove", true);
779 addedSynthMouseMove
= true;
781 static bool addedPointerEventEnabled
= false;
782 if (!addedPointerEventEnabled
) {
783 Preferences::AddBoolVarCache(&sPointerEventEnabled
,
784 "dom.w3c_pointer_events.enabled", true);
785 addedPointerEventEnabled
= true;
788 mPaintingIsFrozen
= false;
791 NS_IMPL_ISUPPORTS(PresShell
, nsIPresShell
, nsIDocumentObserver
,
792 nsISelectionController
,
793 nsISelectionDisplay
, nsIObserver
, nsISupportsWeakReference
,
796 PresShell::~PresShell()
798 if (!mHaveShutDown
) {
799 NS_NOTREACHED("Someone did not call nsIPresShell::destroy");
803 NS_ASSERTION(mCurrentEventContentStack
.Count() == 0,
804 "Huh, event content left on the stack in pres shell dtor!");
805 NS_ASSERTION(mFirstCallbackEventRequest
== nullptr &&
806 mLastCallbackEventRequest
== nullptr,
807 "post-reflow queues not empty. This means we're leaking");
809 // Verify that if painting was frozen, but we're being removed from the tree,
810 // that we now re-enable painting on our refresh driver, since it may need to
811 // be re-used by another presentation.
812 if (mPaintingIsFrozen
) {
813 mPresContext
->RefreshDriver()->Thaw();
817 MOZ_ASSERT(mPresArenaAllocCount
== 0,
818 "Some pres arena objects were not freed");
822 delete mFrameConstructor
;
824 mCurrentEventContent
= nullptr;
826 NS_IF_RELEASE(mPresContext
);
827 NS_IF_RELEASE(mDocument
);
828 NS_IF_RELEASE(mSelection
);
832 * Initialize the presentation shell. Create view manager and style
834 * Note this can't be merged into our constructor because caret initialization
835 * calls AddRef() on us.
838 PresShell::Init(nsIDocument
* aDocument
,
839 nsPresContext
* aPresContext
,
840 nsViewManager
* aViewManager
,
841 nsStyleSet
* aStyleSet
,
842 nsCompatibility aCompatMode
)
844 NS_PRECONDITION(aDocument
, "null ptr");
845 NS_PRECONDITION(aPresContext
, "null ptr");
846 NS_PRECONDITION(aViewManager
, "null ptr");
847 NS_PRECONDITION(!mDocument
, "already initialized");
849 if (!aDocument
|| !aPresContext
|| !aViewManager
|| mDocument
) {
853 mDocument
= aDocument
;
854 NS_ADDREF(mDocument
);
855 mViewManager
= aViewManager
;
857 // Create our frame constructor.
858 mFrameConstructor
= new nsCSSFrameConstructor(mDocument
, this, aStyleSet
);
860 mFrameManager
= mFrameConstructor
;
862 // The document viewer owns both view manager and pres shell.
863 mViewManager
->SetPresShell(this);
865 // Bind the context to the presentation shell.
866 mPresContext
= aPresContext
;
867 NS_ADDREF(mPresContext
);
868 aPresContext
->SetShell(this);
870 // Now we can initialize the style set.
871 aStyleSet
->Init(aPresContext
);
872 mStyleSet
= aStyleSet
;
874 // Notify our prescontext that it now has a compatibility mode. Note that
875 // this MUST happen after we set up our style set but before we create any
877 mPresContext
->CompatibilityModeChanged();
879 // setup the preference style rules (no forced reflow), and do it
880 // before creating any frames.
881 SetPreferenceStyleRules(false);
883 if (TouchCaretPrefEnabled()) {
884 // Create touch caret handle
885 mTouchCaret
= new TouchCaret(this);
888 if (SelectionCaretPrefEnabled()) {
889 // Create selection caret handle
890 mSelectionCarets
= new SelectionCarets(this);
894 NS_ADDREF(mSelection
= new nsFrameSelection());
896 mSelection
->Init(this, nullptr);
898 // Important: this has to happen after the selection has been set up
901 mCaret
= new nsCaret();
903 mOriginalCaret
= mCaret
;
905 //SetCaretEnabled(true); // make it show in browser windows
907 //set up selection to be displayed in document
908 // Don't enable selection for print media
909 nsPresContext::nsPresContextType type
= aPresContext
->Type();
910 if (type
!= nsPresContext::eContext_PrintPreview
&&
911 type
!= nsPresContext::eContext_Print
)
912 SetDisplaySelection(nsISelectionController::SELECTION_DISABLED
);
914 if (gMaxRCProcessingTime
== -1) {
915 gMaxRCProcessingTime
=
916 Preferences::GetInt("layout.reflow.timeslice", NS_MAX_REFLOW_TIME
);
920 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
922 os
->AddObserver(this, "agent-sheet-added", false);
923 os
->AddObserver(this, "user-sheet-added", false);
924 os
->AddObserver(this, "author-sheet-added", false);
925 os
->AddObserver(this, "agent-sheet-removed", false);
926 os
->AddObserver(this, "user-sheet-removed", false);
927 os
->AddObserver(this, "author-sheet-removed", false);
929 os
->AddObserver(this, "chrome-flush-skin-caches", false);
934 #ifdef MOZ_REFLOW_PERF
935 if (mReflowCountMgr
) {
936 bool paintFrameCounts
=
937 Preferences::GetBool("layout.reflow.showframecounts");
939 bool dumpFrameCounts
=
940 Preferences::GetBool("layout.reflow.dumpframecounts");
942 bool dumpFrameByFrameCounts
=
943 Preferences::GetBool("layout.reflow.dumpframebyframecounts");
945 mReflowCountMgr
->SetDumpFrameCounts(dumpFrameCounts
);
946 mReflowCountMgr
->SetDumpFrameByFrameCounts(dumpFrameByFrameCounts
);
947 mReflowCountMgr
->SetPaintFrameCounts(paintFrameCounts
);
951 if (mDocument
->HasAnimationController()) {
952 nsSMILAnimationController
* animCtrl
= mDocument
->GetAnimationController();
953 animCtrl
->NotifyRefreshDriverCreated(GetPresContext()->RefreshDriver());
956 // Get our activeness from the docShell.
959 // Setup our font inflation preferences.
960 SetupFontInflation();
964 enum TextPerfLogType
{
971 LogTextPerfStats(gfxTextPerfMetrics
* aTextPerf
,
972 PresShell
* aPresShell
,
973 const gfxTextPerfMetrics::TextCounts
& aCounts
,
974 float aTime
, TextPerfLogType aLogType
, const char* aURL
)
980 sprintf(prefix
, "(textperf-reflow) %p time-ms: %7.0f", aPresShell
, aTime
);
983 sprintf(prefix
, "(textperf-loaddone) %p time-ms: %7.0f", aPresShell
, aTime
);
986 MOZ_ASSERT(aLogType
== eLog_totals
, "unknown textperf log type");
987 sprintf(prefix
, "(textperf-totals) %p", aPresShell
);
990 PRLogModuleInfo
* tpLog
= gfxPlatform::GetLog(eGfxLog_textperf
);
992 // ignore XUL contexts unless at debug level
993 PRLogModuleLevel logLevel
= PR_LOG_WARNING
;
994 if (aCounts
.numContentTextRuns
== 0) {
995 logLevel
= PR_LOG_DEBUG
;
998 double hitRatio
= 0.0;
999 uint32_t lookups
= aCounts
.wordCacheHit
+ aCounts
.wordCacheMiss
;
1001 hitRatio
= double(aCounts
.wordCacheHit
) / double(lookups
);
1004 if (aLogType
== eLog_loaddone
) {
1005 PR_LOG(tpLog
, logLevel
,
1006 ("%s reflow: %d chars: %d "
1008 "content-textruns: %d chrome-textruns: %d "
1009 "max-textrun-len: %d "
1010 "word-cache-lookups: %d word-cache-hit-ratio: %4.3f "
1011 "word-cache-space: %d word-cache-long: %d "
1012 "pref-fallbacks: %d system-fallbacks: %d "
1013 "textruns-const: %d textruns-destr: %d "
1014 "cumulative-textruns-destr: %d\n",
1015 prefix
, aTextPerf
->reflowCount
, aCounts
.numChars
,
1017 aCounts
.numContentTextRuns
, aCounts
.numChromeTextRuns
,
1018 aCounts
.maxTextRunLen
,
1020 aCounts
.wordCacheSpaceRules
, aCounts
.wordCacheLong
,
1021 aCounts
.fallbackPrefs
, aCounts
.fallbackSystem
,
1022 aCounts
.textrunConst
, aCounts
.textrunDestr
,
1023 aTextPerf
->cumulative
.textrunDestr
));
1025 PR_LOG(tpLog
, logLevel
,
1026 ("%s reflow: %d chars: %d "
1027 "content-textruns: %d chrome-textruns: %d "
1028 "max-textrun-len: %d "
1029 "word-cache-lookups: %d word-cache-hit-ratio: %4.3f "
1030 "word-cache-space: %d word-cache-long: %d "
1031 "pref-fallbacks: %d system-fallbacks: %d "
1032 "textruns-const: %d textruns-destr: %d "
1033 "cumulative-textruns-destr: %d\n",
1034 prefix
, aTextPerf
->reflowCount
, aCounts
.numChars
,
1035 aCounts
.numContentTextRuns
, aCounts
.numChromeTextRuns
,
1036 aCounts
.maxTextRunLen
,
1038 aCounts
.wordCacheSpaceRules
, aCounts
.wordCacheLong
,
1039 aCounts
.fallbackPrefs
, aCounts
.fallbackSystem
,
1040 aCounts
.textrunConst
, aCounts
.textrunDestr
,
1041 aTextPerf
->cumulative
.textrunDestr
));
1047 PresShell::Destroy()
1049 NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
1050 "destroy called on presshell while scripts not blocked");
1052 // dump out cumulative text perf metrics
1054 gfxTextPerfMetrics
* tp
;
1055 if (mPresContext
&& (tp
= mPresContext
->GetTextPerfMetrics())) {
1057 if (tp
->cumulative
.numChars
> 0) {
1058 LogTextPerfStats(tp
, this, tp
->cumulative
, 0.0, eLog_totals
, nullptr);
1063 #ifdef MOZ_REFLOW_PERF
1065 if (mReflowCountMgr
) {
1066 delete mReflowCountMgr
;
1067 mReflowCountMgr
= nullptr;
1074 #ifdef ACCESSIBILITY
1075 if (mDocAccessible
) {
1077 if (a11y::logging::IsEnabled(a11y::logging::eDocDestroy
))
1078 a11y::logging::DocDestroy("presshell destroyed", mDocument
);
1081 mDocAccessible
->Shutdown();
1082 mDocAccessible
= nullptr;
1084 #endif // ACCESSIBILITY
1086 MaybeReleaseCapturingContent();
1088 if (gKeyDownTarget
&& gKeyDownTarget
->OwnerDoc() == mDocument
) {
1089 NS_RELEASE(gKeyDownTarget
);
1092 if (mContentToScrollTo
) {
1093 mContentToScrollTo
->DeleteProperty(nsGkAtoms::scrolling
);
1094 mContentToScrollTo
= nullptr;
1098 // We need to notify the destroying the nsPresContext to ESM for
1099 // suppressing to use from ESM.
1100 mPresContext
->EventStateManager()->NotifyDestroyPresContext(mPresContext
);
1104 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
1106 os
->RemoveObserver(this, "agent-sheet-added");
1107 os
->RemoveObserver(this, "user-sheet-added");
1108 os
->RemoveObserver(this, "author-sheet-added");
1109 os
->RemoveObserver(this, "agent-sheet-removed");
1110 os
->RemoveObserver(this, "user-sheet-removed");
1111 os
->RemoveObserver(this, "author-sheet-removed");
1113 os
->RemoveObserver(this, "chrome-flush-skin-caches");
1118 // If our paint suppression timer is still active, kill it.
1119 if (mPaintSuppressionTimer
) {
1120 mPaintSuppressionTimer
->Cancel();
1121 mPaintSuppressionTimer
= nullptr;
1124 // Same for our reflow continuation timer
1125 if (mReflowContinueTimer
) {
1126 mReflowContinueTimer
->Cancel();
1127 mReflowContinueTimer
= nullptr;
1130 if (mDelayedPaintTimer
) {
1131 mDelayedPaintTimer
->Cancel();
1132 mDelayedPaintTimer
= nullptr;
1135 mSynthMouseMoveEvent
.Revoke();
1137 mUpdateImageVisibilityEvent
.Revoke();
1139 ClearVisibleImagesList();
1142 mCaret
->Terminate();
1147 mSelection
->DisconnectFromPresShell();
1151 mTouchCaret
->Terminate();
1152 mTouchCaret
= nullptr;
1155 if (mSelectionCarets
) {
1156 mSelectionCarets
->Terminate();
1157 mSelectionCarets
= nullptr;
1160 // release our pref style sheet, if we have one still
1161 ClearPreferenceStyleRules();
1163 mIsDestroying
= true;
1165 // We can't release all the event content in
1166 // mCurrentEventContentStack here since there might be code on the
1167 // stack that will release the event content too. Double release
1170 // The frames will be torn down, so remove them from the current
1171 // event frame stack (since they'd be dangling references if we'd
1172 // leave them in) and null out the mCurrentEventFrame pointer as
1175 mCurrentEventFrame
= nullptr;
1177 int32_t i
, count
= mCurrentEventFrameStack
.Length();
1178 for (i
= 0; i
< count
; i
++) {
1179 mCurrentEventFrameStack
[i
] = nullptr;
1182 mFramesToDirty
.Clear();
1185 // Clear the view manager's weak pointer back to |this| in case it
1187 mViewManager
->SetPresShell(nullptr);
1188 mViewManager
= nullptr;
1191 mStyleSet
->BeginShutdown(mPresContext
);
1192 nsRefreshDriver
* rd
= GetPresContext()->RefreshDriver();
1194 // This shell must be removed from the document before the frame
1195 // hierarchy is torn down to avoid finding deleted frames through
1196 // this presshell while the frames are being torn down
1198 NS_ASSERTION(mDocument
->GetShell() == this, "Wrong shell?");
1199 mDocument
->DeleteShell();
1201 if (mDocument
->HasAnimationController()) {
1202 mDocument
->GetAnimationController()->NotifyRefreshDriverDestroying(rd
);
1206 // Revoke any pending events. We need to do this and cancel pending reflows
1207 // before we destroy the frame manager, since apparently frame destruction
1208 // sometimes spins the event queue when plug-ins are involved(!).
1209 rd
->RemoveLayoutFlushObserver(this);
1210 if (mHiddenInvalidationObserverRefreshDriver
) {
1211 mHiddenInvalidationObserverRefreshDriver
->RemovePresShellToInvalidateIfHidden(this);
1214 if (rd
->PresContext() == GetPresContext()) {
1215 rd
->RevokeViewManagerFlush();
1218 mResizeEvent
.Revoke();
1219 if (mAsyncResizeTimerIsActive
) {
1220 mAsyncResizeEventTimer
->Cancel();
1221 mAsyncResizeTimerIsActive
= false;
1224 CancelAllPendingReflows();
1225 CancelPostedReflowCallbacks();
1227 // Destroy the frame manager. This will destroy the frame hierarchy
1228 mFrameConstructor
->WillDestroyFrameTree();
1230 // Destroy all frame properties (whose destruction was suppressed
1231 // while destroying the frame tree, but which might contain more
1232 // frames within the properties.
1234 // Clear out the prescontext's property table -- since our frame tree is
1235 // now dead, we shouldn't be looking up any more properties in that table.
1236 // We want to do this before we call SetShell() on the prescontext, so
1237 // property destructors can usefully call GetPresShell() on the
1239 mPresContext
->PropertyTable()->DeleteAll();
1243 NS_WARN_IF_FALSE(!mWeakFrames
, "Weak frames alive after destroying FrameManager");
1244 while (mWeakFrames
) {
1245 mWeakFrames
->Clear(this);
1248 // Let the style set do its cleanup.
1249 mStyleSet
->Shutdown(mPresContext
);
1252 // We hold a reference to the pres context, and it holds a weak link back
1253 // to us. To avoid the pres context having a dangling reference, set its
1254 // pres shell to nullptr
1255 mPresContext
->SetShell(nullptr);
1257 // Clear the link handler (weak reference) as well
1258 mPresContext
->SetLinkHandler(nullptr);
1261 mHaveShutDown
= true;
1267 PresShell::MakeZombie()
1270 CancelAllPendingReflows();
1274 nsIPresShell::SetAuthorStyleDisabled(bool aStyleDisabled
)
1276 if (aStyleDisabled
!= mStyleSet
->GetAuthorStyleDisabled()) {
1277 mStyleSet
->SetAuthorStyleDisabled(aStyleDisabled
);
1278 ReconstructStyleData();
1280 nsCOMPtr
<nsIObserverService
> observerService
=
1281 mozilla::services::GetObserverService();
1282 if (observerService
) {
1283 observerService
->NotifyObservers(mDocument
,
1284 "author-style-disabled-changed",
1291 nsIPresShell::GetAuthorStyleDisabled() const
1293 return mStyleSet
->GetAuthorStyleDisabled();
1297 PresShell::SetPreferenceStyleRules(bool aForceReflow
)
1300 return NS_ERROR_NULL_POINTER
;
1303 nsPIDOMWindow
*window
= mDocument
->GetWindow();
1305 // If the document doesn't have a window there's no need to notify
1306 // its presshell about changes to preferences since the document is
1307 // in a state where it doesn't matter any more (see
1308 // nsDocumentViewer::Close()).
1311 return NS_ERROR_NULL_POINTER
;
1314 NS_PRECONDITION(mPresContext
, "presContext cannot be null");
1316 // first, make sure this is not a chrome shell
1317 if (nsContentUtils::IsInChromeDocshell(mDocument
)) {
1321 #ifdef DEBUG_attinasi
1322 printf("Setting Preference Style Rules:\n");
1324 // if here, we need to create rules for the prefs
1325 // - this includes the background-color, the text-color,
1326 // the link color, the visited link color and the link-underlining
1328 // first clear any exising rules
1329 nsresult result
= ClearPreferenceStyleRules();
1331 // now the link rules (must come after the color rules, or links will not be correct color!)
1332 // XXX - when there is both an override and agent pref stylesheet this won't matter,
1333 // as the color rules will be overrides and the links rules will be agent
1334 if (NS_SUCCEEDED(result
)) {
1335 result
= SetPrefLinkRules();
1337 if (NS_SUCCEEDED(result
)) {
1338 result
= SetPrefFocusRules();
1340 if (NS_SUCCEEDED(result
)) {
1341 result
= SetPrefNoScriptRule();
1343 if (NS_SUCCEEDED(result
)) {
1344 result
= SetPrefNoFramesRule();
1346 #ifdef DEBUG_attinasi
1347 printf( "Preference Style Rules set: error=%ld\n", (long)result
);
1350 // Note that this method never needs to force any calculation; the caller
1351 // will recalculate style if needed
1356 return NS_ERROR_NULL_POINTER
;
1359 nsresult
PresShell::ClearPreferenceStyleRules(void)
1361 nsresult result
= NS_OK
;
1362 if (mPrefStyleSheet
) {
1363 NS_ASSERTION(mStyleSet
, "null styleset entirely unexpected!");
1365 // remove the sheet from the styleset:
1366 // - note that we have to check for success by comparing the count before and after...
1368 int32_t numBefore
= mStyleSet
->SheetCount(nsStyleSet::eUserSheet
);
1369 NS_ASSERTION(numBefore
> 0, "no user stylesheets in styleset, but we have one!");
1371 mStyleSet
->RemoveStyleSheet(nsStyleSet::eUserSheet
, mPrefStyleSheet
);
1373 #ifdef DEBUG_attinasi
1374 NS_ASSERTION((numBefore
- 1) == mStyleSet
->GetNumberOfUserStyleSheets(),
1375 "Pref stylesheet was not removed");
1376 printf("PrefStyleSheet removed\n");
1378 // clear the sheet pointer: it is strictly historical now
1379 mPrefStyleSheet
= nullptr;
1386 PresShell::CreatePreferenceStyleSheet()
1388 NS_ASSERTION(!mPrefStyleSheet
, "prefStyleSheet already exists");
1389 mPrefStyleSheet
= new CSSStyleSheet(CORS_NONE
);
1390 nsCOMPtr
<nsIURI
> uri
;
1391 nsresult rv
= NS_NewURI(getter_AddRefs(uri
), "about:PreferenceStyleSheet", nullptr);
1392 if (NS_FAILED(rv
)) {
1393 mPrefStyleSheet
= nullptr;
1396 NS_ASSERTION(uri
, "null but no error");
1397 mPrefStyleSheet
->SetURIs(uri
, uri
, uri
);
1398 mPrefStyleSheet
->SetComplete();
1401 mPrefStyleSheet
->InsertRuleInternal(NS_LITERAL_STRING("@namespace svg url(http://www.w3.org/2000/svg);"),
1403 if (NS_FAILED(rv
)) {
1404 mPrefStyleSheet
= nullptr;
1408 mPrefStyleSheet
->InsertRuleInternal(NS_LITERAL_STRING("@namespace url(http://www.w3.org/1999/xhtml);"),
1410 if (NS_FAILED(rv
)) {
1411 mPrefStyleSheet
= nullptr;
1415 mStyleSet
->AppendStyleSheet(nsStyleSet::eUserSheet
, mPrefStyleSheet
);
1419 // XXX We want these after the @namespace rules. Does order matter
1420 // for these rules, or can we call StyleRule::StyleRuleCount()
1421 // and just "append"?
1422 static uint32_t sInsertPrefSheetRulesAt
= 2;
1425 PresShell::SetPrefNoScriptRule()
1427 nsresult rv
= NS_OK
;
1429 // also handle the case where print is done from print preview
1430 // see bug #342439 for more details
1431 nsIDocument
* doc
= mDocument
;
1432 if (doc
->IsStaticDocument()) {
1433 doc
= doc
->GetOriginalDocument();
1436 bool scriptEnabled
= doc
->IsScriptEnabled();
1437 if (scriptEnabled
) {
1438 if (!mPrefStyleSheet
) {
1439 rv
= CreatePreferenceStyleSheet();
1440 NS_ENSURE_SUCCESS(rv
, rv
);
1445 InsertRuleInternal(NS_LITERAL_STRING("noscript{display:none!important}"),
1446 sInsertPrefSheetRulesAt
, &index
);
1452 nsresult
PresShell::SetPrefNoFramesRule(void)
1454 NS_ASSERTION(mPresContext
,"null prescontext not allowed");
1455 if (!mPresContext
) {
1456 return NS_ERROR_FAILURE
;
1459 nsresult rv
= NS_OK
;
1461 if (!mPrefStyleSheet
) {
1462 rv
= CreatePreferenceStyleSheet();
1463 NS_ENSURE_SUCCESS(rv
, rv
);
1466 NS_ASSERTION(mPrefStyleSheet
, "prefstylesheet should not be null");
1468 bool allowSubframes
= true;
1469 nsCOMPtr
<nsIDocShell
> docShell(mPresContext
->GetDocShell());
1471 docShell
->GetAllowSubframes(&allowSubframes
);
1473 if (!allowSubframes
) {
1475 rv
= mPrefStyleSheet
->
1476 InsertRuleInternal(NS_LITERAL_STRING("noframes{display:block}"),
1477 sInsertPrefSheetRulesAt
, &index
);
1478 NS_ENSURE_SUCCESS(rv
, rv
);
1479 rv
= mPrefStyleSheet
->
1480 InsertRuleInternal(NS_LITERAL_STRING("frame, frameset, iframe {display:none!important}"),
1481 sInsertPrefSheetRulesAt
, &index
);
1486 nsresult
PresShell::SetPrefLinkRules(void)
1488 NS_ASSERTION(mPresContext
,"null prescontext not allowed");
1489 if (!mPresContext
) {
1490 return NS_ERROR_FAILURE
;
1493 nsresult rv
= NS_OK
;
1495 if (!mPrefStyleSheet
) {
1496 rv
= CreatePreferenceStyleSheet();
1497 NS_ENSURE_SUCCESS(rv
, rv
);
1500 NS_ASSERTION(mPrefStyleSheet
, "prefstylesheet should not be null");
1502 // support default link colors:
1503 // this means the link colors need to be overridable,
1504 // which they are if we put them in the agent stylesheet,
1505 // though if using an override sheet this will cause authors grief still
1506 // In the agent stylesheet, they are !important when we are ignoring document colors
1508 nscolor
linkColor(mPresContext
->DefaultLinkColor());
1509 nscolor
activeColor(mPresContext
->DefaultActiveLinkColor());
1510 nscolor
visitedColor(mPresContext
->DefaultVisitedLinkColor());
1512 NS_NAMED_LITERAL_STRING(ruleClose
, "}");
1514 nsAutoString strColor
;
1516 // insert a rule to color links: '*|*:link {color: #RRGGBB [!important];}'
1517 ColorToString(linkColor
, strColor
);
1518 rv
= mPrefStyleSheet
->
1519 InsertRuleInternal(NS_LITERAL_STRING("*|*:link{color:") +
1520 strColor
+ ruleClose
,
1521 sInsertPrefSheetRulesAt
, &index
);
1522 NS_ENSURE_SUCCESS(rv
, rv
);
1524 // - visited links: '*|*:visited {color: #RRGGBB [!important];}'
1525 ColorToString(visitedColor
, strColor
);
1526 rv
= mPrefStyleSheet
->
1527 InsertRuleInternal(NS_LITERAL_STRING("*|*:visited{color:") +
1528 strColor
+ ruleClose
,
1529 sInsertPrefSheetRulesAt
, &index
);
1530 NS_ENSURE_SUCCESS(rv
, rv
);
1532 // - active links: '*|*:-moz-any-link:active {color: #RRGGBB [!important];}'
1533 ColorToString(activeColor
, strColor
);
1534 rv
= mPrefStyleSheet
->
1535 InsertRuleInternal(NS_LITERAL_STRING("*|*:-moz-any-link:active{color:") +
1536 strColor
+ ruleClose
,
1537 sInsertPrefSheetRulesAt
, &index
);
1538 NS_ENSURE_SUCCESS(rv
, rv
);
1540 bool underlineLinks
=
1541 mPresContext
->GetCachedBoolPref(kPresContext_UnderlineLinks
);
1543 if (underlineLinks
) {
1544 // create a rule to make underlining happen
1545 // '*|*:-moz-any-link {text-decoration:[underline|none];}'
1546 // no need for important, we want these to be overridable
1547 // NOTE: these must go in the agent stylesheet or they cannot be
1548 // overridden by authors
1549 rv
= mPrefStyleSheet
->
1550 InsertRuleInternal(NS_LITERAL_STRING("*|*:-moz-any-link:not(svg|a){text-decoration:underline}"),
1551 sInsertPrefSheetRulesAt
, &index
);
1553 rv
= mPrefStyleSheet
->
1554 InsertRuleInternal(NS_LITERAL_STRING("*|*:-moz-any-link{text-decoration:none}"),
1555 sInsertPrefSheetRulesAt
, &index
);
1561 nsresult
PresShell::SetPrefFocusRules(void)
1563 NS_ASSERTION(mPresContext
,"null prescontext not allowed");
1564 nsresult result
= NS_OK
;
1567 result
= NS_ERROR_FAILURE
;
1569 if (NS_SUCCEEDED(result
) && !mPrefStyleSheet
)
1570 result
= CreatePreferenceStyleSheet();
1572 if (NS_SUCCEEDED(result
)) {
1573 NS_ASSERTION(mPrefStyleSheet
, "prefstylesheet should not be null");
1575 if (mPresContext
->GetUseFocusColors()) {
1576 nscolor
focusBackground(mPresContext
->FocusBackgroundColor());
1577 nscolor
focusText(mPresContext
->FocusTextColor());
1579 // insert a rule to make focus the preferred color
1581 nsAutoString strRule
, strColor
;
1583 ///////////////////////////////////////////////////////////////
1584 // - focus: '*:focus
1585 ColorToString(focusText
,strColor
);
1586 strRule
.AppendLiteral("*:focus,*:focus>font {color: ");
1587 strRule
.Append(strColor
);
1588 strRule
.AppendLiteral(" !important; background-color: ");
1589 ColorToString(focusBackground
,strColor
);
1590 strRule
.Append(strColor
);
1591 strRule
.AppendLiteral(" !important; } ");
1593 result
= mPrefStyleSheet
->
1594 InsertRuleInternal(strRule
, sInsertPrefSheetRulesAt
, &index
);
1596 uint8_t focusRingWidth
= mPresContext
->FocusRingWidth();
1597 bool focusRingOnAnything
= mPresContext
->GetFocusRingOnAnything();
1598 uint8_t focusRingStyle
= mPresContext
->GetFocusRingStyle();
1600 if ((NS_SUCCEEDED(result
) && focusRingWidth
!= 1 && focusRingWidth
<= 4 ) || focusRingOnAnything
) {
1602 nsAutoString strRule
;
1603 if (!focusRingOnAnything
)
1604 strRule
.AppendLiteral("*|*:link:focus, *|*:visited"); // If we only want focus rings on the normal things like links
1605 strRule
.AppendLiteral(":focus {outline: "); // For example 3px dotted WindowText (maximum 4)
1606 strRule
.AppendInt(focusRingWidth
);
1607 if (focusRingStyle
== 0) // solid
1608 strRule
.AppendLiteral("px solid -moz-mac-focusring !important; -moz-outline-radius: 3px; outline-offset: 1px; } ");
1610 strRule
.AppendLiteral("px dotted WindowText !important; } ");
1612 result
= mPrefStyleSheet
->
1613 InsertRuleInternal(strRule
, sInsertPrefSheetRulesAt
, &index
);
1614 NS_ENSURE_SUCCESS(result
, result
);
1615 if (focusRingWidth
!= 1) {
1616 // If the focus ring width is different from the default, fix buttons with rings
1617 strRule
.AssignLiteral("button::-moz-focus-inner, input[type=\"reset\"]::-moz-focus-inner,");
1618 strRule
.AppendLiteral("input[type=\"button\"]::-moz-focus-inner, ");
1619 strRule
.AppendLiteral("input[type=\"submit\"]::-moz-focus-inner { padding: 1px 2px 1px 2px; border: ");
1620 strRule
.AppendInt(focusRingWidth
);
1621 if (focusRingStyle
== 0) // solid
1622 strRule
.AppendLiteral("px solid transparent !important; } ");
1624 strRule
.AppendLiteral("px dotted transparent !important; } ");
1625 result
= mPrefStyleSheet
->
1626 InsertRuleInternal(strRule
, sInsertPrefSheetRulesAt
, &index
);
1627 NS_ENSURE_SUCCESS(result
, result
);
1629 strRule
.AssignLiteral("button:focus::-moz-focus-inner, input[type=\"reset\"]:focus::-moz-focus-inner,");
1630 strRule
.AppendLiteral("input[type=\"button\"]:focus::-moz-focus-inner, input[type=\"submit\"]:focus::-moz-focus-inner {");
1631 strRule
.AppendLiteral("border-color: ButtonText !important; }");
1632 result
= mPrefStyleSheet
->
1633 InsertRuleInternal(strRule
, sInsertPrefSheetRulesAt
, &index
);
1641 PresShell::AddUserSheet(nsISupports
* aSheet
)
1643 // Make sure this does what nsDocumentViewer::CreateStyleSet does wrt
1644 // ordering. We want this new sheet to come after all the existing stylesheet
1645 // service sheets, but before other user sheets; see nsIStyleSheetService.idl
1646 // for the ordering. Just remove and readd all the nsStyleSheetService
1648 nsCOMPtr
<nsIStyleSheetService
> dummy
=
1649 do_GetService(NS_STYLESHEETSERVICE_CONTRACTID
);
1651 mStyleSet
->BeginUpdate();
1653 nsStyleSheetService
*sheetService
= nsStyleSheetService::gInstance
;
1654 nsCOMArray
<nsIStyleSheet
> & userSheets
= *sheetService
->UserStyleSheets();
1656 // Iterate forwards when removing so the searches for RemoveStyleSheet are as
1657 // short as possible.
1658 for (i
= 0; i
< userSheets
.Count(); ++i
) {
1659 mStyleSet
->RemoveStyleSheet(nsStyleSet::eUserSheet
, userSheets
[i
]);
1662 // Now iterate backwards, so that the order of userSheets will be the same as
1663 // the order of sheets from it in the style set.
1664 for (i
= userSheets
.Count() - 1; i
>= 0; --i
) {
1665 mStyleSet
->PrependStyleSheet(nsStyleSet::eUserSheet
, userSheets
[i
]);
1668 mStyleSet
->EndUpdate();
1670 ReconstructStyleData();
1674 PresShell::AddAgentSheet(nsISupports
* aSheet
)
1676 // Make sure this does what nsDocumentViewer::CreateStyleSet does
1678 nsCOMPtr
<nsIStyleSheet
> sheet
= do_QueryInterface(aSheet
);
1683 mStyleSet
->AppendStyleSheet(nsStyleSet::eAgentSheet
, sheet
);
1684 ReconstructStyleData();
1688 PresShell::AddAuthorSheet(nsISupports
* aSheet
)
1690 nsCOMPtr
<nsIStyleSheet
> sheet
= do_QueryInterface(aSheet
);
1695 // Document specific "additional" Author sheets should be stronger than the ones
1696 // added with the StyleSheetService.
1697 nsIStyleSheet
* firstAuthorSheet
= mDocument
->FirstAdditionalAuthorSheet();
1698 if (firstAuthorSheet
) {
1699 mStyleSet
->InsertStyleSheetBefore(nsStyleSet::eDocSheet
, sheet
, firstAuthorSheet
);
1701 mStyleSet
->AppendStyleSheet(nsStyleSet::eDocSheet
, sheet
);
1704 ReconstructStyleData();
1708 PresShell::RemoveSheet(nsStyleSet::sheetType aType
, nsISupports
* aSheet
)
1710 nsCOMPtr
<nsIStyleSheet
> sheet
= do_QueryInterface(aSheet
);
1715 mStyleSet
->RemoveStyleSheet(aType
, sheet
);
1716 ReconstructStyleData();
1720 PresShell::SetDisplaySelection(int16_t aToggle
)
1722 mSelection
->SetDisplaySelection(aToggle
);
1727 PresShell::GetDisplaySelection(int16_t *aToggle
)
1729 *aToggle
= mSelection
->GetDisplaySelection();
1734 PresShell::GetSelection(SelectionType aType
, nsISelection
**aSelection
)
1736 if (!aSelection
|| !mSelection
)
1737 return NS_ERROR_NULL_POINTER
;
1739 *aSelection
= mSelection
->GetSelection(aType
);
1742 return NS_ERROR_INVALID_ARG
;
1744 NS_ADDREF(*aSelection
);
1750 PresShell::GetCurrentSelection(SelectionType aType
)
1755 return mSelection
->GetSelection(aType
);
1759 PresShell::ScrollSelectionIntoView(SelectionType aType
, SelectionRegion aRegion
,
1763 return NS_ERROR_NULL_POINTER
;
1765 return mSelection
->ScrollSelectionIntoView(aType
, aRegion
, aFlags
);
1769 PresShell::RepaintSelection(SelectionType aType
)
1772 return NS_ERROR_NULL_POINTER
;
1774 return mSelection
->RepaintSelection(aType
);
1777 // Make shell be a document observer
1779 PresShell::BeginObservingDocument()
1781 if (mDocument
&& !mIsDestroying
) {
1782 mDocument
->AddObserver(this);
1783 if (mIsDocumentGone
) {
1784 NS_WARNING("Adding a presshell that was disconnected from the document "
1785 "as a document observer? Sounds wrong...");
1786 mIsDocumentGone
= false;
1791 // Make shell stop being a document observer
1793 PresShell::EndObservingDocument()
1795 // XXXbz do we need to tell the frame constructor that the document
1796 // is gone, perhaps? Except for printing it's NOT gone, sometimes.
1797 mIsDocumentGone
= true;
1799 mDocument
->RemoveObserver(this);
1804 char* nsPresShell_ReflowStackPointerTop
;
1808 PresShell::Initialize(nscoord aWidth
, nscoord aHeight
)
1810 if (mIsDestroying
) {
1819 mozilla::TimeStamp timerStart
= mozilla::TimeStamp::Now();
1821 NS_ASSERTION(!mDidInitialize
, "Why are we being called?");
1823 nsCOMPtr
<nsIPresShell
> kungFuDeathGrip(this);
1824 mDidInitialize
= true;
1827 if (VERIFY_REFLOW_NOISY_RC
& gVerifyReflowFlags
) {
1829 nsIURI
*uri
= mDocument
->GetDocumentURI();
1833 printf("*** PresShell::Initialize (this=%p, url='%s')\n", (void*)this, url
.get());
1839 // XXX Do a full invalidate at the beginning so that invalidates along
1840 // the way don't have region accumulation issues?
1842 mPresContext
->SetVisibleArea(nsRect(0, 0, aWidth
, aHeight
));
1844 // Get the root frame from the frame manager
1845 // XXXbz it would be nice to move this somewhere else... like frame manager
1846 // Init(), say. But we need to make sure our views are all set up by the
1848 nsIFrame
* rootFrame
= mFrameConstructor
->GetRootFrame();
1849 NS_ASSERTION(!rootFrame
, "How did that happen, exactly?");
1851 nsAutoScriptBlocker scriptBlocker
;
1852 mFrameConstructor
->BeginUpdate();
1853 rootFrame
= mFrameConstructor
->ConstructRootFrame();
1854 mFrameConstructor
->SetRootFrame(rootFrame
);
1855 mFrameConstructor
->EndUpdate();
1858 NS_ENSURE_STATE(!mHaveShutDown
);
1861 return NS_ERROR_OUT_OF_MEMORY
;
1864 nsIFrame
* invalidateFrame
= nullptr;
1865 for (nsIFrame
* f
= rootFrame
; f
; f
= nsLayoutUtils::GetCrossDocParentFrame(f
)) {
1866 if (f
->GetStateBits() & NS_FRAME_NO_COMPONENT_ALPHA
) {
1867 invalidateFrame
= f
;
1868 f
->RemoveStateBits(NS_FRAME_NO_COMPONENT_ALPHA
);
1870 nsCOMPtr
<nsIPresShell
> shell
;
1871 if (f
->GetType() == nsGkAtoms::subDocumentFrame
&&
1872 (shell
= static_cast<nsSubDocumentFrame
*>(f
)->GetSubdocumentPresShellForPainting(0)) &&
1873 shell
->GetPresContext()->IsRootContentDocument()) {
1874 // Root content documents build a 'force active' layer, and component alpha flattening
1875 // can't be propagated across that so no need to invalidate above this frame.
1881 if (invalidateFrame
) {
1882 invalidateFrame
->InvalidateFrameSubtree();
1885 Element
*root
= mDocument
->GetRootElement();
1889 nsAutoCauseReflowNotifier
reflowNotifier(this);
1890 mFrameConstructor
->BeginUpdate();
1892 // Have the style sheet processor construct frame for the root
1893 // content object down
1894 mFrameConstructor
->ContentInserted(nullptr, root
, nullptr, false);
1897 // Something in mFrameConstructor->ContentInserted may have caused
1898 // Destroy() to get called, bug 337586.
1899 NS_ENSURE_STATE(!mHaveShutDown
);
1901 mFrameConstructor
->EndUpdate();
1904 // nsAutoScriptBlocker going out of scope may have killed us too
1905 NS_ENSURE_STATE(!mHaveShutDown
);
1907 // Run the XBL binding constructors for any new frames we've constructed
1908 mDocument
->BindingManager()->ProcessAttachedQueue();
1910 // Constructors may have killed us too
1911 NS_ENSURE_STATE(!mHaveShutDown
);
1913 // Now flush out pending restyles before we actually reflow, in
1914 // case XBL constructors changed styles somewhere.
1916 nsAutoScriptBlocker scriptBlocker
;
1917 mPresContext
->RestyleManager()->ProcessPendingRestyles();
1920 // And that might have run _more_ XBL constructors
1921 NS_ENSURE_STATE(!mHaveShutDown
);
1924 NS_ASSERTION(rootFrame
, "How did that happen?");
1926 // Note: when the frame was created above it had the NS_FRAME_IS_DIRTY bit
1927 // set, but XBL processing could have caused a reflow which clears it.
1928 if (MOZ_LIKELY(rootFrame
->GetStateBits() & NS_FRAME_IS_DIRTY
)) {
1929 // Unset the DIRTY bits so that FrameNeedsReflow() will work right.
1930 rootFrame
->RemoveStateBits(NS_FRAME_IS_DIRTY
|
1931 NS_FRAME_HAS_DIRTY_CHILDREN
);
1932 NS_ASSERTION(!mDirtyRoots
.Contains(rootFrame
),
1933 "Why is the root in mDirtyRoots already?");
1934 FrameNeedsReflow(rootFrame
, eResize
, NS_FRAME_IS_DIRTY
);
1935 NS_ASSERTION(mDirtyRoots
.Contains(rootFrame
),
1936 "Should be in mDirtyRoots now");
1937 NS_ASSERTION(mReflowScheduled
, "Why no reflow scheduled?");
1940 // Restore our root scroll position now if we're getting here after EndLoad
1941 // got called, since this is our one chance to do it. Note that we need not
1942 // have reflowed for this to work; when the scrollframe is finally reflowed
1943 // it'll pick up the position we store in it here.
1944 if (!mDocumentLoading
) {
1945 RestoreRootScrollPosition();
1948 // For printing, we just immediately unsuppress.
1949 if (!mPresContext
->IsPaginated()) {
1950 // Kick off a one-shot timer based off our pref value. When this timer
1951 // fires, if painting is still locked down, then we will go ahead and
1952 // trigger a full invalidate and allow painting to proceed normally.
1953 mPaintingSuppressed
= true;
1954 // Don't suppress painting if the document isn't loading.
1955 nsIDocument::ReadyState readyState
= mDocument
->GetReadyStateEnum();
1956 if (readyState
!= nsIDocument::READYSTATE_COMPLETE
) {
1957 mPaintSuppressionTimer
= do_CreateInstance("@mozilla.org/timer;1");
1959 if (!mPaintSuppressionTimer
) {
1960 mPaintingSuppressed
= false;
1962 // Initialize the timer.
1964 // Default to PAINTLOCK_EVENT_DELAY if we can't get the pref value.
1966 Preferences::GetInt("nglayout.initialpaint.delay",
1967 PAINTLOCK_EVENT_DELAY
);
1969 mPaintSuppressionTimer
->InitWithFuncCallback(sPaintSuppressionCallback
,
1971 nsITimer::TYPE_ONE_SHOT
);
1975 if (root
&& root
->IsXUL()) {
1976 mozilla::Telemetry::AccumulateTimeDelta(Telemetry::XUL_INITIAL_FRAME_CONSTRUCTION
,
1980 return NS_OK
; //XXX this needs to be real. MMP
1984 PresShell::sPaintSuppressionCallback(nsITimer
*aTimer
, void* aPresShell
)
1986 nsRefPtr
<PresShell
> self
= static_cast<PresShell
*>(aPresShell
);
1988 self
->UnsuppressPainting();
1992 PresShell::AsyncResizeEventCallback(nsITimer
* aTimer
, void* aPresShell
)
1994 static_cast<PresShell
*>(aPresShell
)->FireResizeEvent();
1998 PresShell::ResizeReflowOverride(nscoord aWidth
, nscoord aHeight
)
2000 mViewportOverridden
= true;
2001 return ResizeReflowIgnoreOverride(aWidth
, aHeight
);
2005 PresShell::ResizeReflow(nscoord aWidth
, nscoord aHeight
)
2007 if (mViewportOverridden
) {
2008 // The viewport has been overridden, and this reflow request
2009 // didn't ask to ignore the override. Pretend it didn't happen.
2012 return ResizeReflowIgnoreOverride(aWidth
, aHeight
);
2016 PresShell::ResizeReflowIgnoreOverride(nscoord aWidth
, nscoord aHeight
)
2018 NS_PRECONDITION(!mIsReflowing
, "Shouldn't be in reflow here!");
2019 NS_PRECONDITION(aWidth
!= NS_UNCONSTRAINEDSIZE
,
2020 "shouldn't use unconstrained widths anymore");
2022 // If we don't have a root frame yet, that means we haven't had our initial
2023 // reflow... If that's the case, and aWidth or aHeight is unconstrained,
2024 // ignore them altogether.
2025 nsIFrame
* rootFrame
= mFrameConstructor
->GetRootFrame();
2026 if (!rootFrame
&& aHeight
== NS_UNCONSTRAINEDSIZE
) {
2027 // We can't do the work needed for SizeToContent without a root
2028 // frame, and we want to return before setting the visible area.
2029 return NS_ERROR_NOT_AVAILABLE
;
2032 mPresContext
->SetVisibleArea(nsRect(0, 0, aWidth
, aHeight
));
2034 // There isn't anything useful we can do if the initial reflow hasn't happened.
2039 nsRefPtr
<nsViewManager
> viewManagerDeathGrip
= mViewManager
;
2040 // Take this ref after viewManager so it'll make sure to go away first.
2041 nsCOMPtr
<nsIPresShell
> kungFuDeathGrip(this);
2043 if (!GetPresContext()->SupressingResizeReflow()) {
2044 // Have to make sure that the content notifications are flushed before we
2045 // start messing with the frame model; otherwise we can get content doubling.
2046 mDocument
->FlushPendingNotifications(Flush_ContentAndNotify
);
2048 // Make sure style is up to date
2050 nsAutoScriptBlocker scriptBlocker
;
2051 mPresContext
->RestyleManager()->ProcessPendingRestyles();
2054 rootFrame
= mFrameConstructor
->GetRootFrame();
2055 if (!mIsDestroying
&& rootFrame
) {
2056 // XXX Do a full invalidate at the beginning so that invalidates along
2057 // the way don't have region accumulation issues?
2060 nsAutoCauseReflowNotifier
crNotifier(this);
2063 // Kick off a top-down reflow
2064 AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Reflow
);
2065 nsViewManager::AutoDisableRefresh
refreshBlocker(mViewManager
);
2067 mDirtyRoots
.RemoveElement(rootFrame
);
2068 DoReflow(rootFrame
, true);
2071 DidDoReflow(true, false);
2075 rootFrame
= mFrameConstructor
->GetRootFrame();
2076 if (aHeight
== NS_UNCONSTRAINEDSIZE
&& rootFrame
) {
2077 mPresContext
->SetVisibleArea(
2078 nsRect(0, 0, aWidth
, rootFrame
->GetRect().height
));
2081 if (!mIsDestroying
&& !mResizeEvent
.IsPending() &&
2082 !mAsyncResizeTimerIsActive
) {
2084 if (!mAsyncResizeEventTimer
) {
2085 mAsyncResizeEventTimer
= do_CreateInstance("@mozilla.org/timer;1");
2087 if (mAsyncResizeEventTimer
) {
2088 mAsyncResizeTimerIsActive
= true;
2089 mAsyncResizeEventTimer
->InitWithFuncCallback(AsyncResizeEventCallback
,
2091 nsITimer::TYPE_ONE_SHOT
);
2094 nsRefPtr
<nsRunnableMethod
<PresShell
> > resizeEvent
=
2095 NS_NewRunnableMethod(this, &PresShell::FireResizeEvent
);
2096 if (NS_SUCCEEDED(NS_DispatchToCurrentThread(resizeEvent
))) {
2097 mResizeEvent
= resizeEvent
;
2098 mDocument
->SetNeedStyleFlush();
2103 return NS_OK
; //XXX this needs to be real. MMP
2107 PresShell::FireResizeEvent()
2109 if (mAsyncResizeTimerIsActive
) {
2110 mAsyncResizeTimerIsActive
= false;
2111 mAsyncResizeEventTimer
->Cancel();
2113 mResizeEvent
.Revoke();
2115 if (mIsDocumentGone
)
2118 //Send resize event from here.
2119 WidgetEvent
event(true, NS_RESIZE_EVENT
);
2120 nsEventStatus status
= nsEventStatus_eIgnore
;
2122 nsPIDOMWindow
*window
= mDocument
->GetWindow();
2124 nsCOMPtr
<nsIPresShell
> kungFuDeathGrip(this);
2126 EventDispatcher::Dispatch(window
, mPresContext
, &event
, nullptr, &status
);
2132 PresShell::SetIgnoreFrameDestruction(bool aIgnore
)
2135 // We need to tell the ImageLoader to drop all its references to frames
2136 // because they're about to go away and it won't get notifications of that.
2137 mDocument
->StyleImageLoader()->ClearFrames();
2139 mIgnoreFrameDestruction
= aIgnore
;
2143 PresShell::NotifyDestroyingFrame(nsIFrame
* aFrame
)
2145 if (!mIgnoreFrameDestruction
) {
2146 mDocument
->StyleImageLoader()->DropRequestsForFrame(aFrame
);
2148 mFrameConstructor
->NotifyDestroyingFrame(aFrame
);
2150 for (int32_t idx
= mDirtyRoots
.Length(); idx
; ) {
2152 if (mDirtyRoots
[idx
] == aFrame
) {
2153 mDirtyRoots
.RemoveElementAt(idx
);
2157 // Remove frame properties
2158 mPresContext
->NotifyDestroyingFrame(aFrame
);
2160 if (aFrame
== mCurrentEventFrame
) {
2161 mCurrentEventContent
= aFrame
->GetContent();
2162 mCurrentEventFrame
= nullptr;
2166 if (aFrame
== mDrawEventTargetFrame
) {
2167 mDrawEventTargetFrame
= nullptr;
2171 for (unsigned int i
=0; i
< mCurrentEventFrameStack
.Length(); i
++) {
2172 if (aFrame
== mCurrentEventFrameStack
.ElementAt(i
)) {
2173 //One of our stack frames was deleted. Get its content so that when we
2174 //pop it we can still get its new frame from its content
2175 nsIContent
*currentEventContent
= aFrame
->GetContent();
2176 mCurrentEventContentStack
.ReplaceObjectAt(currentEventContent
, i
);
2177 mCurrentEventFrameStack
[i
] = nullptr;
2181 mFramesToDirty
.RemoveEntry(aFrame
);
2183 // We must delete this property in situ so that its destructor removes the
2184 // frame from FrameLayerBuilder::DisplayItemData::mFrameList -- otherwise
2185 // the DisplayItemData destructor will use the destroyed frame when it
2186 // tries to remove it from the (array) value of this property.
2187 mPresContext
->PropertyTable()->
2188 Delete(aFrame
, FrameLayerBuilder::LayerManagerDataProperty());
2192 already_AddRefed
<nsCaret
> PresShell::GetCaret() const
2194 nsRefPtr
<nsCaret
> caret
= mCaret
;
2195 return caret
.forget();
2199 already_AddRefed
<TouchCaret
> PresShell::GetTouchCaret() const
2201 nsRefPtr
<TouchCaret
> touchCaret
= mTouchCaret
;
2202 return touchCaret
.forget();
2205 already_AddRefed
<SelectionCarets
> PresShell::GetSelectionCarets() const
2207 nsRefPtr
<SelectionCarets
> selectionCaret
= mSelectionCarets
;
2208 return selectionCaret
.forget();
2211 void PresShell::SetCaret(nsCaret
*aNewCaret
)
2216 void PresShell::RestoreCaret()
2218 mCaret
= mOriginalCaret
;
2221 NS_IMETHODIMP
PresShell::SetCaretEnabled(bool aInEnable
)
2223 bool oldEnabled
= mCaretEnabled
;
2225 mCaretEnabled
= aInEnable
;
2227 if (mCaretEnabled
!= oldEnabled
)
2229 /* Don't change the caret's selection here! This was an evil side-effect of SetCaretEnabled()
2230 nsCOMPtr<nsIDOMSelection> domSel;
2231 if (NS_SUCCEEDED(GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(domSel))) && domSel)
2232 mCaret->SetCaretDOMSelection(domSel);
2235 MOZ_ASSERT(mCaret
|| mTouchCaret
);
2237 mCaret
->SetVisible(mCaretEnabled
);
2240 mTouchCaret
->SyncVisibilityWithCaret();
2247 NS_IMETHODIMP
PresShell::SetCaretReadOnly(bool aReadOnly
)
2250 mCaret
->SetCaretReadOnly(aReadOnly
);
2254 NS_IMETHODIMP
PresShell::GetCaretEnabled(bool *aOutEnabled
)
2256 NS_ENSURE_ARG_POINTER(aOutEnabled
);
2257 *aOutEnabled
= mCaretEnabled
;
2261 NS_IMETHODIMP
PresShell::SetCaretVisibilityDuringSelection(bool aVisibility
)
2264 mCaret
->SetVisibilityDuringSelection(aVisibility
);
2268 NS_IMETHODIMP
PresShell::GetCaretVisible(bool *aOutIsVisible
)
2270 *aOutIsVisible
= false;
2272 *aOutIsVisible
= mCaret
->IsVisible();
2277 NS_IMETHODIMP
PresShell::SetSelectionFlags(int16_t aInEnable
)
2279 mSelectionFlags
= aInEnable
;
2283 NS_IMETHODIMP
PresShell::GetSelectionFlags(int16_t *aOutEnable
)
2286 return NS_ERROR_INVALID_ARG
;
2287 *aOutEnable
= mSelectionFlags
;
2291 //implementation of nsISelectionController
2294 PresShell::CharacterMove(bool aForward
, bool aExtend
)
2296 return mSelection
->CharacterMove(aForward
, aExtend
);
2300 PresShell::CharacterExtendForDelete()
2302 return mSelection
->CharacterExtendForDelete();
2306 PresShell::CharacterExtendForBackspace()
2308 return mSelection
->CharacterExtendForBackspace();
2312 PresShell::WordMove(bool aForward
, bool aExtend
)
2314 nsresult result
= mSelection
->WordMove(aForward
, aExtend
);
2315 // if we can't go down/up any more we must then move caret completely to
2316 // end/beginning respectively.
2317 if (NS_FAILED(result
))
2318 result
= CompleteMove(aForward
, aExtend
);
2323 PresShell::WordExtendForDelete(bool aForward
)
2325 return mSelection
->WordExtendForDelete(aForward
);
2329 PresShell::LineMove(bool aForward
, bool aExtend
)
2331 nsresult result
= mSelection
->LineMove(aForward
, aExtend
);
2332 // if we can't go down/up any more we must then move caret completely to
2333 // end/beginning respectively.
2334 if (NS_FAILED(result
))
2335 result
= CompleteMove(aForward
,aExtend
);
2340 PresShell::IntraLineMove(bool aForward
, bool aExtend
)
2342 return mSelection
->IntraLineMove(aForward
, aExtend
);
2348 PresShell::PageMove(bool aForward
, bool aExtend
)
2350 nsIScrollableFrame
*scrollableFrame
=
2351 GetFrameToScrollAsScrollable(nsIPresShell::eVertical
);
2352 if (!scrollableFrame
)
2355 mSelection
->CommonPageMove(aForward
, aExtend
, scrollableFrame
);
2356 // After ScrollSelectionIntoView(), the pending notifications might be
2357 // flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
2358 return ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL
,
2359 nsISelectionController::SELECTION_FOCUS_REGION
,
2360 nsISelectionController::SCROLL_SYNCHRONOUS
);
2366 PresShell::ScrollPage(bool aForward
)
2368 nsIScrollableFrame
* scrollFrame
=
2369 GetFrameToScrollAsScrollable(nsIPresShell::eVertical
);
2371 scrollFrame
->ScrollBy(nsIntPoint(0, aForward
? 1 : -1),
2372 nsIScrollableFrame::PAGES
,
2373 nsIScrollableFrame::SMOOTH
);
2379 PresShell::ScrollLine(bool aForward
)
2381 nsIScrollableFrame
* scrollFrame
=
2382 GetFrameToScrollAsScrollable(nsIPresShell::eVertical
);
2384 int32_t lineCount
= Preferences::GetInt("toolkit.scrollbox.verticalScrollDistance",
2385 NS_DEFAULT_VERTICAL_SCROLL_DISTANCE
);
2386 scrollFrame
->ScrollBy(nsIntPoint(0, aForward
? lineCount
: -lineCount
),
2387 nsIScrollableFrame::LINES
,
2388 nsIScrollableFrame::SMOOTH
);
2394 PresShell::ScrollCharacter(bool aRight
)
2396 nsIScrollableFrame
* scrollFrame
=
2397 GetFrameToScrollAsScrollable(nsIPresShell::eHorizontal
);
2399 int32_t h
= Preferences::GetInt("toolkit.scrollbox.horizontalScrollDistance",
2400 NS_DEFAULT_HORIZONTAL_SCROLL_DISTANCE
);
2401 scrollFrame
->ScrollBy(nsIntPoint(aRight
? h
: -h
, 0),
2402 nsIScrollableFrame::LINES
,
2403 nsIScrollableFrame::SMOOTH
);
2409 PresShell::CompleteScroll(bool aForward
)
2411 nsIScrollableFrame
* scrollFrame
=
2412 GetFrameToScrollAsScrollable(nsIPresShell::eVertical
);
2414 scrollFrame
->ScrollBy(nsIntPoint(0, aForward
? 1 : -1),
2415 nsIScrollableFrame::WHOLE
,
2416 nsIScrollableFrame::SMOOTH
);
2422 PresShell::CompleteMove(bool aForward
, bool aExtend
)
2424 // Beware! This may flush notifications via synchronous
2425 // ScrollSelectionIntoView.
2426 nsIContent
* limiter
= mSelection
->GetAncestorLimiter();
2427 nsIFrame
* frame
= limiter
? limiter
->GetPrimaryFrame()
2428 : FrameConstructor()->GetRootElementFrame();
2430 return NS_ERROR_FAILURE
;
2431 nsIFrame::CaretPosition pos
=
2432 frame
->GetExtremeCaretPosition(!aForward
);
2433 mSelection
->HandleClick(pos
.mResultContent
, pos
.mContentOffset
,
2434 pos
.mContentOffset
, aExtend
, false,
2435 aForward
? CARET_ASSOCIATE_AFTER
: CARET_ASSOCIATE_BEFORE
);
2437 // HandleClick resets ancestorLimiter, so set it again.
2438 mSelection
->SetAncestorLimiter(limiter
);
2441 // After ScrollSelectionIntoView(), the pending notifications might be
2442 // flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
2443 return ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL
,
2444 nsISelectionController::SELECTION_FOCUS_REGION
,
2445 nsISelectionController::SCROLL_SYNCHRONOUS
);
2449 PresShell::SelectAll()
2451 return mSelection
->SelectAll();
2455 DoCheckVisibility(nsPresContext
* aPresContext
,
2457 int16_t aStartOffset
,
2461 nsIFrame
* frame
= aNode
->GetPrimaryFrame();
2463 // No frame to look at so it must not be visible.
2467 // Start process now to go through all frames to find startOffset. Then check
2468 // chars after that to see if anything until EndOffset is visible.
2469 bool finished
= false;
2470 frame
->CheckVisibility(aPresContext
, aStartOffset
, aEndOffset
, true,
2471 &finished
, aRetval
);
2472 // Don't worry about other return value.
2476 PresShell::CheckVisibility(nsIDOMNode
*node
, int16_t startOffset
, int16_t EndOffset
, bool *_retval
)
2478 if (!node
|| startOffset
>EndOffset
|| !_retval
|| startOffset
<0 || EndOffset
<0)
2479 return NS_ERROR_INVALID_ARG
;
2480 *_retval
= false; //initialize return parameter
2481 nsCOMPtr
<nsIContent
> content(do_QueryInterface(node
));
2483 return NS_ERROR_FAILURE
;
2485 DoCheckVisibility(mPresContext
, content
, startOffset
, EndOffset
, _retval
);
2490 PresShell::CheckVisibilityContent(nsIContent
* aNode
, int16_t aStartOffset
,
2491 int16_t aEndOffset
, bool* aRetval
)
2493 if (!aNode
|| aStartOffset
> aEndOffset
|| !aRetval
||
2494 aStartOffset
< 0 || aEndOffset
< 0) {
2495 return NS_ERROR_INVALID_ARG
;
2499 DoCheckVisibility(mPresContext
, aNode
, aStartOffset
, aEndOffset
, aRetval
);
2503 //end implementations nsISelectionController
2506 nsIPresShell::GetRootFrameExternal() const
2508 return mFrameConstructor
->GetRootFrame();
2512 nsIPresShell::GetRootScrollFrame() const
2514 nsIFrame
* rootFrame
= mFrameConstructor
->GetRootFrame();
2515 // Ensure root frame is a viewport frame
2516 if (!rootFrame
|| nsGkAtoms::viewportFrame
!= rootFrame
->GetType())
2518 nsIFrame
* theFrame
= rootFrame
->GetFirstPrincipalChild();
2519 if (!theFrame
|| nsGkAtoms::scrollFrame
!= theFrame
->GetType())
2525 nsIPresShell::GetRootScrollFrameAsScrollable() const
2527 nsIFrame
* frame
= GetRootScrollFrame();
2530 nsIScrollableFrame
* scrollableFrame
= do_QueryFrame(frame
);
2531 NS_ASSERTION(scrollableFrame
,
2532 "All scroll frames must implement nsIScrollableFrame");
2533 return scrollableFrame
;
2537 nsIPresShell::GetRootScrollFrameAsScrollableExternal() const
2539 return GetRootScrollFrameAsScrollable();
2542 nsIPageSequenceFrame
*
2543 PresShell::GetPageSequenceFrame() const
2545 nsIFrame
* frame
= mFrameConstructor
->GetPageSequenceFrame();
2546 return do_QueryFrame(frame
);
2550 PresShell::GetCanvasFrame() const
2552 nsIFrame
* frame
= mFrameConstructor
->GetDocElementContainingBlock();
2553 return do_QueryFrame(frame
);
2557 PresShell::GetTouchCaretElement() const
2559 return GetCanvasFrame() ? GetCanvasFrame()->GetTouchCaretElement() : nullptr;
2563 PresShell::SetMayHaveTouchCaret(bool aSet
)
2565 if (!mPresContext
) {
2569 if (!mPresContext
->IsRoot()) {
2570 nsIPresShell
* rootPresShell
= GetRootPresShell();
2571 if (rootPresShell
) {
2572 rootPresShell
->SetMayHaveTouchCaret(aSet
);
2577 nsIDocument
* document
= GetDocument();
2579 nsPIDOMWindow
* innerWin
= document
->GetInnerWindow();
2581 innerWin
->SetMayHaveTouchCaret(aSet
);
2587 PresShell::MayHaveTouchCaret()
2589 if (!mPresContext
) {
2593 if (!mPresContext
->IsRoot()) {
2594 nsIPresShell
* rootPresShell
= GetRootPresShell();
2595 return rootPresShell
? rootPresShell
->MayHaveTouchCaret() : false;
2598 nsIDocument
* document
= GetDocument();
2600 nsPIDOMWindow
* innerWin
= document
->GetInnerWindow();
2602 return innerWin
->MayHaveTouchCaret();
2609 PresShell::GetSelectionCaretsStartElement() const
2611 return GetCanvasFrame() ? GetCanvasFrame()->GetSelectionCaretsStartElement() : nullptr;
2615 PresShell::GetSelectionCaretsEndElement() const
2617 return GetCanvasFrame() ? GetCanvasFrame()->GetSelectionCaretsEndElement() : nullptr;
2621 PresShell::BeginUpdate(nsIDocument
*aDocument
, nsUpdateType aUpdateType
)
2626 mFrameConstructor
->BeginUpdate();
2628 if (aUpdateType
& UPDATE_STYLE
)
2629 mStyleSet
->BeginUpdate();
2633 PresShell::EndUpdate(nsIDocument
*aDocument
, nsUpdateType aUpdateType
)
2636 NS_PRECONDITION(0 != mUpdateCount
, "too many EndUpdate's");
2640 if (aUpdateType
& UPDATE_STYLE
) {
2641 mStyleSet
->EndUpdate();
2642 if (mStylesHaveChanged
|| !mChangedScopeStyleRoots
.IsEmpty())
2643 ReconstructStyleData();
2646 mFrameConstructor
->EndUpdate();
2650 PresShell::RestoreRootScrollPosition()
2652 nsIScrollableFrame
* scrollableFrame
= GetRootScrollFrameAsScrollable();
2653 if (scrollableFrame
) {
2654 scrollableFrame
->ScrollToRestoredPosition();
2659 PresShell::MaybeReleaseCapturingContent()
2661 nsRefPtr
<nsFrameSelection
> frameSelection
= FrameSelection();
2662 if (frameSelection
) {
2663 frameSelection
->SetDragState(false);
2665 if (gCaptureInfo
.mContent
&&
2666 gCaptureInfo
.mContent
->OwnerDoc() == mDocument
) {
2667 SetCapturingContent(nullptr, 0);
2672 PresShell::BeginLoad(nsIDocument
*aDocument
)
2674 mDocumentLoading
= true;
2677 gfxTextPerfMetrics
*tp
= nullptr;
2679 tp
= mPresContext
->GetTextPerfMetrics();
2682 bool shouldLog
= gLog
&& PR_LOG_TEST(gLog
, PR_LOG_DEBUG
);
2683 if (shouldLog
|| tp
) {
2684 mLoadBegin
= TimeStamp::Now();
2688 nsIURI
* uri
= mDocument
->GetDocumentURI();
2693 PR_LOG(gLog
, PR_LOG_DEBUG
,
2694 ("(presshell) %p load begin [%s]\n",
2701 PresShell::EndLoad(nsIDocument
*aDocument
)
2703 NS_PRECONDITION(aDocument
== mDocument
, "Wrong document");
2705 RestoreRootScrollPosition();
2707 mDocumentLoading
= false;
2711 PresShell::LoadComplete()
2714 gfxTextPerfMetrics
*tp
= nullptr;
2716 tp
= mPresContext
->GetTextPerfMetrics();
2720 bool shouldLog
= gLog
&& PR_LOG_TEST(gLog
, PR_LOG_DEBUG
);
2721 if (shouldLog
|| tp
) {
2722 TimeDuration loadTime
= TimeStamp::Now() - mLoadBegin
;
2723 nsIURI
* uri
= mDocument
->GetDocumentURI();
2729 PR_LOG(gLog
, PR_LOG_DEBUG
,
2730 ("(presshell) %p load done time-ms: %9.2f [%s]\n",
2731 this, loadTime
.ToMilliseconds(), spec
.get()));
2735 if (tp
->cumulative
.numChars
> 0) {
2736 LogTextPerfStats(tp
, this, tp
->cumulative
, loadTime
.ToMilliseconds(),
2737 eLog_loaddone
, spec
.get());
2746 PresShell::VerifyHasDirtyRootAncestor(nsIFrame
* aFrame
)
2748 // XXXbz due to bug 372769, can't actually assert anything here...
2751 // XXXbz shouldn't need this part; remove it once FrameNeedsReflow
2752 // handles the root frame correctly.
2753 if (!aFrame
->GetParent()) {
2757 // Make sure that there is a reflow root ancestor of |aFrame| that's
2758 // in mDirtyRoots already.
2759 while (aFrame
&& (aFrame
->GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN
)) {
2760 if (((aFrame
->GetStateBits() & NS_FRAME_REFLOW_ROOT
) ||
2761 !aFrame
->GetParent()) &&
2762 mDirtyRoots
.Contains(aFrame
)) {
2766 aFrame
= aFrame
->GetParent();
2768 NS_NOTREACHED("Frame has dirty bits set but isn't scheduled to be "
2774 PresShell::FrameNeedsReflow(nsIFrame
*aFrame
, IntrinsicDirty aIntrinsicDirty
,
2775 nsFrameState aBitToAdd
)
2777 NS_PRECONDITION(aBitToAdd
== NS_FRAME_IS_DIRTY
||
2778 aBitToAdd
== NS_FRAME_HAS_DIRTY_CHILDREN
||
2780 "Unexpected bits being added");
2781 NS_PRECONDITION(!(aIntrinsicDirty
== eStyleChange
&&
2782 aBitToAdd
== NS_FRAME_HAS_DIRTY_CHILDREN
),
2783 "bits don't correspond to style change reason");
2785 NS_ASSERTION(!mIsReflowing
, "can't mark frame dirty during reflow");
2787 // If we've not yet done the initial reflow, then don't bother
2788 // enqueuing a reflow command yet.
2789 if (! mDidInitialize
)
2792 // If we're already destroying, don't bother with this either.
2797 //printf("gShellCounter: %d\n", gShellCounter++);
2798 if (mInVerifyReflow
)
2801 if (VERIFY_REFLOW_NOISY_RC
& gVerifyReflowFlags
) {
2802 printf("\nPresShell@%p: frame %p needs reflow\n", (void*)this, (void*)aFrame
);
2803 if (VERIFY_REFLOW_REALLY_NOISY_RC
& gVerifyReflowFlags
) {
2804 printf("Current content model:\n");
2805 Element
*rootElement
= mDocument
->GetRootElement();
2807 rootElement
->List(stdout
, 0);
2813 nsAutoTArray
<nsIFrame
*, 4> subtrees
;
2814 subtrees
.AppendElement(aFrame
);
2817 nsIFrame
*subtreeRoot
= subtrees
.ElementAt(subtrees
.Length() - 1);
2818 subtrees
.RemoveElementAt(subtrees
.Length() - 1);
2820 // Grab |wasDirty| now so we can go ahead and update the bits on
2822 bool wasDirty
= NS_SUBTREE_DIRTY(subtreeRoot
);
2823 subtreeRoot
->AddStateBits(aBitToAdd
);
2825 // Now if subtreeRoot is a reflow root we can cut off this reflow at it if
2826 // the bit being added is NS_FRAME_HAS_DIRTY_CHILDREN.
2827 bool targetFrameDirty
= (aBitToAdd
== NS_FRAME_IS_DIRTY
);
2829 #define FRAME_IS_REFLOW_ROOT(_f) \
2830 ((_f->GetStateBits() & NS_FRAME_REFLOW_ROOT) && \
2831 (_f != subtreeRoot || !targetFrameDirty))
2834 // Mark the intrinsic widths as dirty on the frame, all of its ancestors,
2835 // and all of its descendants, if needed:
2837 if (aIntrinsicDirty
!= eResize
) {
2838 // Mark argument and all ancestors dirty. (Unless we hit a reflow
2839 // root that should contain the reflow. That root could be
2840 // subtreeRoot itself if it's not dirty, or it could be some
2841 // ancestor of subtreeRoot.)
2842 for (nsIFrame
*a
= subtreeRoot
;
2843 a
&& !FRAME_IS_REFLOW_ROOT(a
);
2845 a
->MarkIntrinsicISizesDirty();
2848 if (aIntrinsicDirty
== eStyleChange
) {
2849 // Mark all descendants dirty (using an nsTArray stack rather than
2851 // Note that nsHTMLReflowState::InitResizeFlags has some similar
2852 // code; see comments there for how and why it differs.
2853 nsAutoTArray
<nsIFrame
*, 32> stack
;
2854 stack
.AppendElement(subtreeRoot
);
2857 nsIFrame
*f
= stack
.ElementAt(stack
.Length() - 1);
2858 stack
.RemoveElementAt(stack
.Length() - 1);
2860 if (f
->GetType() == nsGkAtoms::placeholderFrame
) {
2861 nsIFrame
*oof
= nsPlaceholderFrame::GetRealFrameForPlaceholder(f
);
2862 if (!nsLayoutUtils::IsProperAncestorFrame(subtreeRoot
, oof
)) {
2863 // We have another distinct subtree we need to mark.
2864 subtrees
.AppendElement(oof
);
2868 nsIFrame::ChildListIterator
lists(f
);
2869 for (; !lists
.IsDone(); lists
.Next()) {
2870 nsFrameList::Enumerator
childFrames(lists
.CurrentList());
2871 for (; !childFrames
.AtEnd(); childFrames
.Next()) {
2872 nsIFrame
* kid
= childFrames
.get();
2873 kid
->MarkIntrinsicISizesDirty();
2874 stack
.AppendElement(kid
);
2877 } while (stack
.Length() != 0);
2880 // Skip setting dirty bits up the tree if we weren't given a bit to add.
2885 // Set NS_FRAME_HAS_DIRTY_CHILDREN bits (via nsIFrame::ChildIsDirty)
2886 // up the tree until we reach either a frame that's already dirty or
2888 nsIFrame
*f
= subtreeRoot
;
2890 if (FRAME_IS_REFLOW_ROOT(f
) || !f
->GetParent()) {
2891 // we've hit a reflow root or the root frame
2893 mDirtyRoots
.AppendElement(f
);
2894 mDocument
->SetNeedLayoutFlush();
2898 VerifyHasDirtyRootAncestor(f
);
2905 nsIFrame
*child
= f
;
2907 wasDirty
= NS_SUBTREE_DIRTY(f
);
2908 f
->ChildIsDirty(child
);
2909 NS_ASSERTION(f
->GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN
,
2910 "ChildIsDirty didn't do its job");
2912 // This frame was already marked dirty.
2914 VerifyHasDirtyRootAncestor(f
);
2919 } while (subtrees
.Length() != 0);
2921 MaybeScheduleReflow();
2925 PresShell::FrameNeedsToContinueReflow(nsIFrame
*aFrame
)
2927 NS_ASSERTION(mIsReflowing
, "Must be in reflow when marking path dirty.");
2928 NS_PRECONDITION(mCurrentReflowRoot
, "Must have a current reflow root here");
2929 NS_ASSERTION(aFrame
== mCurrentReflowRoot
||
2930 nsLayoutUtils::IsProperAncestorFrame(mCurrentReflowRoot
, aFrame
),
2931 "Frame passed in is not the descendant of mCurrentReflowRoot");
2932 NS_ASSERTION(aFrame
->GetStateBits() & NS_FRAME_IN_REFLOW
,
2933 "Frame passed in not in reflow?");
2935 mFramesToDirty
.PutEntry(aFrame
);
2939 nsIPresShell::GetFrameToScrollAsScrollable(
2940 nsIPresShell::ScrollDirection aDirection
)
2942 nsIScrollableFrame
* scrollFrame
= nullptr;
2944 nsCOMPtr
<nsIContent
> focusedContent
;
2945 nsIFocusManager
* fm
= nsFocusManager::GetFocusManager();
2946 if (fm
&& mDocument
) {
2947 nsCOMPtr
<nsIDOMWindow
> window
= do_QueryInterface(mDocument
->GetWindow());
2949 nsCOMPtr
<nsIDOMElement
> focusedElement
;
2950 fm
->GetFocusedElementForWindow(window
, false, nullptr, getter_AddRefs(focusedElement
));
2951 focusedContent
= do_QueryInterface(focusedElement
);
2953 if (!focusedContent
&& mSelection
) {
2954 nsISelection
* domSelection
= mSelection
->
2955 GetSelection(nsISelectionController::SELECTION_NORMAL
);
2957 nsCOMPtr
<nsIDOMNode
> focusedNode
;
2958 domSelection
->GetFocusNode(getter_AddRefs(focusedNode
));
2959 focusedContent
= do_QueryInterface(focusedNode
);
2962 if (focusedContent
) {
2963 nsIFrame
* startFrame
= focusedContent
->GetPrimaryFrame();
2965 scrollFrame
= startFrame
->GetScrollTargetFrame();
2967 startFrame
= scrollFrame
->GetScrolledFrame();
2969 if (aDirection
== nsIPresShell::eEither
) {
2971 nsLayoutUtils::GetNearestScrollableFrame(startFrame
);
2974 nsLayoutUtils::GetNearestScrollableFrameForDirection(startFrame
,
2975 aDirection
== eVertical
? nsLayoutUtils::eVertical
:
2976 nsLayoutUtils::eHorizontal
);
2981 scrollFrame
= GetRootScrollFrameAsScrollable();
2987 PresShell::CancelAllPendingReflows()
2989 mDirtyRoots
.Clear();
2991 if (mReflowScheduled
) {
2992 GetPresContext()->RefreshDriver()->RemoveLayoutFlushObserver(this);
2993 mReflowScheduled
= false;
2996 ASSERT_REFLOW_SCHEDULED_STATE();
3000 PresShell::RecreateFramesFor(nsIContent
* aContent
)
3002 NS_ENSURE_TRUE(mPresContext
, NS_ERROR_FAILURE
);
3003 if (!mDidInitialize
) {
3004 // Nothing to do here. In fact, if we proceed and aContent is the
3005 // root we will crash.
3009 // Don't call RecreateFramesForContent since that is not exported and we want
3010 // to keep the number of entrypoints down.
3012 NS_ASSERTION(mViewManager
, "Should have view manager");
3014 // Have to make sure that the content notifications are flushed before we
3015 // start messing with the frame model; otherwise we can get content doubling.
3016 mDocument
->FlushPendingNotifications(Flush_ContentAndNotify
);
3018 nsAutoScriptBlocker scriptBlocker
;
3020 nsStyleChangeList changeList
;
3021 changeList
.AppendChange(nullptr, aContent
, nsChangeHint_ReconstructFrame
);
3023 // Mark ourselves as not safe to flush while we're doing frame construction.
3025 RestyleManager
* restyleManager
= mPresContext
->RestyleManager();
3026 nsresult rv
= restyleManager
->ProcessRestyledFrames(changeList
);
3027 restyleManager
->FlushOverflowChangedTracker();
3034 nsIPresShell::PostRecreateFramesFor(Element
* aElement
)
3036 mPresContext
->RestyleManager()->PostRestyleEvent(aElement
, nsRestyleHint(0),
3037 nsChangeHint_ReconstructFrame
);
3041 nsIPresShell::RestyleForAnimation(Element
* aElement
, nsRestyleHint aHint
)
3043 mPresContext
->RestyleManager()->PostAnimationRestyleEvent(aElement
, aHint
,
3044 NS_STYLE_HINT_NONE
);
3048 nsIPresShell::SetForwardingContainer(const WeakPtr
<nsDocShell
> &aContainer
)
3050 mForwardingContainer
= aContainer
;
3054 PresShell::ClearFrameRefs(nsIFrame
* aFrame
)
3056 mPresContext
->EventStateManager()->ClearFrameRefs(aFrame
);
3058 nsWeakFrame
* weakFrame
= mWeakFrames
;
3060 nsWeakFrame
* prev
= weakFrame
->GetPreviousWeakFrame();
3061 if (weakFrame
->GetFrame() == aFrame
) {
3062 // This removes weakFrame from mWeakFrames.
3063 weakFrame
->Clear(this);
3069 already_AddRefed
<nsRenderingContext
>
3070 PresShell::CreateReferenceRenderingContext()
3072 nsDeviceContext
* devCtx
= mPresContext
->DeviceContext();
3073 nsRefPtr
<nsRenderingContext
> rc
;
3074 if (mPresContext
->IsScreen()) {
3075 rc
= new nsRenderingContext();
3076 rc
->Init(devCtx
, gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget());
3078 rc
= devCtx
->CreateRenderingContext();
3081 MOZ_ASSERT(rc
, "shouldn't break promise to return non-null");
3086 PresShell::GoToAnchor(const nsAString
& aAnchorName
, bool aScroll
)
3089 return NS_ERROR_FAILURE
;
3092 const Element
*root
= mDocument
->GetRootElement();
3093 if (root
&& root
->IsSVG(nsGkAtoms::svg
)) {
3094 // We need to execute this even if there is an empty anchor name
3095 // so that any existing SVG fragment identifier effect is removed
3096 if (SVGFragmentIdentifier::ProcessFragmentIdentifier(mDocument
, aAnchorName
)) {
3101 // Hold a reference to the ESM in case event dispatch tears us down.
3102 nsRefPtr
<EventStateManager
> esm
= mPresContext
->EventStateManager();
3104 if (aAnchorName
.IsEmpty()) {
3105 NS_ASSERTION(!aScroll
, "can't scroll to empty anchor name");
3106 esm
->SetContentState(nullptr, NS_EVENT_STATE_URLTARGET
);
3110 nsCOMPtr
<nsIDOMHTMLDocument
> htmlDoc
= do_QueryInterface(mDocument
);
3111 nsresult rv
= NS_OK
;
3112 nsCOMPtr
<nsIContent
> content
;
3114 // Search for an element with a matching "id" attribute
3116 content
= mDocument
->GetElementById(aAnchorName
);
3119 // Search for an anchor element with a matching "name" attribute
3120 if (!content
&& htmlDoc
) {
3121 nsCOMPtr
<nsIDOMNodeList
> list
;
3122 // Find a matching list of named nodes
3123 rv
= htmlDoc
->GetElementsByName(aAnchorName
, getter_AddRefs(list
));
3124 if (NS_SUCCEEDED(rv
) && list
) {
3126 // Loop through the named nodes looking for the first anchor
3127 for (i
= 0; true; i
++) {
3128 nsCOMPtr
<nsIDOMNode
> node
;
3129 rv
= list
->Item(i
, getter_AddRefs(node
));
3130 if (!node
) { // End of list
3133 // Ensure it's an anchor element
3134 content
= do_QueryInterface(node
);
3136 if (content
->Tag() == nsGkAtoms::a
&& content
->IsHTML()) {
3145 // Search for anchor in the HTML namespace with a matching name
3146 if (!content
&& !htmlDoc
)
3148 nsCOMPtr
<nsIDOMDocument
> doc
= do_QueryInterface(mDocument
);
3149 nsCOMPtr
<nsIDOMNodeList
> list
;
3150 NS_NAMED_LITERAL_STRING(nameSpace
, "http://www.w3.org/1999/xhtml");
3151 // Get the list of anchor elements
3152 rv
= doc
->GetElementsByTagNameNS(nameSpace
, NS_LITERAL_STRING("a"), getter_AddRefs(list
));
3153 if (NS_SUCCEEDED(rv
) && list
) {
3155 // Loop through the named nodes looking for the first anchor
3156 for (i
= 0; true; i
++) {
3157 nsCOMPtr
<nsIDOMNode
> node
;
3158 rv
= list
->Item(i
, getter_AddRefs(node
));
3159 if (!node
) { // End of list
3162 // Compare the name attribute
3163 nsCOMPtr
<nsIDOMElement
> element
= do_QueryInterface(node
);
3165 if (element
&& NS_SUCCEEDED(element
->GetAttribute(NS_LITERAL_STRING("name"), value
))) {
3166 if (value
.Equals(aAnchorName
)) {
3167 content
= do_QueryInterface(element
);
3175 esm
->SetContentState(content
, NS_EVENT_STATE_URLTARGET
);
3177 #ifdef ACCESSIBILITY
3178 nsIContent
*anchorTarget
= content
;
3181 nsIScrollableFrame
* rootScroll
= GetRootScrollFrameAsScrollable();
3182 if (rootScroll
&& rootScroll
->DidHistoryRestore()) {
3183 // Scroll position restored from history trumps scrolling to anchor.
3185 rootScroll
->ClearDidHistoryRestore();
3190 rv
= ScrollContentIntoView(content
,
3191 ScrollAxis(SCROLL_TOP
, SCROLL_ALWAYS
),
3193 ANCHOR_SCROLL_FLAGS
);
3194 NS_ENSURE_SUCCESS(rv
, rv
);
3196 nsIScrollableFrame
* rootScroll
= GetRootScrollFrameAsScrollable();
3198 mLastAnchorScrolledTo
= content
;
3199 mLastAnchorScrollPositionY
= rootScroll
->GetScrollPosition().y
;
3203 // Should we select the target? This action is controlled by a
3204 // preference: the default is to not select.
3205 bool selectAnchor
= Preferences::GetBool("layout.selectanchor");
3207 // Even if select anchor pref is false, we must still move the
3208 // caret there. That way tabbing will start from the new
3210 nsRefPtr
<nsIDOMRange
> jumpToRange
= new nsRange(mDocument
);
3211 while (content
&& content
->GetFirstChild()) {
3212 content
= content
->GetFirstChild();
3214 nsCOMPtr
<nsIDOMNode
> node(do_QueryInterface(content
));
3215 NS_ASSERTION(node
, "No nsIDOMNode for descendant of anchor");
3216 jumpToRange
->SelectNodeContents(node
);
3217 // Select the anchor
3218 nsISelection
* sel
= mSelection
->
3219 GetSelection(nsISelectionController::SELECTION_NORMAL
);
3221 sel
->RemoveAllRanges();
3222 sel
->AddRange(jumpToRange
);
3223 if (!selectAnchor
) {
3224 // Use a caret (collapsed selection) at the start of the anchor
3225 sel
->CollapseToStart();
3228 // Selection is at anchor.
3229 // Now focus the document itself if focus is on an element within it.
3230 nsPIDOMWindow
*win
= mDocument
->GetWindow();
3232 nsIFocusManager
* fm
= nsFocusManager::GetFocusManager();
3234 nsCOMPtr
<nsIDOMWindow
> focusedWindow
;
3235 fm
->GetFocusedWindow(getter_AddRefs(focusedWindow
));
3236 if (SameCOMIdentity(win
, focusedWindow
)) {
3237 fm
->ClearFocus(focusedWindow
);
3241 // If the target is an animation element, activate the animation
3242 if (content
->IsNodeOfType(nsINode::eANIMATION
)) {
3243 SVGContentUtils::ActivateByHyperlink(content
.get());
3246 rv
= NS_ERROR_FAILURE
;
3247 NS_NAMED_LITERAL_STRING(top
, "top");
3248 if (nsContentUtils::EqualsIgnoreASCIICase(aAnchorName
, top
)) {
3249 // Scroll to the top/left if aAnchorName is "top" and there is no element
3250 // with such a name or id.
3252 nsIScrollableFrame
* sf
= GetRootScrollFrameAsScrollable();
3253 // Check |aScroll| after setting |rv| so we set |rv| to the same
3254 // thing whether or not |aScroll| is true.
3255 if (aScroll
&& sf
) {
3256 // Scroll to the top of the page
3257 sf
->ScrollTo(nsPoint(0, 0), nsIScrollableFrame::INSTANT
);
3262 #ifdef ACCESSIBILITY
3264 nsAccessibilityService
* accService
= AccService();
3266 accService
->NotifyOfAnchorJumpTo(anchorTarget
);
3274 PresShell::ScrollToAnchor()
3276 if (!mLastAnchorScrolledTo
) {
3279 NS_ASSERTION(mDidInitialize
, "should have done initial reflow by now");
3281 nsIScrollableFrame
* rootScroll
= GetRootScrollFrameAsScrollable();
3283 mLastAnchorScrollPositionY
!= rootScroll
->GetScrollPosition().y
) {
3286 nsresult rv
= ScrollContentIntoView(mLastAnchorScrolledTo
,
3287 ScrollAxis(SCROLL_TOP
, SCROLL_ALWAYS
),
3289 ANCHOR_SCROLL_FLAGS
);
3290 mLastAnchorScrolledTo
= nullptr;
3295 * Helper (per-continuation) for ScrollContentIntoView.
3297 * @param aContainerFrame [in] the frame which aRect is relative to
3298 * @param aFrame [in] Frame whose bounds should be unioned
3299 * @param aUseWholeLineHeightForInlines [in] if true, then for inline frames
3300 * we should include the top of the line in the added rectangle
3301 * @param aRect [inout] rect into which its bounds should be unioned
3302 * @param aHaveRect [inout] whether aRect contains data yet
3303 * @param aPrevBlock [inout] the block aLines is a line iterator for
3304 * @param aLines [inout] the line iterator we're using
3305 * @param aCurLine [inout] the line to start looking from in this iterator
3308 AccumulateFrameBounds(nsIFrame
* aContainerFrame
,
3310 bool aUseWholeLineHeightForInlines
,
3313 nsIFrame
*& aPrevBlock
,
3314 nsAutoLineIterator
& aLines
,
3317 nsIFrame
* frame
= aFrame
;
3318 nsRect frameBounds
= nsRect(nsPoint(0, 0), aFrame
->GetSize());
3320 // If this is an inline frame and either the bounds height is 0 (quirks
3321 // layout model) or aUseWholeLineHeightForInlines is set, we need to
3322 // change the top of the bounds to include the whole line.
3323 if (frameBounds
.height
== 0 || aUseWholeLineHeightForInlines
) {
3324 nsIFrame
*prevFrame
= aFrame
;
3325 nsIFrame
*f
= aFrame
;
3327 while (f
&& f
->IsFrameOfType(nsIFrame::eLineParticipant
) &&
3328 !f
->IsTransformed() && !f
->IsPositioned()) {
3330 f
= prevFrame
->GetParent();
3335 f
->GetType() == nsGkAtoms::blockFrame
) {
3336 // find the line containing aFrame and increase the top of |offset|.
3337 if (f
!= aPrevBlock
) {
3338 aLines
= f
->GetLineIterator();
3343 int32_t index
= aLines
->FindLineContaining(prevFrame
, aCurLine
);
3351 if (NS_SUCCEEDED(aLines
->GetLine(index
, &trash1
, &trash2
,
3352 lineBounds
, &trash3
))) {
3353 frameBounds
+= frame
->GetOffsetTo(f
);
3355 if (lineBounds
.y
< frameBounds
.y
) {
3356 frameBounds
.height
= frameBounds
.YMost() - lineBounds
.y
;
3357 frameBounds
.y
= lineBounds
.y
;
3365 nsRect transformedBounds
= nsLayoutUtils::TransformFrameRectToAncestor(frame
,
3366 frameBounds
, aContainerFrame
);
3369 // We can't use nsRect::UnionRect since it drops empty rects on
3370 // the floor, and we need to include them. (Thus we need
3371 // aHaveRect to know when to drop the initial value on the floor.)
3372 aRect
.UnionRectEdges(aRect
, transformedBounds
);
3375 aRect
= transformedBounds
;
3380 ComputeNeedToScroll(nsIPresShell::WhenToScroll aWhenToScroll
,
3386 // See how the rect should be positioned vertically
3387 if (nsIPresShell::SCROLL_ALWAYS
== aWhenToScroll
) {
3388 // The caller wants the frame as visible as possible
3390 } else if (nsIPresShell::SCROLL_IF_NOT_VISIBLE
== aWhenToScroll
) {
3391 // Scroll only if no part of the frame is visible in this view
3392 return aRectMax
- aLineSize
<= aViewMin
||
3393 aRectMin
+ aLineSize
>= aViewMax
;
3394 } else if (nsIPresShell::SCROLL_IF_NOT_FULLY_VISIBLE
== aWhenToScroll
) {
3395 // Scroll only if part of the frame is hidden and more can fit in view
3396 return !(aRectMin
>= aViewMin
&& aRectMax
<= aViewMax
) &&
3397 std::min(aViewMax
, aRectMax
) - std::max(aRectMin
, aViewMin
) < aViewMax
- aViewMin
;
3403 ComputeWhereToScroll(int16_t aWhereToScroll
,
3404 nscoord aOriginalCoord
,
3410 nscoord
* aRangeMax
) {
3411 nscoord resultCoord
= aOriginalCoord
;
3412 // Allow the scroll operation to land anywhere that
3413 // makes the whole rectangle visible.
3414 if (nsIPresShell::SCROLL_MINIMUM
== aWhereToScroll
) {
3415 if (aRectMin
< aViewMin
) {
3416 // Scroll up so the frame's top edge is visible
3417 resultCoord
= aRectMin
;
3418 } else if (aRectMax
> aViewMax
) {
3419 // Scroll down so the frame's bottom edge is visible. Make sure the
3420 // frame's top edge is still visible
3421 resultCoord
= aOriginalCoord
+ aRectMax
- aViewMax
;
3422 if (resultCoord
> aRectMin
) {
3423 resultCoord
= aRectMin
;
3427 nscoord frameAlignCoord
=
3428 NSToCoordRound(aRectMin
+ (aRectMax
- aRectMin
) * (aWhereToScroll
/ 100.0f
));
3429 resultCoord
= NSToCoordRound(frameAlignCoord
- (aViewMax
- aViewMin
) * (
3430 aWhereToScroll
/ 100.0f
));
3432 nscoord scrollPortLength
= aViewMax
- aViewMin
;
3433 // Force the scroll range to extend to include resultCoord.
3434 *aRangeMin
= std::min(resultCoord
, aRectMax
- scrollPortLength
);
3435 *aRangeMax
= std::max(resultCoord
, aRectMin
);
3440 * This function takes a scrollable frame, a rect in the coordinate system
3441 * of the scrolled frame, and a desired percentage-based scroll
3442 * position and attempts to scroll the rect to that position in the
3445 * This needs to work even if aRect has a width or height of zero.
3447 static void ScrollToShowRect(nsIFrame
* aFrame
,
3448 nsIScrollableFrame
* aFrameAsScrollable
,
3449 const nsRect
& aRect
,
3450 nsIPresShell::ScrollAxis aVertical
,
3451 nsIPresShell::ScrollAxis aHorizontal
,
3454 nsPoint scrollPt
= aFrameAsScrollable
->GetScrollPosition();
3455 nsRect
visibleRect(scrollPt
,
3456 aFrameAsScrollable
->GetScrollPositionClampingScrollPortSize());
3458 // If this is the root scroll frame, make sure to take into account the
3459 // content document fixed position margins. When set, these indicate that
3460 // chrome is obscuring the viewport.
3461 nsRect
targetRect(aRect
);
3462 nsIPresShell
*presShell
= aFrame
->PresContext()->PresShell();
3463 if (aFrameAsScrollable
== presShell
->GetRootScrollFrameAsScrollable()) {
3464 targetRect
.Inflate(presShell
->GetContentDocumentFixedPositionMargins());
3468 // Don't call GetLineScrollAmount unless we actually need it. Not only
3469 // does this save time, but it's not safe to call GetLineScrollAmount
3470 // during reflow (because it depends on font size inflation and doesn't
3471 // use the in-reflow-safe font-size inflation path). If we did call it,
3472 // it would assert and possible give the wrong result.
3473 if (aVertical
.mWhenToScroll
== nsIPresShell::SCROLL_IF_NOT_VISIBLE
||
3474 aHorizontal
.mWhenToScroll
== nsIPresShell::SCROLL_IF_NOT_VISIBLE
) {
3475 lineSize
= aFrameAsScrollable
->GetLineScrollAmount();
3477 ScrollbarStyles ss
= aFrameAsScrollable
->GetScrollbarStyles();
3478 nsRect
allowedRange(scrollPt
, nsSize(0, 0));
3479 bool needToScroll
= false;
3480 uint32_t directions
= aFrameAsScrollable
->GetPerceivedScrollingDirections();
3482 if (((aFlags
& nsIPresShell::SCROLL_OVERFLOW_HIDDEN
) ||
3483 ss
.mVertical
!= NS_STYLE_OVERFLOW_HIDDEN
) &&
3484 (!aVertical
.mOnlyIfPerceivedScrollableDirection
||
3485 (directions
& nsIScrollableFrame::VERTICAL
))) {
3487 if (ComputeNeedToScroll(aVertical
.mWhenToScroll
,
3492 visibleRect
.YMost())) {
3494 scrollPt
.y
= ComputeWhereToScroll(aVertical
.mWhereToScroll
,
3499 visibleRect
.YMost(),
3500 &allowedRange
.y
, &maxHeight
);
3501 allowedRange
.height
= maxHeight
- allowedRange
.y
;
3502 needToScroll
= true;
3506 if (((aFlags
& nsIPresShell::SCROLL_OVERFLOW_HIDDEN
) ||
3507 ss
.mHorizontal
!= NS_STYLE_OVERFLOW_HIDDEN
) &&
3508 (!aHorizontal
.mOnlyIfPerceivedScrollableDirection
||
3509 (directions
& nsIScrollableFrame::HORIZONTAL
))) {
3511 if (ComputeNeedToScroll(aHorizontal
.mWhenToScroll
,
3516 visibleRect
.XMost())) {
3518 scrollPt
.x
= ComputeWhereToScroll(aHorizontal
.mWhereToScroll
,
3523 visibleRect
.XMost(),
3524 &allowedRange
.x
, &maxWidth
);
3525 allowedRange
.width
= maxWidth
- allowedRange
.x
;
3526 needToScroll
= true;
3530 // If we don't need to scroll, then don't try since it might cancel
3531 // a current smooth scroll operation.
3533 nsIScrollableFrame::ScrollMode scrollMode
= nsIScrollableFrame::INSTANT
;
3534 if (gfxPrefs::ScrollBehaviorEnabled() && aFlags
& nsIPresShell::SCROLL_SMOOTH
) {
3535 scrollMode
= nsIScrollableFrame::SMOOTH_MSD
;
3537 aFrameAsScrollable
->ScrollTo(scrollPt
, scrollMode
, &allowedRange
);
3542 PresShell::ScrollContentIntoView(nsIContent
* aContent
,
3543 nsIPresShell::ScrollAxis aVertical
,
3544 nsIPresShell::ScrollAxis aHorizontal
,
3547 NS_ENSURE_TRUE(aContent
, NS_ERROR_NULL_POINTER
);
3548 nsCOMPtr
<nsIDocument
> composedDoc
= aContent
->GetComposedDoc();
3549 NS_ENSURE_STATE(composedDoc
);
3551 NS_ASSERTION(mDidInitialize
, "should have done initial reflow by now");
3553 if (mContentToScrollTo
) {
3554 mContentToScrollTo
->DeleteProperty(nsGkAtoms::scrolling
);
3556 mContentToScrollTo
= aContent
;
3557 ScrollIntoViewData
* data
= new ScrollIntoViewData();
3558 data
->mContentScrollVAxis
= aVertical
;
3559 data
->mContentScrollHAxis
= aHorizontal
;
3560 data
->mContentToScrollToFlags
= aFlags
;
3561 if (NS_FAILED(mContentToScrollTo
->SetProperty(nsGkAtoms::scrolling
, data
,
3562 nsINode::DeleteProperty
<PresShell::ScrollIntoViewData
>))) {
3563 mContentToScrollTo
= nullptr;
3566 // Flush layout and attempt to scroll in the process.
3567 composedDoc
->SetNeedLayoutFlush();
3568 composedDoc
->FlushPendingNotifications(Flush_InterruptibleLayout
);
3570 // If mContentToScrollTo is non-null, that means we interrupted the reflow
3571 // (or suppressed it altogether because we're suppressing interruptible
3572 // flushes right now) and won't necessarily get the position correct, but do
3573 // a best-effort scroll here. The other option would be to do this inside
3574 // FlushPendingNotifications, but I'm not sure the repeated scrolling that
3575 // could trigger if reflows keep getting interrupted would be more desirable
3576 // than a single best-effort scroll followed by one final scroll on the first
3577 // completed reflow.
3578 if (mContentToScrollTo
) {
3579 DoScrollContentIntoView();
3585 PresShell::DoScrollContentIntoView()
3587 NS_ASSERTION(mDidInitialize
, "should have done initial reflow by now");
3589 nsIFrame
* frame
= mContentToScrollTo
->GetPrimaryFrame();
3591 mContentToScrollTo
->DeleteProperty(nsGkAtoms::scrolling
);
3592 mContentToScrollTo
= nullptr;
3596 if (frame
->GetStateBits() & NS_FRAME_FIRST_REFLOW
) {
3597 // The reflow flush before this scroll got interrupted, and this frame's
3598 // coords and size are all zero, and it has no content showing anyway.
3599 // Don't bother scrolling to it. We'll try again when we finish up layout.
3603 // Make sure we skip 'frame' ... if it's scrollable, we should use its
3604 // scrollable ancestor as the container.
3605 nsIFrame
* container
=
3606 nsLayoutUtils::GetClosestFrameOfType(frame
->GetParent(), nsGkAtoms::scrollFrame
);
3608 // nothing can be scrolled
3612 ScrollIntoViewData
* data
= static_cast<ScrollIntoViewData
*>(
3613 mContentToScrollTo
->GetProperty(nsGkAtoms::scrolling
));
3614 if (MOZ_UNLIKELY(!data
)) {
3615 mContentToScrollTo
= nullptr;
3619 // This is a two-step process.
3620 // Step 1: Find the bounds of the rect we want to scroll into view. For
3621 // example, for an inline frame we may want to scroll in the whole
3622 // line, or we may want to scroll multiple lines into view.
3623 // Step 2: Walk container frame and its ancestors and scroll them
3625 // frameBounds is relative to container. We're assuming
3626 // that scrollframes don't split so every continuation of frame will
3627 // be a descendant of container. (Things would still mostly work
3628 // even if that assumption was false.)
3630 bool haveRect
= false;
3631 bool useWholeLineHeightForInlines
=
3632 data
->mContentScrollVAxis
.mWhenToScroll
!= nsIPresShell::SCROLL_IF_NOT_FULLY_VISIBLE
;
3633 // Reuse the same line iterator across calls to AccumulateFrameBounds. We set
3634 // it every time we detect a new block (stored in prevBlock).
3635 nsIFrame
* prevBlock
= nullptr;
3636 nsAutoLineIterator lines
;
3637 // The last line we found a continuation on in |lines|. We assume that later
3638 // continuations cannot come on earlier lines.
3639 int32_t curLine
= 0;
3641 AccumulateFrameBounds(container
, frame
, useWholeLineHeightForInlines
,
3642 frameBounds
, haveRect
, prevBlock
, lines
, curLine
);
3643 } while ((frame
= frame
->GetNextContinuation()));
3645 ScrollFrameRectIntoView(container
, frameBounds
, data
->mContentScrollVAxis
,
3646 data
->mContentScrollHAxis
,
3647 data
->mContentToScrollToFlags
);
3651 PresShell::ScrollFrameRectIntoView(nsIFrame
* aFrame
,
3652 const nsRect
& aRect
,
3653 nsIPresShell::ScrollAxis aVertical
,
3654 nsIPresShell::ScrollAxis aHorizontal
,
3657 bool didScroll
= false;
3658 // This function needs to work even if rect has a width or height of 0.
3659 nsRect rect
= aRect
;
3660 nsIFrame
* container
= aFrame
;
3661 // Walk up the frame hierarchy scrolling the rect into view and
3662 // keeping rect relative to container
3664 nsIScrollableFrame
* sf
= do_QueryFrame(container
);
3666 nsPoint oldPosition
= sf
->GetScrollPosition();
3667 nsRect targetRect
= rect
;
3668 if (container
->StyleDisplay()->mOverflowClipBox
==
3669 NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX
) {
3670 nsMargin padding
= container
->GetUsedPadding();
3671 targetRect
.Inflate(padding
);
3673 ScrollToShowRect(container
, sf
, targetRect
- sf
->GetScrolledFrame()->GetPosition(),
3674 aVertical
, aHorizontal
, aFlags
);
3675 nsPoint newPosition
= sf
->GetScrollPosition();
3676 // If the scroll position increased, that means our content moved up,
3677 // so our rect's offset should decrease
3678 rect
+= oldPosition
- newPosition
;
3680 if (oldPosition
!= newPosition
) {
3684 // only scroll one container when this flag is set
3685 if (aFlags
& nsIPresShell::SCROLL_FIRST_ANCESTOR_ONLY
) {
3690 if (container
->IsTransformed()) {
3691 container
->GetTransformMatrix(nullptr, &parent
);
3692 rect
= nsLayoutUtils::TransformFrameRectToAncestor(container
, rect
, parent
);
3694 rect
+= container
->GetPosition();
3695 parent
= container
->GetParent();
3697 if (!parent
&& !(aFlags
& nsIPresShell::SCROLL_NO_PARENT_FRAMES
)) {
3698 nsPoint
extraOffset(0,0);
3699 parent
= nsLayoutUtils::GetCrossDocParentFrame(container
, &extraOffset
);
3701 int32_t APD
= container
->PresContext()->AppUnitsPerDevPixel();
3702 int32_t parentAPD
= parent
->PresContext()->AppUnitsPerDevPixel();
3703 rect
= rect
.ConvertAppUnitsRoundOut(APD
, parentAPD
);
3704 rect
+= extraOffset
;
3708 } while (container
);
3714 PresShell::GetRectVisibility(nsIFrame
* aFrame
,
3715 const nsRect
&aRect
,
3716 nscoord aMinTwips
) const
3718 NS_ASSERTION(aFrame
->PresContext() == GetPresContext(),
3719 "prescontext mismatch?");
3720 nsIFrame
* rootFrame
= mFrameConstructor
->GetRootFrame();
3721 NS_ASSERTION(rootFrame
,
3722 "How can someone have a frame for this presshell when there's no root?");
3723 nsIScrollableFrame
* sf
= GetRootScrollFrameAsScrollable();
3724 nsRect scrollPortRect
;
3726 scrollPortRect
= sf
->GetScrollPortRect();
3727 nsIFrame
* f
= do_QueryFrame(sf
);
3728 scrollPortRect
+= f
->GetOffsetTo(rootFrame
);
3730 scrollPortRect
= nsRect(nsPoint(0,0), rootFrame
->GetSize());
3733 nsRect r
= aRect
+ aFrame
->GetOffsetTo(rootFrame
);
3734 // If aRect is entirely visible then we don't need to ensure that
3735 // at least aMinTwips of it is visible
3736 if (scrollPortRect
.Contains(r
))
3737 return nsRectVisibility_kVisible
;
3739 nsRect insetRect
= scrollPortRect
;
3740 insetRect
.Deflate(aMinTwips
, aMinTwips
);
3741 if (r
.YMost() <= insetRect
.y
)
3742 return nsRectVisibility_kAboveViewport
;
3743 if (r
.y
>= insetRect
.YMost())
3744 return nsRectVisibility_kBelowViewport
;
3745 if (r
.XMost() <= insetRect
.x
)
3746 return nsRectVisibility_kLeftOfViewport
;
3747 if (r
.x
>= insetRect
.XMost())
3748 return nsRectVisibility_kRightOfViewport
;
3750 return nsRectVisibility_kVisible
;
3753 class PaintTimerCallBack MOZ_FINAL
: public nsITimerCallback
3756 explicit PaintTimerCallBack(PresShell
* aShell
) : mShell(aShell
) {}
3760 NS_IMETHODIMP
Notify(nsITimer
* aTimer
) MOZ_FINAL
3762 mShell
->SetNextPaintCompressed();
3763 mShell
->AddInvalidateHiddenPresShellObserver(mShell
->GetPresContext()->RefreshDriver());
3764 mShell
->ScheduleViewManagerFlush();
3769 ~PaintTimerCallBack() {}
3774 NS_IMPL_ISUPPORTS(PaintTimerCallBack
, nsITimerCallback
)
3777 PresShell::ScheduleViewManagerFlush(PaintType aType
)
3779 if (aType
== PAINT_DELAYED_COMPRESS
) {
3780 // Delay paint for 1 second.
3781 static const uint32_t kPaintDelayPeriod
= 1000;
3782 if (!mDelayedPaintTimer
) {
3783 mDelayedPaintTimer
= do_CreateInstance(NS_TIMER_CONTRACTID
);
3784 nsRefPtr
<PaintTimerCallBack
> cb
= new PaintTimerCallBack(this);
3785 mDelayedPaintTimer
->InitWithCallback(cb
, kPaintDelayPeriod
, nsITimer::TYPE_ONE_SHOT
);
3790 nsPresContext
* presContext
= GetPresContext();
3792 presContext
->RefreshDriver()->ScheduleViewManagerFlush();
3795 mDocument
->SetNeedLayoutFlush();
3800 PresShell::DispatchSynthMouseMove(WidgetGUIEvent
* aEvent
,
3801 bool aFlushOnHoverChange
)
3803 RestyleManager
* restyleManager
= mPresContext
->RestyleManager();
3804 uint32_t hoverGenerationBefore
= restyleManager
->GetHoverGeneration();
3805 nsEventStatus status
;
3806 nsView
* targetView
= nsView::GetViewFor(aEvent
->widget
);
3809 targetView
->GetViewManager()->DispatchEvent(aEvent
, targetView
, &status
);
3810 if (MOZ_UNLIKELY(mIsDestroying
)) {
3813 if (aFlushOnHoverChange
&&
3814 hoverGenerationBefore
!= restyleManager
->GetHoverGeneration()) {
3815 // Flush so that the resulting reflow happens now so that our caller
3816 // can suppress any synthesized mouse moves caused by that reflow.
3817 FlushPendingNotifications(Flush_Layout
);
3822 PresShell::ClearMouseCaptureOnView(nsView
* aView
)
3824 if (gCaptureInfo
.mContent
) {
3826 // if a view was specified, ensure that the captured content is within
3828 nsIFrame
* frame
= gCaptureInfo
.mContent
->GetPrimaryFrame();
3830 nsView
* view
= frame
->GetClosestView();
3831 // if there is no view, capturing won't be handled any more, so
3832 // just release the capture.
3835 if (view
== aView
) {
3836 NS_RELEASE(gCaptureInfo
.mContent
);
3837 // the view containing the captured content likely disappeared so
3838 // disable capture for now.
3839 gCaptureInfo
.mAllowed
= false;
3843 view
= view
->GetParent();
3845 // return if the view wasn't found
3851 NS_RELEASE(gCaptureInfo
.mContent
);
3854 // disable mouse capture until the next mousedown as a dialog has opened
3855 // or a drag has started. Otherwise, someone could start capture during
3856 // the modal dialog or drag.
3857 gCaptureInfo
.mAllowed
= false;
3861 nsIPresShell::ClearMouseCapture(nsIFrame
* aFrame
)
3863 if (!gCaptureInfo
.mContent
) {
3864 gCaptureInfo
.mAllowed
= false;
3868 // null frame argument means clear the capture
3870 NS_RELEASE(gCaptureInfo
.mContent
);
3871 gCaptureInfo
.mAllowed
= false;
3875 nsIFrame
* capturingFrame
= gCaptureInfo
.mContent
->GetPrimaryFrame();
3876 if (!capturingFrame
) {
3877 NS_RELEASE(gCaptureInfo
.mContent
);
3878 gCaptureInfo
.mAllowed
= false;
3882 if (nsLayoutUtils::IsAncestorFrameCrossDoc(aFrame
, capturingFrame
)) {
3883 NS_RELEASE(gCaptureInfo
.mContent
);
3884 gCaptureInfo
.mAllowed
= false;
3889 PresShell::CaptureHistoryState(nsILayoutHistoryState
** aState
)
3891 NS_PRECONDITION(nullptr != aState
, "null state pointer");
3893 // We actually have to mess with the docshell here, since we want to
3894 // store the state back in it.
3895 // XXXbz this isn't really right, since this is being called in the
3896 // content viewer's Hide() method... by that point the docshell's
3897 // state could be wrong. We should sort out a better ownership
3898 // model for the layout history state.
3899 nsCOMPtr
<nsIDocShell
> docShell(mPresContext
->GetDocShell());
3901 return NS_ERROR_FAILURE
;
3903 nsCOMPtr
<nsILayoutHistoryState
> historyState
;
3904 docShell
->GetLayoutHistoryState(getter_AddRefs(historyState
));
3905 if (!historyState
) {
3906 // Create the document state object
3907 historyState
= NS_NewLayoutHistoryState();
3908 docShell
->SetLayoutHistoryState(historyState
);
3911 *aState
= historyState
;
3912 NS_IF_ADDREF(*aState
);
3914 // Capture frame state for the entire frame hierarchy
3915 nsIFrame
* rootFrame
= mFrameConstructor
->GetRootFrame();
3916 if (!rootFrame
) return NS_OK
;
3918 mFrameConstructor
->CaptureFrameState(rootFrame
, historyState
);
3924 PresShell::UnsuppressAndInvalidate()
3926 // Note: We ignore the EnsureVisible check for resource documents, because
3927 // they won't have a docshell, so they'll always fail EnsureVisible.
3928 if ((!mDocument
->IsResourceDoc() && !mPresContext
->EnsureVisible()) ||
3930 // No point; we're about to be torn down anyway.
3934 if (!mDocument
->IsResourceDoc()) {
3935 // Notify observers that a new page is about to be drawn. Execute this
3936 // as soon as it is safe to run JS, which is guaranteed to be before we
3937 // go back to the event loop and actually draw the page.
3938 nsContentUtils::AddScriptRunner(new nsBeforeFirstPaintDispatcher(mDocument
));
3941 mPaintingSuppressed
= false;
3942 nsIFrame
* rootFrame
= mFrameConstructor
->GetRootFrame();
3944 // let's assume that outline on a root frame is not supported
3945 rootFrame
->InvalidateFrame();
3948 mTouchCaret
->UpdatePositionIfNeeded();
3952 // now that painting is unsuppressed, focus may be set on the document
3953 nsPIDOMWindow
*win
= mDocument
->GetWindow();
3955 win
->SetReadyForFocus();
3957 if (!mHaveShutDown
) {
3958 SynthesizeMouseMove(false);
3959 ScheduleImageVisibilityUpdate();
3964 PresShell::UnsuppressPainting()
3966 if (mPaintSuppressionTimer
) {
3967 mPaintSuppressionTimer
->Cancel();
3968 mPaintSuppressionTimer
= nullptr;
3971 if (mIsDocumentGone
|| !mPaintingSuppressed
)
3974 // If we have reflows pending, just wait until we process
3975 // the reflows and get all the frames where we want them
3976 // before actually unlocking the painting. Otherwise
3977 // go ahead and unlock now.
3978 if (!mDirtyRoots
.IsEmpty())
3979 mShouldUnsuppressPainting
= true;
3981 UnsuppressAndInvalidate();
3984 // Post a request to handle an arbitrary callback after reflow has finished.
3986 PresShell::PostReflowCallback(nsIReflowCallback
* aCallback
)
3988 void* result
= AllocateMisc(sizeof(nsCallbackEventRequest
));
3989 nsCallbackEventRequest
* request
= (nsCallbackEventRequest
*)result
;
3991 request
->callback
= aCallback
;
3992 request
->next
= nullptr;
3994 if (mLastCallbackEventRequest
) {
3995 mLastCallbackEventRequest
= mLastCallbackEventRequest
->next
= request
;
3997 mFirstCallbackEventRequest
= request
;
3998 mLastCallbackEventRequest
= request
;
4005 PresShell::CancelReflowCallback(nsIReflowCallback
* aCallback
)
4007 nsCallbackEventRequest
* before
= nullptr;
4008 nsCallbackEventRequest
* node
= mFirstCallbackEventRequest
;
4011 nsIReflowCallback
* callback
= node
->callback
;
4013 if (callback
== aCallback
)
4015 nsCallbackEventRequest
* toFree
= node
;
4016 if (node
== mFirstCallbackEventRequest
) {
4018 mFirstCallbackEventRequest
= node
;
4019 NS_ASSERTION(before
== nullptr, "impossible");
4022 before
->next
= node
;
4025 if (toFree
== mLastCallbackEventRequest
) {
4026 mLastCallbackEventRequest
= before
;
4029 FreeMisc(sizeof(nsCallbackEventRequest
), toFree
);
4038 PresShell::CancelPostedReflowCallbacks()
4040 while (mFirstCallbackEventRequest
) {
4041 nsCallbackEventRequest
* node
= mFirstCallbackEventRequest
;
4042 mFirstCallbackEventRequest
= node
->next
;
4043 if (!mFirstCallbackEventRequest
) {
4044 mLastCallbackEventRequest
= nullptr;
4046 nsIReflowCallback
* callback
= node
->callback
;
4047 FreeMisc(sizeof(nsCallbackEventRequest
), node
);
4049 callback
->ReflowCallbackCanceled();
4055 PresShell::HandlePostedReflowCallbacks(bool aInterruptible
)
4057 bool shouldFlush
= false;
4059 while (mFirstCallbackEventRequest
) {
4060 nsCallbackEventRequest
* node
= mFirstCallbackEventRequest
;
4061 mFirstCallbackEventRequest
= node
->next
;
4062 if (!mFirstCallbackEventRequest
) {
4063 mLastCallbackEventRequest
= nullptr;
4065 nsIReflowCallback
* callback
= node
->callback
;
4066 FreeMisc(sizeof(nsCallbackEventRequest
), node
);
4068 if (callback
->ReflowFinished()) {
4074 mozFlushType flushType
=
4075 aInterruptible
? Flush_InterruptibleLayout
: Flush_Layout
;
4076 if (shouldFlush
&& !mIsDestroying
) {
4077 FlushPendingNotifications(flushType
);
4082 PresShell::IsSafeToFlush() const
4084 // Not safe if we are reflowing or in the middle of frame construction
4085 bool isSafeToFlush
= !mIsReflowing
&&
4088 if (isSafeToFlush
) {
4089 // Not safe if we are painting
4090 nsViewManager
* viewManager
= GetViewManager();
4092 bool isPainting
= false;
4093 viewManager
->IsPainting(isPainting
);
4095 isSafeToFlush
= false;
4100 return isSafeToFlush
;
4105 PresShell::FlushPendingNotifications(mozFlushType aType
)
4107 // by default, flush animations if aType >= Flush_Style
4108 mozilla::ChangesToFlush
flush(aType
, aType
>= Flush_Style
);
4109 FlushPendingNotifications(flush
);
4113 PresShell::FlushPendingNotifications(mozilla::ChangesToFlush aFlush
)
4120 * VERY IMPORTANT: If you add some sort of new flushing to this
4121 * method, make sure to add the relevant SetNeedLayoutFlush or
4122 * SetNeedStyleFlush calls on the document.
4124 mozFlushType flushType
= aFlush
.mFlushType
;
4126 #ifdef MOZ_ENABLE_PROFILER_SPS
4127 static const char flushTypeNames
[][20] = {
4131 "InterruptibleLayout",
4136 // Make sure that we don't miss things added to mozFlushType!
4137 MOZ_ASSERT(static_cast<uint32_t>(flushType
) <= ArrayLength(flushTypeNames
));
4139 PROFILER_LABEL_PRINTF("PresShell", "Flush",
4140 js::ProfileEntry::Category::GRAPHICS
, "(Flush_%s)", flushTypeNames
[flushType
- 1]);
4143 #ifdef ACCESSIBILITY
4145 nsAccessibilityService
* accService
= GetAccService();
4147 NS_ASSERTION(!accService
->IsProcessingRefreshDriverNotification(),
4148 "Flush during accessible tree update!");
4153 NS_ASSERTION(flushType
>= Flush_Frames
, "Why did we get called?");
4155 bool isSafeToFlush
= IsSafeToFlush();
4157 // If layout could possibly trigger scripts, then it's only safe to flush if
4158 // it's safe to run script.
4159 bool hasHadScriptObject
;
4160 if (mDocument
->GetScriptHandlingObject(hasHadScriptObject
) ||
4161 hasHadScriptObject
) {
4162 isSafeToFlush
= isSafeToFlush
&& nsContentUtils::IsSafeToRunScript();
4165 NS_ASSERTION(!isSafeToFlush
|| mViewManager
, "Must have view manager");
4166 // Make sure the view manager stays alive.
4167 nsRefPtr
<nsViewManager
> viewManagerDeathGrip
= mViewManager
;
4168 bool didStyleFlush
= false;
4169 bool didLayoutFlush
= false;
4170 if (isSafeToFlush
&& mViewManager
) {
4171 // Processing pending notifications can kill us, and some callers only
4172 // hold weak refs when calling FlushPendingNotifications(). :(
4173 nsCOMPtr
<nsIPresShell
> kungFuDeathGrip(this);
4175 if (mResizeEvent
.IsPending()) {
4177 if (mIsDestroying
) {
4182 // We need to make sure external resource documents are flushed too (for
4183 // example, svg filters that reference a filter in an external document
4184 // need the frames in the external document to be constructed for the
4185 // filter to work). We only need external resources to be flushed when the
4186 // main document is flushing >= Flush_Frames, so we flush external
4187 // resources here instead of nsDocument::FlushPendingNotifications.
4188 mDocument
->FlushExternalResources(flushType
);
4190 // Force flushing of any pending content notifications that might have
4191 // queued up while our event was pending. That will ensure that we don't
4192 // construct frames for content right now that's still waiting to be
4194 mDocument
->FlushPendingNotifications(Flush_ContentAndNotify
);
4196 // Process pending restyles, since any flush of the presshell wants
4197 // up-to-date style data.
4198 if (!mIsDestroying
) {
4199 mViewManager
->FlushDelayedResize(false);
4200 mPresContext
->FlushPendingMediaFeatureValuesChanged();
4202 // Flush any pending update of the user font set, since that could
4203 // cause style changes (for updating ex/ch units, and to cause a
4205 mPresContext
->FlushUserFontSet();
4207 mPresContext
->FlushCounterStyles();
4209 // Flush any requested SMIL samples.
4210 if (mDocument
->HasAnimationController()) {
4211 mDocument
->GetAnimationController()->FlushResampleRequests();
4214 if (aFlush
.mFlushAnimations
&&
4215 !mPresContext
->StyleUpdateForAllAnimationsIsUpToDate()) {
4216 if (mPresContext
->AnimationManager()) {
4217 mPresContext
->AnimationManager()->
4218 FlushAnimations(CommonAnimationManager::Cannot_Throttle
);
4220 if (mPresContext
->TransitionManager()) {
4221 mPresContext
->TransitionManager()->
4222 FlushTransitions(CommonAnimationManager::Cannot_Throttle
);
4224 mPresContext
->TickLastStyleUpdateForAllAnimations();
4227 // The FlushResampleRequests() above flushed style changes.
4228 if (!mIsDestroying
) {
4229 nsAutoScriptBlocker scriptBlocker
;
4230 mPresContext
->RestyleManager()->ProcessPendingRestyles();
4234 // Dispatch any 'animationstart' events those (or earlier) restyles
4236 if (!mIsDestroying
) {
4237 mPresContext
->AnimationManager()->DispatchEvents();
4240 // Process whatever XBL constructors those restyles queued up. This
4241 // ensures that onload doesn't fire too early and that we won't do extra
4242 // reflows after those constructors run.
4243 if (!mIsDestroying
) {
4244 mDocument
->BindingManager()->ProcessAttachedQueue();
4247 // Now those constructors or events might have posted restyle
4248 // events. At the same time, we still need up-to-date style data.
4249 // In particular, reflow depends on style being completely up to
4250 // date. If it's not, then style context reparenting, which can
4251 // happen during reflow, might suddenly pick up the new rules and
4252 // we'll end up with frames whose style doesn't match the frame
4254 if (!mIsDestroying
) {
4255 nsAutoScriptBlocker scriptBlocker
;
4256 mPresContext
->RestyleManager()->ProcessPendingRestyles();
4259 didStyleFlush
= true;
4262 // There might be more pending constructors now, but we're not going to
4263 // worry about them. They can't be triggered during reflow, so we should
4266 if (flushType
>= (mSuppressInterruptibleReflows
? Flush_Layout
: Flush_InterruptibleLayout
) &&
4268 didLayoutFlush
= true;
4269 mFrameConstructor
->RecalcQuotesAndCounters();
4270 mViewManager
->FlushDelayedResize(true);
4271 if (ProcessReflowCommands(flushType
< Flush_Layout
) && mContentToScrollTo
) {
4272 // We didn't get interrupted. Go ahead and scroll to our content
4273 DoScrollContentIntoView();
4274 if (mContentToScrollTo
) {
4275 mContentToScrollTo
->DeleteProperty(nsGkAtoms::scrolling
);
4276 mContentToScrollTo
= nullptr;
4281 if (flushType
>= Flush_Layout
) {
4282 if (!mIsDestroying
) {
4283 mViewManager
->UpdateWidgetGeometry();
4288 if (!didStyleFlush
&& flushType
>= Flush_Style
&& !mIsDestroying
) {
4289 mDocument
->SetNeedStyleFlush();
4292 if (!didLayoutFlush
&& !mIsDestroying
&&
4294 (mSuppressInterruptibleReflows
? Flush_Layout
: Flush_InterruptibleLayout
))) {
4295 // We suppressed this flush due to mSuppressInterruptibleReflows or
4296 // !isSafeToFlush, but the document thinks it doesn't
4297 // need to flush anymore. Let it know what's really going on.
4298 mDocument
->SetNeedLayoutFlush();
4303 PresShell::CharacterDataChanged(nsIDocument
*aDocument
,
4304 nsIContent
* aContent
,
4305 CharacterDataChangeInfo
* aInfo
)
4307 NS_PRECONDITION(!mIsDocumentGone
, "Unexpected CharacterDataChanged");
4308 NS_PRECONDITION(aDocument
== mDocument
, "Unexpected aDocument");
4310 nsAutoCauseReflowNotifier
crNotifier(this);
4312 // Call this here so it only happens for real content mutations and
4313 // not cases when the frame constructor calls its own methods to force
4314 // frame reconstruction.
4315 nsIContent
*container
= aContent
->GetParent();
4316 uint32_t selectorFlags
=
4317 container
? (container
->GetFlags() & NODE_ALL_SELECTOR_FLAGS
) : 0;
4318 if (selectorFlags
!= 0 && !aContent
->IsRootOfAnonymousSubtree()) {
4319 Element
* element
= container
->AsElement();
4320 if (aInfo
->mAppend
&& !aContent
->GetNextSibling())
4321 mPresContext
->RestyleManager()->RestyleForAppend(element
, aContent
);
4323 mPresContext
->RestyleManager()->RestyleForInsertOrChange(element
, aContent
);
4326 mFrameConstructor
->CharacterDataChanged(aContent
, aInfo
);
4331 PresShell::ContentStateChanged(nsIDocument
* aDocument
,
4332 nsIContent
* aContent
,
4333 EventStates aStateMask
)
4335 NS_PRECONDITION(!mIsDocumentGone
, "Unexpected ContentStateChanged");
4336 NS_PRECONDITION(aDocument
== mDocument
, "Unexpected aDocument");
4338 if (mDidInitialize
) {
4339 nsAutoCauseReflowNotifier
crNotifier(this);
4340 mPresContext
->RestyleManager()->ContentStateChanged(aContent
, aStateMask
);
4346 PresShell::DocumentStatesChanged(nsIDocument
* aDocument
,
4347 EventStates aStateMask
)
4349 NS_PRECONDITION(!mIsDocumentGone
, "Unexpected DocumentStatesChanged");
4350 NS_PRECONDITION(aDocument
== mDocument
, "Unexpected aDocument");
4352 if (mDidInitialize
&&
4353 mStyleSet
->HasDocumentStateDependentStyle(mPresContext
,
4354 mDocument
->GetRootElement(),
4356 mPresContext
->RestyleManager()->PostRestyleEvent(mDocument
->GetRootElement(),
4358 NS_STYLE_HINT_NONE
);
4362 if (aStateMask
.HasState(NS_DOCUMENT_STATE_WINDOW_INACTIVE
)) {
4363 nsIFrame
* root
= mFrameConstructor
->GetRootFrame();
4365 root
->SchedulePaint();
4371 PresShell::AttributeWillChange(nsIDocument
* aDocument
,
4373 int32_t aNameSpaceID
,
4374 nsIAtom
* aAttribute
,
4377 NS_PRECONDITION(!mIsDocumentGone
, "Unexpected AttributeWillChange");
4378 NS_PRECONDITION(aDocument
== mDocument
, "Unexpected aDocument");
4380 // XXXwaterson it might be more elegant to wait until after the
4381 // initial reflow to begin observing the document. That would
4382 // squelch any other inappropriate notifications as well.
4383 if (mDidInitialize
) {
4384 nsAutoCauseReflowNotifier
crNotifier(this);
4385 mPresContext
->RestyleManager()->AttributeWillChange(aElement
, aNameSpaceID
,
4386 aAttribute
, aModType
);
4392 PresShell::AttributeChanged(nsIDocument
* aDocument
,
4394 int32_t aNameSpaceID
,
4395 nsIAtom
* aAttribute
,
4398 NS_PRECONDITION(!mIsDocumentGone
, "Unexpected AttributeChanged");
4399 NS_PRECONDITION(aDocument
== mDocument
, "Unexpected aDocument");
4401 // XXXwaterson it might be more elegant to wait until after the
4402 // initial reflow to begin observing the document. That would
4403 // squelch any other inappropriate notifications as well.
4404 if (mDidInitialize
) {
4405 nsAutoCauseReflowNotifier
crNotifier(this);
4406 mPresContext
->RestyleManager()->AttributeChanged(aElement
, aNameSpaceID
,
4407 aAttribute
, aModType
);
4413 PresShell::ContentAppended(nsIDocument
*aDocument
,
4414 nsIContent
* aContainer
,
4415 nsIContent
* aFirstNewContent
,
4416 int32_t aNewIndexInContainer
)
4418 NS_PRECONDITION(!mIsDocumentGone
, "Unexpected ContentAppended");
4419 NS_PRECONDITION(aDocument
== mDocument
, "Unexpected aDocument");
4420 NS_PRECONDITION(aContainer
, "must have container");
4422 if (!mDidInitialize
) {
4426 nsAutoCauseReflowNotifier
crNotifier(this);
4428 // Call this here so it only happens for real content mutations and
4429 // not cases when the frame constructor calls its own methods to force
4430 // frame reconstruction.
4431 if (aContainer
->IsElement()) {
4432 // Ensure the container is an element before trying to restyle
4433 // because it can be the case that the container is a ShadowRoot
4434 // which is a document fragment.
4435 mPresContext
->RestyleManager()->
4436 RestyleForAppend(aContainer
->AsElement(), aFirstNewContent
);
4439 mFrameConstructor
->ContentAppended(aContainer
, aFirstNewContent
, true);
4441 if (static_cast<nsINode
*>(aContainer
) == static_cast<nsINode
*>(aDocument
) &&
4442 aFirstNewContent
->NodeType() == nsIDOMNode::DOCUMENT_TYPE_NODE
) {
4443 NotifyFontSizeInflationEnabledIsDirty();
4450 PresShell::ContentInserted(nsIDocument
* aDocument
,
4451 nsIContent
* aContainer
,
4453 int32_t aIndexInContainer
)
4455 NS_PRECONDITION(!mIsDocumentGone
, "Unexpected ContentInserted");
4456 NS_PRECONDITION(aDocument
== mDocument
, "Unexpected aDocument");
4458 if (!mDidInitialize
) {
4462 nsAutoCauseReflowNotifier
crNotifier(this);
4464 // Call this here so it only happens for real content mutations and
4465 // not cases when the frame constructor calls its own methods to force
4466 // frame reconstruction.
4467 if (aContainer
&& aContainer
->IsElement()) {
4468 // Ensure the container is an element before trying to restyle
4469 // because it can be the case that the container is a ShadowRoot
4470 // which is a document fragment.
4471 mPresContext
->RestyleManager()->
4472 RestyleForInsertOrChange(aContainer
->AsElement(), aChild
);
4475 mFrameConstructor
->ContentInserted(aContainer
, aChild
, nullptr, true);
4477 if (((!aContainer
&& aDocument
) ||
4478 (static_cast<nsINode
*>(aContainer
) == static_cast<nsINode
*>(aDocument
))) &&
4479 aChild
->NodeType() == nsIDOMNode::DOCUMENT_TYPE_NODE
) {
4480 NotifyFontSizeInflationEnabledIsDirty();
4487 PresShell::ContentRemoved(nsIDocument
*aDocument
,
4488 nsIContent
* aContainer
,
4490 int32_t aIndexInContainer
,
4491 nsIContent
* aPreviousSibling
)
4493 NS_PRECONDITION(!mIsDocumentGone
, "Unexpected ContentRemoved");
4494 NS_PRECONDITION(aDocument
== mDocument
, "Unexpected aDocument");
4496 // Notify the ESM that the content has been removed, so that
4497 // it can clean up any state related to the content.
4499 // XXX_jwir3: There is no null check for aDocument necessary, since, even
4500 // though by nsIMutationObserver, aDocument could be null, the
4501 // precondition check that mDocument == aDocument ensures that
4502 // aDocument will not be null (since mDocument can't be null unless
4503 // we're still intializing).
4504 mPresContext
->EventStateManager()->ContentRemoved(aDocument
, aChild
);
4506 nsAutoCauseReflowNotifier
crNotifier(this);
4508 // Call this here so it only happens for real content mutations and
4509 // not cases when the frame constructor calls its own methods to force
4510 // frame reconstruction.
4511 nsIContent
* oldNextSibling
;
4513 oldNextSibling
= aContainer
->GetChildAt(aIndexInContainer
);
4515 oldNextSibling
= nullptr;
4518 if (aContainer
&& aContainer
->IsElement()) {
4519 mPresContext
->RestyleManager()->
4520 RestyleForRemove(aContainer
->AsElement(), aChild
, oldNextSibling
);
4523 bool didReconstruct
;
4524 mFrameConstructor
->ContentRemoved(aContainer
, aChild
, oldNextSibling
,
4525 nsCSSFrameConstructor::REMOVE_CONTENT
,
4530 static_cast<nsINode
*>(aContainer
) == static_cast<nsINode
*>(aDocument
)) ||
4531 aDocument
) && aChild
->NodeType() == nsIDOMNode::DOCUMENT_TYPE_NODE
) {
4532 NotifyFontSizeInflationEnabledIsDirty();
4539 PresShell::NotifyCounterStylesAreDirty()
4541 nsAutoCauseReflowNotifier
reflowNotifier(this);
4542 mFrameConstructor
->BeginUpdate();
4543 mFrameConstructor
->NotifyCounterStylesAreDirty();
4544 mFrameConstructor
->EndUpdate();
4548 PresShell::ReconstructFrames(void)
4550 NS_PRECONDITION(!mFrameConstructor
->GetRootFrame() || mDidInitialize
,
4551 "Must not have root frame before initial reflow");
4552 if (!mDidInitialize
) {
4553 // Nothing to do here
4557 nsCOMPtr
<nsIPresShell
> kungFuDeathGrip(this);
4559 // Have to make sure that the content notifications are flushed before we
4560 // start messing with the frame model; otherwise we can get content doubling.
4561 mDocument
->FlushPendingNotifications(Flush_ContentAndNotify
);
4563 nsAutoCauseReflowNotifier
crNotifier(this);
4564 mFrameConstructor
->BeginUpdate();
4565 nsresult rv
= mFrameConstructor
->ReconstructDocElementHierarchy();
4567 mFrameConstructor
->EndUpdate();
4573 nsIPresShell::ReconstructStyleDataInternal()
4575 nsAutoTArray
<nsRefPtr
<mozilla::dom::Element
>,1> scopeRoots
;
4576 mChangedScopeStyleRoots
.SwapElements(scopeRoots
);
4578 if (mStylesHaveChanged
) {
4579 // If we need to restyle everything, no need to restyle individual
4580 // scoped style roots.
4584 mStylesHaveChanged
= false;
4586 if (mIsDestroying
) {
4587 // We don't want to mess with restyles at this point
4592 mPresContext
->RebuildUserFontSet();
4593 mPresContext
->RebuildCounterStyles();
4596 Element
* root
= mDocument
->GetRootElement();
4597 if (!mDidInitialize
) {
4598 // Nothing to do here, since we have no frames yet
4603 // No content to restyle
4607 RestyleManager
* restyleManager
= mPresContext
->RestyleManager();
4608 if (scopeRoots
.IsEmpty()) {
4609 // If scopeRoots is empty, we know that mStylesHaveChanged was true at
4610 // the beginning of this function, and that we need to restyle the whole
4612 restyleManager
->PostRestyleEvent(root
, eRestyle_Subtree
,
4613 NS_STYLE_HINT_NONE
);
4615 for (uint32_t i
= 0; i
< scopeRoots
.Length(); i
++) {
4616 Element
* scopeRoot
= scopeRoots
[i
];
4617 restyleManager
->PostRestyleEvent(scopeRoot
, eRestyle_Subtree
,
4618 NS_STYLE_HINT_NONE
);
4624 nsIPresShell::ReconstructStyleDataExternal()
4626 ReconstructStyleDataInternal();
4630 PresShell::RecordStyleSheetChange(nsIStyleSheet
* aStyleSheet
)
4632 if (mStylesHaveChanged
)
4635 nsRefPtr
<CSSStyleSheet
> cssStyleSheet
= do_QueryObject(aStyleSheet
);
4636 if (cssStyleSheet
) {
4637 Element
* scopeElement
= cssStyleSheet
->GetScopeElement();
4639 mChangedScopeStyleRoots
.AppendElement(scopeElement
);
4644 mStylesHaveChanged
= true;
4648 PresShell::StyleSheetAdded(nsIDocument
*aDocument
,
4649 nsIStyleSheet
* aStyleSheet
,
4650 bool aDocumentSheet
)
4652 // We only care when enabled sheets are added
4653 NS_PRECONDITION(aStyleSheet
, "Must have a style sheet!");
4655 if (aStyleSheet
->IsApplicable() && aStyleSheet
->HasRules()) {
4656 RecordStyleSheetChange(aStyleSheet
);
4661 PresShell::StyleSheetRemoved(nsIDocument
*aDocument
,
4662 nsIStyleSheet
* aStyleSheet
,
4663 bool aDocumentSheet
)
4665 // We only care when enabled sheets are removed
4666 NS_PRECONDITION(aStyleSheet
, "Must have a style sheet!");
4668 if (aStyleSheet
->IsApplicable() && aStyleSheet
->HasRules()) {
4669 RecordStyleSheetChange(aStyleSheet
);
4674 PresShell::StyleSheetApplicableStateChanged(nsIDocument
*aDocument
,
4675 nsIStyleSheet
* aStyleSheet
,
4678 if (aStyleSheet
->HasRules()) {
4679 RecordStyleSheetChange(aStyleSheet
);
4684 PresShell::StyleRuleChanged(nsIDocument
*aDocument
,
4685 nsIStyleSheet
* aStyleSheet
,
4686 nsIStyleRule
* aOldStyleRule
,
4687 nsIStyleRule
* aNewStyleRule
)
4689 RecordStyleSheetChange(aStyleSheet
);
4693 PresShell::StyleRuleAdded(nsIDocument
*aDocument
,
4694 nsIStyleSheet
* aStyleSheet
,
4695 nsIStyleRule
* aStyleRule
)
4697 RecordStyleSheetChange(aStyleSheet
);
4701 PresShell::StyleRuleRemoved(nsIDocument
*aDocument
,
4702 nsIStyleSheet
* aStyleSheet
,
4703 nsIStyleRule
* aStyleRule
)
4705 RecordStyleSheetChange(aStyleSheet
);
4709 PresShell::GetRealPrimaryFrameFor(nsIContent
* aContent
) const
4711 if (aContent
->GetComposedDoc() != GetDocument()) {
4714 nsIFrame
*primaryFrame
= aContent
->GetPrimaryFrame();
4717 return nsPlaceholderFrame::GetRealFrameFor(primaryFrame
);
4721 PresShell::GetPlaceholderFrameFor(nsIFrame
* aFrame
) const
4723 return mFrameConstructor
->GetPlaceholderFrameFor(aFrame
);
4727 PresShell::RenderDocument(const nsRect
& aRect
, uint32_t aFlags
,
4728 nscolor aBackgroundColor
,
4729 gfxContext
* aThebesContext
)
4731 NS_ENSURE_TRUE(!(aFlags
& RENDER_IS_UNTRUSTED
), NS_ERROR_NOT_IMPLEMENTED
);
4733 nsRootPresContext
* rootPresContext
= mPresContext
->GetRootPresContext();
4734 if (rootPresContext
) {
4735 rootPresContext
->FlushWillPaintObservers();
4740 nsAutoScriptBlocker blockScripts
;
4742 // Set up the rectangle as the path in aThebesContext
4744 nsPresContext::AppUnitsToFloatCSSPixels(aRect
.width
),
4745 nsPresContext::AppUnitsToFloatCSSPixels(aRect
.height
));
4746 aThebesContext
->NewPath();
4747 #ifdef MOZ_GFX_OPTIMIZE_MOBILE
4748 aThebesContext
->Rectangle(r
, true);
4750 aThebesContext
->Rectangle(r
);
4753 nsIFrame
* rootFrame
= mFrameConstructor
->GetRootFrame();
4755 // Nothing to paint, just fill the rect
4756 aThebesContext
->SetColor(gfxRGBA(aBackgroundColor
));
4757 aThebesContext
->Fill();
4761 gfxContextAutoSaveRestore
save(aThebesContext
);
4763 gfxContext::GraphicsOperator oldOperator
= aThebesContext
->CurrentOperator();
4764 if (oldOperator
== gfxContext::OPERATOR_OVER
) {
4765 // Clip to the destination rectangle before we push the group,
4766 // to limit the size of the temporary surface
4767 aThebesContext
->Clip();
4770 // we want the window to be composited as a single image using
4771 // whatever operator was set; set OPERATOR_OVER here, which is
4772 // either already the case, or overrides the operator in a group.
4773 // the original operator will be present when we PopGroup.
4774 // we can avoid using a temporary surface if we're using OPERATOR_OVER
4775 bool needsGroup
= oldOperator
!= gfxContext::OPERATOR_OVER
;
4778 aThebesContext
->PushGroup(NS_GET_A(aBackgroundColor
) == 0xff ?
4779 gfxContentType::COLOR
:
4780 gfxContentType::COLOR_ALPHA
);
4781 aThebesContext
->Save();
4783 if (oldOperator
!= gfxContext::OPERATOR_OVER
) {
4784 // Clip now while we paint to the temporary surface. For
4785 // non-source-bounded operators (e.g., SOURCE), we need to do clip
4786 // here after we've pushed the group, so that eventually popping
4787 // the group and painting it will be able to clear the entire
4788 // destination surface.
4789 aThebesContext
->Clip();
4790 aThebesContext
->SetOperator(gfxContext::OPERATOR_OVER
);
4794 aThebesContext
->Translate(gfxPoint(-nsPresContext::AppUnitsToFloatCSSPixels(aRect
.x
),
4795 -nsPresContext::AppUnitsToFloatCSSPixels(aRect
.y
)));
4797 nsDeviceContext
* devCtx
= mPresContext
->DeviceContext();
4798 gfxFloat scale
= gfxFloat(devCtx
->AppUnitsPerDevPixel())/nsPresContext::AppUnitsPerCSSPixel();
4799 aThebesContext
->Scale(scale
, scale
);
4801 // Since canvas APIs use floats to set up their matrices, we may have
4802 // some slight inaccuracy here. Adjust matrix components that are
4803 // integers up to the accuracy of floats to be those integers.
4804 aThebesContext
->NudgeCurrentMatrixToIntegers();
4806 AutoSaveRestoreRenderingState
_(this);
4808 nsRefPtr
<nsRenderingContext
> rc
= new nsRenderingContext();
4809 rc
->Init(devCtx
, aThebesContext
);
4811 bool wouldFlushRetainedLayers
= false;
4812 uint32_t flags
= nsLayoutUtils::PAINT_IGNORE_SUPPRESSION
;
4813 if (aThebesContext
->CurrentMatrix().HasNonIntegerTranslation()) {
4814 flags
|= nsLayoutUtils::PAINT_IN_TRANSFORM
;
4816 if (!(aFlags
& RENDER_ASYNC_DECODE_IMAGES
)) {
4817 flags
|= nsLayoutUtils::PAINT_SYNC_DECODE_IMAGES
;
4819 if (aFlags
& RENDER_USE_WIDGET_LAYERS
) {
4820 // We only support using widget layers on display root's with widgets.
4821 nsView
* view
= rootFrame
->GetView();
4822 if (view
&& view
->GetWidget() &&
4823 nsLayoutUtils::GetDisplayRootFrame(rootFrame
) == rootFrame
) {
4824 flags
|= nsLayoutUtils::PAINT_WIDGET_LAYERS
;
4827 if (!(aFlags
& RENDER_CARET
)) {
4828 wouldFlushRetainedLayers
= true;
4829 flags
|= nsLayoutUtils::PAINT_HIDE_CARET
;
4831 if (aFlags
& RENDER_IGNORE_VIEWPORT_SCROLLING
) {
4832 wouldFlushRetainedLayers
= !IgnoringViewportScrolling();
4833 mRenderFlags
= ChangeFlag(mRenderFlags
, true, STATE_IGNORING_VIEWPORT_SCROLLING
);
4835 if (aFlags
& RENDER_DRAWWINDOW_NOT_FLUSHING
) {
4836 mRenderFlags
= ChangeFlag(mRenderFlags
, true, STATE_DRAWWINDOW_NOT_FLUSHING
);
4838 if (aFlags
& RENDER_DOCUMENT_RELATIVE
) {
4839 // XXX be smarter about this ... drawWindow might want a rect
4840 // that's "pretty close" to what our retained layer tree covers.
4841 // In that case, it wouldn't disturb normal rendering too much,
4842 // and we should allow it.
4843 wouldFlushRetainedLayers
= true;
4844 flags
|= nsLayoutUtils::PAINT_DOCUMENT_RELATIVE
;
4847 // Don't let drawWindow blow away our retained layer tree
4848 if ((flags
& nsLayoutUtils::PAINT_WIDGET_LAYERS
) && wouldFlushRetainedLayers
) {
4849 flags
&= ~nsLayoutUtils::PAINT_WIDGET_LAYERS
;
4852 nsLayoutUtils::PaintFrame(rc
, rootFrame
, nsRegion(aRect
),
4853 aBackgroundColor
, flags
);
4855 // if we had to use a group, paint it to the destination now
4857 aThebesContext
->Restore();
4858 aThebesContext
->PopGroupToSource();
4859 aThebesContext
->Paint();
4866 * Clip the display list aList to a range. Returns the clipped
4867 * rectangle surrounding the range.
4870 PresShell::ClipListToRange(nsDisplayListBuilder
*aBuilder
,
4871 nsDisplayList
* aList
,
4874 // iterate though the display items and add up the bounding boxes of each.
4875 // This will allow the total area of the frames within the range to be
4876 // determined. To do this, remove an item from the bottom of the list, check
4877 // whether it should be part of the range, and if so, append it to the top
4878 // of the temporary list tmpList. If the item is a text frame at the end of
4879 // the selection range, clip it to the portion of the text frame that is
4880 // part of the selection. Then, append the wrapper to the top of the list.
4881 // Otherwise, just delete the item and don't append it.
4883 nsDisplayList tmpList
;
4886 while ((i
= aList
->RemoveBottom())) {
4887 // itemToInsert indiciates the item that should be inserted into the
4888 // temporary list. If null, no item should be inserted.
4889 nsDisplayItem
* itemToInsert
= nullptr;
4890 nsIFrame
* frame
= i
->Frame();
4891 nsIContent
* content
= frame
->GetContent();
4893 bool atStart
= (content
== aRange
->GetStartParent());
4894 bool atEnd
= (content
== aRange
->GetEndParent());
4895 if ((atStart
|| atEnd
) && frame
->GetType() == nsGkAtoms::textFrame
) {
4896 int32_t frameStartOffset
, frameEndOffset
;
4897 frame
->GetOffsets(frameStartOffset
, frameEndOffset
);
4899 int32_t hilightStart
=
4900 atStart
? std::max(aRange
->StartOffset(), frameStartOffset
) : frameStartOffset
;
4901 int32_t hilightEnd
=
4902 atEnd
? std::min(aRange
->EndOffset(), frameEndOffset
) : frameEndOffset
;
4903 if (hilightStart
< hilightEnd
) {
4904 // determine the location of the start and end edges of the range.
4905 nsPoint startPoint
, endPoint
;
4906 frame
->GetPointFromOffset(hilightStart
, &startPoint
);
4907 frame
->GetPointFromOffset(hilightEnd
, &endPoint
);
4909 // the clip rectangle is determined by taking the the start and
4910 // end points of the range, offset from the reference frame.
4911 // Because of rtl, the end point may be to the left of the
4912 // start point, so x is set to the lowest value
4913 nsRect
textRect(aBuilder
->ToReferenceFrame(frame
), frame
->GetSize());
4914 nscoord x
= std::min(startPoint
.x
, endPoint
.x
);
4916 textRect
.width
= std::max(startPoint
.x
, endPoint
.x
) - x
;
4917 surfaceRect
.UnionRect(surfaceRect
, textRect
);
4919 DisplayItemClip newClip
;
4920 newClip
.SetTo(textRect
);
4921 newClip
.IntersectWith(i
->GetClip());
4922 i
->SetClip(aBuilder
, newClip
);
4926 // Don't try to descend into subdocuments.
4927 // If this ever changes we'd need to add handling for subdocuments with
4928 // different zoom levels.
4929 else if (content
->GetCurrentDoc() ==
4930 aRange
->GetStartParent()->GetCurrentDoc()) {
4931 // if the node is within the range, append it to the temporary list
4934 nsRange::CompareNodeToRange(content
, aRange
, &before
, &after
);
4935 if (NS_SUCCEEDED(rv
) && !before
&& !after
) {
4938 surfaceRect
.UnionRect(surfaceRect
, i
->GetBounds(aBuilder
, &snap
));
4943 // insert the item into the list if necessary. If the item has a child
4944 // list, insert that as well
4945 nsDisplayList
* sublist
= i
->GetSameCoordinateSystemChildren();
4946 if (itemToInsert
|| sublist
) {
4947 tmpList
.AppendToTop(itemToInsert
? itemToInsert
: i
);
4948 // if the item is a list, iterate over it as well
4950 surfaceRect
.UnionRect(surfaceRect
,
4951 ClipListToRange(aBuilder
, sublist
, aRange
));
4954 // otherwise, just delete the item and don't readd it to the list
4955 i
->~nsDisplayItem();
4959 // now add all the items back onto the original list again
4960 aList
->AppendToTop(&tmpList
);
4968 static bool gDumpRangePaintList
= false;
4972 PresShell::CreateRangePaintInfo(nsIDOMRange
* aRange
,
4973 nsRect
& aSurfaceRect
,
4974 bool aForPrimarySelection
)
4976 RangePaintInfo
* info
= nullptr;
4978 nsRange
* range
= static_cast<nsRange
*>(aRange
);
4980 nsIFrame
* ancestorFrame
;
4981 nsIFrame
* rootFrame
= GetRootFrame();
4983 // If the start or end of the range is the document, just use the root
4984 // frame, otherwise get the common ancestor of the two endpoints of the
4986 nsINode
* startParent
= range
->GetStartParent();
4987 nsINode
* endParent
= range
->GetEndParent();
4988 nsIDocument
* doc
= startParent
->GetCrossShadowCurrentDoc();
4989 if (startParent
== doc
|| endParent
== doc
) {
4990 ancestorFrame
= rootFrame
;
4993 nsINode
* ancestor
= nsContentUtils::GetCommonAncestor(startParent
, endParent
);
4994 NS_ASSERTION(!ancestor
|| ancestor
->IsNodeOfType(nsINode::eCONTENT
),
4995 "common ancestor is not content");
4996 if (!ancestor
|| !ancestor
->IsNodeOfType(nsINode::eCONTENT
))
4999 nsIContent
* ancestorContent
= static_cast<nsIContent
*>(ancestor
);
5000 ancestorFrame
= ancestorContent
->GetPrimaryFrame();
5002 // use the nearest ancestor frame that includes all continuations as the
5003 // root for building the display list
5004 while (ancestorFrame
&&
5005 nsLayoutUtils::GetNextContinuationOrIBSplitSibling(ancestorFrame
))
5006 ancestorFrame
= ancestorFrame
->GetParent();
5012 info
= new RangePaintInfo(range
, ancestorFrame
);
5014 nsRect ancestorRect
= ancestorFrame
->GetVisualOverflowRect();
5016 // get a display list containing the range
5017 info
->mBuilder
.SetIncludeAllOutOfFlows();
5018 if (aForPrimarySelection
) {
5019 info
->mBuilder
.SetSelectedFramesOnly();
5021 info
->mBuilder
.EnterPresShell(ancestorFrame
, ancestorRect
);
5022 ancestorFrame
->BuildDisplayListForStackingContext(&info
->mBuilder
,
5023 ancestorRect
, &info
->mList
);
5026 if (gDumpRangePaintList
) {
5027 fprintf(stderr
, "CreateRangePaintInfo --- before ClipListToRange:\n");
5028 nsFrame::PrintDisplayList(&(info
->mBuilder
), info
->mList
);
5032 nsRect rangeRect
= ClipListToRange(&info
->mBuilder
, &info
->mList
, range
);
5034 info
->mBuilder
.LeavePresShell(ancestorFrame
, ancestorRect
);
5037 if (gDumpRangePaintList
) {
5038 fprintf(stderr
, "CreateRangePaintInfo --- after ClipListToRange:\n");
5039 nsFrame::PrintDisplayList(&(info
->mBuilder
), info
->mList
);
5043 // determine the offset of the reference frame for the display list
5044 // to the root frame. This will allow the coordinates used when painting
5045 // to all be offset from the same point
5046 info
->mRootOffset
= ancestorFrame
->GetOffsetTo(rootFrame
);
5047 rangeRect
.MoveBy(info
->mRootOffset
);
5048 aSurfaceRect
.UnionRect(aSurfaceRect
, rangeRect
);
5053 TemporaryRef
<SourceSurface
>
5054 PresShell::PaintRangePaintInfo(nsTArray
<nsAutoPtr
<RangePaintInfo
> >* aItems
,
5055 nsISelection
* aSelection
,
5056 nsIntRegion
* aRegion
,
5059 nsIntRect
* aScreenRect
)
5061 nsPresContext
* pc
= GetPresContext();
5062 if (!pc
|| aArea
.width
== 0 || aArea
.height
== 0)
5065 nsDeviceContext
* deviceContext
= pc
->DeviceContext();
5067 // use the rectangle to create the surface
5068 nsIntRect pixelArea
= aArea
.ToOutsidePixels(pc
->AppUnitsPerDevPixel());
5070 // if the area of the image is larger than the maximum area, scale it down
5072 nsIntRect rootScreenRect
=
5073 GetRootFrame()->GetScreenRectInAppUnits().ToNearestPixels(
5074 pc
->AppUnitsPerDevPixel());
5076 // if the image is larger in one or both directions than half the size of
5077 // the available screen area, scale the image down to that size.
5079 deviceContext
->GetClientRect(maxSize
);
5080 nscoord maxWidth
= pc
->AppUnitsToDevPixels(maxSize
.width
>> 1);
5081 nscoord maxHeight
= pc
->AppUnitsToDevPixels(maxSize
.height
>> 1);
5082 bool resize
= (pixelArea
.width
> maxWidth
|| pixelArea
.height
> maxHeight
);
5085 // divide the maximum size by the image size in both directions. Whichever
5086 // direction produces the smallest result determines how much should be
5088 if (pixelArea
.width
> maxWidth
)
5089 scale
= std::min(scale
, float(maxWidth
) / pixelArea
.width
);
5090 if (pixelArea
.height
> maxHeight
)
5091 scale
= std::min(scale
, float(maxHeight
) / pixelArea
.height
);
5093 pixelArea
.width
= NSToIntFloor(float(pixelArea
.width
) * scale
);
5094 pixelArea
.height
= NSToIntFloor(float(pixelArea
.height
) * scale
);
5096 // adjust the screen position based on the rescaled size
5097 nscoord left
= rootScreenRect
.x
+ pixelArea
.x
;
5098 nscoord top
= rootScreenRect
.y
+ pixelArea
.y
;
5099 aScreenRect
->x
= NSToIntFloor(aPoint
.x
- float(aPoint
.x
- left
) * scale
);
5100 aScreenRect
->y
= NSToIntFloor(aPoint
.y
- float(aPoint
.y
- top
) * scale
);
5103 // move aScreenRect to the position of the surface in screen coordinates
5104 aScreenRect
->MoveTo(rootScreenRect
.x
+ pixelArea
.x
, rootScreenRect
.y
+ pixelArea
.y
);
5106 aScreenRect
->width
= pixelArea
.width
;
5107 aScreenRect
->height
= pixelArea
.height
;
5109 RefPtr
<DrawTarget
> dt
=
5110 gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
5111 IntSize(pixelArea
.width
, pixelArea
.height
),
5112 SurfaceFormat::B8G8R8A8
);
5117 nsRefPtr
<gfxContext
> ctx
= new gfxContext(dt
);
5118 nsRefPtr
<nsRenderingContext
> rc
= new nsRenderingContext();
5119 rc
->Init(deviceContext
, ctx
);
5122 // Convert aRegion from CSS pixels to dev pixels
5123 nsIntRegion region
=
5124 aRegion
->ToAppUnits(nsPresContext::AppUnitsPerCSSPixel())
5125 .ToOutsidePixels(pc
->AppUnitsPerDevPixel());
5126 rc
->SetClip(region
);
5130 rc
->Scale(scale
, scale
);
5132 // translate so that points are relative to the surface area
5133 rc
->Translate(-aArea
.TopLeft());
5135 // temporarily hide the selection so that text is drawn normally. If a
5136 // selection is being rendered, use that, otherwise use the presshell's
5138 nsRefPtr
<nsFrameSelection
> frameSelection
;
5140 frameSelection
= static_cast<Selection
*>(aSelection
)->GetFrameSelection();
5143 frameSelection
= FrameSelection();
5145 int16_t oldDisplaySelection
= frameSelection
->GetDisplaySelection();
5146 frameSelection
->SetDisplaySelection(nsISelectionController::SELECTION_HIDDEN
);
5148 // next, paint each range in the selection
5149 int32_t count
= aItems
->Length();
5150 for (int32_t i
= 0; i
< count
; i
++) {
5151 RangePaintInfo
* rangeInfo
= (*aItems
)[i
];
5152 // the display lists paint relative to the offset from the reference
5153 // frame, so translate the rendering context
5154 nsRenderingContext::AutoPushTranslation
5155 translate(rc
, rangeInfo
->mRootOffset
);
5157 aArea
.MoveBy(-rangeInfo
->mRootOffset
.x
, -rangeInfo
->mRootOffset
.y
);
5158 nsRegion
visible(aArea
);
5159 rangeInfo
->mList
.PaintRoot(&rangeInfo
->mBuilder
, rc
, nsDisplayList::PAINT_DEFAULT
);
5160 aArea
.MoveBy(rangeInfo
->mRootOffset
.x
, rangeInfo
->mRootOffset
.y
);
5163 // restore the old selection display state
5164 frameSelection
->SetDisplaySelection(oldDisplaySelection
);
5166 return dt
->Snapshot();
5169 TemporaryRef
<SourceSurface
>
5170 PresShell::RenderNode(nsIDOMNode
* aNode
,
5171 nsIntRegion
* aRegion
,
5173 nsIntRect
* aScreenRect
)
5175 // area will hold the size of the surface needed to draw the node, measured
5176 // from the root frame.
5178 nsTArray
<nsAutoPtr
<RangePaintInfo
> > rangeItems
;
5180 // nothing to draw if the node isn't in a document
5181 nsCOMPtr
<nsINode
> node
= do_QueryInterface(aNode
);
5182 if (!node
->IsInDoc())
5185 nsRefPtr
<nsRange
> range
= new nsRange(node
);
5186 if (NS_FAILED(range
->SelectNode(aNode
)))
5189 RangePaintInfo
* info
= CreateRangePaintInfo(range
, area
, false);
5190 if (info
&& !rangeItems
.AppendElement(info
)) {
5196 // combine the area with the supplied region
5197 nsIntRect rrectPixels
= aRegion
->GetBounds();
5199 nsRect rrect
= rrectPixels
.ToAppUnits(nsPresContext::AppUnitsPerCSSPixel());
5200 area
.IntersectRect(area
, rrect
);
5202 nsPresContext
* pc
= GetPresContext();
5206 // move the region so that it is offset from the topleft corner of the surface
5207 aRegion
->MoveBy(-pc
->AppUnitsToDevPixels(area
.x
),
5208 -pc
->AppUnitsToDevPixels(area
.y
));
5211 return PaintRangePaintInfo(&rangeItems
, nullptr, aRegion
, area
, aPoint
,
5215 TemporaryRef
<SourceSurface
>
5216 PresShell::RenderSelection(nsISelection
* aSelection
,
5218 nsIntRect
* aScreenRect
)
5220 // area will hold the size of the surface needed to draw the selection,
5221 // measured from the root frame.
5223 nsTArray
<nsAutoPtr
<RangePaintInfo
> > rangeItems
;
5225 // iterate over each range and collect them into the rangeItems array.
5226 // This is done so that the size of selection can be determined so as
5227 // to allocate a surface area
5229 aSelection
->GetRangeCount(&numRanges
);
5230 NS_ASSERTION(numRanges
> 0, "RenderSelection called with no selection");
5232 for (int32_t r
= 0; r
< numRanges
; r
++)
5234 nsCOMPtr
<nsIDOMRange
> range
;
5235 aSelection
->GetRangeAt(r
, getter_AddRefs(range
));
5237 RangePaintInfo
* info
= CreateRangePaintInfo(range
, area
, true);
5238 if (info
&& !rangeItems
.AppendElement(info
)) {
5244 return PaintRangePaintInfo(&rangeItems
, aSelection
, nullptr, area
, aPoint
,
5249 PresShell::AddPrintPreviewBackgroundItem(nsDisplayListBuilder
& aBuilder
,
5250 nsDisplayList
& aList
,
5252 const nsRect
& aBounds
)
5254 aList
.AppendNewToBottom(new (&aBuilder
)
5255 nsDisplaySolidColor(&aBuilder
, aFrame
, aBounds
, NS_RGB(115, 115, 115)));
5259 AddCanvasBackgroundColor(const nsDisplayList
& aList
, nsIFrame
* aCanvasFrame
,
5262 for (nsDisplayItem
* i
= aList
.GetBottom(); i
; i
= i
->GetAbove()) {
5263 if (i
->Frame() == aCanvasFrame
&&
5264 i
->GetType() == nsDisplayItem::TYPE_CANVAS_BACKGROUND_COLOR
) {
5265 nsDisplayCanvasBackgroundColor
* bg
= static_cast<nsDisplayCanvasBackgroundColor
*>(i
);
5266 bg
->SetExtraBackgroundColor(aColor
);
5269 nsDisplayList
* sublist
= i
->GetSameCoordinateSystemChildren();
5271 i
->GetType() != nsDisplayItem::TYPE_BLEND_CONTAINER
&&
5272 AddCanvasBackgroundColor(*sublist
, aCanvasFrame
, aColor
))
5279 PresShell::AddCanvasBackgroundColorItem(nsDisplayListBuilder
& aBuilder
,
5280 nsDisplayList
& aList
,
5282 const nsRect
& aBounds
,
5283 nscolor aBackstopColor
,
5286 if (aBounds
.IsEmpty()) {
5289 // We don't want to add an item for the canvas background color if the frame
5290 // (sub)tree we are painting doesn't include any canvas frames. There isn't
5291 // an easy way to check this directly, but if we check if the root of the
5292 // (sub)tree we are painting is a canvas frame that should cover us in all
5293 // cases (it will usually be a viewport frame when we have a canvas frame in
5295 if (!(aFlags
& nsIPresShell::FORCE_DRAW
) &&
5296 !nsCSSRendering::IsCanvasFrame(aFrame
)) {
5300 nscolor bgcolor
= NS_ComposeColors(aBackstopColor
, mCanvasBackgroundColor
);
5301 if (NS_GET_A(bgcolor
) == 0)
5304 // To make layers work better, we want to avoid having a big non-scrolled
5305 // color background behind a scrolled transparent background. Instead,
5306 // we'll try to move the color background into the scrolled content
5307 // by making nsDisplayCanvasBackground paint it.
5308 if (!aFrame
->GetParent()) {
5309 nsIScrollableFrame
* sf
=
5310 aFrame
->PresContext()->PresShell()->GetRootScrollFrameAsScrollable();
5312 nsCanvasFrame
* canvasFrame
= do_QueryFrame(sf
->GetScrolledFrame());
5313 if (canvasFrame
&& canvasFrame
->IsVisibleForPainting(&aBuilder
)) {
5314 if (AddCanvasBackgroundColor(aList
, canvasFrame
, bgcolor
))
5320 aList
.AppendNewToBottom(
5321 new (&aBuilder
) nsDisplaySolidColor(&aBuilder
, aFrame
, aBounds
, bgcolor
));
5324 static bool IsTransparentContainerElement(nsPresContext
* aPresContext
)
5326 nsCOMPtr
<nsIDocShell
> docShell
= aPresContext
->GetDocShell();
5331 nsCOMPtr
<nsPIDOMWindow
> pwin
= docShell
->GetWindow();
5334 nsCOMPtr
<Element
> containerElement
= pwin
->GetFrameElementInternal();
5335 return containerElement
&&
5336 containerElement
->HasAttr(kNameSpaceID_None
, nsGkAtoms::transparent
);
5339 nscolor
PresShell::GetDefaultBackgroundColorToDraw()
5341 if (!mPresContext
|| !mPresContext
->GetBackgroundColorDraw()) {
5342 return NS_RGB(255,255,255);
5344 return mPresContext
->DefaultBackgroundColor();
5347 void PresShell::UpdateCanvasBackground()
5349 // If we have a frame tree and it has style information that
5350 // specifies the background color of the canvas, update our local
5351 // cache of that color.
5352 nsIFrame
* rootStyleFrame
= FrameConstructor()->GetRootElementStyleFrame();
5353 if (rootStyleFrame
) {
5354 nsStyleContext
* bgStyle
=
5355 nsCSSRendering::FindRootFrameBackground(rootStyleFrame
);
5356 // XXX We should really be passing the canvasframe, not the root element
5357 // style frame but we don't have access to the canvasframe here. It isn't
5358 // a problem because only a few frames can return something other than true
5359 // and none of them would be a canvas frame or root element style frame.
5360 bool drawBackgroundImage
;
5361 bool drawBackgroundColor
;
5363 mCanvasBackgroundColor
=
5364 nsCSSRendering::DetermineBackgroundColor(mPresContext
, bgStyle
,
5366 drawBackgroundImage
,
5367 drawBackgroundColor
);
5368 if (GetPresContext()->IsCrossProcessRootContentDocument() &&
5369 !IsTransparentContainerElement(mPresContext
)) {
5370 mCanvasBackgroundColor
=
5371 NS_ComposeColors(GetDefaultBackgroundColorToDraw(), mCanvasBackgroundColor
);
5375 // If the root element of the document (ie html) has style 'display: none'
5376 // then the document's background color does not get drawn; cache the
5377 // color we actually draw.
5378 if (!FrameConstructor()->GetRootElementFrame()) {
5379 mCanvasBackgroundColor
= GetDefaultBackgroundColorToDraw();
5381 if (XRE_GetProcessType() == GeckoProcessType_Content
) {
5382 if (TabChild
* tabChild
= TabChild::GetFrom(this)) {
5383 tabChild
->SetBackgroundColor(mCanvasBackgroundColor
);
5388 nscolor
PresShell::ComputeBackstopColor(nsView
* aDisplayRoot
)
5390 nsIWidget
* widget
= aDisplayRoot
->GetWidget();
5391 if (widget
&& (widget
->GetTransparencyMode() != eTransparencyOpaque
||
5392 widget
->WidgetPaintsBackground())) {
5393 // Within a transparent widget, so the backstop color must be
5394 // totally transparent.
5395 return NS_RGBA(0,0,0,0);
5397 // Within an opaque widget (or no widget at all), so the backstop
5398 // color must be totally opaque. The user's default background
5399 // as reported by the prescontext is guaranteed to be opaque.
5400 return GetDefaultBackgroundColorToDraw();
5403 struct PaintParams
{
5404 nscolor mBackgroundColor
;
5407 LayerManager
* PresShell::GetLayerManager()
5409 NS_ASSERTION(mViewManager
, "Should have view manager");
5411 nsView
* rootView
= mViewManager
->GetRootView();
5413 if (nsIWidget
* widget
= rootView
->GetWidget()) {
5414 return widget
->GetLayerManager();
5420 void PresShell::SetIgnoreViewportScrolling(bool aIgnore
)
5422 if (IgnoringViewportScrolling() == aIgnore
) {
5425 RenderingState
state(this);
5426 state
.mRenderFlags
= ChangeFlag(state
.mRenderFlags
, aIgnore
,
5427 STATE_IGNORING_VIEWPORT_SCROLLING
);
5428 SetRenderingState(state
);
5431 nsresult
PresShell::SetResolution(float aXResolution
, float aYResolution
)
5433 if (!(aXResolution
> 0.0 && aYResolution
> 0.0)) {
5434 return NS_ERROR_ILLEGAL_VALUE
;
5436 if (aXResolution
== mXResolution
&& aYResolution
== mYResolution
) {
5439 RenderingState
state(this);
5440 state
.mXResolution
= aXResolution
;
5441 state
.mYResolution
= aYResolution
;
5442 SetRenderingState(state
);
5446 gfxSize
PresShell::GetCumulativeResolution()
5448 gfxSize resolution
= GetResolution();
5449 nsPresContext
* parentCtx
= GetPresContext()->GetParentPresContext();
5451 resolution
= resolution
* parentCtx
->PresShell()->GetCumulativeResolution();
5456 void PresShell::SetRenderingState(const RenderingState
& aState
)
5458 if (mRenderFlags
!= aState
.mRenderFlags
) {
5459 // Rendering state changed in a way that forces us to flush any
5460 // retained layers we might already have.
5461 LayerManager
* manager
= GetLayerManager();
5463 FrameLayerBuilder::InvalidateAllLayers(manager
);
5467 mRenderFlags
= aState
.mRenderFlags
;
5468 mXResolution
= aState
.mXResolution
;
5469 mYResolution
= aState
.mYResolution
;
5472 void PresShell::SynthesizeMouseMove(bool aFromScroll
)
5474 if (!sSynthMouseMove
)
5477 if (mPaintingSuppressed
|| !mIsActive
|| !mPresContext
) {
5481 if (!mPresContext
->IsRoot()) {
5482 nsIPresShell
* rootPresShell
= GetRootPresShell();
5483 if (rootPresShell
) {
5484 rootPresShell
->SynthesizeMouseMove(aFromScroll
);
5489 if (mMouseLocation
== nsPoint(NS_UNCONSTRAINEDSIZE
, NS_UNCONSTRAINEDSIZE
))
5492 if (!mSynthMouseMoveEvent
.IsPending()) {
5493 nsRefPtr
<nsSynthMouseMoveEvent
> ev
=
5494 new nsSynthMouseMoveEvent(this, aFromScroll
);
5496 if (!GetPresContext()->RefreshDriver()->AddRefreshObserver(ev
,
5498 NS_WARNING("failed to dispatch nsSynthMouseMoveEvent");
5502 mSynthMouseMoveEvent
= ev
;
5507 * Find the first floating view with a widget in a postorder traversal of the
5508 * view tree that contains the point. Thus more deeply nested floating views
5509 * are preferred over their ancestors, and floating views earlier in the
5510 * view hierarchy (i.e., added later) are preferred over their siblings.
5511 * This is adequate for finding the "topmost" floating view under a point,
5512 * given that floating views don't supporting having a specific z-index.
5514 * We cannot exit early when aPt is outside the view bounds, because floating
5515 * views aren't necessarily included in their parent's bounds, so this could
5516 * traverse the entire view hierarchy --- use carefully.
5518 static nsView
* FindFloatingViewContaining(nsView
* aView
, nsPoint aPt
)
5520 if (aView
->GetVisibility() == nsViewVisibility_kHide
)
5521 // No need to look into descendants.
5524 nsIFrame
* frame
= aView
->GetFrame();
5526 if (!frame
->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY
) ||
5527 !frame
->PresContext()->PresShell()->IsActive()) {
5532 for (nsView
* v
= aView
->GetFirstChild(); v
; v
= v
->GetNextSibling()) {
5533 nsView
* r
= FindFloatingViewContaining(v
, v
->ConvertFromParentCoords(aPt
));
5538 if (aView
->GetFloating() && aView
->HasWidget() &&
5539 aView
->GetDimensions().Contains(aPt
))
5546 * This finds the first view containing the given point in a postorder
5547 * traversal of the view tree that contains the point, assuming that the
5548 * point is not in a floating view. It assumes that only floating views
5549 * extend outside the bounds of their parents.
5551 * This methods should only be called if FindFloatingViewContaining
5554 static nsView
* FindViewContaining(nsView
* aView
, nsPoint aPt
)
5556 if (!aView
->GetDimensions().Contains(aPt
) ||
5557 aView
->GetVisibility() == nsViewVisibility_kHide
) {
5561 nsIFrame
* frame
= aView
->GetFrame();
5563 if (!frame
->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY
) ||
5564 !frame
->PresContext()->PresShell()->IsActive()) {
5569 for (nsView
* v
= aView
->GetFirstChild(); v
; v
= v
->GetNextSibling()) {
5570 nsView
* r
= FindViewContaining(v
, v
->ConvertFromParentCoords(aPt
));
5579 PresShell::ProcessSynthMouseMoveEvent(bool aFromScroll
)
5581 // If drag session has started, we shouldn't synthesize mousemove event.
5582 nsCOMPtr
<nsIDragSession
> dragSession
= nsContentUtils::GetDragSession();
5584 mSynthMouseMoveEvent
.Forget();
5588 // allow new event to be posted while handling this one only if the
5589 // source of the event is a scroll (to prevent infinite reflow loops)
5591 mSynthMouseMoveEvent
.Forget();
5594 nsView
* rootView
= mViewManager
? mViewManager
->GetRootView() : nullptr;
5595 if (mMouseLocation
== nsPoint(NS_UNCONSTRAINEDSIZE
, NS_UNCONSTRAINEDSIZE
) ||
5596 !rootView
|| !rootView
->HasWidget() || !mPresContext
) {
5597 mSynthMouseMoveEvent
.Forget();
5601 NS_ASSERTION(mPresContext
->IsRoot(), "Only a root pres shell should be here");
5603 // Hold a ref to ourselves so DispatchEvent won't destroy us (since
5604 // we need to access members after we call DispatchEvent).
5605 nsCOMPtr
<nsIPresShell
> kungFuDeathGrip(this);
5607 #ifdef DEBUG_MOUSE_LOCATION
5608 printf("[ps=%p]synthesizing mouse move to (%d,%d)\n",
5609 this, mMouseLocation
.x
, mMouseLocation
.y
);
5612 int32_t APD
= mPresContext
->AppUnitsPerDevPixel();
5614 // We need a widget to put in the event we are going to dispatch so we look
5615 // for a view that has a widget and the mouse location is over. We first look
5616 // for floating views, if there isn't one we use the root view. |view| holds
5618 nsView
* view
= nullptr;
5620 // The appunits per devpixel ratio of |view|.
5623 // refPoint will be mMouseLocation relative to the widget of |view|, the
5624 // widget we will put in the event we dispatch, in viewAPD appunits
5625 nsPoint
refpoint(0, 0);
5627 // We always dispatch the event to the pres shell that contains the view that
5628 // the mouse is over. pointVM is the VM of that pres shell.
5629 nsViewManager
*pointVM
= nullptr;
5631 // This could be a bit slow (traverses entire view hierarchy)
5632 // but it's OK to do it once per synthetic mouse event
5633 view
= FindFloatingViewContaining(rootView
, mMouseLocation
);
5636 nsView
*pointView
= FindViewContaining(rootView
, mMouseLocation
);
5637 // pointView can be null in situations related to mouse capture
5638 pointVM
= (pointView
? pointView
: view
)->GetViewManager();
5639 refpoint
= mMouseLocation
+ rootView
->ViewToWidgetOffset();
5642 pointVM
= view
->GetViewManager();
5643 nsIFrame
* frame
= view
->GetFrame();
5644 NS_ASSERTION(frame
, "floating views can't be anonymous");
5645 viewAPD
= frame
->PresContext()->AppUnitsPerDevPixel();
5646 refpoint
= mMouseLocation
.ConvertAppUnits(APD
, viewAPD
);
5647 refpoint
-= view
->GetOffsetTo(rootView
);
5648 refpoint
+= view
->ViewToWidgetOffset();
5650 NS_ASSERTION(view
->GetWidget(), "view should have a widget here");
5651 WidgetMouseEvent
event(true, NS_MOUSE_MOVE
, view
->GetWidget(),
5652 WidgetMouseEvent::eSynthesized
);
5653 event
.refPoint
= LayoutDeviceIntPoint::FromAppUnitsToNearest(refpoint
, viewAPD
);
5654 event
.time
= PR_IntervalNow();
5655 // XXX set event.modifiers ?
5656 // XXX mnakano I think that we should get the latest information from widget.
5658 nsCOMPtr
<nsIPresShell
> shell
= pointVM
->GetPresShell();
5660 shell
->DispatchSynthMouseMove(&event
, !aFromScroll
);
5664 mSynthMouseMoveEvent
.Forget();
5669 PresShell::MarkImagesInListVisible(const nsDisplayList
& aList
)
5671 for (nsDisplayItem
* item
= aList
.GetBottom(); item
; item
= item
->GetAbove()) {
5672 nsDisplayList
* sublist
= item
->GetChildren();
5674 MarkImagesInListVisible(*sublist
);
5677 nsIFrame
* f
= item
->Frame();
5678 // We could check the type of the display item, only a handful can hold an
5679 // image loading content.
5680 // dont bother nscomptr here, it is wasteful
5681 nsCOMPtr
<nsIImageLoadingContent
> content(do_QueryInterface(f
->GetContent()));
5683 // use the presshell containing the image
5684 PresShell
* presShell
= static_cast<PresShell
*>(f
->PresContext()->PresShell());
5685 uint32_t count
= presShell
->mVisibleImages
.Count();
5686 presShell
->mVisibleImages
.PutEntry(content
);
5687 if (presShell
->mVisibleImages
.Count() > count
) {
5688 // content was added to mVisibleImages, so we need to increment its visible count
5689 content
->IncrementVisibleCount();
5695 static PLDHashOperator
5696 RemoveAndStore(nsRefPtrHashKey
<nsIImageLoadingContent
>* aEntry
, void* userArg
)
5698 nsTArray
< nsRefPtr
<nsIImageLoadingContent
> >* array
=
5699 static_cast< nsTArray
< nsRefPtr
<nsIImageLoadingContent
> >* >(userArg
);
5700 array
->AppendElement(aEntry
->GetKey());
5701 return PL_DHASH_REMOVE
;
5705 PresShell::RebuildImageVisibilityDisplayList(const nsDisplayList
& aList
)
5707 MOZ_ASSERT(!mImageVisibilityVisited
, "already visited?");
5708 mImageVisibilityVisited
= true;
5709 // Remove the entries of the mVisibleImages hashtable and put them in the
5710 // beforeImageList array.
5711 nsTArray
< nsRefPtr
<nsIImageLoadingContent
> > beforeImageList
;
5712 beforeImageList
.SetCapacity(mVisibleImages
.Count());
5713 mVisibleImages
.EnumerateEntries(RemoveAndStore
, &beforeImageList
);
5714 MarkImagesInListVisible(aList
);
5715 for (size_t i
= 0; i
< beforeImageList
.Length(); ++i
) {
5716 beforeImageList
[i
]->DecrementVisibleCount();
5721 PresShell::ClearImageVisibilityVisited(nsView
* aView
, bool aClear
)
5723 nsViewManager
* vm
= aView
->GetViewManager();
5725 PresShell
* presShell
= static_cast<PresShell
*>(vm
->GetPresShell());
5726 if (!presShell
->mImageVisibilityVisited
) {
5727 presShell
->ClearVisibleImagesList();
5729 presShell
->mImageVisibilityVisited
= false;
5731 for (nsView
* v
= aView
->GetFirstChild(); v
; v
= v
->GetNextSibling()) {
5732 ClearImageVisibilityVisited(v
, v
->GetViewManager() != vm
);
5736 static PLDHashOperator
5737 DecrementVisibleCount(nsRefPtrHashKey
<nsIImageLoadingContent
>* aEntry
, void* userArg
)
5739 aEntry
->GetKey()->DecrementVisibleCount();
5740 return PL_DHASH_NEXT
;
5744 PresShell::ClearVisibleImagesList()
5746 mVisibleImages
.EnumerateEntries(DecrementVisibleCount
, nullptr);
5747 mVisibleImages
.Clear();
5751 PresShell::MarkImagesInSubtreeVisible(nsIFrame
* aFrame
, const nsRect
& aRect
)
5753 MOZ_ASSERT(aFrame
->PresContext()->PresShell() == this, "wrong presshell");
5755 nsCOMPtr
<nsIImageLoadingContent
> content(do_QueryInterface(aFrame
->GetContent()));
5756 if (content
&& aFrame
->StyleVisibility()->IsVisible()) {
5757 uint32_t count
= mVisibleImages
.Count();
5758 mVisibleImages
.PutEntry(content
);
5759 if (mVisibleImages
.Count() > count
) {
5760 // content was added to mVisibleImages, so we need to increment its visible count
5761 content
->IncrementVisibleCount();
5765 nsSubDocumentFrame
* subdocFrame
= do_QueryFrame(aFrame
);
5767 nsIPresShell
* presShell
= subdocFrame
->GetSubdocumentPresShellForPainting(
5768 nsSubDocumentFrame::IGNORE_PAINT_SUPPRESSION
);
5770 nsRect rect
= aRect
;
5771 nsIFrame
* root
= presShell
->GetRootFrame();
5773 rect
.MoveBy(aFrame
->GetOffsetToCrossDoc(root
));
5775 rect
.MoveBy(-aFrame
->GetContentRectRelativeToSelf().TopLeft());
5777 rect
= rect
.ConvertAppUnitsRoundOut(
5778 aFrame
->PresContext()->AppUnitsPerDevPixel(),
5779 presShell
->GetPresContext()->AppUnitsPerDevPixel());
5781 presShell
->RebuildImageVisibility(&rect
);
5786 nsRect rect
= aRect
;
5788 nsIScrollableFrame
* scrollFrame
= do_QueryFrame(aFrame
);
5791 bool usingDisplayport
= nsLayoutUtils::GetDisplayPort(aFrame
->GetContent(), &displayPort
);
5792 if (usingDisplayport
) {
5795 rect
= rect
.Intersect(scrollFrame
->GetScrollPortRect());
5797 rect
= scrollFrame
->ExpandRectToNearlyVisible(rect
);
5800 bool preserves3DChildren
= aFrame
->Preserves3DChildren();
5802 // we assume all images in popups are visible elsewhere, so we skip them here
5803 const nsIFrame::ChildListIDs
skip(nsIFrame::kPopupList
|
5804 nsIFrame::kSelectPopupList
);
5805 for (nsIFrame::ChildListIterator
childLists(aFrame
);
5806 !childLists
.IsDone(); childLists
.Next()) {
5807 if (skip
.Contains(childLists
.CurrentID())) {
5811 nsFrameList children
= childLists
.CurrentList();
5812 for (nsFrameList::Enumerator
e(children
); !e
.AtEnd(); e
.Next()) {
5813 nsIFrame
* child
= e
.get();
5815 nsRect r
= rect
- child
->GetPosition();
5816 if (!r
.IntersectRect(r
, child
->GetVisualOverflowRect())) {
5819 if (child
->IsTransformed()) {
5820 // for children of a preserve3d element we just pass down the same dirty rect
5821 if (!preserves3DChildren
|| !child
->Preserves3D()) {
5822 const nsRect overflow
= child
->GetVisualOverflowRectRelativeToSelf();
5824 if (nsDisplayTransform::UntransformRect(r
, overflow
, child
, nsPoint(0,0), &out
)) {
5831 MarkImagesInSubtreeVisible(child
, r
);
5837 PresShell::RebuildImageVisibility(nsRect
* aRect
)
5839 MOZ_ASSERT(!mImageVisibilityVisited
, "already visited?");
5840 mImageVisibilityVisited
= true;
5842 nsIFrame
* rootFrame
= GetRootFrame();
5847 // Remove the entries of the mVisibleImages hashtable and put them in the
5848 // beforeImageList array.
5849 nsTArray
< nsRefPtr
<nsIImageLoadingContent
> > beforeImageList
;
5850 beforeImageList
.SetCapacity(mVisibleImages
.Count());
5851 mVisibleImages
.EnumerateEntries(RemoveAndStore
, &beforeImageList
);
5853 nsRect
vis(nsPoint(0, 0), rootFrame
->GetSize());
5857 MarkImagesInSubtreeVisible(rootFrame
, vis
);
5859 for (size_t i
= 0; i
< beforeImageList
.Length(); ++i
) {
5860 beforeImageList
[i
]->DecrementVisibleCount();
5865 PresShell::UpdateImageVisibility()
5867 MOZ_ASSERT(!mPresContext
|| mPresContext
->IsRootContentDocument(),
5868 "updating image visibility on a non-root content document?");
5870 mUpdateImageVisibilityEvent
.Revoke();
5872 if (mHaveShutDown
|| mIsDestroying
) {
5876 // call update on that frame
5877 nsIFrame
* rootFrame
= GetRootFrame();
5879 ClearVisibleImagesList();
5883 RebuildImageVisibility();
5884 ClearImageVisibilityVisited(rootFrame
->GetView(), true);
5886 #ifdef DEBUG_IMAGE_VISIBILITY_DISPLAY_LIST
5887 // This can be used to debug the frame walker by comparing beforeImageList and
5888 // mVisibleImages in RebuildImageVisibilityDisplayList to see if they produce
5889 // the same results (mVisibleImages holds the images the display list thinks
5890 // are visible, beforeImageList holds the images the frame walker thinks are
5892 nsDisplayListBuilder
builder(rootFrame
, nsDisplayListBuilder::IMAGE_VISIBILITY
, false);
5893 nsRect
updateRect(nsPoint(0, 0), rootFrame
->GetSize());
5894 nsIFrame
* rootScroll
= GetRootScrollFrame();
5896 nsIContent
* content
= rootScroll
->GetContent();
5898 nsLayoutUtils::GetDisplayPort(content
, &updateRect
);
5901 if (IgnoringViewportScrolling()) {
5902 builder
.SetIgnoreScrollFrame(rootScroll
);
5903 // The ExpandRectToNearlyVisible that the root scroll frame would do gets short
5904 // circuited due to us ignoring the root scroll frame, so we do it here.
5905 nsIScrollableFrame
* rootScrollable
= do_QueryFrame(rootScroll
);
5906 updateRect
= rootScrollable
->ExpandRectToNearlyVisible(updateRect
);
5909 builder
.IgnorePaintSuppression();
5910 builder
.EnterPresShell(rootFrame
, updateRect
);
5912 rootFrame
->BuildDisplayListForStackingContext(&builder
, updateRect
, &list
);
5913 builder
.LeavePresShell(rootFrame
, updateRect
);
5915 RebuildImageVisibilityDisplayList(list
);
5917 ClearImageVisibilityVisited(rootFrame
->GetView(), true);
5924 PresShell::AssumeAllImagesVisible()
5926 static bool sImageVisibilityEnabled
= true;
5927 static bool sImageVisibilityEnabledForBrowserElementsOnly
= false;
5928 static bool sImageVisibilityPrefCached
= false;
5930 if (!sImageVisibilityPrefCached
) {
5931 Preferences::AddBoolVarCache(&sImageVisibilityEnabled
,
5932 "layout.imagevisibility.enabled", true);
5933 Preferences::AddBoolVarCache(&sImageVisibilityEnabledForBrowserElementsOnly
,
5934 "layout.imagevisibility.enabled_for_browser_elements_only", false);
5935 sImageVisibilityPrefCached
= true;
5938 if ((!sImageVisibilityEnabled
&&
5939 !sImageVisibilityEnabledForBrowserElementsOnly
) ||
5940 !mPresContext
|| !mDocument
) {
5944 // We assume all images are visible in print, print preview, chrome, xul, and
5945 // resource docs and don't keep track of them.
5946 if (mPresContext
->Type() == nsPresContext::eContext_PrintPreview
||
5947 mPresContext
->Type() == nsPresContext::eContext_Print
||
5948 mPresContext
->IsChrome() ||
5949 mDocument
->IsResourceDoc() ||
5950 mDocument
->IsXUL()) {
5954 if (!sImageVisibilityEnabled
&&
5955 sImageVisibilityEnabledForBrowserElementsOnly
) {
5956 nsCOMPtr
<nsIDocShell
> docshell(mPresContext
->GetDocShell());
5957 if (!docshell
|| !docshell
->GetIsInBrowserElement()) {
5966 PresShell::ScheduleImageVisibilityUpdate()
5968 if (AssumeAllImagesVisible())
5971 if (!mPresContext
->IsRootContentDocument()) {
5972 nsPresContext
* presContext
= mPresContext
->GetToplevelContentDocumentPresContext();
5975 MOZ_ASSERT(presContext
->IsRootContentDocument(),
5976 "Didn't get a root prescontext from GetToplevelContentDocumentPresContext?");
5977 presContext
->PresShell()->ScheduleImageVisibilityUpdate();
5981 if (mHaveShutDown
|| mIsDestroying
)
5984 if (mUpdateImageVisibilityEvent
.IsPending())
5987 nsRefPtr
<nsRunnableMethod
<PresShell
> > ev
=
5988 NS_NewRunnableMethod(this, &PresShell::UpdateImageVisibility
);
5989 if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev
))) {
5990 mUpdateImageVisibilityEvent
= ev
;
5995 PresShell::EnsureImageInVisibleList(nsIImageLoadingContent
* aImage
)
5997 if (AssumeAllImagesVisible()) {
5998 aImage
->IncrementVisibleCount();
6003 // if it has a frame make sure its in this presshell
6004 nsCOMPtr
<nsIContent
> content
= do_QueryInterface(aImage
);
6006 PresShell
* shell
= static_cast<PresShell
*>(content
->OwnerDoc()->GetShell());
6007 MOZ_ASSERT(!shell
|| shell
== this, "wrong shell");
6011 if (!mVisibleImages
.Contains(aImage
)) {
6012 mVisibleImages
.PutEntry(aImage
);
6013 aImage
->IncrementVisibleCount();
6018 PresShell::RemoveImageFromVisibleList(nsIImageLoadingContent
* aImage
)
6021 // if it has a frame make sure its in this presshell
6022 nsCOMPtr
<nsIContent
> content
= do_QueryInterface(aImage
);
6024 PresShell
* shell
= static_cast<PresShell
*>(content
->OwnerDoc()->GetShell());
6025 MOZ_ASSERT(!shell
|| shell
== this, "wrong shell");
6029 if (AssumeAllImagesVisible()) {
6030 MOZ_ASSERT(mVisibleImages
.Count() == 0, "shouldn't have any images in the table");
6034 uint32_t count
= mVisibleImages
.Count();
6035 mVisibleImages
.RemoveEntry(aImage
);
6036 if (mVisibleImages
.Count() < count
) {
6037 // aImage was in the hashtable, so we need to decrement its visible count
6038 aImage
->DecrementVisibleCount();
6042 class nsAutoNotifyDidPaint
6045 nsAutoNotifyDidPaint(PresShell
* aShell
, uint32_t aFlags
)
6046 : mShell(aShell
), mFlags(aFlags
)
6049 ~nsAutoNotifyDidPaint()
6051 mShell
->GetPresContext()->NotifyDidPaintForSubtree(mFlags
);
6059 class AutoUpdateHitRegion
6062 AutoUpdateHitRegion(PresShell
* aShell
, nsIFrame
* aFrame
)
6063 : mShell(aShell
), mFrame(aFrame
)
6066 ~AutoUpdateHitRegion()
6068 if (XRE_GetProcessType() != GeckoProcessType_Content
||
6069 !mFrame
|| !mShell
) {
6072 TabChild
* tabChild
= TabChild::GetFrom(mShell
);
6073 if (!tabChild
|| !tabChild
->GetUpdateHitRegion()) {
6077 nsDisplayListBuilder
builder(mFrame
,
6078 nsDisplayListBuilder::EVENT_DELIVERY
,
6079 /* aBuildCert= */ false);
6081 nsAutoTArray
<nsIFrame
*, 100> outFrames
;
6082 nsDisplayItem::HitTestState hitTestState
;
6083 nsRect bounds
= mShell
->GetPresContext()->GetVisibleArea();
6084 builder
.EnterPresShell(mFrame
, bounds
);
6085 mFrame
->BuildDisplayListForStackingContext(&builder
, bounds
, &list
);
6086 builder
.LeavePresShell(mFrame
, bounds
);
6087 list
.HitTest(&builder
, bounds
, &hitTestState
, &outFrames
);
6089 for (int32_t i
= outFrames
.Length() - 1; i
>= 0; --i
) {
6090 region
.Or(region
, nsLayoutUtils::TransformFrameRectToAncestor(
6091 outFrames
[i
], nsRect(nsPoint(0, 0), outFrames
[i
]->GetSize()), mFrame
));
6093 tabChild
->UpdateHitRegion(region
);
6101 PresShell::RecordShadowStyleChange(ShadowRoot
* aShadowRoot
)
6103 mChangedScopeStyleRoots
.AppendElement(aShadowRoot
->GetHost()->AsElement());
6107 PresShell::Paint(nsView
* aViewToPaint
,
6108 const nsRegion
& aDirtyRegion
,
6111 PROFILER_LABEL("PresShell", "Paint",
6112 js::ProfileEntry::Category::GRAPHICS
);
6114 NS_ASSERTION(!mIsDestroying
, "painting a destroyed PresShell");
6115 NS_ASSERTION(aViewToPaint
, "null view");
6117 MOZ_ASSERT(!mImageVisibilityVisited
, "should have been cleared");
6119 if (!mIsActive
|| mIsZombie
) {
6123 nsPresContext
* presContext
= GetPresContext();
6124 AUTO_LAYOUT_PHASE_ENTRY_POINT(presContext
, Paint
);
6126 nsIFrame
* frame
= aViewToPaint
->GetFrame();
6128 bool isRetainingManager
;
6129 LayerManager
* layerManager
=
6130 aViewToPaint
->GetWidget()->GetLayerManager(&isRetainingManager
);
6131 NS_ASSERTION(layerManager
, "Must be in paint event");
6132 bool shouldInvalidate
= layerManager
->NeedsWidgetInvalidation();
6134 nsAutoNotifyDidPaint
notifyDidPaint(this, aFlags
);
6135 AutoUpdateHitRegion
updateHitRegion(this, frame
);
6137 // Whether or not we should set first paint when painting is
6138 // suppressed is debatable. For now we'll do it because
6139 // B2G relies on first paint to configure the viewport and
6140 // we only want to do that when we have real content to paint.
6142 if (mIsFirstPaint
&& !mPaintingSuppressed
) {
6143 layerManager
->SetIsFirstPaint();
6144 mIsFirstPaint
= false;
6147 layerManager
->BeginTransaction();
6149 if (frame
&& isRetainingManager
) {
6150 // Try to do an empty transaction, if the frame tree does not
6151 // need to be updated. Do not try to do an empty transaction on
6152 // a non-retained layer manager (like the BasicLayerManager that
6153 // draws the window title bar on Mac), because a) it won't work
6154 // and b) below we don't want to clear NS_FRAME_UPDATE_LAYER_TREE,
6155 // that will cause us to forget to update the real layer manager!
6157 if (!(aFlags
& PAINT_LAYERS
)) {
6158 if (layerManager
->EndEmptyTransaction()) {
6161 NS_WARNING("Must complete empty transaction when compositing!");
6164 if (!(frame
->GetStateBits() & NS_FRAME_UPDATE_LAYER_TREE
) &&
6165 !mNextPaintCompressed
) {
6166 NotifySubDocInvalidationFunc computeInvalidFunc
=
6167 presContext
->MayHavePaintEventListenerInSubDocument() ? nsPresContext::NotifySubDocInvalidation
: 0;
6168 bool computeInvalidRect
= computeInvalidFunc
||
6169 (layerManager
->GetBackendType() == LayersBackend::LAYERS_BASIC
);
6171 UniquePtr
<LayerProperties
> props
;
6172 if (computeInvalidRect
) {
6173 props
= Move(LayerProperties::CloneFrom(layerManager
->GetRoot()));
6176 MaybeSetupTransactionIdAllocator(layerManager
, aViewToPaint
);
6178 if (layerManager
->EndEmptyTransaction((aFlags
& PAINT_COMPOSITE
) ?
6179 LayerManager::END_DEFAULT
: LayerManager::END_NO_COMPOSITE
)) {
6180 nsIntRegion invalid
;
6182 invalid
= props
->ComputeDifferences(layerManager
->GetRoot(), computeInvalidFunc
);
6184 LayerProperties::ClearInvalidations(layerManager
->GetRoot());
6187 if (!invalid
.IsEmpty()) {
6188 nsIntRect bounds
= invalid
.GetBounds();
6189 nsRect
rect(presContext
->DevPixelsToAppUnits(bounds
.x
),
6190 presContext
->DevPixelsToAppUnits(bounds
.y
),
6191 presContext
->DevPixelsToAppUnits(bounds
.width
),
6192 presContext
->DevPixelsToAppUnits(bounds
.height
));
6193 if (shouldInvalidate
) {
6194 aViewToPaint
->GetViewManager()->InvalidateViewNoSuppression(aViewToPaint
, rect
);
6196 presContext
->NotifyInvalidation(bounds
, 0);
6198 } else if (shouldInvalidate
) {
6199 aViewToPaint
->GetViewManager()->InvalidateView(aViewToPaint
);
6202 frame
->UpdatePaintCountForPaintedPresShells();
6206 frame
->RemoveStateBits(NS_FRAME_UPDATE_LAYER_TREE
);
6209 frame
->ClearPresShellsFromLastPaint();
6212 nscolor bgcolor
= ComputeBackstopColor(aViewToPaint
);
6213 uint32_t flags
= nsLayoutUtils::PAINT_WIDGET_LAYERS
| nsLayoutUtils::PAINT_EXISTING_TRANSACTION
;
6214 if (!(aFlags
& PAINT_COMPOSITE
)) {
6215 flags
|= nsLayoutUtils::PAINT_NO_COMPOSITE
;
6217 if (mNextPaintCompressed
) {
6218 flags
|= nsLayoutUtils::PAINT_COMPRESSED
;
6219 mNextPaintCompressed
= false;
6223 // We can paint directly into the widget using its layer manager.
6224 nsLayoutUtils::PaintFrame(nullptr, frame
, aDirtyRegion
, bgcolor
, flags
);
6228 nsRefPtr
<ColorLayer
> root
= layerManager
->CreateColorLayer();
6230 nsPresContext
* pc
= GetPresContext();
6232 pc
->GetVisibleArea().ToOutsidePixels(pc
->AppUnitsPerDevPixel());
6233 bgcolor
= NS_ComposeColors(bgcolor
, mCanvasBackgroundColor
);
6234 root
->SetColor(bgcolor
);
6235 root
->SetVisibleRegion(bounds
);
6236 layerManager
->SetRoot(root
);
6238 MaybeSetupTransactionIdAllocator(layerManager
, aViewToPaint
);
6239 layerManager
->EndTransaction(nullptr, nullptr, (aFlags
& PAINT_COMPOSITE
) ?
6240 LayerManager::END_DEFAULT
: LayerManager::END_NO_COMPOSITE
);
6245 nsIPresShell::SetCapturingContent(nsIContent
* aContent
, uint8_t aFlags
)
6247 // If capture was set for pointer lock, don't unlock unless we are coming
6248 // out of pointer lock explicitly.
6249 if (!aContent
&& gCaptureInfo
.mPointerLock
&&
6250 !(aFlags
& CAPTURE_POINTERLOCK
)) {
6254 NS_IF_RELEASE(gCaptureInfo
.mContent
);
6256 // only set capturing content if allowed or the CAPTURE_IGNOREALLOWED or
6257 // CAPTURE_POINTERLOCK flags are used.
6258 if ((aFlags
& CAPTURE_IGNOREALLOWED
) || gCaptureInfo
.mAllowed
||
6259 (aFlags
& CAPTURE_POINTERLOCK
)) {
6261 NS_ADDREF(gCaptureInfo
.mContent
= aContent
);
6263 // CAPTURE_POINTERLOCK is the same as CAPTURE_RETARGETTOELEMENT & CAPTURE_IGNOREALLOWED
6264 gCaptureInfo
.mRetargetToElement
= ((aFlags
& CAPTURE_RETARGETTOELEMENT
) != 0) ||
6265 ((aFlags
& CAPTURE_POINTERLOCK
) != 0);
6266 gCaptureInfo
.mPreventDrag
= (aFlags
& CAPTURE_PREVENTDRAG
) != 0;
6267 gCaptureInfo
.mPointerLock
= (aFlags
& CAPTURE_POINTERLOCK
) != 0;
6272 nsIPresShell::SetPointerCapturingContent(uint32_t aPointerId
, nsIContent
* aContent
)
6274 nsIContent
* content
= GetPointerCapturingContent(aPointerId
);
6276 PointerInfo
* pointerInfo
= nullptr;
6277 if (!content
&& gActivePointersIds
->Get(aPointerId
, &pointerInfo
) &&
6279 nsIDOMMouseEvent::MOZ_SOURCE_MOUSE
== pointerInfo
->mPointerType
) {
6280 SetCapturingContent(aContent
, CAPTURE_PREVENTDRAG
);
6284 // Releasing capture for given pointer.
6285 gPointerCaptureList
->Remove(aPointerId
);
6286 DispatchGotOrLostPointerCaptureEvent(false, aPointerId
, content
);
6287 // Need to check the state because a lostpointercapture listener
6288 // may have called SetPointerCapture
6289 if (GetPointerCapturingContent(aPointerId
)) {
6294 gPointerCaptureList
->Put(aPointerId
, aContent
);
6295 DispatchGotOrLostPointerCaptureEvent(true, aPointerId
, aContent
);
6299 nsIPresShell::ReleasePointerCapturingContent(uint32_t aPointerId
, nsIContent
* aContent
)
6301 if (gActivePointersIds
->Get(aPointerId
)) {
6302 SetCapturingContent(nullptr, CAPTURE_PREVENTDRAG
);
6305 // Releasing capture for given pointer.
6306 gPointerCaptureList
->Remove(aPointerId
);
6308 DispatchGotOrLostPointerCaptureEvent(false, aPointerId
, aContent
);
6311 /* static */ nsIContent
*
6312 nsIPresShell::GetPointerCapturingContent(uint32_t aPointerId
)
6314 return gPointerCaptureList
->GetWeak(aPointerId
);
6318 nsIPresShell::GetPointerInfo(uint32_t aPointerId
, bool& aActiveState
)
6320 PointerInfo
* pointerInfo
= nullptr;
6321 if (gActivePointersIds
->Get(aPointerId
, &pointerInfo
) && pointerInfo
) {
6322 aActiveState
= pointerInfo
->mActiveState
;
6329 PresShell::UpdateActivePointerState(WidgetGUIEvent
* aEvent
)
6331 switch (aEvent
->message
) {
6332 case NS_MOUSE_ENTER
:
6333 // In this case we have to know information about available mouse pointers
6334 if (WidgetMouseEvent
* mouseEvent
= aEvent
->AsMouseEvent()) {
6335 gActivePointersIds
->Put(mouseEvent
->pointerId
, new PointerInfo(false, mouseEvent
->inputSource
));
6338 case NS_POINTER_DOWN
:
6339 // In this case we switch pointer to active state
6340 if (WidgetPointerEvent
* pointerEvent
= aEvent
->AsPointerEvent()) {
6341 gActivePointersIds
->Put(pointerEvent
->pointerId
, new PointerInfo(true, pointerEvent
->inputSource
));
6345 // In this case we remove information about pointer or turn off active state
6346 if (WidgetPointerEvent
* pointerEvent
= aEvent
->AsPointerEvent()) {
6347 if(pointerEvent
->inputSource
!= nsIDOMMouseEvent::MOZ_SOURCE_TOUCH
) {
6348 gActivePointersIds
->Put(pointerEvent
->pointerId
, new PointerInfo(false, pointerEvent
->inputSource
));
6350 gActivePointersIds
->Remove(pointerEvent
->pointerId
);
6355 // In this case we have to remove information about disappeared mouse pointers
6356 if (WidgetMouseEvent
* mouseEvent
= aEvent
->AsMouseEvent()) {
6357 gActivePointersIds
->Remove(mouseEvent
->pointerId
);
6364 PresShell::GetCurrentEventContent()
6366 if (mCurrentEventContent
&&
6367 mCurrentEventContent
->GetCrossShadowCurrentDoc() != mDocument
) {
6368 mCurrentEventContent
= nullptr;
6369 mCurrentEventFrame
= nullptr;
6371 return mCurrentEventContent
;
6375 PresShell::GetCurrentEventFrame()
6377 if (MOZ_UNLIKELY(mIsDestroying
)) {
6381 // GetCurrentEventContent() makes sure the content is still in the
6382 // same document that this pres shell belongs to. If not, then the
6383 // frame shouldn't get an event, nor should we even assume its safe
6384 // to try and find the frame.
6385 nsIContent
* content
= GetCurrentEventContent();
6386 if (!mCurrentEventFrame
&& content
) {
6387 mCurrentEventFrame
= content
->GetPrimaryFrame();
6388 MOZ_ASSERT(!mCurrentEventFrame
||
6389 mCurrentEventFrame
->PresContext()->GetPresShell() == this);
6391 return mCurrentEventFrame
;
6395 PresShell::GetEventTargetFrame()
6397 return GetCurrentEventFrame();
6400 already_AddRefed
<nsIContent
>
6401 PresShell::GetEventTargetContent(WidgetEvent
* aEvent
)
6403 nsCOMPtr
<nsIContent
> content
= GetCurrentEventContent();
6405 nsIFrame
* currentEventFrame
= GetCurrentEventFrame();
6406 if (currentEventFrame
) {
6407 currentEventFrame
->GetContentForEvent(aEvent
, getter_AddRefs(content
));
6408 NS_ASSERTION(!content
|| content
->GetCrossShadowCurrentDoc() == mDocument
,
6409 "handing out content from a different doc");
6412 return content
.forget();
6416 PresShell::PushCurrentEventInfo(nsIFrame
* aFrame
, nsIContent
* aContent
)
6418 if (mCurrentEventFrame
|| mCurrentEventContent
) {
6419 mCurrentEventFrameStack
.InsertElementAt(0, mCurrentEventFrame
);
6420 mCurrentEventContentStack
.InsertObjectAt(mCurrentEventContent
, 0);
6422 mCurrentEventFrame
= aFrame
;
6423 mCurrentEventContent
= aContent
;
6427 PresShell::PopCurrentEventInfo()
6429 mCurrentEventFrame
= nullptr;
6430 mCurrentEventContent
= nullptr;
6432 if (0 != mCurrentEventFrameStack
.Length()) {
6433 mCurrentEventFrame
= mCurrentEventFrameStack
.ElementAt(0);
6434 mCurrentEventFrameStack
.RemoveElementAt(0);
6435 mCurrentEventContent
= mCurrentEventContentStack
.ObjectAt(0);
6436 mCurrentEventContentStack
.RemoveObjectAt(0);
6438 // Don't use it if it has moved to a different document.
6439 if (mCurrentEventContent
&&
6440 mCurrentEventContent
->GetCrossShadowCurrentDoc() != mDocument
) {
6441 mCurrentEventContent
= nullptr;
6442 mCurrentEventFrame
= nullptr;
6447 bool PresShell::InZombieDocument(nsIContent
*aContent
)
6449 // If a content node points to a null document, or the document is not
6450 // attached to a window, then it is possibly in a zombie document,
6451 // about to be replaced by a newly loading document.
6452 // Such documents cannot handle DOM events.
6453 // It might actually be in a node not attached to any document,
6454 // in which case there is not parent presshell to retarget it to.
6455 nsIDocument
* doc
= aContent
->GetComposedDoc();
6456 return !doc
|| !doc
->GetWindow();
6459 already_AddRefed
<nsPIDOMWindow
>
6460 PresShell::GetRootWindow()
6462 nsCOMPtr
<nsPIDOMWindow
> window
=
6463 do_QueryInterface(mDocument
->GetWindow());
6465 nsCOMPtr
<nsPIDOMWindow
> rootWindow
= window
->GetPrivateRoot();
6466 NS_ASSERTION(rootWindow
, "nsPIDOMWindow::GetPrivateRoot() returns NULL");
6467 return rootWindow
.forget();
6470 // If we don't have DOM window, we're zombie, we should find the root window
6471 // with our parent shell.
6472 nsCOMPtr
<nsIPresShell
> parent
= GetParentPresShellForEventHandling();
6473 NS_ENSURE_TRUE(parent
, nullptr);
6474 return parent
->GetRootWindow();
6477 already_AddRefed
<nsIPresShell
>
6478 PresShell::GetParentPresShellForEventHandling()
6480 NS_ENSURE_TRUE(mPresContext
, nullptr);
6482 // Now, find the parent pres shell and send the event there
6483 nsCOMPtr
<nsIDocShellTreeItem
> treeItem
= mPresContext
->GetDocShell();
6485 treeItem
= mForwardingContainer
.get();
6488 // Might have gone away, or never been around to start with
6489 NS_ENSURE_TRUE(treeItem
, nullptr);
6491 nsCOMPtr
<nsIDocShellTreeItem
> parentTreeItem
;
6492 treeItem
->GetParent(getter_AddRefs(parentTreeItem
));
6493 nsCOMPtr
<nsIDocShell
> parentDocShell
= do_QueryInterface(parentTreeItem
);
6494 NS_ENSURE_TRUE(parentDocShell
&& treeItem
!= parentTreeItem
, nullptr);
6496 nsCOMPtr
<nsIPresShell
> parentPresShell
= parentDocShell
->GetPresShell();
6497 return parentPresShell
.forget();
6501 PresShell::RetargetEventToParent(WidgetGUIEvent
* aEvent
,
6502 nsEventStatus
* aEventStatus
)
6504 // Send this events straight up to the parent pres shell.
6505 // We do this for keystroke events in zombie documents or if either a frame
6506 // or a root content is not present.
6507 // That way at least the UI key bindings can work.
6509 nsCOMPtr
<nsIPresShell
> kungFuDeathGrip(this);
6510 nsCOMPtr
<nsIPresShell
> parentPresShell
= GetParentPresShellForEventHandling();
6511 NS_ENSURE_TRUE(parentPresShell
, NS_ERROR_FAILURE
);
6513 // Fake the event as though it's from the parent pres shell's root frame.
6514 return parentPresShell
->HandleEvent(parentPresShell
->GetRootFrame(), aEvent
, true, aEventStatus
);
6518 PresShell::DisableNonTestMouseEvents(bool aDisable
)
6520 sDisableNonTestMouseEvents
= aDisable
;
6523 already_AddRefed
<nsPIDOMWindow
>
6524 PresShell::GetFocusedDOMWindowInOurWindow()
6526 nsCOMPtr
<nsPIDOMWindow
> rootWindow
= GetRootWindow();
6527 NS_ENSURE_TRUE(rootWindow
, nullptr);
6528 nsCOMPtr
<nsPIDOMWindow
> focusedWindow
;
6529 nsFocusManager::GetFocusedDescendant(rootWindow
, true,
6530 getter_AddRefs(focusedWindow
));
6531 return focusedWindow
.forget();
6535 PresShell::RecordMouseLocation(WidgetGUIEvent
* aEvent
)
6540 if (!mPresContext
->IsRoot()) {
6541 PresShell
* rootPresShell
= GetRootPresShell();
6542 if (rootPresShell
) {
6543 rootPresShell
->RecordMouseLocation(aEvent
);
6548 if ((aEvent
->message
== NS_MOUSE_MOVE
&&
6549 aEvent
->AsMouseEvent()->reason
== WidgetMouseEvent::eReal
) ||
6550 aEvent
->message
== NS_MOUSE_ENTER
||
6551 aEvent
->message
== NS_MOUSE_BUTTON_DOWN
||
6552 aEvent
->message
== NS_MOUSE_BUTTON_UP
) {
6553 nsIFrame
* rootFrame
= GetRootFrame();
6555 nsView
* rootView
= mViewManager
->GetRootView();
6556 mMouseLocation
= nsLayoutUtils::TranslateWidgetToView(mPresContext
,
6557 aEvent
->widget
, LayoutDeviceIntPoint::ToUntyped(aEvent
->refPoint
),
6561 nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent
, rootFrame
);
6563 #ifdef DEBUG_MOUSE_LOCATION
6564 if (aEvent
->message
== NS_MOUSE_ENTER
)
6565 printf("[ps=%p]got mouse enter for %p\n",
6566 this, aEvent
->widget
);
6567 printf("[ps=%p]setting mouse location to (%d,%d)\n",
6568 this, mMouseLocation
.x
, mMouseLocation
.y
);
6570 if (aEvent
->message
== NS_MOUSE_ENTER
)
6571 SynthesizeMouseMove(false);
6572 } else if (aEvent
->message
== NS_MOUSE_EXIT
) {
6573 // Although we only care about the mouse moving into an area for which this
6574 // pres shell doesn't receive mouse move events, we don't check which widget
6575 // the mouse exit was for since this seems to vary by platform. Hopefully
6576 // this won't matter at all since we'll get the mouse move or enter after
6577 // the mouse exit when the mouse moves from one of our widgets into another.
6578 mMouseLocation
= nsPoint(NS_UNCONSTRAINEDSIZE
, NS_UNCONSTRAINEDSIZE
);
6579 #ifdef DEBUG_MOUSE_LOCATION
6580 printf("[ps=%p]got mouse exit for %p\n",
6581 this, aEvent
->widget
);
6582 printf("[ps=%p]clearing mouse location\n",
6589 EvictTouchPoint(nsRefPtr
<dom::Touch
>& aTouch
,
6590 nsIDocument
* aLimitToDocument
= nullptr)
6592 nsCOMPtr
<nsINode
> node(do_QueryInterface(aTouch
->mTarget
));
6594 nsIDocument
* doc
= node
->GetCurrentDoc();
6595 if (doc
&& (!aLimitToDocument
|| aLimitToDocument
== doc
)) {
6596 nsIPresShell
* presShell
= doc
->GetShell();
6598 nsIFrame
* frame
= presShell
->GetRootFrame();
6600 nsPoint
pt(aTouch
->mRefPoint
.x
, aTouch
->mRefPoint
.y
);
6601 nsCOMPtr
<nsIWidget
> widget
= frame
->GetView()->GetNearestWidget(&pt
);
6603 WidgetTouchEvent
event(true, NS_TOUCH_END
, widget
);
6604 event
.widget
= widget
;
6605 event
.time
= PR_IntervalNow();
6606 event
.touches
.AppendElement(aTouch
);
6607 nsEventStatus status
;
6608 widget
->DispatchEvent(&event
, status
);
6615 if (!node
|| !aLimitToDocument
|| node
->OwnerDoc() == aLimitToDocument
) {
6616 // We couldn't dispatch touchend. Remove the touch from gCaptureTouchList
6618 nsIPresShell::gCaptureTouchList
->Remove(aTouch
->Identifier());
6622 static PLDHashOperator
6623 AppendToTouchList(const uint32_t& aKey
, nsRefPtr
<dom::Touch
>& aData
, void *aTouchList
)
6625 WidgetTouchEvent::TouchArray
* touches
=
6626 static_cast<WidgetTouchEvent::TouchArray
*>(aTouchList
);
6627 aData
->mChanged
= false;
6628 touches
->AppendElement(aData
);
6629 return PL_DHASH_NEXT
;
6633 PresShell::EvictTouches()
6635 WidgetTouchEvent::AutoTouchArray touches
;
6636 gCaptureTouchList
->Enumerate(&AppendToTouchList
, &touches
);
6637 for (uint32_t i
= 0; i
< touches
.Length(); ++i
) {
6638 EvictTouchPoint(touches
[i
], mDocument
);
6642 static PLDHashOperator
6643 FindAnyTarget(const uint32_t& aKey
, nsRefPtr
<dom::Touch
>& aData
,
6647 dom::EventTarget
* target
= aData
->GetTarget();
6649 nsCOMPtr
<nsIContent
>* content
=
6650 static_cast<nsCOMPtr
<nsIContent
>*>(aAnyTarget
);
6651 *content
= do_QueryInterface(target
);
6652 return PL_DHASH_STOP
;
6655 return PL_DHASH_NEXT
;
6658 nsIFrame
* GetNearestFrameContainingPresShell(nsIPresShell
* aPresShell
)
6660 nsView
* view
= aPresShell
->GetViewManager()->GetRootView();
6661 while (view
&& !view
->GetFrame()) {
6662 view
= view
->GetParent();
6665 nsIFrame
* frame
= nullptr;
6667 frame
= view
->GetFrame();
6674 FlushThrottledStyles(nsIDocument
*aDocument
, void *aData
)
6676 nsIPresShell
* shell
= aDocument
->GetShell();
6677 if (shell
&& shell
->IsVisible()) {
6678 nsPresContext
* presContext
= shell
->GetPresContext();
6680 presContext
->RestyleManager()->UpdateOnlyAnimationStyles();
6688 DispatchPointerFromMouseOrTouch(PresShell
* aShell
,
6690 WidgetGUIEvent
* aEvent
,
6691 bool aDontRetargetEvents
,
6692 nsEventStatus
* aStatus
)
6694 uint32_t pointerMessage
= 0;
6695 if (aEvent
->mClass
== eMouseEventClass
) {
6696 WidgetMouseEvent
* mouseEvent
= aEvent
->AsMouseEvent();
6697 // if it is not mouse then it is likely will come as touch event
6698 if (!mouseEvent
->convertToPointer
) {
6701 int16_t button
= mouseEvent
->button
;
6702 switch (mouseEvent
->message
) {
6704 if (mouseEvent
->buttons
== 0) {
6707 pointerMessage
= NS_POINTER_MOVE
;
6709 case NS_MOUSE_BUTTON_UP
:
6710 pointerMessage
= NS_POINTER_UP
;
6712 case NS_MOUSE_BUTTON_DOWN
:
6713 pointerMessage
= NS_POINTER_DOWN
;
6719 WidgetPointerEvent
event(*mouseEvent
);
6720 event
.message
= pointerMessage
;
6721 event
.button
= button
;
6722 event
.pressure
= event
.buttons
?
6723 mouseEvent
->pressure
? mouseEvent
->pressure
: 0.5f
:
6725 event
.convertToPointer
= mouseEvent
->convertToPointer
= false;
6726 aShell
->HandleEvent(aFrame
, &event
, aDontRetargetEvents
, aStatus
);
6727 } else if (aEvent
->mClass
== eTouchEventClass
) {
6728 WidgetTouchEvent
* touchEvent
= aEvent
->AsTouchEvent();
6729 // loop over all touches and dispatch pointer events on each touch
6731 switch (touchEvent
->message
) {
6733 pointerMessage
= NS_POINTER_MOVE
;
6736 pointerMessage
= NS_POINTER_UP
;
6738 case NS_TOUCH_START
:
6739 pointerMessage
= NS_POINTER_DOWN
;
6741 case NS_TOUCH_CANCEL
:
6742 pointerMessage
= NS_POINTER_CANCEL
;
6748 for (uint32_t i
= 0; i
< touchEvent
->touches
.Length(); ++i
) {
6749 mozilla::dom::Touch
* touch
= touchEvent
->touches
[i
];
6750 if (!touch
|| !touch
->convertToPointer
) {
6754 WidgetPointerEvent
event(touchEvent
->mFlags
.mIsTrusted
, pointerMessage
, touchEvent
->widget
);
6755 event
.isPrimary
= i
== 0;
6756 event
.pointerId
= touch
->Identifier();
6757 event
.refPoint
.x
= touch
->mRefPoint
.x
;
6758 event
.refPoint
.y
= touch
->mRefPoint
.y
;
6759 event
.modifiers
= touchEvent
->modifiers
;
6760 event
.width
= touch
->RadiusX();
6761 event
.height
= touch
->RadiusY();
6762 event
.tiltX
= touch
->tiltX
;
6763 event
.tiltY
= touch
->tiltY
;
6764 event
.time
= touchEvent
->time
;
6765 event
.timeStamp
= touchEvent
->timeStamp
;
6766 event
.mFlags
= touchEvent
->mFlags
;
6767 event
.button
= WidgetMouseEvent::eLeftButton
;
6768 event
.buttons
= WidgetMouseEvent::eLeftButtonFlag
;
6769 event
.inputSource
= nsIDOMMouseEvent::MOZ_SOURCE_TOUCH
;
6770 event
.convertToPointer
= touch
->convertToPointer
= false;
6771 aShell
->HandleEvent(aFrame
, &event
, aDontRetargetEvents
, aStatus
);
6777 class ReleasePointerCaptureCaller
6780 ReleasePointerCaptureCaller() :
6785 ~ReleasePointerCaptureCaller()
6788 nsIPresShell::ReleasePointerCapturingContent(mPointerId
, mContent
);
6791 void SetTarget(uint32_t aPointerId
, nsIContent
* aContent
)
6793 mPointerId
= aPointerId
;
6794 mContent
= aContent
;
6799 nsCOMPtr
<nsIContent
> mContent
;
6803 PresShell::HandleEvent(nsIFrame
* aFrame
,
6804 WidgetGUIEvent
* aEvent
,
6805 bool aDontRetargetEvents
,
6806 nsEventStatus
* aEventStatus
)
6808 #ifdef MOZ_TASK_TRACER
6809 // Make touch events, mouse events and hardware key events to be the source
6810 // events of TaskTracer, and originate the rest correlation tasks from here.
6811 SourceEventType type
= SourceEventType::UNKNOWN
;
6812 if (WidgetTouchEvent
* inputEvent
= aEvent
->AsTouchEvent()) {
6813 type
= SourceEventType::TOUCH
;
6814 } else if (WidgetMouseEvent
* inputEvent
= aEvent
->AsMouseEvent()) {
6815 type
= SourceEventType::MOUSE
;
6816 } else if (WidgetKeyboardEvent
* inputEvent
= aEvent
->AsKeyboardEvent()) {
6817 type
= SourceEventType::KEY
;
6819 AutoSourceEvent
taskTracerEvent(type
);
6822 if (sPointerEventEnabled
) {
6823 DispatchPointerFromMouseOrTouch(this, aFrame
, aEvent
, aDontRetargetEvents
, aEventStatus
);
6826 NS_ASSERTION(aFrame
, "null frame");
6828 if (mIsDestroying
||
6829 (sDisableNonTestMouseEvents
&& !aEvent
->mFlags
.mIsSynthesizedForTests
&&
6830 aEvent
->HasMouseEventMessage())) {
6834 RecordMouseLocation(aEvent
);
6836 // Determine whether event need to be consumed by touch caret or not.
6837 if (TouchCaretPrefEnabled() || SelectionCaretPrefEnabled()) {
6838 // We have to target the focus window because regardless of where the
6839 // touch goes, we want to access the touch caret when user is typing on an
6840 // editable element.
6841 nsCOMPtr
<nsPIDOMWindow
> window
= GetFocusedDOMWindowInOurWindow();
6842 nsCOMPtr
<nsIDocument
> retargetEventDoc
= window
? window
->GetExtantDoc() : nullptr;
6843 nsCOMPtr
<nsIPresShell
> presShell
= retargetEventDoc
?
6844 retargetEventDoc
->GetShell() :
6847 // Bug 1057256: Touch caret should handle the event before selection carets.
6848 // Otherwise, a long tap on touch caret will be incorrectly handled by
6849 // selection carets which makes moving touch caret failed.
6850 nsRefPtr
<TouchCaret
> touchCaret
= presShell
?
6851 presShell
->GetTouchCaret() :
6854 *aEventStatus
= touchCaret
->HandleEvent(aEvent
);
6855 if (*aEventStatus
== nsEventStatus_eConsumeNoDefault
) {
6856 // If the event is consumed by the touch caret, cancel APZC panning by
6857 // setting mMultipleActionsPrevented.
6858 aEvent
->mFlags
.mMultipleActionsPrevented
= true;
6863 nsRefPtr
<SelectionCarets
> selectionCaret
= presShell
?
6864 presShell
->GetSelectionCarets() :
6866 if (selectionCaret
) {
6867 *aEventStatus
= selectionCaret
->HandleEvent(aEvent
);
6868 if (*aEventStatus
== nsEventStatus_eConsumeNoDefault
) {
6869 // If the event is consumed by the selection carets, cancel APZC panning by
6870 // setting mMultipleActionsPrevented.
6871 aEvent
->mFlags
.mMultipleActionsPrevented
= true;
6877 if (sPointerEventEnabled
) {
6878 UpdateActivePointerState(aEvent
);
6881 if (!nsContentUtils::IsSafeToRunScript() &&
6882 aEvent
->IsAllowedToDispatchDOMEvent()) {
6884 if (aEvent
->IsIMERelatedEvent()) {
6885 nsPrintfCString
warning("%d event is discarded", aEvent
->message
);
6886 NS_WARNING(warning
.get());
6889 nsContentUtils::WarnScriptWasIgnored(GetDocument());
6893 nsIContent
* capturingContent
=
6894 (aEvent
->HasMouseEventMessage() ||
6895 aEvent
->mClass
== eWheelEventClass
? GetCapturingContent() : nullptr);
6897 nsCOMPtr
<nsIDocument
> retargetEventDoc
;
6898 if (!aDontRetargetEvents
) {
6899 // key and IME related events should not cross top level window boundary.
6900 // Basically, such input events should be fired only on focused widget.
6901 // However, some IMEs might need to clean up composition after focused
6902 // window is deactivated. And also some tests on MozMill want to test key
6903 // handling on deactivated window because MozMill window can be activated
6904 // during tests. So, there is no merit the events should be redirected to
6905 // active window. So, the events should be handled on the last focused
6906 // content in the last focused DOM window in same top level window.
6907 // Note, if no DOM window has been focused yet, we can discard the events.
6908 if (aEvent
->IsTargetedAtFocusedWindow()) {
6909 nsCOMPtr
<nsPIDOMWindow
> window
= GetFocusedDOMWindowInOurWindow();
6910 // No DOM window in same top level window has not been focused yet,
6911 // discard the events.
6916 retargetEventDoc
= window
->GetExtantDoc();
6917 if (!retargetEventDoc
)
6919 } else if (capturingContent
) {
6920 // if the mouse is being captured then retarget the mouse event at the
6921 // document that is being captured.
6922 retargetEventDoc
= capturingContent
->GetCrossShadowCurrentDoc();
6924 } else if (aEvent
->mClass
== eTouchEventClass
||
6925 (aEvent
->AsMouseEvent() && aEvent
->AsMouseEvent()->inputSource
== nsIDOMMouseEvent::MOZ_SOURCE_TOUCH
)) {
6926 retargetEventDoc
= GetTouchEventTargetDocument();
6930 if (retargetEventDoc
) {
6931 nsCOMPtr
<nsIPresShell
> presShell
= retargetEventDoc
->GetShell();
6935 if (presShell
!= this) {
6936 nsIFrame
* frame
= presShell
->GetRootFrame();
6938 if (aEvent
->message
== NS_QUERY_TEXT_CONTENT
||
6939 aEvent
->IsContentCommandEvent()) {
6943 frame
= GetNearestFrameContainingPresShell(presShell
);
6949 nsCOMPtr
<nsIPresShell
> shell
= frame
->PresContext()->GetPresShell();
6950 return shell
->HandleEvent(frame
, aEvent
, true, aEventStatus
);
6955 if (aEvent
->mClass
== eKeyboardEventClass
&&
6956 mDocument
&& mDocument
->EventHandlingSuppressed()) {
6957 if (aEvent
->message
== NS_KEY_DOWN
) {
6958 mNoDelayedKeyEvents
= true;
6959 } else if (!mNoDelayedKeyEvents
) {
6960 DelayedEvent
* event
= new DelayedKeyEvent(aEvent
->AsKeyboardEvent());
6961 if (!mDelayedEvents
.AppendElement(event
)) {
6968 nsIFrame
* frame
= aFrame
;
6970 if (aEvent
->IsUsingCoordinates()) {
6971 ReleasePointerCaptureCaller releasePointerCaptureCaller
;
6972 if (nsLayoutUtils::AreAsyncAnimationsEnabled() && mDocument
) {
6973 if (aEvent
->mClass
== eTouchEventClass
) {
6974 nsIDocument::UnlockPointer();
6977 nsWeakFrame
weakFrame(frame
);
6978 { // scope for scriptBlocker.
6979 nsAutoScriptBlocker scriptBlocker
;
6980 GetRootPresShell()->GetDocument()->
6981 EnumerateSubDocuments(FlushThrottledStyles
, nullptr);
6984 if (!weakFrame
.IsAlive()) {
6985 frame
= GetNearestFrameContainingPresShell(this);
6989 NS_WARN_IF_FALSE(frame
, "Nothing to handle this event!");
6993 nsPresContext
* framePresContext
= frame
->PresContext();
6994 nsPresContext
* rootPresContext
= framePresContext
->GetRootPresContext();
6995 NS_ASSERTION(rootPresContext
== mPresContext
->GetRootPresContext(),
6996 "How did we end up outside the connected prescontext/viewmanager hierarchy?");
6997 // If we aren't starting our event dispatch from the root frame of the root prescontext,
6998 // then someone must be capturing the mouse. In that case we don't want to search the popup
7000 if (framePresContext
== rootPresContext
&&
7001 frame
== mFrameConstructor
->GetRootFrame()) {
7002 nsIFrame
* popupFrame
=
7003 nsLayoutUtils::GetPopupFrameForEventCoordinates(rootPresContext
, aEvent
);
7004 // If the popupFrame is an ancestor of the 'frame', the frame should
7005 // handle the event, otherwise, the popup should handle it.
7007 !nsContentUtils::ContentIsCrossDocDescendantOf(
7008 framePresContext
->GetPresShell()->GetDocument(),
7009 popupFrame
->GetContent())) {
7014 bool captureRetarget
= false;
7015 if (capturingContent
) {
7016 // If a capture is active, determine if the docshell is visible. If not,
7017 // clear the capture and target the mouse event normally instead. This
7018 // would occur if the mouse button is held down while a tab change occurs.
7019 // If the docshell is visible, look for a scrolling container.
7021 nsCOMPtr
<nsIBaseWindow
> baseWin
=
7022 do_QueryInterface(mPresContext
->GetContainerWeak());
7023 if (baseWin
&& NS_SUCCEEDED(baseWin
->GetVisibility(&vis
)) && vis
) {
7024 captureRetarget
= gCaptureInfo
.mRetargetToElement
;
7025 if (!captureRetarget
) {
7026 // A check was already done above to ensure that capturingContent is
7027 // in this presshell.
7028 NS_ASSERTION(capturingContent
->GetCrossShadowCurrentDoc() == GetDocument(),
7029 "Unexpected document");
7030 nsIFrame
* captureFrame
= capturingContent
->GetPrimaryFrame();
7032 if (capturingContent
->Tag() == nsGkAtoms::select
&&
7033 capturingContent
->IsHTML()) {
7034 // a dropdown <select> has a child in its selectPopupList and we should
7035 // capture on that instead.
7036 nsIFrame
* childFrame
= captureFrame
->GetChildList(nsIFrame::kSelectPopupList
).FirstChild();
7038 captureFrame
= childFrame
;
7042 // scrollable frames should use the scrolling container as
7043 // the root instead of the document
7044 nsIScrollableFrame
* scrollFrame
= do_QueryFrame(captureFrame
);
7046 frame
= scrollFrame
->GetScrolledFrame();
7052 ClearMouseCapture(nullptr);
7053 capturingContent
= nullptr;
7057 // all touch events except for touchstart use a captured target
7058 if (aEvent
->mClass
== eTouchEventClass
&&
7059 aEvent
->message
!= NS_TOUCH_START
) {
7060 captureRetarget
= true;
7063 WidgetMouseEvent
* mouseEvent
= aEvent
->AsMouseEvent();
7064 bool isWindowLevelMouseExit
= (aEvent
->message
== NS_MOUSE_EXIT
) &&
7065 (mouseEvent
&& mouseEvent
->exit
== WidgetMouseEvent::eTopLevel
);
7067 // Get the frame at the event point. However, don't do this if we're
7068 // capturing and retargeting the event because the captured frame will
7069 // be used instead below. Also keep using the root frame if we're dealing
7070 // with a window-level mouse exit event since we want to start sending
7071 // mouse out events at the root EventStateManager.
7072 if (!captureRetarget
&& !isWindowLevelMouseExit
) {
7075 if (aEvent
->message
== NS_TOUCH_START
) {
7076 flags
|= INPUT_IGNORE_ROOT_SCROLL_FRAME
;
7077 WidgetTouchEvent
* touchEvent
= aEvent
->AsTouchEvent();
7078 // if this is a continuing session, ensure that all these events are
7079 // in the same document by taking the target of the events already in
7081 nsCOMPtr
<nsIContent
> anyTarget
;
7082 if (gCaptureTouchList
->Count() > 0 && touchEvent
->touches
.Length() > 1) {
7083 gCaptureTouchList
->Enumerate(&FindAnyTarget
, &anyTarget
);
7085 gPreventMouseEvents
= false;
7088 for (int32_t i
= touchEvent
->touches
.Length(); i
; ) {
7090 dom::Touch
* touch
= touchEvent
->touches
[i
];
7092 int32_t id
= touch
->Identifier();
7093 if (!gCaptureTouchList
->Get(id
, nullptr)) {
7094 // find the target for this touch
7095 eventPoint
= nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent
,
7098 nsIFrame
* target
= FindFrameTargetedByInputEvent(aEvent
,
7102 if (target
&& !anyTarget
) {
7103 target
->GetContentForEvent(aEvent
, getter_AddRefs(anyTarget
));
7104 while (anyTarget
&& !anyTarget
->IsElement()) {
7105 anyTarget
= anyTarget
->GetParent();
7107 touch
->SetTarget(anyTarget
);
7109 nsIFrame
* newTargetFrame
= nullptr;
7110 for (nsIFrame
* f
= target
; f
;
7111 f
= nsLayoutUtils::GetParentOrPlaceholderForCrossDoc(f
)) {
7112 if (f
->PresContext()->Document() == anyTarget
->OwnerDoc()) {
7116 // We must be in a subdocument so jump directly to the root frame.
7117 // GetParentOrPlaceholderForCrossDoc gets called immediately to
7118 // jump up to the containing document.
7119 f
= f
->PresContext()->GetPresShell()->GetRootFrame();
7122 // if we couldn't find a target frame in the same document as
7123 // anyTarget, remove the touch from the capture touch list, as
7124 // well as the event->touches array. touchmove events that aren't
7125 // in the captured touch list will be discarded
7126 if (!newTargetFrame
) {
7127 touchEvent
->touches
.RemoveElementAt(i
);
7129 target
= newTargetFrame
;
7130 nsCOMPtr
<nsIContent
> targetContent
;
7131 target
->GetContentForEvent(aEvent
, getter_AddRefs(targetContent
));
7132 while (targetContent
&& !targetContent
->IsElement()) {
7133 targetContent
= targetContent
->GetParent();
7135 touch
->SetTarget(targetContent
);
7142 // This touch is an old touch, we need to ensure that is not
7143 // marked as changed and set its target correctly
7144 touch
->mChanged
= false;
7145 int32_t id
= touch
->Identifier();
7147 nsRefPtr
<dom::Touch
> oldTouch
= gCaptureTouchList
->GetWeak(id
);
7149 touch
->SetTarget(oldTouch
->mTarget
);
7154 eventPoint
= nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent
, frame
);
7156 if (mouseEvent
&& mouseEvent
->mClass
== eMouseEventClass
&&
7157 mouseEvent
->ignoreRootScrollFrame
) {
7158 flags
|= INPUT_IGNORE_ROOT_SCROLL_FRAME
;
7161 FindFrameTargetedByInputEvent(aEvent
, frame
, eventPoint
, flags
);
7167 // if a node is capturing the mouse, check if the event needs to be
7168 // retargeted at the capturing content instead. This will be the case when
7169 // capture retargeting is being used, no frame was found or the frame's
7170 // content is not a descendant of the capturing content.
7171 if (capturingContent
&&
7172 (gCaptureInfo
.mRetargetToElement
|| !frame
->GetContent() ||
7173 !nsContentUtils::ContentIsCrossDocDescendantOf(frame
->GetContent(),
7174 capturingContent
))) {
7175 // A check was already done above to ensure that capturingContent is
7176 // in this presshell.
7177 NS_ASSERTION(capturingContent
->GetCrossShadowCurrentDoc() == GetDocument(),
7178 "Unexpected document");
7179 nsIFrame
* capturingFrame
= capturingContent
->GetPrimaryFrame();
7180 if (capturingFrame
) {
7181 frame
= capturingFrame
;
7185 if (aEvent
->mClass
== ePointerEventClass
&&
7186 aEvent
->message
!= NS_POINTER_DOWN
) {
7187 if (WidgetPointerEvent
* pointerEvent
= aEvent
->AsPointerEvent()) {
7188 uint32_t pointerId
= pointerEvent
->pointerId
;
7189 nsIContent
* pointerCapturingContent
= GetPointerCapturingContent(pointerId
);
7191 if (pointerCapturingContent
) {
7192 if (nsIFrame
* capturingFrame
= pointerCapturingContent
->GetPrimaryFrame()) {
7193 // If pointer capture is set, we should suppress pointerover/pointerenter events
7194 // for all elements except element which have pointer capture. (Code in EventStateManager)
7195 pointerEvent
->retargetedByPointerCapture
= (frame
!= capturingFrame
);
7196 frame
= capturingFrame
;
7199 if (pointerEvent
->message
== NS_POINTER_UP
||
7200 pointerEvent
->message
== NS_POINTER_CANCEL
) {
7201 // Implicitly releasing capture for given pointer.
7202 // LOST_POINTER_CAPTURE should be send after NS_POINTER_UP or NS_POINTER_CANCEL.
7203 releasePointerCaptureCaller
.SetTarget(pointerId
, pointerCapturingContent
);
7209 // Suppress mouse event if it's being targeted at an element inside
7210 // a document which needs events suppressed
7211 if (aEvent
->mClass
== eMouseEventClass
&&
7212 frame
->PresContext()->Document()->EventHandlingSuppressed()) {
7213 if (aEvent
->message
== NS_MOUSE_BUTTON_DOWN
) {
7214 mNoDelayedMouseEvents
= true;
7215 } else if (!mNoDelayedMouseEvents
&& aEvent
->message
== NS_MOUSE_BUTTON_UP
) {
7216 DelayedEvent
* event
= new DelayedMouseEvent(aEvent
->AsMouseEvent());
7217 if (!mDelayedEvents
.AppendElement(event
)) {
7226 static_cast<PresShell
*>(frame
->PresContext()->PresShell());
7227 switch (aEvent
->message
) {
7229 case NS_TOUCH_CANCEL
:
7230 case NS_TOUCH_END
: {
7231 // get the correct shell to dispatch to
7232 WidgetTouchEvent
* touchEvent
= aEvent
->AsTouchEvent();
7233 WidgetTouchEvent::TouchArray
& touches
= touchEvent
->touches
;
7234 for (uint32_t i
= 0; i
< touches
.Length(); ++i
) {
7235 dom::Touch
* touch
= touches
[i
];
7240 nsRefPtr
<dom::Touch
> oldTouch
=
7241 gCaptureTouchList
->GetWeak(touch
->Identifier());
7246 nsCOMPtr
<nsIContent
> content
=
7247 do_QueryInterface(oldTouch
->GetTarget());
7252 nsIFrame
* contentFrame
= content
->GetPrimaryFrame();
7253 if (!contentFrame
) {
7257 shell
= static_cast<PresShell
*>(
7258 contentFrame
->PresContext()->PresShell());
7267 // Check if we have an active EventStateManager which isn't the
7268 // EventStateManager of the current PresContext.
7269 // If that is the case, and mouse is over some ancestor document,
7270 // forward event handling to the active document.
7271 // This way content can get mouse events even when
7272 // mouse is over the chrome or outside the window.
7274 // Note, currently for backwards compatibility we don't forward mouse events
7275 // to the active document when mouse is over some subdocument.
7276 EventStateManager
* activeESM
=
7277 EventStateManager::GetActiveEventStateManager();
7278 if (activeESM
&& aEvent
->HasMouseEventMessage() &&
7279 activeESM
!= shell
->GetPresContext()->EventStateManager() &&
7280 static_cast<EventStateManager
*>(activeESM
)->GetPresContext()) {
7281 nsIPresShell
* activeShell
=
7282 static_cast<EventStateManager
*>(activeESM
)->GetPresContext()->
7285 nsContentUtils::ContentIsCrossDocDescendantOf(activeShell
->GetDocument(),
7286 shell
->GetDocument())) {
7287 shell
= static_cast<PresShell
*>(activeShell
);
7288 frame
= shell
->GetRootFrame();
7292 if (shell
!= this) {
7293 // Handle the event in the correct shell.
7294 // Prevent deletion until we're done with event handling (bug 336582).
7295 nsCOMPtr
<nsIPresShell
> kungFuDeathGrip(shell
);
7296 // We pass the subshell's root frame as the frame to start from. This is
7297 // the only correct alternative; if the event was captured then it
7298 // must have been captured by us or some ancestor shell and we
7299 // now ask the subshell to dispatch it normally.
7300 return shell
->HandlePositionedEvent(frame
, aEvent
, aEventStatus
);
7303 return HandlePositionedEvent(frame
, aEvent
, aEventStatus
);
7306 nsresult rv
= NS_OK
;
7309 PushCurrentEventInfo(nullptr, nullptr);
7311 // key and IME related events go to the focused frame in this DOM window.
7312 if (aEvent
->IsTargetedAtFocusedContent()) {
7313 mCurrentEventContent
= nullptr;
7315 nsCOMPtr
<nsPIDOMWindow
> window
=
7316 do_QueryInterface(mDocument
->GetWindow());
7317 nsCOMPtr
<nsPIDOMWindow
> focusedWindow
;
7318 nsCOMPtr
<nsIContent
> eventTarget
=
7319 nsFocusManager::GetFocusedDescendant(window
, false,
7320 getter_AddRefs(focusedWindow
));
7322 // otherwise, if there is no focused content or the focused content has
7323 // no frame, just use the root content. This ensures that key events
7324 // still get sent to the window properly if nothing is focused or if a
7325 // frame goes away while it is focused.
7326 if (!eventTarget
|| !eventTarget
->GetPrimaryFrame()) {
7327 nsCOMPtr
<nsIDOMHTMLDocument
> htmlDoc
= do_QueryInterface(mDocument
);
7329 nsCOMPtr
<nsIDOMHTMLElement
> body
;
7330 htmlDoc
->GetBody(getter_AddRefs(body
));
7331 eventTarget
= do_QueryInterface(body
);
7333 eventTarget
= mDocument
->GetRootElement();
7336 eventTarget
= mDocument
->GetRootElement();
7340 if (aEvent
->message
== NS_KEY_DOWN
) {
7341 NS_IF_RELEASE(gKeyDownTarget
);
7342 NS_IF_ADDREF(gKeyDownTarget
= eventTarget
);
7344 else if ((aEvent
->message
== NS_KEY_PRESS
|| aEvent
->message
== NS_KEY_UP
) &&
7346 // If a different element is now focused for the keypress/keyup event
7347 // than what was focused during the keydown event, check if the new
7348 // focused element is not in a chrome document any more, and if so,
7349 // retarget the event back at the keydown target. This prevents a
7350 // content area from grabbing the focus from chrome in-between key
7353 nsContentUtils::IsChromeDoc(gKeyDownTarget
->GetComposedDoc()) !=
7354 nsContentUtils::IsChromeDoc(eventTarget
->GetComposedDoc())) {
7355 eventTarget
= gKeyDownTarget
;
7358 if (aEvent
->message
== NS_KEY_UP
) {
7359 NS_RELEASE(gKeyDownTarget
);
7363 mCurrentEventFrame
= nullptr;
7364 nsIDocument
* targetDoc
= eventTarget
? eventTarget
->OwnerDoc() : nullptr;
7365 if (targetDoc
&& targetDoc
!= mDocument
) {
7366 PopCurrentEventInfo();
7367 nsCOMPtr
<nsIPresShell
> shell
= targetDoc
->GetShell();
7369 rv
= static_cast<PresShell
*>(shell
.get())->
7370 HandleRetargetedEvent(aEvent
, aEventStatus
, eventTarget
);
7374 mCurrentEventContent
= eventTarget
;
7377 if (!GetCurrentEventContent() || !GetCurrentEventFrame() ||
7378 InZombieDocument(mCurrentEventContent
)) {
7379 rv
= RetargetEventToParent(aEvent
, aEventStatus
);
7380 PopCurrentEventInfo();
7384 mCurrentEventFrame
= frame
;
7386 if (GetCurrentEventFrame()) {
7387 rv
= HandleEventInternal(aEvent
, aEventStatus
);
7391 ShowEventTargetDebug();
7393 PopCurrentEventInfo();
7395 // Activation events need to be dispatched even if no frame was found, since
7396 // we don't want the focus to be out of sync.
7398 if (!NS_EVENT_NEEDS_FRAME(aEvent
)) {
7399 mCurrentEventFrame
= nullptr;
7400 return HandleEventInternal(aEvent
, aEventStatus
);
7402 else if (aEvent
->HasKeyEventMessage()) {
7403 // Keypress events in new blank tabs should not be completely thrown away.
7404 // Retarget them -- the parent chrome shell might make use of them.
7405 return RetargetEventToParent(aEvent
, aEventStatus
);
7414 PresShell::GetTouchEventTargetDocument()
7416 nsPresContext
* context
= GetPresContext();
7417 if (!context
|| !context
->IsRoot()) {
7421 nsCOMPtr
<nsIDocShellTreeItem
> shellAsTreeItem
= context
->GetDocShell();
7422 if (!shellAsTreeItem
) {
7426 nsCOMPtr
<nsIDocShellTreeOwner
> owner
;
7427 shellAsTreeItem
->GetTreeOwner(getter_AddRefs(owner
));
7432 // now get the primary content shell (active tab)
7433 nsCOMPtr
<nsIDocShellTreeItem
> item
;
7434 owner
->GetPrimaryContentShell(getter_AddRefs(item
));
7435 nsCOMPtr
<nsIDocShell
> childDocShell
= do_QueryInterface(item
);
7436 if (!childDocShell
) {
7440 return childDocShell
->GetDocument();
7446 PresShell::ShowEventTargetDebug()
7448 if (nsFrame::GetShowEventTargetFrameBorder() &&
7449 GetCurrentEventFrame()) {
7450 if (mDrawEventTargetFrame
) {
7451 mDrawEventTargetFrame
->InvalidateFrame();
7454 mDrawEventTargetFrame
= mCurrentEventFrame
;
7455 mDrawEventTargetFrame
->InvalidateFrame();
7461 PresShell::HandlePositionedEvent(nsIFrame
* aTargetFrame
,
7462 WidgetGUIEvent
* aEvent
,
7463 nsEventStatus
* aEventStatus
)
7465 nsresult rv
= NS_OK
;
7467 PushCurrentEventInfo(nullptr, nullptr);
7469 mCurrentEventFrame
= aTargetFrame
;
7471 if (mCurrentEventFrame
) {
7472 nsCOMPtr
<nsIContent
> targetElement
;
7473 mCurrentEventFrame
->GetContentForEvent(aEvent
,
7474 getter_AddRefs(targetElement
));
7476 // If there is no content for this frame, target it anyway. Some
7477 // frames can be targeted but do not have content, particularly
7478 // windows with scrolling off.
7479 if (targetElement
) {
7480 // Bug 103055, bug 185889: mouse events apply to *elements*, not all
7481 // nodes. Thus we get the nearest element parent here.
7482 // XXX we leave the frame the same even if we find an element
7483 // parent, so that the text frame will receive the event (selection
7484 // and friends are the ones who care about that anyway)
7486 // We use weak pointers because during this tight loop, the node
7487 // will *not* go away. And this happens on every mousemove.
7488 while (targetElement
&& !targetElement
->IsElement()) {
7489 targetElement
= targetElement
->GetParent();
7492 // If we found an element, target it. Otherwise, target *nothing*.
7493 if (!targetElement
) {
7494 mCurrentEventContent
= nullptr;
7495 mCurrentEventFrame
= nullptr;
7496 } else if (targetElement
!= mCurrentEventContent
) {
7497 mCurrentEventContent
= targetElement
;
7502 if (GetCurrentEventFrame()) {
7503 rv
= HandleEventInternal(aEvent
, aEventStatus
);
7507 ShowEventTargetDebug();
7509 PopCurrentEventInfo();
7514 PresShell::HandleEventWithTarget(WidgetEvent
* aEvent
, nsIFrame
* aFrame
,
7515 nsIContent
* aContent
, nsEventStatus
* aStatus
)
7518 MOZ_ASSERT(!aFrame
|| aFrame
->PresContext()->GetPresShell() == this,
7521 nsIDocument
* doc
= aContent
->GetCrossShadowCurrentDoc();
7522 NS_ASSERTION(doc
, "event for content that isn't in a document");
7523 NS_ASSERTION(!doc
|| doc
->GetShell() == this, "wrong shell");
7526 NS_ENSURE_STATE(!aContent
|| aContent
->GetCrossShadowCurrentDoc() == mDocument
);
7528 PushCurrentEventInfo(aFrame
, aContent
);
7529 nsresult rv
= HandleEventInternal(aEvent
, aStatus
);
7530 PopCurrentEventInfo();
7535 PresShell::HandleEventInternal(WidgetEvent
* aEvent
, nsEventStatus
* aStatus
)
7537 nsRefPtr
<EventStateManager
> manager
= mPresContext
->EventStateManager();
7538 nsresult rv
= NS_OK
;
7540 if (!NS_EVENT_NEEDS_FRAME(aEvent
) || GetCurrentEventFrame()) {
7541 bool touchIsNew
= false;
7542 bool isHandlingUserInput
= false;
7544 // XXX How about IME events and input events for plugins?
7545 if (aEvent
->mFlags
.mIsTrusted
) {
7546 switch (aEvent
->message
) {
7550 nsIDocument
* doc
= GetCurrentEventContent() ?
7551 mCurrentEventContent
->OwnerDoc() : nullptr;
7552 nsIDocument
* fullscreenAncestor
= nullptr;
7553 if (aEvent
->AsKeyboardEvent()->keyCode
== NS_VK_ESCAPE
) {
7554 if ((fullscreenAncestor
= nsContentUtils::GetFullscreenAncestor(doc
))) {
7555 // Prevent default action on ESC key press when exiting
7556 // DOM fullscreen mode. This prevents the browser ESC key
7557 // handler from stopping all loads in the document, which
7558 // would cause <video> loads to stop.
7559 aEvent
->mFlags
.mDefaultPrevented
= true;
7560 aEvent
->mFlags
.mOnlyChromeDispatch
= true;
7562 if (aEvent
->message
== NS_KEY_UP
) {
7563 // ESC key released while in DOM fullscreen mode.
7564 // If fullscreen is running in content-only mode, exit the target
7565 // doctree branch from fullscreen, otherwise fully exit all
7566 // browser windows and documents from fullscreen mode.
7567 // Note: in the content-only fullscreen case, we pass the
7568 // fullscreenAncestor since |doc| may not actually be fullscreen
7569 // here, and ExitFullscreen() has no affect when passed a
7570 // non-fullscreen document.
7571 nsIDocument::ExitFullscreen(
7572 nsContentUtils::IsFullscreenApiContentOnly() ? fullscreenAncestor
: nullptr,
7576 nsCOMPtr
<nsIDocument
> pointerLockedDoc
=
7577 do_QueryReferent(EventStateManager::sPointerLockedDoc
);
7578 if (pointerLockedDoc
) {
7579 aEvent
->mFlags
.mDefaultPrevented
= true;
7580 aEvent
->mFlags
.mOnlyChromeDispatch
= true;
7581 if (aEvent
->message
== NS_KEY_UP
) {
7582 nsIDocument::UnlockPointer();
7586 // Else not full-screen mode or key code is unrestricted, fall
7587 // through to normal handling.
7589 case NS_MOUSE_BUTTON_DOWN
:
7590 case NS_MOUSE_BUTTON_UP
:
7591 isHandlingUserInput
= true;
7593 case NS_TOUCH_START
: {
7594 isHandlingUserInput
= true;
7595 WidgetTouchEvent
* touchEvent
= aEvent
->AsTouchEvent();
7596 // if there is only one touch in this touchstart event, assume that it is
7597 // the start of a new touch session and evict any old touches in the
7599 if (touchEvent
->touches
.Length() == 1) {
7600 WidgetTouchEvent::AutoTouchArray touches
;
7601 gCaptureTouchList
->Enumerate(&AppendToTouchList
, (void *)&touches
);
7602 for (uint32_t i
= 0; i
< touches
.Length(); ++i
) {
7603 EvictTouchPoint(touches
[i
]);
7606 // Add any new touches to the queue
7607 for (uint32_t i
= 0; i
< touchEvent
->touches
.Length(); ++i
) {
7608 dom::Touch
* touch
= touchEvent
->touches
[i
];
7609 int32_t id
= touch
->Identifier();
7610 if (!gCaptureTouchList
->Get(id
, nullptr)) {
7611 // If it is not already in the queue, it is a new touch
7612 touch
->mChanged
= true;
7614 touch
->mMessage
= aEvent
->message
;
7615 gCaptureTouchList
->Put(id
, touch
);
7620 isHandlingUserInput
= true;
7621 // Fall through to touchcancel code
7622 case NS_TOUCH_CANCEL
: {
7623 // Remove the changed touches
7624 // need to make sure we only remove touches that are ending here
7625 WidgetTouchEvent
* touchEvent
= aEvent
->AsTouchEvent();
7626 WidgetTouchEvent::TouchArray
& touches
= touchEvent
->touches
;
7627 for (uint32_t i
= 0; i
< touches
.Length(); ++i
) {
7628 dom::Touch
* touch
= touches
[i
];
7632 touch
->mMessage
= aEvent
->message
;
7633 touch
->mChanged
= true;
7635 int32_t id
= touch
->Identifier();
7636 nsRefPtr
<dom::Touch
> oldTouch
= gCaptureTouchList
->GetWeak(id
);
7640 nsCOMPtr
<EventTarget
> targetPtr
= oldTouch
->mTarget
;
7642 mCurrentEventContent
= do_QueryInterface(targetPtr
);
7643 touch
->SetTarget(targetPtr
);
7644 gCaptureTouchList
->Remove(id
);
7646 // add any touches left in the touch list, but ensure changed=false
7647 gCaptureTouchList
->Enumerate(&AppendToTouchList
, (void *)&touches
);
7650 case NS_TOUCH_MOVE
: {
7651 // Check for touches that changed. Mark them add to queue
7652 WidgetTouchEvent
* touchEvent
= aEvent
->AsTouchEvent();
7653 WidgetTouchEvent::TouchArray
& touches
= touchEvent
->touches
;
7654 bool haveChanged
= false;
7655 for (int32_t i
= touches
.Length(); i
; ) {
7657 dom::Touch
* touch
= touches
[i
];
7661 int32_t id
= touch
->Identifier();
7662 touch
->mMessage
= aEvent
->message
;
7664 nsRefPtr
<dom::Touch
> oldTouch
= gCaptureTouchList
->GetWeak(id
);
7666 touches
.RemoveElementAt(i
);
7669 if (!touch
->Equals(oldTouch
)) {
7670 touch
->mChanged
= true;
7674 nsCOMPtr
<dom::EventTarget
> targetPtr
= oldTouch
->mTarget
;
7676 touches
.RemoveElementAt(i
);
7679 touch
->SetTarget(targetPtr
);
7681 gCaptureTouchList
->Put(id
, touch
);
7682 // if we're moving from touchstart to touchmove for this touch
7683 // we allow preventDefault to prevent mouse events
7684 if (oldTouch
->mMessage
!= touch
->mMessage
) {
7688 // is nothing has changed, we should just return
7691 // however, if this is the first touchmove after a touchstart,
7692 // it is special in that preventDefault is allowed on it, so
7693 // we must dispatch it to content even if nothing changed. we
7694 // arbitrarily pick the first touch point to be the "changed"
7695 // touch because firing an event with no changed events doesn't
7697 for (uint32_t i
= 0; i
< touchEvent
->touches
.Length(); ++i
) {
7698 if (touchEvent
->touches
[i
]) {
7699 touchEvent
->touches
[i
]->mChanged
= true;
7704 if (gPreventMouseEvents
) {
7705 *aStatus
= nsEventStatus_eConsumeNoDefault
;
7712 case NS_DRAGDROP_DROP
:
7713 nsCOMPtr
<nsIDragSession
> session
= nsContentUtils::GetDragSession();
7715 bool onlyChromeDrop
= false;
7716 session
->GetOnlyChromeDrop(&onlyChromeDrop
);
7717 if (onlyChromeDrop
) {
7718 aEvent
->mFlags
.mOnlyChromeDispatch
= true;
7725 if (aEvent
->message
== NS_CONTEXTMENU
) {
7726 WidgetMouseEvent
* mouseEvent
= aEvent
->AsMouseEvent();
7727 if (mouseEvent
->context
== WidgetMouseEvent::eContextMenuKey
&&
7728 !AdjustContextMenuKeyEvent(mouseEvent
)) {
7731 if (mouseEvent
->IsShift()) {
7732 aEvent
->mFlags
.mOnlyChromeDispatch
= true;
7733 aEvent
->mFlags
.mRetargetToNonNativeAnonymous
= true;
7737 AutoHandlingUserInputStatePusher
userInpStatePusher(isHandlingUserInput
,
7740 if (aEvent
->mFlags
.mIsTrusted
&& aEvent
->message
== NS_MOUSE_MOVE
) {
7741 nsIPresShell::AllowMouseCapture(
7742 EventStateManager::GetActiveEventStateManager() == manager
);
7745 nsAutoPopupStatePusher
popupStatePusher(
7746 Event::GetEventPopupControlState(aEvent
));
7748 // FIXME. If the event was reused, we need to clear the old target,
7750 aEvent
->target
= nullptr;
7752 // 1. Give event to event manager for pre event state changes and
7753 // generation of synthetic events.
7754 rv
= manager
->PreHandleEvent(mPresContext
, aEvent
, mCurrentEventFrame
, aStatus
);
7756 // 2. Give event to the DOM for third party and JS use.
7757 if (NS_SUCCEEDED(rv
)) {
7758 bool wasHandlingKeyBoardEvent
=
7759 nsContentUtils::IsHandlingKeyBoardEvent();
7760 if (aEvent
->mClass
== eKeyboardEventClass
) {
7761 nsContentUtils::SetIsHandlingKeyBoardEvent(true);
7763 if (aEvent
->IsAllowedToDispatchDOMEvent()) {
7764 MOZ_ASSERT(nsContentUtils::IsSafeToRunScript(),
7765 "Somebody changed aEvent to cause a DOM event!");
7766 nsPresShellEventCB
eventCB(this);
7767 if (aEvent
->mClass
== eTouchEventClass
) {
7768 DispatchTouchEvent(aEvent
, aStatus
, &eventCB
, touchIsNew
);
7770 nsCOMPtr
<nsINode
> eventTarget
= mCurrentEventContent
.get();
7771 nsPresShellEventCB
* eventCBPtr
= &eventCB
;
7773 nsCOMPtr
<nsIContent
> targetContent
;
7774 if (mCurrentEventFrame
) {
7775 rv
= mCurrentEventFrame
->
7776 GetContentForEvent(aEvent
, getter_AddRefs(targetContent
));
7778 if (NS_SUCCEEDED(rv
) && targetContent
) {
7779 eventTarget
= do_QueryInterface(targetContent
);
7780 } else if (mDocument
) {
7781 eventTarget
= do_QueryInterface(mDocument
);
7782 // If we don't have any content, the callback wouldn't probably
7784 eventCBPtr
= nullptr;
7788 if (aEvent
->mClass
== eCompositionEventClass
||
7789 aEvent
->mClass
== eTextEventClass
) {
7790 IMEStateManager::DispatchCompositionEvent(eventTarget
,
7791 mPresContext
, aEvent
, aStatus
, eventCBPtr
);
7793 EventDispatcher::Dispatch(eventTarget
, mPresContext
,
7794 aEvent
, nullptr, aStatus
, eventCBPtr
);
7800 nsContentUtils::SetIsHandlingKeyBoardEvent(wasHandlingKeyBoardEvent
);
7802 // 3. Give event to event manager for post event state changes and
7803 // generation of synthetic events.
7804 if (!mIsDestroying
&& NS_SUCCEEDED(rv
)) {
7805 rv
= manager
->PostHandleEvent(mPresContext
, aEvent
,
7806 GetCurrentEventFrame(), aStatus
);
7810 if (aEvent
->message
== NS_MOUSE_BUTTON_UP
) {
7811 // reset the capturing content now that the mouse button is up
7812 SetCapturingContent(nullptr, 0);
7813 } else if (aEvent
->message
== NS_MOUSE_MOVE
) {
7814 nsIPresShell::AllowMouseCapture(false);
7821 nsIPresShell::DispatchGotOrLostPointerCaptureEvent(bool aIsGotCapture
,
7822 uint32_t aPointerId
,
7823 nsIContent
* aCaptureTarget
)
7825 PointerEventInit init
;
7826 init
.mPointerId
= aPointerId
;
7827 init
.mBubbles
= true;
7828 nsRefPtr
<mozilla::dom::PointerEvent
> event
;
7829 event
= PointerEvent::Constructor(aCaptureTarget
,
7831 ? NS_LITERAL_STRING("gotpointercapture")
7832 : NS_LITERAL_STRING("lostpointercapture"),
7836 aCaptureTarget
->DispatchEvent(event
->InternalDOMEvent(), &dummy
);
7841 PresShell::DispatchTouchEvent(WidgetEvent
* aEvent
,
7842 nsEventStatus
* aStatus
,
7843 nsPresShellEventCB
* aEventCB
,
7846 // calling preventDefault on touchstart or the first touchmove for a
7847 // point prevents mouse events. calling it on the touchend should
7848 // prevent click dispatching.
7849 bool canPrevent
= (aEvent
->message
== NS_TOUCH_START
) ||
7850 (aEvent
->message
== NS_TOUCH_MOVE
&& aTouchIsNew
) ||
7851 (aEvent
->message
== NS_TOUCH_END
);
7852 bool preventDefault
= false;
7853 nsEventStatus tmpStatus
= nsEventStatus_eIgnore
;
7854 WidgetTouchEvent
* touchEvent
= aEvent
->AsTouchEvent();
7856 // loop over all touches and dispatch events on any that have changed
7857 for (uint32_t i
= 0; i
< touchEvent
->touches
.Length(); ++i
) {
7858 dom::Touch
* touch
= touchEvent
->touches
[i
];
7859 if (!touch
|| !touch
->mChanged
) {
7863 nsCOMPtr
<EventTarget
> targetPtr
= touch
->mTarget
;
7864 nsCOMPtr
<nsIContent
> content
= do_QueryInterface(targetPtr
);
7869 nsIDocument
* doc
= content
->OwnerDoc();
7870 nsIContent
* capturingContent
= GetCapturingContent();
7871 if (capturingContent
) {
7872 if (capturingContent
->OwnerDoc() != doc
) {
7873 // Wrong document, don't dispatch anything.
7876 content
= capturingContent
;
7879 WidgetTouchEvent
newEvent(touchEvent
->mFlags
.mIsTrusted
,
7880 touchEvent
->message
, touchEvent
->widget
);
7881 newEvent
.AssignTouchEventData(*touchEvent
, false);
7882 newEvent
.target
= targetPtr
;
7884 nsRefPtr
<PresShell
> contentPresShell
;
7885 if (doc
== mDocument
) {
7886 contentPresShell
= static_cast<PresShell
*>(doc
->GetShell());
7887 if (contentPresShell
) {
7888 //XXXsmaug huge hack. Pushing possibly capturing content,
7889 // even though event target is something else.
7890 contentPresShell
->PushCurrentEventInfo(
7891 content
->GetPrimaryFrame(), content
);
7895 nsIPresShell
*presShell
= doc
->GetShell();
7900 nsPresContext
*context
= presShell
->GetPresContext();
7902 tmpStatus
= nsEventStatus_eIgnore
;
7903 EventDispatcher::Dispatch(targetPtr
, context
,
7904 &newEvent
, nullptr, &tmpStatus
, aEventCB
);
7905 if (nsEventStatus_eConsumeNoDefault
== tmpStatus
||
7906 newEvent
.mFlags
.mMultipleActionsPrevented
) {
7907 preventDefault
= true;
7910 if (newEvent
.mFlags
.mMultipleActionsPrevented
) {
7911 touchEvent
->mFlags
.mMultipleActionsPrevented
= true;
7914 if (contentPresShell
) {
7915 contentPresShell
->PopCurrentEventInfo();
7919 // if preventDefault was called on any of the events dispatched
7920 // and this is touchstart, or the first touchmove, widget should consume
7921 // other events that would be associated with this touch session
7922 if (preventDefault
&& canPrevent
) {
7923 gPreventMouseEvents
= true;
7926 if (gPreventMouseEvents
) {
7927 *aStatus
= nsEventStatus_eConsumeNoDefault
;
7929 *aStatus
= nsEventStatus_eIgnore
;
7933 // Dispatch event to content only (NOT full processing)
7934 // See also HandleEventWithTarget which does full event processing.
7936 PresShell::HandleDOMEventWithTarget(nsIContent
* aTargetContent
,
7937 WidgetEvent
* aEvent
,
7938 nsEventStatus
* aStatus
)
7940 nsresult rv
= NS_OK
;
7942 PushCurrentEventInfo(nullptr, aTargetContent
);
7944 // Bug 41013: Check if the event should be dispatched to content.
7945 // It's possible that we are in the middle of destroying the window
7946 // and the js context is out of date. This check detects the case
7947 // that caused a crash in bug 41013, but there may be a better way
7948 // to handle this situation!
7949 nsCOMPtr
<nsISupports
> container
= mPresContext
->GetContainerWeak();
7952 // Dispatch event to content
7953 rv
= EventDispatcher::Dispatch(aTargetContent
, mPresContext
, aEvent
,
7957 PopCurrentEventInfo();
7961 // See the method above.
7963 PresShell::HandleDOMEventWithTarget(nsIContent
* aTargetContent
,
7964 nsIDOMEvent
* aEvent
,
7965 nsEventStatus
* aStatus
)
7967 nsresult rv
= NS_OK
;
7969 PushCurrentEventInfo(nullptr, aTargetContent
);
7970 nsCOMPtr
<nsISupports
> container
= mPresContext
->GetContainerWeak();
7972 rv
= EventDispatcher::DispatchDOMEvent(aTargetContent
, nullptr, aEvent
,
7973 mPresContext
, aStatus
);
7976 PopCurrentEventInfo();
7981 PresShell::AdjustContextMenuKeyEvent(WidgetMouseEvent
* aEvent
)
7984 // if a menu is open, open the context menu relative to the active item on the menu.
7985 nsXULPopupManager
* pm
= nsXULPopupManager::GetInstance();
7987 nsIFrame
* popupFrame
= pm
->GetTopPopup(ePopupTypeMenu
);
7989 nsIFrame
* itemFrame
=
7990 (static_cast<nsMenuPopupFrame
*>(popupFrame
))->GetCurrentMenuItem();
7992 itemFrame
= popupFrame
;
7994 nsCOMPtr
<nsIWidget
> widget
= popupFrame
->GetNearestWidget();
7995 aEvent
->widget
= widget
;
7996 nsIntPoint widgetPoint
= widget
->WidgetToScreenOffset();
7997 aEvent
->refPoint
= LayoutDeviceIntPoint::FromUntyped(
7998 itemFrame
->GetScreenRect().BottomLeft() - widgetPoint
);
8000 mCurrentEventContent
= itemFrame
->GetContent();
8001 mCurrentEventFrame
= itemFrame
;
8008 // If we're here because of the key-equiv for showing context menus, we
8009 // have to twiddle with the NS event to make sure the context menu comes
8010 // up in the upper left of the relevant content area before we create
8011 // the DOM event. Since we never call InitMouseEvent() on the event,
8012 // the client X/Y will be 0,0. We can make use of that if the widget is null.
8013 // Use the root view manager's widget since it's most likely to have one,
8014 // and the coordinates returned by GetCurrentItemAndPositionForElement
8015 // are relative to the widget of the root of the root view manager.
8016 nsRootPresContext
* rootPC
= mPresContext
->GetRootPresContext();
8017 aEvent
->refPoint
.x
= 0;
8018 aEvent
->refPoint
.y
= 0;
8020 rootPC
->PresShell()->GetViewManager()->
8021 GetRootWidget(getter_AddRefs(aEvent
->widget
));
8023 if (aEvent
->widget
) {
8024 // default the refpoint to the topleft of our document
8025 nsPoint
offset(0, 0);
8026 nsIFrame
* rootFrame
= mFrameConstructor
->GetRootFrame();
8028 nsView
* view
= rootFrame
->GetClosestView(&offset
);
8029 offset
+= view
->GetOffsetToWidget(aEvent
->widget
);
8031 LayoutDeviceIntPoint::FromAppUnitsToNearest(offset
, mPresContext
->AppUnitsPerDevPixel());
8035 aEvent
->widget
= nullptr;
8038 // see if we should use the caret position for the popup
8039 nsIntPoint caretPoint
;
8040 // Beware! This may flush notifications via synchronous
8041 // ScrollSelectionIntoView.
8042 if (PrepareToUseCaretPosition(aEvent
->widget
, caretPoint
)) {
8043 // caret position is good
8044 aEvent
->refPoint
= LayoutDeviceIntPoint::FromUntyped(caretPoint
);
8048 // If we're here because of the key-equiv for showing context menus, we
8049 // have to reset the event target to the currently focused element. Get it
8050 // from the focus controller.
8051 nsCOMPtr
<nsIDOMElement
> currentFocus
;
8052 nsIFocusManager
* fm
= nsFocusManager::GetFocusManager();
8054 fm
->GetFocusedElement(getter_AddRefs(currentFocus
));
8056 // Reset event coordinates relative to focused frame in view
8058 nsCOMPtr
<nsIContent
> currentPointElement
;
8059 GetCurrentItemAndPositionForElement(currentFocus
,
8060 getter_AddRefs(currentPointElement
),
8063 if (currentPointElement
) {
8064 mCurrentEventContent
= currentPointElement
;
8065 mCurrentEventFrame
= nullptr;
8066 GetCurrentEventFrame();
8073 // PresShell::PrepareToUseCaretPosition
8075 // This checks to see if we should use the caret position for popup context
8076 // menus. Returns true if the caret position should be used, and the
8077 // coordinates of that position is returned in aTargetPt. This function
8078 // will also scroll the window as needed to make the caret visible.
8080 // The event widget should be the widget that generated the event, and
8081 // whose coordinate system the resulting event's refPoint should be
8082 // relative to. The returned point is in device pixels realtive to the
8083 // widget passed in.
8085 PresShell::PrepareToUseCaretPosition(nsIWidget
* aEventWidget
, nsIntPoint
& aTargetPt
)
8089 // check caret visibility
8090 nsRefPtr
<nsCaret
> caret
= GetCaret();
8091 NS_ENSURE_TRUE(caret
, false);
8093 bool caretVisible
= caret
->IsVisible();
8097 // caret selection, this is a temporary weak reference, so no refcounting is
8099 nsISelection
* domSelection
= caret
->GetSelection();
8100 NS_ENSURE_TRUE(domSelection
, false);
8102 // since the match could be an anonymous textnode inside a
8103 // <textarea> or text <input>, we need to get the outer frame
8104 // note: frames are not refcounted
8105 nsIFrame
* frame
= nullptr; // may be nullptr
8106 nsCOMPtr
<nsIDOMNode
> node
;
8107 rv
= domSelection
->GetFocusNode(getter_AddRefs(node
));
8108 NS_ENSURE_SUCCESS(rv
, false);
8109 NS_ENSURE_TRUE(node
, false);
8110 nsCOMPtr
<nsIContent
> content(do_QueryInterface(node
));
8112 nsIContent
* nonNative
= content
->FindFirstNonChromeOnlyAccessContent();
8113 content
= nonNative
;
8117 // It seems like ScrollSelectionIntoView should be enough, but it's
8118 // not. The problem is that scrolling the selection into view when it is
8119 // below the current viewport will align the top line of the frame exactly
8120 // with the bottom of the window. This is fine, BUT, the popup event causes
8121 // the control to be re-focused which does this exact call to
8122 // ScrollContentIntoView, which has a one-pixel disagreement of whether the
8123 // frame is actually in view. The result is that the frame is aligned with
8124 // the top of the window, but the menu is still at the bottom.
8126 // Doing this call first forces the frame to be in view, eliminating the
8127 // problem. The only difference in the result is that if your cursor is in
8128 // an edit box below the current view, you'll get the edit box aligned with
8129 // the top of the window. This is arguably better behavior anyway.
8130 rv
= ScrollContentIntoView(content
,
8131 nsIPresShell::ScrollAxis(
8132 nsIPresShell::SCROLL_MINIMUM
,
8133 nsIPresShell::SCROLL_IF_NOT_VISIBLE
),
8134 nsIPresShell::ScrollAxis(
8135 nsIPresShell::SCROLL_MINIMUM
,
8136 nsIPresShell::SCROLL_IF_NOT_VISIBLE
),
8137 nsIPresShell::SCROLL_OVERFLOW_HIDDEN
);
8138 NS_ENSURE_SUCCESS(rv
, false);
8139 frame
= content
->GetPrimaryFrame();
8140 NS_WARN_IF_FALSE(frame
, "No frame for focused content?");
8143 // Actually scroll the selection (ie caret) into view. Note that this must
8144 // be synchronous since we will be checking the caret position on the screen.
8146 // Be easy about errors, and just don't scroll in those cases. Better to have
8147 // the correct menu at a weird place than the wrong menu.
8148 // After ScrollSelectionIntoView(), the pending notifications might be
8149 // flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
8150 nsCOMPtr
<nsISelectionController
> selCon
;
8152 frame
->GetSelectionController(GetPresContext(), getter_AddRefs(selCon
));
8154 selCon
= static_cast<nsISelectionController
*>(this);
8156 rv
= selCon
->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL
,
8157 nsISelectionController::SELECTION_FOCUS_REGION
,
8158 nsISelectionController::SCROLL_SYNCHRONOUS
);
8159 NS_ENSURE_SUCCESS(rv
, false);
8162 nsPresContext
* presContext
= GetPresContext();
8164 // get caret position relative to the closest view
8166 nsIFrame
* caretFrame
= caret
->GetGeometry(&caretCoords
);
8170 nsView
* view
= caretFrame
->GetClosestView(&viewOffset
);
8173 // and then get the caret coords relative to the event widget
8175 viewOffset
+= view
->GetOffsetToWidget(aEventWidget
);
8177 caretCoords
.MoveBy(viewOffset
);
8179 // caret coordinates are in app units, convert to pixels
8181 presContext
->AppUnitsToDevPixels(caretCoords
.x
+ caretCoords
.width
);
8183 presContext
->AppUnitsToDevPixels(caretCoords
.y
+ caretCoords
.height
);
8185 // make sure rounding doesn't return a pixel which is outside the caret
8186 // (e.g. one line lower)
8193 PresShell::GetCurrentItemAndPositionForElement(nsIDOMElement
*aCurrentEl
,
8194 nsIContent
** aTargetToUse
,
8195 LayoutDeviceIntPoint
& aTargetPt
,
8196 nsIWidget
*aRootWidget
)
8198 nsCOMPtr
<nsIContent
> focusedContent(do_QueryInterface(aCurrentEl
));
8199 ScrollContentIntoView(focusedContent
,
8202 nsIPresShell::SCROLL_OVERFLOW_HIDDEN
);
8204 nsPresContext
* presContext
= GetPresContext();
8206 bool istree
= false, checkLineHeight
= true;
8207 nscoord extraTreeY
= 0;
8210 // Set the position to just underneath the current item for multi-select
8211 // lists or just underneath the selected item for single-select lists. If
8212 // the element is not a list, or there is no selection, leave the position
8214 nsCOMPtr
<nsIDOMXULSelectControlItemElement
> item
;
8215 nsCOMPtr
<nsIDOMXULMultiSelectControlElement
> multiSelect
=
8216 do_QueryInterface(aCurrentEl
);
8218 checkLineHeight
= false;
8220 int32_t currentIndex
;
8221 multiSelect
->GetCurrentIndex(¤tIndex
);
8222 if (currentIndex
>= 0) {
8223 nsCOMPtr
<nsIDOMXULElement
> xulElement(do_QueryInterface(aCurrentEl
));
8225 nsCOMPtr
<nsIBoxObject
> box
;
8226 xulElement
->GetBoxObject(getter_AddRefs(box
));
8227 nsCOMPtr
<nsITreeBoxObject
> treeBox(do_QueryInterface(box
));
8228 // Tree view special case (tree items have no frames)
8229 // Get the focused row and add its coordinates, which are already in pixels
8230 // XXX Boris, should we create a new interface so that this doesn't
8231 // need to know about trees? Something like nsINodelessChildCreator which
8232 // could provide the current focus coordinates?
8234 treeBox
->EnsureRowIsVisible(currentIndex
);
8235 int32_t firstVisibleRow
, rowHeight
;
8236 treeBox
->GetFirstVisibleRow(&firstVisibleRow
);
8237 treeBox
->GetRowHeight(&rowHeight
);
8239 extraTreeY
+= presContext
->CSSPixelsToAppUnits(
8240 (currentIndex
- firstVisibleRow
+ 1) * rowHeight
);
8243 nsCOMPtr
<nsITreeColumns
> cols
;
8244 treeBox
->GetColumns(getter_AddRefs(cols
));
8246 nsCOMPtr
<nsITreeColumn
> col
;
8247 cols
->GetFirstColumn(getter_AddRefs(col
));
8249 nsCOMPtr
<nsIDOMElement
> colElement
;
8250 col
->GetElement(getter_AddRefs(colElement
));
8251 nsCOMPtr
<nsIContent
> colContent(do_QueryInterface(colElement
));
8253 nsIFrame
* frame
= colContent
->GetPrimaryFrame();
8255 extraTreeY
+= frame
->GetSize().height
;
8262 multiSelect
->GetCurrentItem(getter_AddRefs(item
));
8268 // don't check menulists as the selected item will be inside a popup.
8269 nsCOMPtr
<nsIDOMXULMenuListElement
> menulist
= do_QueryInterface(aCurrentEl
);
8271 nsCOMPtr
<nsIDOMXULSelectControlElement
> select
=
8272 do_QueryInterface(aCurrentEl
);
8274 checkLineHeight
= false;
8275 select
->GetSelectedItem(getter_AddRefs(item
));
8281 focusedContent
= do_QueryInterface(item
);
8284 nsIFrame
*frame
= focusedContent
->GetPrimaryFrame();
8286 NS_ASSERTION(frame
->PresContext() == GetPresContext(),
8287 "handling event for focused content that is not in our document?");
8289 nsPoint
frameOrigin(0, 0);
8291 // Get the frame's origin within its view
8292 nsView
*view
= frame
->GetClosestView(&frameOrigin
);
8293 NS_ASSERTION(view
, "No view for frame");
8295 // View's origin relative the widget
8297 frameOrigin
+= view
->GetOffsetToWidget(aRootWidget
);
8300 // Start context menu down and to the right from top left of frame
8301 // use the lineheight. This is a good distance to move the context
8302 // menu away from the top left corner of the frame. If we always
8303 // used the frame height, the context menu could end up far away,
8304 // for example when we're focused on linked images.
8305 // On the other hand, we want to use the frame height if it's less
8306 // than the current line height, so that the context menu appears
8307 // associated with the correct frame.
8310 extra
= frame
->GetSize().height
;
8311 if (checkLineHeight
) {
8312 nsIScrollableFrame
*scrollFrame
=
8313 nsLayoutUtils::GetNearestScrollableFrame(frame
);
8315 nsSize scrollAmount
= scrollFrame
->GetLineScrollAmount();
8316 nsIFrame
* f
= do_QueryFrame(scrollFrame
);
8317 int32_t APD
= presContext
->AppUnitsPerDevPixel();
8318 int32_t scrollAPD
= f
->PresContext()->AppUnitsPerDevPixel();
8319 scrollAmount
= scrollAmount
.ConvertAppUnits(scrollAPD
, APD
);
8320 if (extra
> scrollAmount
.height
) {
8321 extra
= scrollAmount
.height
;
8327 aTargetPt
.x
= presContext
->AppUnitsToDevPixels(frameOrigin
.x
);
8328 aTargetPt
.y
= presContext
->AppUnitsToDevPixels(
8329 frameOrigin
.y
+ extra
+ extraTreeY
);
8332 NS_IF_ADDREF(*aTargetToUse
= focusedContent
);
8336 PresShell::ShouldIgnoreInvalidation()
8338 return mPaintingSuppressed
|| !mIsActive
|| mIsNeverPainting
;
8342 PresShell::WillPaint()
8344 nsRootPresContext
* rootPresContext
= mPresContext
->GetRootPresContext();
8345 if (!rootPresContext
) {
8346 // In some edge cases, such as when we don't have a root frame yet,
8347 // we can't find the root prescontext. There's nothing to do in that
8352 // Don't bother doing anything if some viewmanager in our tree is painting
8353 // while we still have painting suppressed or we are not active.
8354 if (mPaintingSuppressed
|| !mIsActive
|| !IsVisible()) {
8358 rootPresContext
->FlushWillPaintObservers();
8362 // Process reflows, if we have them, to reduce flicker due to invalidates and
8363 // reflow being interspersed. Note that we _do_ allow this to be
8364 // interruptible; if we can't do all the reflows it's better to flicker a bit
8365 // than to freeze up.
8366 FlushPendingNotifications(ChangesToFlush(Flush_InterruptibleLayout
, false));
8370 PresShell::WillPaintWindow()
8372 nsRootPresContext
* rootPresContext
= mPresContext
->GetRootPresContext();
8373 if (rootPresContext
!= mPresContext
) {
8374 // This could be a popup's presshell. We don't allow plugins in popups
8375 // so there's nothing to do here.
8380 rootPresContext
->ApplyPluginGeometryUpdates();
8385 PresShell::DidPaintWindow()
8388 nsCOMPtr
<nsPIDOMWindow
> window
= mDocument
->GetWindow();
8390 window
->SendAfterRemotePaintIfRequested();
8394 nsRootPresContext
* rootPresContext
= mPresContext
->GetRootPresContext();
8395 if (rootPresContext
!= mPresContext
) {
8396 // This could be a popup's presshell. No point in notifying XPConnect
8397 // about compositing of popups.
8403 PresShell::IsVisible()
8408 nsView
* view
= mViewManager
->GetRootView();
8412 // inner view of subdoc frame
8413 view
= view
->GetParent();
8418 view
= view
->GetParent();
8422 nsIFrame
* frame
= view
->GetFrame();
8426 return frame
->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY
);
8430 PresShell::GetAgentStyleSheets(nsCOMArray
<nsIStyleSheet
>& aSheets
)
8433 int32_t sheetCount
= mStyleSet
->SheetCount(nsStyleSet::eAgentSheet
);
8435 for (int32_t i
= 0; i
< sheetCount
; ++i
) {
8436 nsIStyleSheet
*sheet
= mStyleSet
->StyleSheetAt(nsStyleSet::eAgentSheet
, i
);
8437 if (!aSheets
.AppendObject(sheet
))
8438 return NS_ERROR_OUT_OF_MEMORY
;
8445 PresShell::SetAgentStyleSheets(const nsCOMArray
<nsIStyleSheet
>& aSheets
)
8447 return mStyleSet
->ReplaceSheets(nsStyleSet::eAgentSheet
, aSheets
);
8451 PresShell::AddOverrideStyleSheet(nsIStyleSheet
*aSheet
)
8453 return mStyleSet
->PrependStyleSheet(nsStyleSet::eOverrideSheet
, aSheet
);
8457 PresShell::RemoveOverrideStyleSheet(nsIStyleSheet
*aSheet
)
8459 return mStyleSet
->RemoveStyleSheet(nsStyleSet::eOverrideSheet
, aSheet
);
8463 FreezeElement(nsISupports
*aSupports
, void * /* unused */)
8465 nsCOMPtr
<nsIObjectLoadingContent
> olc(do_QueryInterface(aSupports
));
8467 olc
->StopPluginInstance();
8472 FreezeSubDocument(nsIDocument
*aDocument
, void *aData
)
8474 nsIPresShell
*shell
= aDocument
->GetShell();
8484 mUpdateImageVisibilityEvent
.Revoke();
8486 MaybeReleaseCapturingContent();
8488 mDocument
->EnumerateActivityObservers(FreezeElement
, nullptr);
8491 SetCaretEnabled(false);
8494 mPaintingSuppressed
= true;
8497 mDocument
->EnumerateSubDocuments(FreezeSubDocument
, nullptr);
8500 nsPresContext
* presContext
= GetPresContext();
8502 presContext
->RefreshDriver()->PresContext() == presContext
) {
8503 presContext
->RefreshDriver()->Freeze();
8508 UpdateImageLockingState();
8513 PresShell::FireOrClearDelayedEvents(bool aFireEvents
)
8515 mNoDelayedMouseEvents
= false;
8516 mNoDelayedKeyEvents
= false;
8518 mDelayedEvents
.Clear();
8523 nsCOMPtr
<nsIDocument
> doc
= mDocument
;
8524 while (!mIsDestroying
&& mDelayedEvents
.Length() &&
8525 !doc
->EventHandlingSuppressed()) {
8526 nsAutoPtr
<DelayedEvent
> ev(mDelayedEvents
[0].forget());
8527 mDelayedEvents
.RemoveElementAt(0);
8530 if (!doc
->EventHandlingSuppressed()) {
8531 mDelayedEvents
.Clear();
8537 ThawElement(nsISupports
*aSupports
, void *aShell
)
8539 nsCOMPtr
<nsIObjectLoadingContent
> olc(do_QueryInterface(aSupports
));
8541 olc
->AsyncStartPluginInstance();
8546 ThawSubDocument(nsIDocument
*aDocument
, void *aData
)
8548 nsIPresShell
*shell
= aDocument
->GetShell();
8558 nsPresContext
* presContext
= GetPresContext();
8560 presContext
->RefreshDriver()->PresContext() == presContext
) {
8561 presContext
->RefreshDriver()->Thaw();
8564 mDocument
->EnumerateActivityObservers(ThawElement
, this);
8567 mDocument
->EnumerateSubDocuments(ThawSubDocument
, nullptr);
8569 // Get the activeness of our presshell, as this might have changed
8570 // while we were in the bfcache
8573 // We're now unfrozen
8575 UpdateImageLockingState();
8577 UnsuppressPainting();
8580 //--------------------------------------------------------
8581 // Start of protected and private methods on the PresShell
8582 //--------------------------------------------------------
8585 PresShell::MaybeScheduleReflow()
8587 ASSERT_REFLOW_SCHEDULED_STATE();
8588 if (mReflowScheduled
|| mIsDestroying
|| mIsReflowing
||
8589 mDirtyRoots
.Length() == 0)
8592 if (!mPresContext
->HasPendingInterrupt() || !ScheduleReflowOffTimer()) {
8596 ASSERT_REFLOW_SCHEDULED_STATE();
8600 PresShell::ScheduleReflow()
8602 NS_PRECONDITION(!mReflowScheduled
, "Why are we trying to schedule a reflow?");
8603 ASSERT_REFLOW_SCHEDULED_STATE();
8605 if (GetPresContext()->RefreshDriver()->AddLayoutFlushObserver(this)) {
8606 mReflowScheduled
= true;
8609 ASSERT_REFLOW_SCHEDULED_STATE();
8613 PresShell::DidCauseReflow()
8615 NS_ASSERTION(mChangeNestCount
!= 0, "Unexpected call to DidCauseReflow()");
8617 nsContentUtils::RemoveScriptBlocker();
8623 PresShell::WillDoReflow()
8625 mPresContext
->FlushUserFontSet();
8627 mPresContext
->FlushCounterStyles();
8629 mFrameConstructor
->BeginUpdate();
8631 mLastReflowStart
= GetPerformanceNow();
8635 PresShell::DidDoReflow(bool aInterruptible
, bool aWasInterrupted
)
8637 mFrameConstructor
->EndUpdate();
8639 HandlePostedReflowCallbacks(aInterruptible
);
8641 nsCOMPtr
<nsIDocShell
> docShell
= mPresContext
->GetDocShell();
8643 DOMHighResTimeStamp now
= GetPerformanceNow();
8644 docShell
->NotifyReflowObservers(aInterruptible
, mLastReflowStart
, now
);
8647 if (sSynthMouseMove
) {
8648 SynthesizeMouseMove(false);
8652 mTouchCaret
->UpdatePositionIfNeeded();
8655 if (!aWasInterrupted
) {
8656 ClearReflowOnZoomPending();
8661 PresShell::GetPerformanceNow()
8663 DOMHighResTimeStamp now
= 0;
8664 nsPIDOMWindow
* window
= mDocument
->GetInnerWindow();
8667 nsPerformance
* perf
= window
->GetPerformance();
8677 static PLDHashOperator
8678 MarkFramesDirtyToRoot(nsPtrHashKey
<nsIFrame
>* p
, void* closure
)
8680 nsIFrame
* target
= static_cast<nsIFrame
*>(closure
);
8681 for (nsIFrame
* f
= p
->GetKey(); f
&& !NS_SUBTREE_DIRTY(f
);
8682 f
= f
->GetParent()) {
8683 f
->AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN
);
8690 return PL_DHASH_NEXT
;
8694 PresShell::sReflowContinueCallback(nsITimer
* aTimer
, void* aPresShell
)
8696 nsRefPtr
<PresShell
> self
= static_cast<PresShell
*>(aPresShell
);
8698 NS_PRECONDITION(aTimer
== self
->mReflowContinueTimer
, "Unexpected timer");
8699 self
->mReflowContinueTimer
= nullptr;
8700 self
->ScheduleReflow();
8704 PresShell::ScheduleReflowOffTimer()
8706 NS_PRECONDITION(!mReflowScheduled
, "Shouldn't get here");
8707 ASSERT_REFLOW_SCHEDULED_STATE();
8709 if (!mReflowContinueTimer
) {
8710 mReflowContinueTimer
= do_CreateInstance("@mozilla.org/timer;1");
8711 if (!mReflowContinueTimer
||
8712 NS_FAILED(mReflowContinueTimer
->
8713 InitWithFuncCallback(sReflowContinueCallback
, this, 30,
8714 nsITimer::TYPE_ONE_SHOT
))) {
8722 PresShell::DoReflow(nsIFrame
* target
, bool aInterruptible
)
8728 gfxTextPerfMetrics
* tp
= mPresContext
->GetTextPerfMetrics();
8729 TimeStamp timeStart
;
8733 timeStart
= TimeStamp::Now();
8736 target
->SchedulePaint();
8737 nsIFrame
*parent
= nsLayoutUtils::GetCrossDocParentFrame(target
);
8739 nsSVGEffects::InvalidateDirectRenderingObservers(parent
);
8740 parent
= nsLayoutUtils::GetCrossDocParentFrame(parent
);
8743 nsAutoCString
docURL("N/A");
8744 nsIURI
*uri
= mDocument
->GetDocumentURI();
8746 uri
->GetSpec(docURL
);
8748 PROFILER_LABEL_PRINTF("PresShell", "DoReflow",
8749 js::ProfileEntry::Category::GRAPHICS
, "(%s)", docURL
.get());
8751 if (mReflowContinueTimer
) {
8752 mReflowContinueTimer
->Cancel();
8753 mReflowContinueTimer
= nullptr;
8756 nsIFrame
* rootFrame
= mFrameConstructor
->GetRootFrame();
8758 nsRefPtr
<nsRenderingContext
> rcx
= CreateReferenceRenderingContext();
8761 mCurrentReflowRoot
= target
;
8764 target
->WillReflow(mPresContext
);
8766 // If the target frame is the root of the frame hierarchy, then
8767 // use all the available space. If it's simply a `reflow root',
8768 // then use the target frame's size as the available space.
8769 WritingMode wm
= target
->GetWritingMode();
8770 LogicalSize
size(wm
);
8771 if (target
== rootFrame
) {
8772 size
= LogicalSize(wm
, mPresContext
->GetVisibleArea().Size());
8774 size
= target
->GetLogicalSize();
8777 NS_ASSERTION(!target
->GetNextInFlow() && !target
->GetPrevInFlow(),
8778 "reflow roots should never split");
8780 // Don't pass size directly to the reflow state, since a
8781 // constrained height implies page/column breaking.
8782 LogicalSize
reflowSize(wm
, size
.ISize(wm
), NS_UNCONSTRAINEDSIZE
);
8783 nsHTMLReflowState
reflowState(mPresContext
, target
, rcx
, reflowSize
,
8784 nsHTMLReflowState::CALLER_WILL_INIT
);
8786 if (rootFrame
== target
) {
8787 reflowState
.Init(mPresContext
);
8789 // When the root frame is being reflowed with unconstrained block-size
8790 // (which happens when we're called from
8791 // nsDocumentViewer::SizeToContent), we're effectively doing a
8792 // resize in the block direction, since it changes the meaning of
8793 // percentage block-sizes even if no block-sizes actually changed.
8794 // The same applies when we reflow again after that computation. This is
8795 // an unusual case, and isn't caught by nsHTMLReflowState::InitResizeFlags.
8796 bool hasUnconstrainedBSize
= size
.BSize(wm
) == NS_UNCONSTRAINEDSIZE
;
8798 if (hasUnconstrainedBSize
|| mLastRootReflowHadUnconstrainedBSize
) {
8799 reflowState
.mFlags
.mVResize
= true;
8802 mLastRootReflowHadUnconstrainedBSize
= hasUnconstrainedBSize
;
8804 // Initialize reflow state with current used border and padding,
8805 // in case this was set specially by the parent frame when the reflow root
8806 // was reflowed by its parent.
8807 nsMargin currentBorder
= target
->GetUsedBorder();
8808 nsMargin currentPadding
= target
->GetUsedPadding();
8809 reflowState
.Init(mPresContext
, -1, -1, ¤tBorder
, ¤tPadding
);
8812 // fix the computed height
8813 NS_ASSERTION(reflowState
.ComputedPhysicalMargin() == nsMargin(0, 0, 0, 0),
8814 "reflow state should not set margin for reflow roots");
8815 if (size
.BSize(wm
) != NS_UNCONSTRAINEDSIZE
) {
8816 nscoord computedBSize
=
8817 size
.BSize(wm
) - reflowState
.ComputedLogicalBorderPadding().BStartEnd(wm
);
8818 computedBSize
= std::max(computedBSize
, 0);
8819 reflowState
.SetComputedBSize(computedBSize
);
8821 NS_ASSERTION(reflowState
.ComputedISize() ==
8823 reflowState
.ComputedLogicalBorderPadding().IStartEnd(wm
),
8824 "reflow state computed incorrect inline size");
8826 mPresContext
->ReflowStarted(aInterruptible
);
8827 mIsReflowing
= true;
8829 nsReflowStatus status
;
8830 nsHTMLReflowMetrics
desiredSize(reflowState
);
8831 target
->Reflow(mPresContext
, desiredSize
, reflowState
, status
);
8833 // If an incremental reflow is initiated at a frame other than the
8834 // root frame, then its desired size had better not change! If it's
8835 // initiated at the root, then the size better not change unless its
8836 // height was unconstrained to start with.
8837 nsRect boundsRelativeToTarget
= nsRect(0, 0, desiredSize
.Width(), desiredSize
.Height());
8838 NS_ASSERTION((target
== rootFrame
&&
8839 size
.BSize(wm
) == NS_UNCONSTRAINEDSIZE
) ||
8840 (desiredSize
.ISize(wm
) == size
.ISize(wm
) &&
8841 desiredSize
.BSize(wm
) == size
.BSize(wm
)),
8842 "non-root frame's desired size changed during an "
8843 "incremental reflow");
8844 NS_ASSERTION(target
== rootFrame
||
8845 desiredSize
.VisualOverflow().IsEqualInterior(boundsRelativeToTarget
),
8846 "non-root reflow roots must not have visible overflow");
8847 NS_ASSERTION(target
== rootFrame
||
8848 desiredSize
.ScrollableOverflow().IsEqualEdges(boundsRelativeToTarget
),
8849 "non-root reflow roots must not have scrollable overflow");
8850 NS_ASSERTION(status
== NS_FRAME_COMPLETE
,
8851 "reflow roots should never split");
8853 target
->SetSize(boundsRelativeToTarget
.Size());
8855 // Always use boundsRelativeToTarget here, not desiredSize.GetVisualOverflowArea(),
8856 // because for root frames (where they could be different, since root frames
8857 // are allowed to have overflow) the root view bounds need to match the
8858 // viewport bounds; the view manager "window dimensions" code depends on it.
8859 nsContainerFrame::SyncFrameViewAfterReflow(mPresContext
, target
,
8861 boundsRelativeToTarget
);
8862 nsContainerFrame::SyncWindowProperties(mPresContext
, target
,
8863 target
->GetView(), rcx
);
8865 target
->DidReflow(mPresContext
, nullptr, nsDidReflowStatus::FINISHED
);
8866 if (target
== rootFrame
&& size
.BSize(wm
) == NS_UNCONSTRAINEDSIZE
) {
8867 mPresContext
->SetVisibleArea(boundsRelativeToTarget
);
8871 mCurrentReflowRoot
= nullptr;
8874 NS_ASSERTION(mPresContext
->HasPendingInterrupt() ||
8875 mFramesToDirty
.Count() == 0,
8876 "Why do we need to dirty anything if not interrupted?");
8878 mIsReflowing
= false;
8879 bool interrupted
= mPresContext
->HasPendingInterrupt();
8881 // Make sure target gets reflowed again.
8882 mFramesToDirty
.EnumerateEntries(&MarkFramesDirtyToRoot
, target
);
8883 NS_ASSERTION(NS_SUBTREE_DIRTY(target
), "Why is the target not dirty?");
8884 mDirtyRoots
.AppendElement(target
);
8885 mDocument
->SetNeedLayoutFlush();
8887 // Clear mFramesToDirty after we've done the NS_SUBTREE_DIRTY(target)
8888 // assertion so that if it fails it's easier to see what's going on.
8889 #ifdef NOISY_INTERRUPTIBLE_REFLOW
8890 printf("mFramesToDirty.Count() == %u\n", mFramesToDirty
.Count());
8891 #endif /* NOISY_INTERRUPTIBLE_REFLOW */
8892 mFramesToDirty
.Clear();
8894 // Any FlushPendingNotifications with interruptible reflows
8895 // should be suppressed now. We don't want to do extra reflow work
8896 // before our reflow event happens.
8897 mSuppressInterruptibleReflows
= true;
8898 MaybeScheduleReflow();
8902 // dump text perf metrics for reflows with significant text processing
8904 if (tp
->current
.numChars
> 100) {
8905 TimeDuration reflowTime
= TimeStamp::Now() - timeStart
;
8906 LogTextPerfStats(tp
, this, tp
->current
,
8907 reflowTime
.ToMilliseconds(), eLog_reflow
, nullptr);
8913 return !interrupted
;
8918 PresShell::DoVerifyReflow()
8920 if (GetVerifyReflowEnable()) {
8921 // First synchronously render what we have so far so that we can
8923 nsView
* rootView
= mViewManager
->GetRootView();
8924 mViewManager
->InvalidateView(rootView
);
8926 FlushPendingNotifications(Flush_Layout
);
8927 mInVerifyReflow
= true;
8928 bool ok
= VerifyIncrementalReflow();
8929 mInVerifyReflow
= false;
8930 if (VERIFY_REFLOW_ALL
& gVerifyReflowFlags
) {
8931 printf("ProcessReflowCommands: finished (%s)\n",
8932 ok
? "ok" : "failed");
8935 if (!mDirtyRoots
.IsEmpty()) {
8936 printf("XXX yikes! reflow commands queued during verify-reflow\n");
8942 // used with Telemetry metrics
8943 #define NS_LONG_REFLOW_TIME_MS 5000
8946 PresShell::ProcessReflowCommands(bool aInterruptible
)
8948 if (mDirtyRoots
.IsEmpty() && !mShouldUnsuppressPainting
) {
8949 // Nothing to do; bail out
8953 mozilla::TimeStamp timerStart
= mozilla::TimeStamp::Now();
8954 bool interrupted
= false;
8955 if (!mDirtyRoots
.IsEmpty()) {
8958 if (VERIFY_REFLOW_DUMP_COMMANDS
& gVerifyReflowFlags
) {
8959 printf("ProcessReflowCommands: begin incremental reflow\n");
8963 // If reflow is interruptible, then make a note of our deadline.
8964 const PRIntervalTime deadline
= aInterruptible
8965 ? PR_IntervalNow() + PR_MicrosecondsToInterval(gMaxRCProcessingTime
)
8966 : (PRIntervalTime
)0;
8968 // Scope for the reflow entry point
8970 nsAutoScriptBlocker scriptBlocker
;
8972 AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Reflow
);
8973 nsViewManager::AutoDisableRefresh
refreshBlocker(mViewManager
);
8976 // Send an incremental reflow notification to the target frame.
8977 int32_t idx
= mDirtyRoots
.Length() - 1;
8978 nsIFrame
*target
= mDirtyRoots
[idx
];
8979 mDirtyRoots
.RemoveElementAt(idx
);
8981 if (!NS_SUBTREE_DIRTY(target
)) {
8982 // It's not dirty anymore, which probably means the notification
8983 // was posted in the middle of a reflow (perhaps with a reflow
8984 // root in the middle). Don't do anything.
8988 interrupted
= !DoReflow(target
, aInterruptible
);
8990 // Keep going until we're out of reflow commands, or we've run
8991 // past our deadline, or we're interrupted.
8992 } while (!interrupted
&& !mDirtyRoots
.IsEmpty() &&
8993 (!aInterruptible
|| PR_IntervalNow() < deadline
));
8995 interrupted
= !mDirtyRoots
.IsEmpty();
8998 // Exiting the scriptblocker might have killed us
8999 if (!mIsDestroying
) {
9000 DidDoReflow(aInterruptible
, interrupted
);
9003 // DidDoReflow might have killed us
9004 if (!mIsDestroying
) {
9006 if (VERIFY_REFLOW_DUMP_COMMANDS
& gVerifyReflowFlags
) {
9007 printf("\nPresShell::ProcessReflowCommands() finished: this=%p\n",
9013 // If any new reflow commands were enqueued during the reflow, schedule
9014 // another reflow event to process them. Note that we want to do this
9015 // after DidDoReflow(), since that method can change whether there are
9016 // dirty roots around by flushing, and there's no point in posting a
9017 // reflow event just to have the flush revoke it.
9018 if (!mDirtyRoots
.IsEmpty()) {
9019 MaybeScheduleReflow();
9020 // And tell our document that we might need flushing
9021 mDocument
->SetNeedLayoutFlush();
9026 if (!mIsDestroying
&& mShouldUnsuppressPainting
&&
9027 mDirtyRoots
.IsEmpty()) {
9028 // We only unlock if we're out of reflows. It's pointless
9029 // to unlock if reflows are still pending, since reflows
9030 // are just going to thrash the frames around some more. By
9031 // waiting we avoid an overeager "jitter" effect.
9032 mShouldUnsuppressPainting
= false;
9033 UnsuppressAndInvalidate();
9036 if (mDocument
->GetRootElement()) {
9037 TimeDuration elapsed
= TimeStamp::Now() - timerStart
;
9038 int32_t intElapsed
= int32_t(elapsed
.ToMilliseconds());
9041 if (mDocument
->GetRootElement()->IsXUL()) {
9043 ? Telemetry::XUL_FOREGROUND_REFLOW_MS
9044 : Telemetry::XUL_BACKGROUND_REFLOW_MS
;
9047 ? Telemetry::HTML_FOREGROUND_REFLOW_MS_2
9048 : Telemetry::HTML_BACKGROUND_REFLOW_MS_2
;
9050 Telemetry::Accumulate(id
, intElapsed
);
9051 if (intElapsed
> NS_LONG_REFLOW_TIME_MS
) {
9052 Telemetry::Accumulate(Telemetry::LONG_REFLOW_INTERRUPTIBLE
,
9053 aInterruptible
? 1 : 0);
9057 return !interrupted
;
9061 PresShell::WindowSizeMoveDone()
9064 EventStateManager::ClearGlobalActiveContent(nullptr);
9065 ClearMouseCapture(nullptr);
9071 * It's better to add stuff to the |DidSetStyleContext| method of the
9072 * relevant frames than adding it here. These methods should (ideally,
9076 // Return value says whether to walk children.
9077 typedef bool (* frameWalkerFn
)(nsIFrame
*aFrame
, void *aClosure
);
9080 ReResolveMenusAndTrees(nsIFrame
*aFrame
, void *aClosure
)
9082 // Trees have a special style cache that needs to be flushed when
9083 // the theme changes.
9084 nsTreeBodyFrame
*treeBody
= do_QueryFrame(aFrame
);
9086 treeBody
->ClearStyleAndImageCaches();
9088 // We deliberately don't re-resolve style on a menu's popup
9089 // sub-content, since doing so slows menus to a crawl. That means we
9090 // have to special-case them on a skin switch, and ensure that the
9091 // popup frames just get destroyed completely.
9092 nsMenuFrame
* menu
= do_QueryFrame(aFrame
);
9094 menu
->CloseMenu(true);
9099 ReframeImageBoxes(nsIFrame
*aFrame
, void *aClosure
)
9101 nsStyleChangeList
*list
= static_cast<nsStyleChangeList
*>(aClosure
);
9102 if (aFrame
->GetType() == nsGkAtoms::imageBoxFrame
) {
9103 list
->AppendChange(aFrame
, aFrame
->GetContent(),
9104 NS_STYLE_HINT_FRAMECHANGE
);
9105 return false; // don't walk descendants
9107 return true; // walk descendants
9111 WalkFramesThroughPlaceholders(nsPresContext
*aPresContext
, nsIFrame
*aFrame
,
9112 frameWalkerFn aFunc
, void *aClosure
)
9114 bool walkChildren
= (*aFunc
)(aFrame
, aClosure
);
9118 nsIFrame::ChildListIterator
lists(aFrame
);
9119 for (; !lists
.IsDone(); lists
.Next()) {
9120 nsFrameList::Enumerator
childFrames(lists
.CurrentList());
9121 for (; !childFrames
.AtEnd(); childFrames
.Next()) {
9122 nsIFrame
* child
= childFrames
.get();
9123 if (!(child
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
)) {
9124 // only do frames that are in flow, and recur through the
9125 // out-of-flows of placeholders.
9126 WalkFramesThroughPlaceholders(aPresContext
,
9127 nsPlaceholderFrame::GetRealFrameFor(child
),
9136 PresShell::Observe(nsISupports
* aSubject
,
9138 const char16_t
* aData
)
9141 if (!nsCRT::strcmp(aTopic
, "chrome-flush-skin-caches")) {
9142 nsIFrame
*rootFrame
= mFrameConstructor
->GetRootFrame();
9143 // Need to null-check because "chrome-flush-skin-caches" can happen
9144 // at interesting times during startup.
9146 NS_ASSERTION(mViewManager
, "View manager must exist");
9148 nsWeakFrame
weakRoot(rootFrame
);
9149 // Have to make sure that the content notifications are flushed before we
9150 // start messing with the frame model; otherwise we can get content doubling.
9151 mDocument
->FlushPendingNotifications(Flush_ContentAndNotify
);
9153 if (weakRoot
.IsAlive()) {
9154 WalkFramesThroughPlaceholders(mPresContext
, rootFrame
,
9155 &ReResolveMenusAndTrees
, nullptr);
9157 // Because "chrome:" URL equality is messy, reframe image box
9159 nsStyleChangeList changeList
;
9160 WalkFramesThroughPlaceholders(mPresContext
, rootFrame
,
9161 ReframeImageBoxes
, &changeList
);
9162 // Mark ourselves as not safe to flush while we're doing frame
9165 nsAutoScriptBlocker scriptBlocker
;
9167 RestyleManager
* restyleManager
= mPresContext
->RestyleManager();
9168 restyleManager
->ProcessRestyledFrames(changeList
);
9169 restyleManager
->FlushOverflowChangedTracker();
9178 if (!nsCRT::strcmp(aTopic
, "agent-sheet-added") && mStyleSet
) {
9179 AddAgentSheet(aSubject
);
9183 if (!nsCRT::strcmp(aTopic
, "user-sheet-added") && mStyleSet
) {
9184 AddUserSheet(aSubject
);
9188 if (!nsCRT::strcmp(aTopic
, "author-sheet-added") && mStyleSet
) {
9189 AddAuthorSheet(aSubject
);
9193 if (!nsCRT::strcmp(aTopic
, "agent-sheet-removed") && mStyleSet
) {
9194 RemoveSheet(nsStyleSet::eAgentSheet
, aSubject
);
9198 if (!nsCRT::strcmp(aTopic
, "user-sheet-removed") && mStyleSet
) {
9199 RemoveSheet(nsStyleSet::eUserSheet
, aSubject
);
9203 if (!nsCRT::strcmp(aTopic
, "author-sheet-removed") && mStyleSet
) {
9204 RemoveSheet(nsStyleSet::eDocSheet
, aSubject
);
9208 NS_WARNING("unrecognized topic in PresShell::Observe");
9209 return NS_ERROR_FAILURE
;
9213 nsIPresShell::AddRefreshObserverInternal(nsARefreshObserver
* aObserver
,
9214 mozFlushType aFlushType
)
9216 nsPresContext
* presContext
= GetPresContext();
9217 return presContext
&&
9218 presContext
->RefreshDriver()->AddRefreshObserver(aObserver
, aFlushType
);
9222 nsIPresShell::AddRefreshObserverExternal(nsARefreshObserver
* aObserver
,
9223 mozFlushType aFlushType
)
9225 return AddRefreshObserverInternal(aObserver
, aFlushType
);
9229 nsIPresShell::RemoveRefreshObserverInternal(nsARefreshObserver
* aObserver
,
9230 mozFlushType aFlushType
)
9232 nsPresContext
* presContext
= GetPresContext();
9233 return presContext
&&
9234 presContext
->RefreshDriver()->RemoveRefreshObserver(aObserver
, aFlushType
);
9238 nsIPresShell::RemoveRefreshObserverExternal(nsARefreshObserver
* aObserver
,
9239 mozFlushType aFlushType
)
9241 return RemoveRefreshObserverInternal(aObserver
, aFlushType
);
9245 nsIPresShell::AddPostRefreshObserver(nsAPostRefreshObserver
* aObserver
)
9247 nsPresContext
* presContext
= GetPresContext();
9251 presContext
->RefreshDriver()->AddPostRefreshObserver(aObserver
);
9256 nsIPresShell::RemovePostRefreshObserver(nsAPostRefreshObserver
* aObserver
)
9258 nsPresContext
* presContext
= GetPresContext();
9262 presContext
->RefreshDriver()->RemovePostRefreshObserver(aObserver
);
9266 //------------------------------------------------------
9267 // End of protected and private methods on the PresShell
9268 //------------------------------------------------------
9270 //------------------------------------------------------------------
9271 //-- Delayed event Classes Impls
9272 //------------------------------------------------------------------
9274 PresShell::DelayedInputEvent::DelayedInputEvent() :
9280 PresShell::DelayedInputEvent::~DelayedInputEvent()
9286 PresShell::DelayedInputEvent::Dispatch()
9288 if (!mEvent
|| !mEvent
->widget
) {
9291 nsCOMPtr
<nsIWidget
> widget
= mEvent
->widget
;
9292 nsEventStatus status
;
9293 widget
->DispatchEvent(mEvent
, status
);
9296 PresShell::DelayedMouseEvent::DelayedMouseEvent(WidgetMouseEvent
* aEvent
) :
9299 WidgetMouseEvent
* mouseEvent
=
9300 new WidgetMouseEvent(aEvent
->mFlags
.mIsTrusted
,
9305 mouseEvent
->AssignMouseEventData(*aEvent
, false);
9306 mEvent
= mouseEvent
;
9309 PresShell::DelayedKeyEvent::DelayedKeyEvent(WidgetKeyboardEvent
* aEvent
) :
9312 WidgetKeyboardEvent
* keyEvent
=
9313 new WidgetKeyboardEvent(aEvent
->mFlags
.mIsTrusted
,
9316 keyEvent
->AssignKeyEventData(*aEvent
, false);
9317 keyEvent
->mFlags
.mIsSynthesizedForTests
= aEvent
->mFlags
.mIsSynthesizedForTests
;
9321 // Start of DEBUG only code
9326 LogVerifyMessage(nsIFrame
* k1
, nsIFrame
* k2
, const char* aMsg
)
9328 nsAutoString n1
, n2
;
9330 k1
->GetFrameName(n1
);
9332 n1
.AssignLiteral(MOZ_UTF16("(null)"));
9336 k2
->GetFrameName(n2
);
9338 n2
.AssignLiteral(MOZ_UTF16("(null)"));
9341 printf("verifyreflow: %s %p != %s %p %s\n",
9342 NS_LossyConvertUTF16toASCII(n1
).get(), (void*)k1
,
9343 NS_LossyConvertUTF16toASCII(n2
).get(), (void*)k2
, aMsg
);
9347 LogVerifyMessage(nsIFrame
* k1
, nsIFrame
* k2
, const char* aMsg
,
9348 const nsRect
& r1
, const nsRect
& r2
)
9350 printf("VerifyReflow Error:\n");
9354 k1
->GetFrameName(name
);
9355 printf(" %s %p ", NS_LossyConvertUTF16toASCII(name
).get(), (void*)k1
);
9357 printf("{%d, %d, %d, %d} != \n", r1
.x
, r1
.y
, r1
.width
, r1
.height
);
9360 k2
->GetFrameName(name
);
9361 printf(" %s %p ", NS_LossyConvertUTF16toASCII(name
).get(), (void*)k2
);
9363 printf("{%d, %d, %d, %d}\n %s\n",
9364 r2
.x
, r2
.y
, r2
.width
, r2
.height
, aMsg
);
9368 LogVerifyMessage(nsIFrame
* k1
, nsIFrame
* k2
, const char* aMsg
,
9369 const nsIntRect
& r1
, const nsIntRect
& r2
)
9371 printf("VerifyReflow Error:\n");
9375 k1
->GetFrameName(name
);
9376 printf(" %s %p ", NS_LossyConvertUTF16toASCII(name
).get(), (void*)k1
);
9378 printf("{%d, %d, %d, %d} != \n", r1
.x
, r1
.y
, r1
.width
, r1
.height
);
9381 k2
->GetFrameName(name
);
9382 printf(" %s %p ", NS_LossyConvertUTF16toASCII(name
).get(), (void*)k2
);
9384 printf("{%d, %d, %d, %d}\n %s\n",
9385 r2
.x
, r2
.y
, r2
.width
, r2
.height
, aMsg
);
9389 CompareTrees(nsPresContext
* aFirstPresContext
, nsIFrame
* aFirstFrame
,
9390 nsPresContext
* aSecondPresContext
, nsIFrame
* aSecondFrame
)
9392 if (!aFirstPresContext
|| !aFirstFrame
|| !aSecondPresContext
|| !aSecondFrame
)
9394 // XXX Evil hack to reduce false positives; I can't seem to figure
9395 // out how to flush scrollbar changes correctly
9396 //if (aFirstFrame->GetType() == nsGkAtoms::scrollbarFrame)
9399 nsIFrame::ChildListIterator
lists1(aFirstFrame
);
9400 nsIFrame::ChildListIterator
lists2(aSecondFrame
);
9402 const nsFrameList
& kids1
= !lists1
.IsDone() ? lists1
.CurrentList() : nsFrameList();
9403 const nsFrameList
& kids2
= !lists2
.IsDone() ? lists2
.CurrentList() : nsFrameList();
9404 int32_t l1
= kids1
.GetLength();
9405 int32_t l2
= kids2
.GetLength();;
9408 LogVerifyMessage(kids1
.FirstChild(), kids2
.FirstChild(),
9409 "child counts don't match: ");
9410 printf("%d != %d\n", l1
, l2
);
9411 if (0 == (VERIFY_REFLOW_ALL
& gVerifyReflowFlags
)) {
9419 for (nsFrameList::Enumerator
e1(kids1
), e2(kids2
);
9421 e1
.Next(), e2
.Next()) {
9422 nsIFrame
* k1
= e1
.get();
9423 nsIFrame
* k2
= e2
.get();
9424 if (((nullptr == k1
) && (nullptr != k2
)) ||
9425 ((nullptr != k1
) && (nullptr == k2
))) {
9427 LogVerifyMessage(k1
, k2
, "child lists are different\n");
9430 else if (nullptr != k1
) {
9431 // Verify that the frames are the same size
9432 if (!k1
->GetRect().IsEqualInterior(k2
->GetRect())) {
9434 LogVerifyMessage(k1
, k2
, "(frame rects)", k1
->GetRect(), k2
->GetRect());
9437 // Make sure either both have views or neither have views; if they
9438 // do have views, make sure the views are the same size. If the
9439 // views have widgets, make sure they both do or neither does. If
9440 // they do, make sure the widgets are the same size.
9443 if (((nullptr == v1
) && (nullptr != v2
)) ||
9444 ((nullptr != v1
) && (nullptr == v2
))) {
9446 LogVerifyMessage(k1
, k2
, "child views are not matched\n");
9448 else if (nullptr != v1
) {
9449 if (!v1
->GetBounds().IsEqualInterior(v2
->GetBounds())) {
9450 LogVerifyMessage(k1
, k2
, "(view rects)", v1
->GetBounds(), v2
->GetBounds());
9453 nsIWidget
* w1
= v1
->GetWidget();
9454 nsIWidget
* w2
= v2
->GetWidget();
9455 if (((nullptr == w1
) && (nullptr != w2
)) ||
9456 ((nullptr != w1
) && (nullptr == w2
))) {
9458 LogVerifyMessage(k1
, k2
, "child widgets are not matched\n");
9460 else if (nullptr != w1
) {
9463 if (!r1
.IsEqualEdges(r2
)) {
9464 LogVerifyMessage(k1
, k2
, "(widget rects)", r1
, r2
);
9468 if (!ok
&& (0 == (VERIFY_REFLOW_ALL
& gVerifyReflowFlags
))) {
9472 // XXX Should perhaps compare their float managers.
9474 // Compare the sub-trees too
9475 if (!CompareTrees(aFirstPresContext
, k1
, aSecondPresContext
, k2
)) {
9477 if (0 == (VERIFY_REFLOW_ALL
& gVerifyReflowFlags
)) {
9486 if (!ok
&& (0 == (VERIFY_REFLOW_ALL
& gVerifyReflowFlags
))) {
9492 if (lists1
.IsDone() != lists2
.IsDone() ||
9493 (!lists1
.IsDone() && lists1
.CurrentID() != lists2
.CurrentID())) {
9494 if (0 == (VERIFY_REFLOW_ALL
& gVerifyReflowFlags
)) {
9497 LogVerifyMessage(kids1
.FirstChild(), kids2
.FirstChild(),
9498 "child list names are not matched: ");
9499 fprintf(stdout
, "%s != %s\n",
9500 !lists1
.IsDone() ? mozilla::layout::ChildListName(lists1
.CurrentID()) : "(null)",
9501 !lists2
.IsDone() ? mozilla::layout::ChildListName(lists2
.CurrentID()) : "(null)");
9504 } while (ok
&& !lists1
.IsDone());
9512 FindTopFrame(nsIFrame
* aRoot
)
9515 nsIContent
* content
= aRoot
->GetContent();
9518 content
->GetTag(tag
);
9519 if (nullptr != tag
) {
9525 // Try one of the children
9526 nsIFrame
* kid
= aRoot
->GetFirstPrincipalChild();
9527 while (nullptr != kid
) {
9528 nsIFrame
* result
= FindTopFrame(kid
);
9529 if (nullptr != result
) {
9532 kid
= kid
->GetNextSibling();
9543 PresShell::CloneStyleSet(nsStyleSet
* aSet
)
9545 nsStyleSet
*clone
= new nsStyleSet();
9547 int32_t i
, n
= aSet
->SheetCount(nsStyleSet::eOverrideSheet
);
9548 for (i
= 0; i
< n
; i
++) {
9549 nsIStyleSheet
* ss
= aSet
->StyleSheetAt(nsStyleSet::eOverrideSheet
, i
);
9551 clone
->AppendStyleSheet(nsStyleSet::eOverrideSheet
, ss
);
9554 // The document expects to insert document stylesheets itself
9556 n
= aSet
->SheetCount(nsStyleSet::eDocSheet
);
9557 for (i
= 0; i
< n
; i
++) {
9558 nsIStyleSheet
* ss
= aSet
->StyleSheetAt(nsStyleSet::eDocSheet
, i
);
9560 clone
->AddDocStyleSheet(ss
, mDocument
);
9564 n
= aSet
->SheetCount(nsStyleSet::eUserSheet
);
9565 for (i
= 0; i
< n
; i
++) {
9566 nsIStyleSheet
* ss
= aSet
->StyleSheetAt(nsStyleSet::eUserSheet
, i
);
9568 clone
->AppendStyleSheet(nsStyleSet::eUserSheet
, ss
);
9571 n
= aSet
->SheetCount(nsStyleSet::eAgentSheet
);
9572 for (i
= 0; i
< n
; i
++) {
9573 nsIStyleSheet
* ss
= aSet
->StyleSheetAt(nsStyleSet::eAgentSheet
, i
);
9575 clone
->AppendStyleSheet(nsStyleSet::eAgentSheet
, ss
);
9580 // After an incremental reflow, we verify the correctness by doing a
9581 // full reflow into a fresh frame tree.
9583 PresShell::VerifyIncrementalReflow()
9585 if (VERIFY_REFLOW_NOISY
& gVerifyReflowFlags
) {
9586 printf("Building Verification Tree...\n");
9589 // Create a presentation context to view the new frame tree
9590 nsRefPtr
<nsPresContext
> cx
=
9591 new nsRootPresContext(mDocument
, mPresContext
->IsPaginated() ?
9592 nsPresContext::eContext_PrintPreview
:
9593 nsPresContext::eContext_Galley
);
9594 NS_ENSURE_TRUE(cx
, false);
9596 nsDeviceContext
*dc
= mPresContext
->DeviceContext();
9597 nsresult rv
= cx
->Init(dc
);
9598 NS_ENSURE_SUCCESS(rv
, false);
9600 // Get our scrolling preference
9601 nsView
* rootView
= mViewManager
->GetRootView();
9602 NS_ENSURE_TRUE(rootView
->HasWidget(), false);
9603 nsIWidget
* parentWidget
= rootView
->GetWidget();
9605 // Create a new view manager.
9606 nsRefPtr
<nsViewManager
> vm
= new nsViewManager();
9607 NS_ENSURE_TRUE(vm
, false);
9609 NS_ENSURE_SUCCESS(rv
, false);
9611 // Create a child window of the parent that is our "root view/window"
9613 nsRect tbounds
= mPresContext
->GetVisibleArea();
9614 nsView
* view
= vm
->CreateView(tbounds
, nullptr);
9615 NS_ENSURE_TRUE(view
, false);
9617 //now create the widget for the view
9618 rv
= view
->CreateWidgetForParent(parentWidget
, nullptr, true);
9619 NS_ENSURE_SUCCESS(rv
, false);
9621 // Setup hierarchical relationship in view manager
9622 vm
->SetRootView(view
);
9624 // Make the new presentation context the same size as our
9625 // presentation context.
9626 nsRect r
= mPresContext
->GetVisibleArea();
9627 cx
->SetVisibleArea(r
);
9629 // Create a new presentation shell to view the document. Use the
9630 // exact same style information that this document has.
9631 nsAutoPtr
<nsStyleSet
> newSet(CloneStyleSet(mStyleSet
));
9632 nsCOMPtr
<nsIPresShell
> sh
= mDocument
->CreateShell(cx
, vm
, newSet
);
9633 NS_ENSURE_TRUE(sh
, false);
9635 // Note that after we create the shell, we must make sure to destroy it
9636 sh
->SetVerifyReflowEnable(false); // turn off verify reflow while we're reflowing the test frame tree
9637 vm
->SetPresShell(sh
);
9639 nsAutoCauseReflowNotifier
crNotifier(this);
9640 sh
->Initialize(r
.width
, r
.height
);
9642 mDocument
->BindingManager()->ProcessAttachedQueue();
9643 sh
->FlushPendingNotifications(Flush_Layout
);
9644 sh
->SetVerifyReflowEnable(true); // turn on verify reflow again now that we're done reflowing the test frame tree
9645 // Force the non-primary presshell to unsuppress; it doesn't want to normally
9646 // because it thinks it's hidden
9647 ((PresShell
*)sh
.get())->mPaintingSuppressed
= false;
9648 if (VERIFY_REFLOW_NOISY
& gVerifyReflowFlags
) {
9649 printf("Verification Tree built, comparing...\n");
9652 // Now that the document has been reflowed, use its frame tree to
9653 // compare against our frame tree.
9654 nsIFrame
* root1
= mFrameConstructor
->GetRootFrame();
9655 nsIFrame
* root2
= sh
->GetRootFrame();
9656 bool ok
= CompareTrees(mPresContext
, root1
, cx
, root2
);
9657 if (!ok
&& (VERIFY_REFLOW_NOISY
& gVerifyReflowFlags
)) {
9658 printf("Verify reflow failed, primary tree:\n");
9659 root1
->List(stdout
, 0);
9660 printf("Verification tree:\n");
9661 root2
->List(stdout
, 0);
9665 // Sample code for dumping page to png
9666 // XXX Needs to be made more flexible
9670 stra
.AppendLiteral("C:\\mozilla\\mozilla\\debug\\filea");
9671 stra
.AppendInt(num
);
9672 stra
.AppendLiteral(".png");
9673 gfxUtils::WriteAsPNG(sh
, stra
);
9675 strb
.AppendLiteral("C:\\mozilla\\mozilla\\debug\\fileb");
9676 strb
.AppendInt(num
);
9677 strb
.AppendLiteral(".png");
9678 gfxUtils::WriteAsPNG(sh
, strb
);
9683 sh
->EndObservingDocument();
9685 if (VERIFY_REFLOW_NOISY
& gVerifyReflowFlags
) {
9686 printf("Finished Verifying Reflow...\n");
9692 // Layout debugging hooks
9694 PresShell::ListStyleContexts(nsIFrame
*aRootFrame
, FILE *out
, int32_t aIndent
)
9696 nsStyleContext
*sc
= aRootFrame
->StyleContext();
9698 sc
->List(out
, aIndent
);
9702 PresShell::ListStyleSheets(FILE *out
, int32_t aIndent
)
9704 int32_t sheetCount
= mStyleSet
->SheetCount(nsStyleSet::eDocSheet
);
9705 for (int32_t i
= 0; i
< sheetCount
; ++i
) {
9706 mStyleSet
->StyleSheetAt(nsStyleSet::eDocSheet
, i
)->List(out
, aIndent
);
9712 PresShell::VerifyStyleTree()
9718 //=============================================================
9719 //=============================================================
9720 //-- Debug Reflow Counts
9721 //=============================================================
9722 //=============================================================
9723 #ifdef MOZ_REFLOW_PERF
9724 //-------------------------------------------------------------
9726 PresShell::DumpReflows()
9728 if (mReflowCountMgr
) {
9729 nsAutoCString uriStr
;
9731 nsIURI
*uri
= mDocument
->GetDocumentURI();
9733 uri
->GetPath(uriStr
);
9736 mReflowCountMgr
->DisplayTotals(uriStr
.get());
9737 mReflowCountMgr
->DisplayHTMLTotals(uriStr
.get());
9738 mReflowCountMgr
->DisplayDiffsInTotals("Differences");
9742 //-------------------------------------------------------------
9744 PresShell::CountReflows(const char * aName
, nsIFrame
* aFrame
)
9746 if (mReflowCountMgr
) {
9747 mReflowCountMgr
->Add(aName
, aFrame
);
9751 //-------------------------------------------------------------
9753 PresShell::PaintCount(const char * aName
,
9754 nsRenderingContext
* aRenderingContext
,
9755 nsPresContext
* aPresContext
,
9757 const nsPoint
& aOffset
,
9760 if (mReflowCountMgr
) {
9761 mReflowCountMgr
->PaintCount(aName
, aRenderingContext
, aPresContext
,
9762 aFrame
, aOffset
, aColor
);
9766 //-------------------------------------------------------------
9768 PresShell::SetPaintFrameCount(bool aPaintFrameCounts
)
9770 if (mReflowCountMgr
) {
9771 mReflowCountMgr
->SetPaintFrameCounts(aPaintFrameCounts
);
9776 PresShell::IsPaintingFrameCounts()
9778 if (mReflowCountMgr
)
9779 return mReflowCountMgr
->IsPaintingFrameCounts();
9783 //------------------------------------------------------------------
9784 //-- Reflow Counter Classes Impls
9785 //------------------------------------------------------------------
9787 //------------------------------------------------------------------
9788 ReflowCounter::ReflowCounter(ReflowCountMgr
* aMgr
) :
9795 //------------------------------------------------------------------
9796 ReflowCounter::~ReflowCounter()
9801 //------------------------------------------------------------------
9802 void ReflowCounter::ClearTotals()
9807 //------------------------------------------------------------------
9808 void ReflowCounter::SetTotalsCache()
9810 mCacheTotal
= mTotal
;
9813 //------------------------------------------------------------------
9814 void ReflowCounter::CalcDiffInTotals()
9816 mCacheTotal
= mTotal
- mCacheTotal
;
9819 //------------------------------------------------------------------
9820 void ReflowCounter::DisplayTotals(const char * aStr
)
9822 DisplayTotals(mTotal
, aStr
?aStr
:"Totals");
9825 //------------------------------------------------------------------
9826 void ReflowCounter::DisplayDiffTotals(const char * aStr
)
9828 DisplayTotals(mCacheTotal
, aStr
?aStr
:"Diff Totals");
9831 //------------------------------------------------------------------
9832 void ReflowCounter::DisplayHTMLTotals(const char * aStr
)
9834 DisplayHTMLTotals(mTotal
, aStr
?aStr
:"Totals");
9837 //------------------------------------------------------------------
9838 void ReflowCounter::DisplayTotals(uint32_t aTotal
, const char * aTitle
)
9844 ReflowCounter
* gTots
= (ReflowCounter
*)mMgr
->LookUp(kGrandTotalsStr
);
9846 printf("%25s\t", aTitle
);
9847 printf("%d\t", aTotal
);
9848 if (gTots
!= this && aTotal
> 0) {
9853 //------------------------------------------------------------------
9854 void ReflowCounter::DisplayHTMLTotals(uint32_t aTotal
, const char * aTitle
)
9860 ReflowCounter
* gTots
= (ReflowCounter
*)mMgr
->LookUp(kGrandTotalsStr
);
9861 FILE * fd
= mMgr
->GetOutFile();
9866 fprintf(fd
, "<tr><td><center>%s</center></td>", aTitle
);
9867 fprintf(fd
, "<td><center>%d</center></td></tr>\n", aTotal
);
9869 if (gTots
!= this && aTotal
> 0) {
9874 //------------------------------------------------------------------
9876 //------------------------------------------------------------------
9878 #define KEY_BUF_SIZE_FOR_PTR 24 // adequate char[] buffer to sprintf a pointer
9880 ReflowCountMgr::ReflowCountMgr()
9882 mCounts
= PL_NewHashTable(10, PL_HashString
, PL_CompareStrings
,
9883 PL_CompareValues
, nullptr, nullptr);
9884 mIndiFrameCounts
= PL_NewHashTable(10, PL_HashString
, PL_CompareStrings
,
9885 PL_CompareValues
, nullptr, nullptr);
9886 mCycledOnce
= false;
9887 mDumpFrameCounts
= false;
9888 mDumpFrameByFrameCounts
= false;
9889 mPaintFrameByFrameCounts
= false;
9892 //------------------------------------------------------------------
9893 ReflowCountMgr::~ReflowCountMgr()
9898 //------------------------------------------------------------------
9899 ReflowCounter
* ReflowCountMgr::LookUp(const char * aName
)
9901 if (nullptr != mCounts
) {
9902 ReflowCounter
* counter
= (ReflowCounter
*)PL_HashTableLookup(mCounts
, aName
);
9909 //------------------------------------------------------------------
9910 void ReflowCountMgr::Add(const char * aName
, nsIFrame
* aFrame
)
9912 NS_ASSERTION(aName
!= nullptr, "Name shouldn't be null!");
9914 if (mDumpFrameCounts
&& nullptr != mCounts
) {
9915 ReflowCounter
* counter
= (ReflowCounter
*)PL_HashTableLookup(mCounts
, aName
);
9916 if (counter
== nullptr) {
9917 counter
= new ReflowCounter(this);
9918 char * name
= NS_strdup(aName
);
9919 NS_ASSERTION(name
!= nullptr, "null ptr");
9920 PL_HashTableAdd(mCounts
, name
, counter
);
9925 if ((mDumpFrameByFrameCounts
|| mPaintFrameByFrameCounts
) &&
9926 nullptr != mIndiFrameCounts
&&
9927 aFrame
!= nullptr) {
9928 char key
[KEY_BUF_SIZE_FOR_PTR
];
9929 sprintf(key
, "%p", (void*)aFrame
);
9930 IndiReflowCounter
* counter
= (IndiReflowCounter
*)PL_HashTableLookup(mIndiFrameCounts
, key
);
9931 if (counter
== nullptr) {
9932 counter
= new IndiReflowCounter(this);
9933 counter
->mFrame
= aFrame
;
9934 counter
->mName
.AssignASCII(aName
);
9935 PL_HashTableAdd(mIndiFrameCounts
, NS_strdup(key
), counter
);
9937 // this eliminates extra counts from super classes
9938 if (counter
!= nullptr && counter
->mName
.EqualsASCII(aName
)) {
9940 counter
->mCounter
.Add(1);
9945 //------------------------------------------------------------------
9946 void ReflowCountMgr::PaintCount(const char* aName
,
9947 nsRenderingContext
* aRenderingContext
,
9948 nsPresContext
* aPresContext
,
9950 const nsPoint
& aOffset
,
9953 if (mPaintFrameByFrameCounts
&&
9954 nullptr != mIndiFrameCounts
&&
9955 aFrame
!= nullptr) {
9956 char key
[KEY_BUF_SIZE_FOR_PTR
];
9957 sprintf(key
, "%p", (void*)aFrame
);
9958 IndiReflowCounter
* counter
=
9959 (IndiReflowCounter
*)PL_HashTableLookup(mIndiFrameCounts
, key
);
9960 if (counter
!= nullptr && counter
->mName
.EqualsASCII(aName
)) {
9961 aRenderingContext
->PushState();
9962 aRenderingContext
->Translate(aOffset
);
9963 nsFont
font(eFamily_serif
, NS_FONT_STYLE_NORMAL
,
9964 NS_FONT_WEIGHT_NORMAL
, NS_FONT_STRETCH_NORMAL
, 0,
9965 nsPresContext::CSSPixelsToAppUnits(11));
9967 nsRefPtr
<nsFontMetrics
> fm
;
9968 aPresContext
->DeviceContext()->GetMetricsFor(font
,
9969 // We have one frame, therefore we must have a root...
9970 aPresContext
->GetPresShell()->GetRootFrame()->
9971 StyleFont()->mLanguage
,
9972 aPresContext
->GetUserFontSet(),
9973 aPresContext
->GetTextPerfMetrics(),
9974 *getter_AddRefs(fm
));
9976 aRenderingContext
->SetFont(fm
);
9978 sprintf(buf
, "%d", counter
->mCount
);
9979 nscoord x
= 0, y
= fm
->MaxAscent();
9980 nscoord width
, height
= fm
->MaxHeight();
9981 aRenderingContext
->SetTextRunRTL(false);
9982 width
= aRenderingContext
->GetWidth(buf
);
9988 color2
= NS_RGB(0,0,0);
9990 uint8_t rc
= 0, gc
= 0, bc
= 0;
9991 if (counter
->mCount
< 5) {
9994 } else if ( counter
->mCount
< 11) {
9999 color
= NS_RGB(rc
,gc
,bc
);
10000 color2
= NS_RGB(rc
/2,gc
/2,bc
/2);
10003 nsRect
rect(0,0, width
+15, height
+15);
10004 aRenderingContext
->SetColor(NS_RGB(0,0,0));
10005 aRenderingContext
->FillRect(rect
);
10006 aRenderingContext
->SetColor(color2
);
10007 aRenderingContext
->DrawString(buf
, strlen(buf
), x
+15,y
+15);
10008 aRenderingContext
->SetColor(color
);
10009 aRenderingContext
->DrawString(buf
, strlen(buf
), x
,y
);
10011 aRenderingContext
->PopState();
10016 //------------------------------------------------------------------
10017 int ReflowCountMgr::RemoveItems(PLHashEntry
*he
, int i
, void *arg
)
10019 char *str
= (char *)he
->key
;
10020 ReflowCounter
* counter
= (ReflowCounter
*)he
->value
;
10024 return HT_ENUMERATE_REMOVE
;
10027 //------------------------------------------------------------------
10028 int ReflowCountMgr::RemoveIndiItems(PLHashEntry
*he
, int i
, void *arg
)
10030 char *str
= (char *)he
->key
;
10031 IndiReflowCounter
* counter
= (IndiReflowCounter
*)he
->value
;
10035 return HT_ENUMERATE_REMOVE
;
10038 //------------------------------------------------------------------
10039 void ReflowCountMgr::CleanUp()
10041 if (nullptr != mCounts
) {
10042 PL_HashTableEnumerateEntries(mCounts
, RemoveItems
, nullptr);
10043 PL_HashTableDestroy(mCounts
);
10047 if (nullptr != mIndiFrameCounts
) {
10048 PL_HashTableEnumerateEntries(mIndiFrameCounts
, RemoveIndiItems
, nullptr);
10049 PL_HashTableDestroy(mIndiFrameCounts
);
10050 mIndiFrameCounts
= nullptr;
10054 //------------------------------------------------------------------
10055 int ReflowCountMgr::DoSingleTotal(PLHashEntry
*he
, int i
, void *arg
)
10057 char *str
= (char *)he
->key
;
10058 ReflowCounter
* counter
= (ReflowCounter
*)he
->value
;
10060 counter
->DisplayTotals(str
);
10062 return HT_ENUMERATE_NEXT
;
10065 //------------------------------------------------------------------
10066 void ReflowCountMgr::DoGrandTotals()
10068 if (nullptr != mCounts
) {
10069 ReflowCounter
* gTots
= (ReflowCounter
*)PL_HashTableLookup(mCounts
, kGrandTotalsStr
);
10070 if (gTots
== nullptr) {
10071 gTots
= new ReflowCounter(this);
10072 PL_HashTableAdd(mCounts
, NS_strdup(kGrandTotalsStr
), gTots
);
10074 gTots
->ClearTotals();
10077 printf("\t\t\t\tTotal\n");
10078 for (uint32_t i
=0;i
<78;i
++) {
10082 PL_HashTableEnumerateEntries(mCounts
, DoSingleTotal
, this);
10086 static void RecurseIndiTotals(nsPresContext
* aPresContext
,
10088 nsIFrame
* aParentFrame
,
10091 if (aParentFrame
== nullptr) {
10095 char key
[KEY_BUF_SIZE_FOR_PTR
];
10096 sprintf(key
, "%p", (void*)aParentFrame
);
10097 IndiReflowCounter
* counter
= (IndiReflowCounter
*)PL_HashTableLookup(aHT
, key
);
10099 counter
->mHasBeenOutput
= true;
10100 char * name
= ToNewCString(counter
->mName
);
10101 for (int32_t i
=0;i
<aLevel
;i
++) printf(" ");
10102 printf("%s - %p [%d][", name
, (void*)aParentFrame
, counter
->mCount
);
10103 printf("%d", counter
->mCounter
.GetTotal());
10105 nsMemory::Free(name
);
10108 nsIFrame
* child
= aParentFrame
->GetFirstPrincipalChild();
10110 RecurseIndiTotals(aPresContext
, aHT
, child
, aLevel
+1);
10111 child
= child
->GetNextSibling();
10116 //------------------------------------------------------------------
10117 int ReflowCountMgr::DoSingleIndi(PLHashEntry
*he
, int i
, void *arg
)
10119 IndiReflowCounter
* counter
= (IndiReflowCounter
*)he
->value
;
10120 if (counter
&& !counter
->mHasBeenOutput
) {
10121 char * name
= ToNewCString(counter
->mName
);
10122 printf("%s - %p [%d][", name
, (void*)counter
->mFrame
, counter
->mCount
);
10123 printf("%d", counter
->mCounter
.GetTotal());
10125 nsMemory::Free(name
);
10127 return HT_ENUMERATE_NEXT
;
10130 //------------------------------------------------------------------
10131 void ReflowCountMgr::DoIndiTotalsTree()
10133 if (nullptr != mCounts
) {
10134 printf("\n------------------------------------------------\n");
10135 printf("-- Individual Frame Counts\n");
10136 printf("------------------------------------------------\n");
10139 nsIFrame
* rootFrame
= mPresShell
->FrameManager()->GetRootFrame();
10140 RecurseIndiTotals(mPresContext
, mIndiFrameCounts
, rootFrame
, 0);
10141 printf("------------------------------------------------\n");
10142 printf("-- Individual Counts of Frames not in Root Tree\n");
10143 printf("------------------------------------------------\n");
10144 PL_HashTableEnumerateEntries(mIndiFrameCounts
, DoSingleIndi
, this);
10149 //------------------------------------------------------------------
10150 int ReflowCountMgr::DoSingleHTMLTotal(PLHashEntry
*he
, int i
, void *arg
)
10152 char *str
= (char *)he
->key
;
10153 ReflowCounter
* counter
= (ReflowCounter
*)he
->value
;
10155 counter
->DisplayHTMLTotals(str
);
10157 return HT_ENUMERATE_NEXT
;
10160 //------------------------------------------------------------------
10161 void ReflowCountMgr::DoGrandHTMLTotals()
10163 if (nullptr != mCounts
) {
10164 ReflowCounter
* gTots
= (ReflowCounter
*)PL_HashTableLookup(mCounts
, kGrandTotalsStr
);
10165 if (gTots
== nullptr) {
10166 gTots
= new ReflowCounter(this);
10167 PL_HashTableAdd(mCounts
, NS_strdup(kGrandTotalsStr
), gTots
);
10169 gTots
->ClearTotals();
10172 static const char * title
[] = {"Class", "Reflows"};
10173 fprintf(mFD
, "<tr>");
10174 for (uint32_t i
=0; i
< ArrayLength(title
); i
++) {
10175 fprintf(mFD
, "<td><center><b>%s<b></center></td>", title
[i
]);
10177 fprintf(mFD
, "</tr>\n");
10178 PL_HashTableEnumerateEntries(mCounts
, DoSingleHTMLTotal
, this);
10182 //------------------------------------
10183 void ReflowCountMgr::DisplayTotals(const char * aStr
)
10186 printf("%s\n", aStr
?aStr
:"No name");
10188 if (mDumpFrameCounts
) {
10191 if (mDumpFrameByFrameCounts
) {
10192 DoIndiTotalsTree();
10196 //------------------------------------
10197 void ReflowCountMgr::DisplayHTMLTotals(const char * aStr
)
10199 #ifdef WIN32x // XXX NOT XP!
10202 char * sptr
= strrchr(aStr
, '/');
10205 strcpy(name
, sptr
);
10206 char * eptr
= strrchr(name
, '.');
10210 strcat(name
, "_stats.html");
10212 mFD
= fopen(name
, "w");
10214 fprintf(mFD
, "<html><head><title>Reflow Stats</title></head><body>\n");
10215 const char * title
= aStr
?aStr
:"No name";
10216 fprintf(mFD
, "<center><b>%s</b><br><table border=1 style=\"background-color:#e0e0e0\">", title
);
10217 DoGrandHTMLTotals();
10218 fprintf(mFD
, "</center></table>\n");
10219 fprintf(mFD
, "</body></html>\n");
10226 //------------------------------------------------------------------
10227 int ReflowCountMgr::DoClearTotals(PLHashEntry
*he
, int i
, void *arg
)
10229 ReflowCounter
* counter
= (ReflowCounter
*)he
->value
;
10230 counter
->ClearTotals();
10232 return HT_ENUMERATE_NEXT
;
10235 //------------------------------------------------------------------
10236 void ReflowCountMgr::ClearTotals()
10238 PL_HashTableEnumerateEntries(mCounts
, DoClearTotals
, this);
10241 //------------------------------------------------------------------
10242 void ReflowCountMgr::ClearGrandTotals()
10244 if (nullptr != mCounts
) {
10245 ReflowCounter
* gTots
= (ReflowCounter
*)PL_HashTableLookup(mCounts
, kGrandTotalsStr
);
10246 if (gTots
== nullptr) {
10247 gTots
= new ReflowCounter(this);
10248 PL_HashTableAdd(mCounts
, NS_strdup(kGrandTotalsStr
), gTots
);
10250 gTots
->ClearTotals();
10251 gTots
->SetTotalsCache();
10256 //------------------------------------------------------------------
10257 int ReflowCountMgr::DoDisplayDiffTotals(PLHashEntry
*he
, int i
, void *arg
)
10259 bool cycledOnce
= (arg
!= 0);
10261 char *str
= (char *)he
->key
;
10262 ReflowCounter
* counter
= (ReflowCounter
*)he
->value
;
10265 counter
->CalcDiffInTotals();
10266 counter
->DisplayDiffTotals(str
);
10268 counter
->SetTotalsCache();
10270 return HT_ENUMERATE_NEXT
;
10273 //------------------------------------------------------------------
10274 void ReflowCountMgr::DisplayDiffsInTotals(const char * aStr
)
10277 printf("Differences\n");
10278 for (int32_t i
=0;i
<78;i
++) {
10282 ClearGrandTotals();
10284 PL_HashTableEnumerateEntries(mCounts
, DoDisplayDiffTotals
, (void *)mCycledOnce
);
10286 mCycledOnce
= true;
10289 #endif // MOZ_REFLOW_PERF
10291 // make a color string like #RRGGBB
10292 void ColorToString(nscolor aColor
, nsAutoString
&aString
)
10296 PR_snprintf(buf
, sizeof(buf
), "#%02x%02x%02x",
10297 NS_GET_R(aColor
), NS_GET_G(aColor
), NS_GET_B(aColor
));
10298 CopyASCIItoUTF16(buf
, aString
);
10301 nsIFrame
* nsIPresShell::GetAbsoluteContainingBlock(nsIFrame
*aFrame
)
10303 return FrameConstructor()->GetAbsoluteContainingBlock(aFrame
,
10304 nsCSSFrameConstructor::ABS_POS
);
10307 #ifdef ACCESSIBILITY
10309 nsIPresShell::IsAccessibilityActive()
10311 return GetAccService() != nullptr;
10314 nsAccessibilityService
*
10315 nsIPresShell::AccService()
10317 return GetAccService();
10321 void nsIPresShell::InitializeStatics()
10323 NS_ASSERTION(!gCaptureTouchList
, "InitializeStatics called multiple times!");
10324 gCaptureTouchList
= new nsRefPtrHashtable
<nsUint32HashKey
, dom::Touch
>;
10325 gPointerCaptureList
= new nsRefPtrHashtable
<nsUint32HashKey
, nsIContent
>;
10326 gActivePointersIds
= new nsClassHashtable
<nsUint32HashKey
, PointerInfo
>;
10329 void nsIPresShell::ReleaseStatics()
10331 NS_ASSERTION(gCaptureTouchList
, "ReleaseStatics called without Initialize!");
10332 delete gCaptureTouchList
;
10333 gCaptureTouchList
= nullptr;
10334 delete gPointerCaptureList
;
10335 gPointerCaptureList
= nullptr;
10336 delete gActivePointersIds
;
10337 gActivePointersIds
= nullptr;
10340 // Asks our docshell whether we're active.
10341 void PresShell::QueryIsActive()
10343 nsCOMPtr
<nsISupports
> container
= mPresContext
->GetContainerWeak();
10345 nsIDocument
* displayDoc
= mDocument
->GetDisplayDocument();
10347 // Ok, we're an external resource document -- we need to use our display
10348 // document's docshell to determine "IsActive" status, since we lack
10350 NS_ABORT_IF_FALSE(!container
,
10351 "external resource doc shouldn't have "
10352 "its own container");
10354 nsIPresShell
* displayPresShell
= displayDoc
->GetShell();
10355 if (displayPresShell
) {
10356 container
= displayPresShell
->GetPresContext()->GetContainerWeak();
10361 nsCOMPtr
<nsIDocShell
> docshell(do_QueryInterface(container
));
10364 nsresult rv
= docshell
->GetIsActive(&isActive
);
10365 if (NS_SUCCEEDED(rv
))
10366 SetIsActive(isActive
);
10370 // Helper for propagating mIsActive changes to external resources
10372 SetExternalResourceIsActive(nsIDocument
* aDocument
, void* aClosure
)
10374 nsIPresShell
* shell
= aDocument
->GetShell();
10376 shell
->SetIsActive(*static_cast<bool*>(aClosure
));
10382 SetPluginIsActive(nsISupports
* aSupports
, void* aClosure
)
10384 nsCOMPtr
<nsIContent
> content(do_QueryInterface(aSupports
));
10389 nsIFrame
*frame
= content
->GetPrimaryFrame();
10390 nsIObjectFrame
*objectFrame
= do_QueryFrame(frame
);
10392 objectFrame
->SetIsDocumentActive(*static_cast<bool*>(aClosure
));
10397 PresShell::SetIsActive(bool aIsActive
)
10399 NS_PRECONDITION(mDocument
, "should only be called with a document");
10401 mIsActive
= aIsActive
;
10402 nsPresContext
* presContext
= GetPresContext();
10404 presContext
->RefreshDriver()->PresContext() == presContext
) {
10405 presContext
->RefreshDriver()->SetThrottled(!mIsActive
);
10408 // Propagate state-change to my resource documents' PresShells
10409 mDocument
->EnumerateExternalResources(SetExternalResourceIsActive
,
10411 mDocument
->EnumerateActivityObservers(SetPluginIsActive
,
10413 nsresult rv
= UpdateImageLockingState();
10414 #ifdef ACCESSIBILITY
10416 nsAccessibilityService
* accService
= AccService();
10418 accService
->PresShellActivated(this);
10423 // We have this odd special case here because remote content behaves
10424 // differently from same-process content when "hidden". In
10425 // desktop-type "browser UIs", hidden "tabs" have documents that are
10426 // part of the chrome tree. When the tabs are hidden, their content
10427 // is no longer part of the visible document tree, and the layers
10428 // for the content are naturally released.
10430 // Remote content is its own top-level tree in its subprocess. When
10431 // it's "hidden", there's no transaction in which the document
10432 // thinks it's not visible, so layers can be retained forever. This
10433 // is problematic when those layers uselessly hold on to precious
10434 // resources like directly texturable memory.
10436 // PresShell::SetIsActive() is the first C++ entry point at which we
10437 // (i) know that our parent process wants our content to be hidden;
10438 // and (ii) has easy access to the TabChild. So we use this
10439 // notification to signal the TabChild to drop its layer tree and
10440 // stop trying to repaint.
10441 if (TabChild
* tab
= TabChild::GetFrom(this)) {
10443 tab
->MakeVisible();
10445 if (nsIFrame
* root
= mFrameConstructor
->GetRootFrame()) {
10446 FrameLayerBuilder::InvalidateAllLayersForFrame(
10447 nsLayoutUtils::GetDisplayRootFrame(root
));
10448 root
->SchedulePaint();
10460 * Determines the current image locking state. Called when one of the
10461 * dependent factors changes.
10464 PresShell::UpdateImageLockingState()
10466 // We're locked if we're both thawed and active.
10467 return mDocument
->SetImageLockingState(!mFrozen
&& mIsActive
);
10471 PresShell::GetRootPresShell()
10473 if (mPresContext
) {
10474 nsPresContext
* rootPresContext
= mPresContext
->GetRootPresContext();
10475 if (rootPresContext
) {
10476 return static_cast<PresShell
*>(rootPresContext
->PresShell());
10483 PresShell::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf
,
10484 nsArenaMemoryStats
*aArenaObjectsSize
,
10485 size_t *aPresShellSize
,
10486 size_t *aStyleSetsSize
,
10487 size_t *aTextRunsSize
,
10488 size_t *aPresContextSize
)
10490 mFrameArena
.AddSizeOfExcludingThis(aMallocSizeOf
, aArenaObjectsSize
);
10491 *aPresShellSize
+= aMallocSizeOf(this);
10493 *aPresShellSize
+= mCaret
->SizeOfIncludingThis(aMallocSizeOf
);
10495 *aPresShellSize
+= mVisibleImages
.SizeOfExcludingThis(nullptr,
10498 *aPresShellSize
+= mFramesToDirty
.SizeOfExcludingThis(nullptr,
10501 *aPresShellSize
+= aArenaObjectsSize
->mOther
;
10503 *aStyleSetsSize
+= StyleSet()->SizeOfIncludingThis(aMallocSizeOf
);
10505 *aTextRunsSize
+= SizeOfTextRuns(aMallocSizeOf
);
10507 *aPresContextSize
+= mPresContext
->SizeOfIncludingThis(aMallocSizeOf
);
10511 PresShell::SizeOfTextRuns(MallocSizeOf aMallocSizeOf
) const
10513 nsIFrame
* rootFrame
= mFrameConstructor
->GetRootFrame();
10518 // clear the TEXT_RUN_MEMORY_ACCOUNTED flags
10519 nsLayoutUtils::SizeOfTextRunsForFrames(rootFrame
, nullptr,
10520 /* clear = */true);
10522 // collect the total memory in use for textruns
10523 return nsLayoutUtils::SizeOfTextRunsForFrames(rootFrame
, aMallocSizeOf
,
10524 /* clear = */false);
10528 nsIPresShell::MarkFixedFramesForReflow(IntrinsicDirty aIntrinsicDirty
)
10530 nsIFrame
* rootFrame
= mFrameConstructor
->GetRootFrame();
10532 const nsFrameList
& childList
= rootFrame
->GetChildList(nsIFrame::kFixedList
);
10533 for (nsFrameList::Enumerator
e(childList
); !e
.AtEnd(); e
.Next()) {
10534 FrameNeedsReflow(e
.get(), aIntrinsicDirty
, NS_FRAME_IS_DIRTY
);
10540 nsIPresShell::SetScrollPositionClampingScrollPortSize(nscoord aWidth
, nscoord aHeight
)
10542 if (!mScrollPositionClampingScrollPortSizeSet
||
10543 mScrollPositionClampingScrollPortSize
.width
!= aWidth
||
10544 mScrollPositionClampingScrollPortSize
.height
!= aHeight
) {
10545 mScrollPositionClampingScrollPortSizeSet
= true;
10546 mScrollPositionClampingScrollPortSize
.width
= aWidth
;
10547 mScrollPositionClampingScrollPortSize
.height
= aHeight
;
10549 if (nsIScrollableFrame
* rootScrollFrame
= GetRootScrollFrameAsScrollable()) {
10550 rootScrollFrame
->MarkScrollbarsDirtyForReflow();
10552 MarkFixedFramesForReflow(eResize
);
10557 nsIPresShell::SetContentDocumentFixedPositionMargins(const nsMargin
& aMargins
)
10559 if (mContentDocumentFixedPositionMargins
== aMargins
) {
10563 mContentDocumentFixedPositionMargins
= aMargins
;
10565 MarkFixedFramesForReflow(eResize
);
10569 PresShell::SetupFontInflation()
10571 mFontSizeInflationEmPerLine
= nsLayoutUtils::FontSizeInflationEmPerLine();
10572 mFontSizeInflationMinTwips
= nsLayoutUtils::FontSizeInflationMinTwips();
10573 mFontSizeInflationLineThreshold
= nsLayoutUtils::FontSizeInflationLineThreshold();
10574 mFontSizeInflationForceEnabled
= nsLayoutUtils::FontSizeInflationForceEnabled();
10575 mFontSizeInflationDisabledInMasterProcess
= nsLayoutUtils::FontSizeInflationDisabledInMasterProcess();
10577 NotifyFontSizeInflationEnabledIsDirty();
10581 nsIPresShell::RecomputeFontSizeInflationEnabled()
10583 mFontSizeInflationEnabledIsDirty
= false;
10585 MOZ_ASSERT(mPresContext
, "our pres context should not be null");
10586 if ((FontSizeInflationEmPerLine() == 0 &&
10587 FontSizeInflationMinTwips() == 0) || mPresContext
->IsChrome()) {
10588 mFontSizeInflationEnabled
= false;
10592 // Force-enabling font inflation always trumps the heuristics here.
10593 if (!FontSizeInflationForceEnabled()) {
10594 if (TabChild
* tab
= TabChild::GetFrom(this)) {
10595 // We're in a child process. Cancel inflation if we're not
10596 // async-pan zoomed.
10597 if (!tab
->IsAsyncPanZoomEnabled()) {
10598 mFontSizeInflationEnabled
= false;
10601 } else if (XRE_GetProcessType() == GeckoProcessType_Default
) {
10602 // We're in the master process. Cancel inflation if it's been
10603 // explicitly disabled.
10604 if (FontSizeInflationDisabledInMasterProcess()) {
10605 mFontSizeInflationEnabled
= false;
10612 // See bug 706918, comment 23 for more information on this particular section
10613 // of the code. We're using "screen size" in place of the size of the content
10614 // area, because on mobile, these are close or equal. This will work for our
10615 // purposes (bug 706198), but it will need to be changed in the future to be
10616 // more correct when we bring the rest of the viewport code into platform.
10617 // We actually want the size of the content area, in the event that we don't
10618 // have any metadata about the width and/or height. On mobile, the screen size
10619 // and the size of the content area are very close, or the same value.
10620 // In XUL fennec, the content area is the size of the <browser> widget, but
10621 // in native fennec, the content area is the size of the Gecko LayerView
10625 // Once bug 716575 has been resolved, this code should be changed so that it
10626 // does the right thing on all platforms.
10628 nsCOMPtr
<nsIScreenManager
> screenMgr
=
10629 do_GetService("@mozilla.org/gfx/screenmanager;1", &rv
);
10630 if (!NS_SUCCEEDED(rv
)) {
10631 mFontSizeInflationEnabled
= false;
10635 nsCOMPtr
<nsIScreen
> screen
;
10636 screenMgr
->GetPrimaryScreen(getter_AddRefs(screen
));
10638 int32_t screenLeft
, screenTop
, screenWidth
, screenHeight
;
10639 screen
->GetRect(&screenLeft
, &screenTop
, &screenWidth
, &screenHeight
);
10641 nsViewportInfo vInf
=
10642 nsContentUtils::GetViewportInfo(GetDocument(), ScreenIntSize(screenWidth
, screenHeight
));
10644 if (vInf
.GetDefaultZoom() >= CSSToScreenScale(1.0f
) || vInf
.IsAutoSizeEnabled()) {
10645 mFontSizeInflationEnabled
= false;
10650 mFontSizeInflationEnabled
= true;
10654 nsIPresShell::FontSizeInflationEnabled()
10656 if (mFontSizeInflationEnabledIsDirty
) {
10657 RecomputeFontSizeInflationEnabled();
10660 return mFontSizeInflationEnabled
;
10664 nsIPresShell::SetMaxLineBoxWidth(nscoord aMaxLineBoxWidth
)
10666 NS_ASSERTION(aMaxLineBoxWidth
>= 0, "attempting to set max line box width to a negative value");
10668 if (mMaxLineBoxWidth
!= aMaxLineBoxWidth
) {
10669 mMaxLineBoxWidth
= aMaxLineBoxWidth
;
10670 mReflowOnZoomPending
= true;
10671 FrameNeedsReflow(GetRootFrame(), eResize
, NS_FRAME_HAS_DIRTY_CHILDREN
);
10676 PresShell::PausePainting()
10678 if (GetPresContext()->RefreshDriver()->PresContext() != GetPresContext())
10681 mPaintingIsFrozen
= true;
10682 GetPresContext()->RefreshDriver()->Freeze();
10686 PresShell::ResumePainting()
10688 if (GetPresContext()->RefreshDriver()->PresContext() != GetPresContext())
10691 mPaintingIsFrozen
= false;
10692 GetPresContext()->RefreshDriver()->Thaw();