Line data Source code
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/.
6 : *
7 : * This Original Code has been modified by IBM Corporation.
8 : * Modifications made by IBM described herein are
9 : * Copyright (c) International Business Machines
10 : * Corporation, 2000
11 : *
12 : * Modifications to Mozilla code or documentation
13 : * identified per MPL Section 3.3
14 : *
15 : * Date Modified by Description of modification
16 : * 05/03/2000 IBM Corp. Observer events for reflow states
17 : */
18 :
19 : /* a presentation of a document, part 2 */
20 :
21 : #include "mozilla/PresShell.h"
22 :
23 : #include "mozilla/ArrayUtils.h"
24 : #include "mozilla/Attributes.h"
25 : #include "mozilla/StyleSheetInlines.h"
26 : #include "mozilla/EventDispatcher.h"
27 : #include "mozilla/EventStateManager.h"
28 : #include "mozilla/EventStates.h"
29 : #include "mozilla/IMEStateManager.h"
30 : #include "mozilla/MemoryReporting.h"
31 : #include "mozilla/dom/TabChild.h"
32 : #include "mozilla/Likely.h"
33 : #include "mozilla/Logging.h"
34 : #include "mozilla/MouseEvents.h"
35 : #include "mozilla/Sprintf.h"
36 : #include "mozilla/TextEvents.h"
37 : #include "mozilla/TimeStamp.h"
38 : #include "mozilla/TouchEvents.h"
39 : #include "mozilla/UniquePtr.h"
40 : #include "mozilla/Unused.h"
41 : #include "mozilla/StyleBackendType.h"
42 : #include <algorithm>
43 :
44 : #ifdef XP_WIN
45 : #include "winuser.h"
46 : #endif
47 :
48 : #include "gfxContext.h"
49 : #include "gfxPrefs.h"
50 : #include "gfxUserFontSet.h"
51 : #include "nsPresContext.h"
52 : #include "nsIContent.h"
53 : #include "nsIContentIterator.h"
54 : #include "mozilla/dom/Element.h"
55 : #include "mozilla/dom/Event.h" // for Event::GetEventPopupControlState()
56 : #include "mozilla/dom/PointerEvent.h"
57 : #include "nsIDocument.h"
58 : #include "nsAnimationManager.h"
59 : #include "nsNameSpaceManager.h" // for Pref-related rule management (bugs 22963,20760,31816)
60 : #include "nsFrame.h"
61 : #include "FrameLayerBuilder.h"
62 : #include "nsViewManager.h"
63 : #include "nsView.h"
64 : #include "nsCRTGlue.h"
65 : #include "prinrval.h"
66 : #include "nsTArray.h"
67 : #include "nsCOMArray.h"
68 : #include "nsContainerFrame.h"
69 : #include "nsISelection.h"
70 : #include "mozilla/dom/Selection.h"
71 : #include "nsGkAtoms.h"
72 : #include "nsIDOMRange.h"
73 : #include "nsIDOMDocument.h"
74 : #include "nsIDOMNode.h"
75 : #include "nsIDOMNodeList.h"
76 : #include "nsIDOMElement.h"
77 : #include "nsRange.h"
78 : #include "nsCOMPtr.h"
79 : #include "nsAutoPtr.h"
80 : #include "nsReadableUtils.h"
81 : #include "nsIPageSequenceFrame.h"
82 : #include "nsIPermissionManager.h"
83 : #include "nsIMozBrowserFrame.h"
84 : #include "nsCaret.h"
85 : #include "AccessibleCaretEventHub.h"
86 : #include "nsIDOMHTMLDocument.h"
87 : #include "nsFrameManager.h"
88 : #include "nsXPCOM.h"
89 : #include "nsILayoutHistoryState.h"
90 : #include "nsILineIterator.h" // for ScrollContentIntoView
91 : #include "PLDHashTable.h"
92 : #include "mozilla/dom/Touch.h"
93 : #include "mozilla/dom/TouchEvent.h"
94 : #include "mozilla/dom/PointerEventBinding.h"
95 : #include "nsIObserverService.h"
96 : #include "nsDocShell.h" // for reflow observation
97 : #include "nsIBaseWindow.h"
98 : #include "nsError.h"
99 : #include "nsLayoutUtils.h"
100 : #include "nsViewportInfo.h"
101 : #include "nsCSSRendering.h"
102 : // for |#ifdef DEBUG| code
103 : #include "prenv.h"
104 : #include "nsDisplayList.h"
105 : #include "nsRegion.h"
106 : #include "nsAutoLayoutPhase.h"
107 : #ifdef MOZ_REFLOW_PERF
108 : #include "nsFontMetrics.h"
109 : #endif
110 : #include "PositionedEventTargeting.h"
111 :
112 : #include "nsIReflowCallback.h"
113 :
114 : #include "nsPIDOMWindow.h"
115 : #include "nsFocusManager.h"
116 : #include "nsIObjectFrame.h"
117 : #include "nsIObjectLoadingContent.h"
118 : #include "nsNetUtil.h"
119 : #include "nsThreadUtils.h"
120 : #include "nsStyleSheetService.h"
121 : #include "gfxUtils.h"
122 : #include "nsSMILAnimationController.h"
123 : #include "SVGContentUtils.h"
124 : #include "nsSVGEffects.h"
125 : #include "SVGFragmentIdentifier.h"
126 : #include "nsArenaMemoryStats.h"
127 : #include "nsFrameSelection.h"
128 :
129 : #include "mozilla/dom/Performance.h"
130 : #include "nsRefreshDriver.h"
131 : #include "nsDOMNavigationTiming.h"
132 :
133 : // Drag & Drop, Clipboard
134 : #include "nsIDocShellTreeItem.h"
135 : #include "nsIURI.h"
136 : #include "nsIScrollableFrame.h"
137 : #include "nsITimer.h"
138 : #ifdef ACCESSIBILITY
139 : #include "nsAccessibilityService.h"
140 : #include "mozilla/a11y/DocAccessible.h"
141 : #ifdef DEBUG
142 : #include "mozilla/a11y/Logging.h"
143 : #endif
144 : #endif
145 :
146 : // For style data reconstruction
147 : #include "nsStyleChangeList.h"
148 : #include "nsCSSFrameConstructor.h"
149 : #ifdef MOZ_XUL
150 : #include "nsMenuFrame.h"
151 : #include "nsTreeBodyFrame.h"
152 : #include "nsIBoxObject.h"
153 : #include "nsITreeBoxObject.h"
154 : #include "nsMenuPopupFrame.h"
155 : #include "nsITreeColumns.h"
156 : #include "nsIDOMXULMultSelectCntrlEl.h"
157 : #include "nsIDOMXULSelectCntrlItemEl.h"
158 : #include "nsIDOMXULMenuListElement.h"
159 : #include "nsXULElement.h"
160 : #include "mozilla/dom/BoxObject.h"
161 : #endif // MOZ_XUL
162 :
163 : #include "mozilla/layers/CompositorBridgeChild.h"
164 : #include "ClientLayerManager.h"
165 : #include "GeckoProfiler.h"
166 : #include "gfxPlatform.h"
167 : #include "Layers.h"
168 : #include "LayerTreeInvalidation.h"
169 : #include "mozilla/css/ImageLoader.h"
170 : #include "mozilla/dom/DocumentTimeline.h"
171 : #include "mozilla/dom/ScriptSettings.h"
172 : #include "mozilla/ErrorResult.h"
173 : #include "mozilla/Preferences.h"
174 : #include "mozilla/Telemetry.h"
175 : #include "nsCanvasFrame.h"
176 : #include "nsIImageLoadingContent.h"
177 : #include "nsImageFrame.h"
178 : #include "nsIScreen.h"
179 : #include "nsIScreenManager.h"
180 : #include "nsPlaceholderFrame.h"
181 : #include "nsTransitionManager.h"
182 : #include "ChildIterator.h"
183 : #include "mozilla/RestyleManager.h"
184 : #include "mozilla/RestyleManagerInlines.h"
185 : #include "nsIDOMHTMLElement.h"
186 : #include "nsIDragSession.h"
187 : #include "nsIFrameInlines.h"
188 : #include "mozilla/gfx/2D.h"
189 : #include "nsSubDocumentFrame.h"
190 : #include "nsQueryObject.h"
191 : #include "nsLayoutStylesheetCache.h"
192 : #include "mozilla/layers/InputAPZContext.h"
193 : #include "mozilla/layers/ScrollInputMethods.h"
194 : #include "mozilla/layers/FocusTarget.h"
195 : #include "nsStyleSet.h"
196 : #include "mozilla/StyleSetHandle.h"
197 : #include "mozilla/StyleSetHandleInlines.h"
198 : #include "mozilla/StyleSheet.h"
199 : #include "mozilla/StyleSheetInlines.h"
200 : #include "mozilla/dom/ImageTracker.h"
201 : #include "nsIDocShellTreeOwner.h"
202 :
203 : #ifdef MOZ_TASK_TRACER
204 : #include "GeckoTaskTracer.h"
205 : using namespace mozilla::tasktracer;
206 : #endif
207 :
208 : #define ANCHOR_SCROLL_FLAGS \
209 : (nsIPresShell::SCROLL_OVERFLOW_HIDDEN | nsIPresShell::SCROLL_NO_PARENT_FRAMES)
210 :
211 : // define the scalfactor of drag and drop images
212 : // relative to the max screen height/width
213 : #define RELATIVE_SCALEFACTOR 0.0925f
214 :
215 : using namespace mozilla;
216 : using namespace mozilla::css;
217 : using namespace mozilla::dom;
218 : using namespace mozilla::gfx;
219 : using namespace mozilla::layers;
220 : using namespace mozilla::gfx;
221 : using namespace mozilla::layout;
222 : using PaintFrameFlags = nsLayoutUtils::PaintFrameFlags;
223 : typedef FrameMetrics::ViewID ViewID;
224 :
225 : CapturingContentInfo nsIPresShell::gCaptureInfo =
226 : { false /* mAllowed */, false /* mPointerLock */, false /* mRetargetToElement */,
227 3 : false /* mPreventDrag */ };
228 : nsIContent* nsIPresShell::gKeyDownTarget;
229 :
230 : // Keeps a map between pointerId and element that currently capturing pointer
231 : // with such pointerId. If pointerId is absent in this map then nobody is
232 : // capturing it. Additionally keep information about pending capturing content.
233 : static nsClassHashtable<nsUint32HashKey,
234 : nsIPresShell::PointerCaptureInfo>* sPointerCaptureList;
235 :
236 : // Keeps information about pointers such as pointerId, activeState, pointerType,
237 : // primaryState
238 : static nsClassHashtable<nsUint32HashKey,
239 : nsIPresShell::PointerInfo>* sActivePointersIds;
240 :
241 : // RangePaintInfo is used to paint ranges to offscreen buffers
242 : struct RangePaintInfo {
243 : RefPtr<nsRange> mRange;
244 : nsDisplayListBuilder mBuilder;
245 : nsDisplayList mList;
246 :
247 : // offset of builder's reference frame to the root frame
248 : nsPoint mRootOffset;
249 :
250 0 : RangePaintInfo(nsRange* aRange, nsIFrame* aFrame)
251 0 : : mRange(aRange), mBuilder(aFrame, nsDisplayListBuilderMode::PAINTING, false)
252 : {
253 0 : MOZ_COUNT_CTOR(RangePaintInfo);
254 0 : }
255 :
256 0 : ~RangePaintInfo()
257 0 : {
258 0 : mList.DeleteAll();
259 0 : MOZ_COUNT_DTOR(RangePaintInfo);
260 0 : }
261 : };
262 :
263 : #undef NOISY
264 :
265 : // ----------------------------------------------------------------------
266 :
267 : #ifdef DEBUG
268 : // Set the environment variable GECKO_VERIFY_REFLOW_FLAGS to one or
269 : // more of the following flags (comma separated) for handy debug
270 : // output.
271 : static uint32_t gVerifyReflowFlags;
272 :
273 : struct VerifyReflowFlags {
274 : const char* name;
275 : uint32_t bit;
276 : };
277 :
278 : static const VerifyReflowFlags gFlags[] = {
279 : { "verify", VERIFY_REFLOW_ON },
280 : { "reflow", VERIFY_REFLOW_NOISY },
281 : { "all", VERIFY_REFLOW_ALL },
282 : { "list-commands", VERIFY_REFLOW_DUMP_COMMANDS },
283 : { "noisy-commands", VERIFY_REFLOW_NOISY_RC },
284 : { "really-noisy-commands", VERIFY_REFLOW_REALLY_NOISY_RC },
285 : { "resize", VERIFY_REFLOW_DURING_RESIZE_REFLOW },
286 : };
287 :
288 : #define NUM_VERIFY_REFLOW_FLAGS (sizeof(gFlags) / sizeof(gFlags[0]))
289 :
290 : static void
291 0 : ShowVerifyReflowFlags()
292 : {
293 0 : printf("Here are the available GECKO_VERIFY_REFLOW_FLAGS:\n");
294 0 : const VerifyReflowFlags* flag = gFlags;
295 0 : const VerifyReflowFlags* limit = gFlags + NUM_VERIFY_REFLOW_FLAGS;
296 0 : while (flag < limit) {
297 0 : printf(" %s\n", flag->name);
298 0 : ++flag;
299 : }
300 0 : printf("Note: GECKO_VERIFY_REFLOW_FLAGS is a comma separated list of flag\n");
301 0 : printf("names (no whitespace)\n");
302 0 : }
303 : #endif
304 :
305 : //========================================================================
306 : //========================================================================
307 : //========================================================================
308 : #ifdef MOZ_REFLOW_PERF
309 : class ReflowCountMgr;
310 :
311 : static const char kGrandTotalsStr[] = "Grand Totals";
312 :
313 : // Counting Class
314 : class ReflowCounter {
315 : public:
316 : explicit ReflowCounter(ReflowCountMgr * aMgr = nullptr);
317 : ~ReflowCounter();
318 :
319 : void ClearTotals();
320 : void DisplayTotals(const char * aStr);
321 : void DisplayDiffTotals(const char * aStr);
322 : void DisplayHTMLTotals(const char * aStr);
323 :
324 0 : void Add() { mTotal++; }
325 0 : void Add(uint32_t aTotal) { mTotal += aTotal; }
326 :
327 : void CalcDiffInTotals();
328 : void SetTotalsCache();
329 :
330 : void SetMgr(ReflowCountMgr * aMgr) { mMgr = aMgr; }
331 :
332 0 : uint32_t GetTotal() { return mTotal; }
333 :
334 : protected:
335 : void DisplayTotals(uint32_t aTotal, const char * aTitle);
336 : void DisplayHTMLTotals(uint32_t aTotal, const char * aTitle);
337 :
338 : uint32_t mTotal;
339 : uint32_t mCacheTotal;
340 :
341 : ReflowCountMgr * mMgr; // weak reference (don't delete)
342 : };
343 :
344 : // Counting Class
345 : class IndiReflowCounter {
346 : public:
347 0 : explicit IndiReflowCounter(ReflowCountMgr * aMgr = nullptr)
348 0 : : mFrame(nullptr),
349 : mCount(0),
350 : mMgr(aMgr),
351 : mCounter(aMgr),
352 0 : mHasBeenOutput(false)
353 0 : {}
354 0 : virtual ~IndiReflowCounter() {}
355 :
356 : nsAutoString mName;
357 : nsIFrame * mFrame; // weak reference (don't delete)
358 : int32_t mCount;
359 :
360 : ReflowCountMgr * mMgr; // weak reference (don't delete)
361 :
362 : ReflowCounter mCounter;
363 : bool mHasBeenOutput;
364 :
365 : };
366 :
367 : //--------------------
368 : // Manager Class
369 : //--------------------
370 : class ReflowCountMgr {
371 : public:
372 : ReflowCountMgr();
373 : virtual ~ReflowCountMgr();
374 :
375 : void ClearTotals();
376 : void ClearGrandTotals();
377 : void DisplayTotals(const char * aStr);
378 : void DisplayHTMLTotals(const char * aStr);
379 : void DisplayDiffsInTotals();
380 :
381 : void Add(const char * aName, nsIFrame * aFrame);
382 : ReflowCounter * LookUp(const char * aName);
383 :
384 : void PaintCount(const char *aName, gfxContext* aRenderingContext,
385 : nsPresContext *aPresContext, nsIFrame *aFrame,
386 : const nsPoint &aOffset, uint32_t aColor);
387 :
388 0 : FILE * GetOutFile() { return mFD; }
389 :
390 : PLHashTable * GetIndiFrameHT() { return mIndiFrameCounts; }
391 :
392 28 : void SetPresContext(nsPresContext * aPresContext) { mPresContext = aPresContext; } // weak reference
393 28 : void SetPresShell(nsIPresShell* aPresShell) { mPresShell= aPresShell; } // weak reference
394 :
395 28 : void SetDumpFrameCounts(bool aVal) { mDumpFrameCounts = aVal; }
396 28 : void SetDumpFrameByFrameCounts(bool aVal) { mDumpFrameByFrameCounts = aVal; }
397 28 : void SetPaintFrameCounts(bool aVal) { mPaintFrameByFrameCounts = aVal; }
398 :
399 121 : bool IsPaintingFrameCounts() { return mPaintFrameByFrameCounts; }
400 :
401 : protected:
402 : void DisplayTotals(uint32_t aTotal, uint32_t * aDupArray, char * aTitle);
403 : void DisplayHTMLTotals(uint32_t aTotal, uint32_t * aDupArray, char * aTitle);
404 :
405 : static int RemoveItems(PLHashEntry *he, int i, void *arg);
406 : static int RemoveIndiItems(PLHashEntry *he, int i, void *arg);
407 : void CleanUp();
408 :
409 : // stdout Output Methods
410 : static int DoSingleTotal(PLHashEntry *he, int i, void *arg);
411 : static int DoSingleIndi(PLHashEntry *he, int i, void *arg);
412 :
413 : void DoGrandTotals();
414 : void DoIndiTotalsTree();
415 :
416 : // HTML Output Methods
417 : static int DoSingleHTMLTotal(PLHashEntry *he, int i, void *arg);
418 : void DoGrandHTMLTotals();
419 :
420 : // Zero Out the Totals
421 : static int DoClearTotals(PLHashEntry *he, int i, void *arg);
422 :
423 : // Displays the Diff Totals
424 : static int DoDisplayDiffTotals(PLHashEntry *he, int i, void *arg);
425 :
426 : PLHashTable * mCounts;
427 : PLHashTable * mIndiFrameCounts;
428 : FILE * mFD;
429 :
430 : bool mDumpFrameCounts;
431 : bool mDumpFrameByFrameCounts;
432 : bool mPaintFrameByFrameCounts;
433 :
434 : bool mCycledOnce;
435 :
436 : // Root Frame for Individual Tracking
437 : nsPresContext * mPresContext;
438 : nsIPresShell* mPresShell;
439 :
440 : // ReflowCountMgr gReflowCountMgr;
441 : };
442 : #endif
443 : //========================================================================
444 :
445 : // comment out to hide caret
446 : #define SHOW_CARET
447 :
448 : // The upper bound on the amount of time to spend reflowing, in
449 : // microseconds. When this bound is exceeded and reflow commands are
450 : // still queued up, a reflow event is posted. The idea is for reflow
451 : // to not hog the processor beyond the time specifed in
452 : // gMaxRCProcessingTime. This data member is initialized from the
453 : // layout.reflow.timeslice pref.
454 : #define NS_MAX_REFLOW_TIME 1000000
455 : static int32_t gMaxRCProcessingTime = -1;
456 :
457 : struct nsCallbackEventRequest
458 : {
459 : nsIReflowCallback* callback;
460 : nsCallbackEventRequest* next;
461 : };
462 :
463 : // ----------------------------------------------------------------------------
464 : #define ASSERT_REFLOW_SCHEDULED_STATE() \
465 : NS_ASSERTION(ObservingLayoutFlushes() == \
466 : GetPresContext()->RefreshDriver()-> \
467 : IsLayoutFlushObserver(this), "Unexpected state")
468 :
469 : class nsAutoCauseReflowNotifier
470 : {
471 : public:
472 830 : explicit nsAutoCauseReflowNotifier(PresShell* aShell)
473 830 : : mShell(aShell)
474 : {
475 830 : mShell->WillCauseReflow();
476 830 : }
477 830 : ~nsAutoCauseReflowNotifier()
478 830 : {
479 : // This check should not be needed. Currently the only place that seem
480 : // to need it is the code that deals with bug 337586.
481 830 : if (!mShell->mHaveShutDown) {
482 830 : mShell->DidCauseReflow();
483 : }
484 : else {
485 0 : nsContentUtils::RemoveScriptBlocker();
486 : }
487 830 : }
488 :
489 : PresShell* mShell;
490 : };
491 :
492 10 : class MOZ_STACK_CLASS nsPresShellEventCB : public EventDispatchingCallback
493 : {
494 : public:
495 10 : explicit nsPresShellEventCB(PresShell* aPresShell) : mPresShell(aPresShell) {}
496 :
497 5 : virtual void HandleEvent(EventChainPostVisitor& aVisitor) override
498 : {
499 5 : if (aVisitor.mPresContext && aVisitor.mEvent->mClass != eBasicEventClass) {
500 10 : if (aVisitor.mEvent->mMessage == eMouseDown ||
501 5 : aVisitor.mEvent->mMessage == eMouseUp) {
502 : // Mouse-up and mouse-down events call nsFrame::HandlePress/Release
503 : // which call GetContentOffsetsFromPoint which requires up-to-date layout.
504 : // Bring layout up-to-date now so that GetCurrentEventFrame() below
505 : // will return a real frame and we don't have to worry about
506 : // destroying it by flushing later.
507 0 : mPresShell->FlushPendingNotifications(FlushType::Layout);
508 5 : } else if (aVisitor.mEvent->mMessage == eWheel &&
509 0 : aVisitor.mEventStatus != nsEventStatus_eConsumeNoDefault) {
510 0 : nsIFrame* frame = mPresShell->GetCurrentEventFrame();
511 0 : if (frame) {
512 : // chrome (including addons) should be able to know if content
513 : // handles both D3E "wheel" event and legacy mouse scroll events.
514 : // We should dispatch legacy mouse events before dispatching the
515 : // "wheel" event into system group.
516 : RefPtr<EventStateManager> esm =
517 0 : aVisitor.mPresContext->EventStateManager();
518 0 : esm->DispatchLegacyMouseScrollEvents(frame,
519 0 : aVisitor.mEvent->AsWheelEvent(),
520 0 : &aVisitor.mEventStatus);
521 : }
522 : }
523 5 : nsIFrame* frame = mPresShell->GetCurrentEventFrame();
524 5 : if (!frame &&
525 0 : (aVisitor.mEvent->mMessage == eMouseUp ||
526 0 : aVisitor.mEvent->mMessage == eTouchEnd)) {
527 : // Redirect BUTTON_UP and TOUCH_END events to the root frame to ensure
528 : // that capturing is released.
529 0 : frame = mPresShell->GetRootFrame();
530 : }
531 5 : if (frame) {
532 10 : frame->HandleEvent(aVisitor.mPresContext,
533 5 : aVisitor.mEvent->AsGUIEvent(),
534 10 : &aVisitor.mEventStatus);
535 : }
536 : }
537 5 : }
538 :
539 : RefPtr<PresShell> mPresShell;
540 : };
541 :
542 9 : class nsBeforeFirstPaintDispatcher : public Runnable
543 : {
544 : public:
545 3 : explicit nsBeforeFirstPaintDispatcher(nsIDocument* aDocument)
546 3 : : mozilla::Runnable("nsBeforeFirstPaintDispatcher")
547 3 : , mDocument(aDocument)
548 : {
549 3 : }
550 :
551 : // Fires the "before-first-paint" event so that interested parties (right now, the
552 : // mobile browser) are aware of it.
553 3 : NS_IMETHOD Run() override
554 : {
555 : nsCOMPtr<nsIObserverService> observerService =
556 6 : mozilla::services::GetObserverService();
557 3 : if (observerService) {
558 3 : observerService->NotifyObservers(mDocument, "before-first-paint",
559 3 : nullptr);
560 : }
561 6 : return NS_OK;
562 : }
563 :
564 : private:
565 : nsCOMPtr<nsIDocument> mDocument;
566 : };
567 :
568 : bool PresShell::sDisableNonTestMouseEvents = false;
569 :
570 : mozilla::LazyLogModule PresShell::gLog("PresShell");
571 :
572 : mozilla::TimeStamp PresShell::sLastInputCreated;
573 : mozilla::TimeStamp PresShell::sLastInputProcessed;
574 :
575 : #ifdef DEBUG
576 : static void
577 836 : VerifyStyleTree(nsPresContext* aPresContext, nsFrameManager* aFrameManager)
578 : {
579 836 : if (nsFrame::GetVerifyStyleTreeEnable()) {
580 0 : if (aPresContext->RestyleManager()->IsServo()) {
581 0 : NS_ERROR("stylo: cannot verify style tree with a ServoRestyleManager");
582 0 : return;
583 : }
584 0 : nsIFrame* rootFrame = aFrameManager->GetRootFrame();
585 0 : aPresContext->RestyleManager()->AsGecko()->DebugVerifyStyleTree(rootFrame);
586 : }
587 : }
588 : #define VERIFY_STYLE_TREE ::VerifyStyleTree(mPresContext, mFrameConstructor)
589 : #else
590 : #define VERIFY_STYLE_TREE
591 : #endif
592 :
593 : static bool gVerifyReflowEnabled;
594 :
595 : bool
596 48 : nsIPresShell::GetVerifyReflowEnable()
597 : {
598 : #ifdef DEBUG
599 : static bool firstTime = true;
600 48 : if (firstTime) {
601 2 : firstTime = false;
602 2 : char* flags = PR_GetEnv("GECKO_VERIFY_REFLOW_FLAGS");
603 2 : if (flags) {
604 0 : bool error = false;
605 :
606 : for (;;) {
607 0 : char* comma = PL_strchr(flags, ',');
608 0 : if (comma)
609 0 : *comma = '\0';
610 :
611 0 : bool found = false;
612 0 : const VerifyReflowFlags* flag = gFlags;
613 0 : const VerifyReflowFlags* limit = gFlags + NUM_VERIFY_REFLOW_FLAGS;
614 0 : while (flag < limit) {
615 0 : if (PL_strcasecmp(flag->name, flags) == 0) {
616 0 : gVerifyReflowFlags |= flag->bit;
617 0 : found = true;
618 0 : break;
619 : }
620 0 : ++flag;
621 : }
622 :
623 0 : if (! found)
624 0 : error = true;
625 :
626 0 : if (! comma)
627 0 : break;
628 :
629 0 : *comma = ',';
630 0 : flags = comma + 1;
631 0 : }
632 :
633 0 : if (error)
634 0 : ShowVerifyReflowFlags();
635 : }
636 :
637 2 : if (VERIFY_REFLOW_ON & gVerifyReflowFlags) {
638 0 : gVerifyReflowEnabled = true;
639 :
640 0 : printf("Note: verifyreflow is enabled");
641 0 : if (VERIFY_REFLOW_NOISY & gVerifyReflowFlags) {
642 0 : printf(" (noisy)");
643 : }
644 0 : if (VERIFY_REFLOW_ALL & gVerifyReflowFlags) {
645 0 : printf(" (all)");
646 : }
647 0 : if (VERIFY_REFLOW_DUMP_COMMANDS & gVerifyReflowFlags) {
648 0 : printf(" (show reflow commands)");
649 : }
650 0 : if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) {
651 0 : printf(" (noisy reflow commands)");
652 0 : if (VERIFY_REFLOW_REALLY_NOISY_RC & gVerifyReflowFlags) {
653 0 : printf(" (REALLY noisy reflow commands)");
654 : }
655 : }
656 0 : printf("\n");
657 : }
658 : }
659 : #endif
660 48 : return gVerifyReflowEnabled;
661 : }
662 :
663 : void
664 0 : nsIPresShell::SetVerifyReflowEnable(bool aEnabled)
665 : {
666 0 : gVerifyReflowEnabled = aEnabled;
667 0 : }
668 :
669 : /* virtual */ void
670 0 : nsIPresShell::AddAutoWeakFrameExternal(AutoWeakFrame* aWeakFrame)
671 : {
672 0 : AddAutoWeakFrameInternal(aWeakFrame);
673 0 : }
674 :
675 : void
676 118 : nsIPresShell::AddAutoWeakFrameInternal(AutoWeakFrame* aWeakFrame)
677 : {
678 118 : if (aWeakFrame->GetFrame()) {
679 118 : aWeakFrame->GetFrame()->AddStateBits(NS_FRAME_EXTERNAL_REFERENCE);
680 : }
681 118 : aWeakFrame->SetPreviousWeakFrame(mAutoWeakFrames);
682 118 : mAutoWeakFrames = aWeakFrame;
683 118 : }
684 :
685 : /* virtual */ void
686 0 : nsIPresShell::AddWeakFrameExternal(WeakFrame* aWeakFrame)
687 : {
688 0 : AddWeakFrameInternal(aWeakFrame);
689 0 : }
690 :
691 : void
692 41 : nsIPresShell::AddWeakFrameInternal(WeakFrame* aWeakFrame)
693 : {
694 41 : if (aWeakFrame->GetFrame()) {
695 41 : aWeakFrame->GetFrame()->AddStateBits(NS_FRAME_EXTERNAL_REFERENCE);
696 : }
697 41 : MOZ_ASSERT(!mWeakFrames.GetEntry(aWeakFrame));
698 41 : mWeakFrames.PutEntry(aWeakFrame);
699 41 : }
700 :
701 : /* virtual */ void
702 0 : nsIPresShell::RemoveAutoWeakFrameExternal(AutoWeakFrame* aWeakFrame)
703 : {
704 0 : RemoveAutoWeakFrameInternal(aWeakFrame);
705 0 : }
706 :
707 : void
708 118 : nsIPresShell::RemoveAutoWeakFrameInternal(AutoWeakFrame* aWeakFrame)
709 : {
710 118 : if (mAutoWeakFrames == aWeakFrame) {
711 118 : mAutoWeakFrames = aWeakFrame->GetPreviousWeakFrame();
712 118 : return;
713 : }
714 0 : AutoWeakFrame* nextWeak = mAutoWeakFrames;
715 0 : while (nextWeak && nextWeak->GetPreviousWeakFrame() != aWeakFrame) {
716 0 : nextWeak = nextWeak->GetPreviousWeakFrame();
717 : }
718 0 : if (nextWeak) {
719 0 : nextWeak->SetPreviousWeakFrame(aWeakFrame->GetPreviousWeakFrame());
720 : }
721 : }
722 :
723 : /* virtual */ void
724 0 : nsIPresShell::RemoveWeakFrameExternal(WeakFrame* aWeakFrame)
725 : {
726 0 : RemoveWeakFrameInternal(aWeakFrame);
727 0 : }
728 :
729 : void
730 41 : nsIPresShell::RemoveWeakFrameInternal(WeakFrame* aWeakFrame)
731 : {
732 41 : MOZ_ASSERT(mWeakFrames.GetEntry(aWeakFrame));
733 41 : mWeakFrames.RemoveEntry(aWeakFrame);
734 41 : }
735 :
736 : already_AddRefed<nsFrameSelection>
737 4 : nsIPresShell::FrameSelection()
738 : {
739 8 : RefPtr<nsFrameSelection> ret = mSelection;
740 8 : return ret.forget();
741 : }
742 :
743 : //----------------------------------------------------------------------
744 :
745 : static bool sSynthMouseMove = true;
746 : static uint32_t sNextPresShellId;
747 : static bool sPointerEventEnabled = true;
748 : static bool sPointerEventImplicitCapture = false;
749 : static bool sAccessibleCaretEnabled = false;
750 : static bool sAccessibleCaretOnTouch = false;
751 :
752 : /* static */ bool
753 38 : PresShell::AccessibleCaretEnabled(nsIDocShell* aDocShell)
754 : {
755 : static bool initialized = false;
756 38 : if (!initialized) {
757 2 : Preferences::AddBoolVarCache(&sAccessibleCaretEnabled, "layout.accessiblecaret.enabled");
758 2 : Preferences::AddBoolVarCache(&sAccessibleCaretOnTouch, "layout.accessiblecaret.enabled_on_touch");
759 2 : initialized = true;
760 : }
761 : // If the pref forces it on, then enable it.
762 38 : if (sAccessibleCaretEnabled) {
763 0 : return true;
764 : }
765 : // If the touch pref is on, and touch events are enabled (this depends
766 : // on the specific device running), then enable it.
767 38 : if (sAccessibleCaretOnTouch && dom::TouchEvent::PrefEnabled(aDocShell)) {
768 0 : return true;
769 : }
770 : // Otherwise, disabled.
771 38 : return false;
772 : }
773 :
774 28 : nsIPresShell::nsIPresShell()
775 : : mFrameConstructor(nullptr)
776 : , mViewManager(nullptr)
777 : , mFrameManager(nullptr)
778 : #ifdef ACCESSIBILITY
779 : , mDocAccessible(nullptr)
780 : #endif
781 : #ifdef DEBUG
782 : , mDrawEventTargetFrame(nullptr)
783 : #endif
784 : , mPaintCount(0)
785 : , mAutoWeakFrames(nullptr)
786 : , mCanvasBackgroundColor(NS_RGBA(0,0,0,0))
787 : , mSelectionFlags(0)
788 : , mRenderFlags(0)
789 : , mDidInitialize(false)
790 : , mIsDestroying(false)
791 : , mIsReflowing(false)
792 : , mPaintingSuppressed(false)
793 : , mIsActive(false)
794 : , mFrozen(false)
795 : , mIsFirstPaint(false)
796 : , mObservesMutationsForPrint(false)
797 : , mSuppressInterruptibleReflows(false)
798 : , mScrollPositionClampingScrollPortSizeSet(false)
799 : , mNeedLayoutFlush(true)
800 : , mNeedStyleFlush(true)
801 : , mObservingStyleFlushes(false)
802 : , mObservingLayoutFlushes(false)
803 : , mNeedThrottledAnimationFlush(true)
804 : , mPresShellId(0)
805 : , mFontSizeInflationEmPerLine(0)
806 : , mFontSizeInflationMinTwips(0)
807 : , mFontSizeInflationLineThreshold(0)
808 : , mFontSizeInflationForceEnabled(false)
809 : , mFontSizeInflationDisabledInMasterProcess(false)
810 : , mFontSizeInflationEnabled(false)
811 : , mFontSizeInflationEnabledIsDirty(false)
812 : , mPaintingIsFrozen(false)
813 : , mIsNeverPainting(false)
814 28 : , mInFlush(false)
815 28 : {}
816 :
817 28 : PresShell::PresShell()
818 : : mCaretEnabled(false)
819 : #ifdef DEBUG
820 : , mInVerifyReflow(false)
821 : , mCurrentReflowRoot(nullptr)
822 : , mUpdateCount(0)
823 : #endif
824 : #ifdef MOZ_REFLOW_PERF
825 : , mReflowCountMgr(nullptr)
826 : #endif
827 : , mMouseLocation(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE)
828 : , mCurrentEventFrame(nullptr)
829 : , mFirstCallbackEventRequest(nullptr)
830 : , mLastCallbackEventRequest(nullptr)
831 : , mLastReflowStart(0.0)
832 : , mLastAnchorScrollPositionY(0)
833 : , mAPZFocusSequenceNumber(0)
834 : , mChangeNestCount(0)
835 : , mDocumentLoading(false)
836 : , mIgnoreFrameDestruction(false)
837 : , mHaveShutDown(false)
838 : , mLastRootReflowHadUnconstrainedBSize(false)
839 : , mNoDelayedMouseEvents(false)
840 : , mNoDelayedKeyEvents(false)
841 : , mIsDocumentGone(false)
842 : , mShouldUnsuppressPainting(false)
843 : , mAsyncResizeTimerIsActive(false)
844 : , mInResize(false)
845 : , mApproximateFrameVisibilityVisited(false)
846 : , mNextPaintCompressed(false)
847 : , mHasCSSBackgroundColor(false)
848 : , mScaleToResolution(false)
849 : , mIsLastChromeOnlyEscapeKeyConsumed(false)
850 28 : , mHasReceivedPaintMessage(false)
851 : {
852 : #ifdef MOZ_REFLOW_PERF
853 28 : mReflowCountMgr = new ReflowCountMgr();
854 28 : mReflowCountMgr->SetPresContext(mPresContext);
855 28 : mReflowCountMgr->SetPresShell(this);
856 : #endif
857 28 : mLastOSWake = mLoadBegin = TimeStamp::Now();
858 :
859 28 : mSelectionFlags = nsISelectionDisplay::DISPLAY_TEXT | nsISelectionDisplay::DISPLAY_IMAGES;
860 28 : mIsActive = true;
861 : // FIXME/bug 735029: find a better solution to this problem
862 28 : mIsFirstPaint = true;
863 28 : mPresShellId = sNextPresShellId++;
864 28 : mFrozen = false;
865 28 : mRenderFlags = 0;
866 :
867 28 : mScrollPositionClampingScrollPortSizeSet = false;
868 :
869 : static bool addedSynthMouseMove = false;
870 28 : if (!addedSynthMouseMove) {
871 : Preferences::AddBoolVarCache(&sSynthMouseMove,
872 2 : "layout.reflow.synthMouseMove", true);
873 2 : addedSynthMouseMove = true;
874 : }
875 : static bool addedPointerEventEnabled = false;
876 28 : if (!addedPointerEventEnabled) {
877 : Preferences::AddBoolVarCache(&sPointerEventEnabled,
878 2 : "dom.w3c_pointer_events.enabled", true);
879 2 : addedPointerEventEnabled = true;
880 : }
881 : static bool addedPointerEventImplicitCapture = false;
882 28 : if (!addedPointerEventImplicitCapture) {
883 : Preferences::AddBoolVarCache(&sPointerEventImplicitCapture,
884 : "dom.w3c_pointer_events.implicit_capture",
885 2 : true);
886 2 : addedPointerEventImplicitCapture = true;
887 : }
888 28 : mPaintingIsFrozen = false;
889 28 : mHasCSSBackgroundColor = true;
890 28 : mIsLastChromeOnlyEscapeKeyConsumed = false;
891 28 : mHasReceivedPaintMessage = false;
892 28 : }
893 :
894 9560 : NS_IMPL_ISUPPORTS(PresShell, nsIPresShell, nsIDocumentObserver,
895 : nsISelectionController,
896 : nsISelectionDisplay, nsIObserver, nsISupportsWeakReference,
897 : nsIMutationObserver)
898 :
899 12 : PresShell::~PresShell()
900 : {
901 4 : if (!mHaveShutDown) {
902 0 : NS_NOTREACHED("Someone did not call nsIPresShell::destroy");
903 0 : Destroy();
904 : }
905 :
906 4 : NS_ASSERTION(mCurrentEventContentStack.Count() == 0,
907 : "Huh, event content left on the stack in pres shell dtor!");
908 4 : NS_ASSERTION(mFirstCallbackEventRequest == nullptr &&
909 : mLastCallbackEventRequest == nullptr,
910 : "post-reflow queues not empty. This means we're leaking");
911 :
912 : // Verify that if painting was frozen, but we're being removed from the tree,
913 : // that we now re-enable painting on our refresh driver, since it may need to
914 : // be re-used by another presentation.
915 4 : if (mPaintingIsFrozen) {
916 0 : mPresContext->RefreshDriver()->Thaw();
917 : }
918 :
919 4 : MOZ_ASSERT(mAllocatedPointers.IsEmpty(), "Some pres arena objects were not freed");
920 :
921 4 : mStyleSet->Delete();
922 4 : delete mFrameConstructor;
923 :
924 4 : mCurrentEventContent = nullptr;
925 12 : }
926 :
927 : /**
928 : * Initialize the presentation shell. Create view manager and style
929 : * manager.
930 : * Note this can't be merged into our constructor because caret initialization
931 : * calls AddRef() on us.
932 : */
933 : void
934 28 : PresShell::Init(nsIDocument* aDocument,
935 : nsPresContext* aPresContext,
936 : nsViewManager* aViewManager,
937 : StyleSetHandle aStyleSet)
938 : {
939 28 : NS_PRECONDITION(aDocument, "null ptr");
940 28 : NS_PRECONDITION(aPresContext, "null ptr");
941 28 : NS_PRECONDITION(aViewManager, "null ptr");
942 28 : NS_PRECONDITION(!mDocument, "already initialized");
943 :
944 28 : if (!aDocument || !aPresContext || !aViewManager || mDocument) {
945 0 : return;
946 : }
947 :
948 28 : mDocument = aDocument;
949 28 : mViewManager = aViewManager;
950 :
951 : // mDocument is now set. It might have a display document whose "need layout/
952 : // style" flush flags are not set, but ours will be set. To keep these
953 : // consistent, call the flag setting functions to propagate those flags up
954 : // to the display document.
955 28 : SetNeedLayoutFlush();
956 28 : SetNeedStyleFlush();
957 :
958 : // Create our frame constructor.
959 56 : mFrameConstructor = new nsCSSFrameConstructor(mDocument, this);
960 :
961 28 : mFrameManager = mFrameConstructor;
962 :
963 : // The document viewer owns both view manager and pres shell.
964 28 : mViewManager->SetPresShell(this);
965 :
966 : // Bind the context to the presentation shell.
967 28 : mPresContext = aPresContext;
968 28 : mPresContext->AttachShell(this, aStyleSet->BackendType());
969 :
970 : // Now we can initialize the style set. Make sure to set the member before
971 : // calling Init, since various subroutines need to find the style set off
972 : // the PresContext during initialization.
973 28 : mStyleSet = aStyleSet;
974 28 : mStyleSet->Init(aPresContext, mDocument->BindingManager());
975 :
976 : // Notify our prescontext that it now has a compatibility mode. Note that
977 : // this MUST happen after we set up our style set but before we create any
978 : // frames.
979 28 : mPresContext->CompatibilityModeChanged();
980 :
981 : // Add the preference style sheet.
982 28 : UpdatePreferenceStyles();
983 :
984 28 : if (AccessibleCaretEnabled(mDocument->GetDocShell())) {
985 : // Need to happen before nsFrameSelection has been set up.
986 0 : mAccessibleCaretEventHub = new AccessibleCaretEventHub(this);
987 : }
988 :
989 28 : mSelection = new nsFrameSelection();
990 :
991 56 : RefPtr<nsFrameSelection> frameSelection = mSelection;
992 28 : frameSelection->Init(this, nullptr);
993 :
994 : // Important: this has to happen after the selection has been set up
995 : #ifdef SHOW_CARET
996 : // make the caret
997 28 : mCaret = new nsCaret();
998 28 : mCaret->Init(this);
999 28 : mOriginalCaret = mCaret;
1000 :
1001 : //SetCaretEnabled(true); // make it show in browser windows
1002 : #endif
1003 : //set up selection to be displayed in document
1004 : // Don't enable selection for print media
1005 28 : nsPresContext::nsPresContextType type = aPresContext->Type();
1006 28 : if (type != nsPresContext::eContext_PrintPreview &&
1007 : type != nsPresContext::eContext_Print)
1008 28 : SetDisplaySelection(nsISelectionController::SELECTION_DISABLED);
1009 :
1010 28 : if (gMaxRCProcessingTime == -1) {
1011 2 : gMaxRCProcessingTime =
1012 2 : Preferences::GetInt("layout.reflow.timeslice", NS_MAX_REFLOW_TIME);
1013 : }
1014 :
1015 28 : if (nsStyleSheetService* ss = nsStyleSheetService::GetInstance()) {
1016 28 : ss->RegisterPresShell(this);
1017 : }
1018 :
1019 : {
1020 56 : nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
1021 28 : if (os) {
1022 : #ifdef MOZ_XUL
1023 28 : os->AddObserver(this, "chrome-flush-skin-caches", false);
1024 : #endif
1025 28 : os->AddObserver(this, "memory-pressure", false);
1026 28 : os->AddObserver(this, NS_WIDGET_WAKE_OBSERVER_TOPIC, false);
1027 : }
1028 : }
1029 :
1030 : #ifdef MOZ_REFLOW_PERF
1031 28 : if (mReflowCountMgr) {
1032 : bool paintFrameCounts =
1033 28 : Preferences::GetBool("layout.reflow.showframecounts");
1034 :
1035 : bool dumpFrameCounts =
1036 28 : Preferences::GetBool("layout.reflow.dumpframecounts");
1037 :
1038 : bool dumpFrameByFrameCounts =
1039 28 : Preferences::GetBool("layout.reflow.dumpframebyframecounts");
1040 :
1041 28 : mReflowCountMgr->SetDumpFrameCounts(dumpFrameCounts);
1042 28 : mReflowCountMgr->SetDumpFrameByFrameCounts(dumpFrameByFrameCounts);
1043 28 : mReflowCountMgr->SetPaintFrameCounts(paintFrameCounts);
1044 : }
1045 : #endif
1046 :
1047 28 : if (mDocument->HasAnimationController()) {
1048 21 : nsSMILAnimationController* animCtrl = mDocument->GetAnimationController();
1049 21 : animCtrl->NotifyRefreshDriverCreated(GetPresContext()->RefreshDriver());
1050 : }
1051 :
1052 28 : for (DocumentTimeline* timeline : mDocument->Timelines()) {
1053 0 : timeline->NotifyRefreshDriverCreated(GetPresContext()->RefreshDriver());
1054 : }
1055 :
1056 : // Get our activeness from the docShell.
1057 28 : QueryIsActive();
1058 :
1059 : // Setup our font inflation preferences.
1060 28 : SetupFontInflation();
1061 :
1062 28 : mTouchManager.Init(this, mDocument);
1063 :
1064 28 : if (mPresContext->IsRootContentDocument()) {
1065 3 : mZoomConstraintsClient = new ZoomConstraintsClient();
1066 3 : mZoomConstraintsClient->Init(this, mDocument);
1067 3 : if (gfxPrefs::MetaViewportEnabled() || gfxPrefs::APZAllowZooming()) {
1068 0 : mMobileViewportManager = new MobileViewportManager(this, mDocument);
1069 : }
1070 : }
1071 : }
1072 :
1073 : enum TextPerfLogType {
1074 : eLog_reflow,
1075 : eLog_loaddone,
1076 : eLog_totals
1077 : };
1078 :
1079 : static void
1080 0 : LogTextPerfStats(gfxTextPerfMetrics* aTextPerf,
1081 : PresShell* aPresShell,
1082 : const gfxTextPerfMetrics::TextCounts& aCounts,
1083 : float aTime, TextPerfLogType aLogType, const char* aURL)
1084 : {
1085 0 : LogModule* tpLog = gfxPlatform::GetLog(eGfxLog_textperf);
1086 :
1087 : // ignore XUL contexts unless at debug level
1088 0 : mozilla::LogLevel logLevel = LogLevel::Warning;
1089 0 : if (aCounts.numContentTextRuns == 0) {
1090 0 : logLevel = LogLevel::Debug;
1091 : }
1092 :
1093 0 : if (!MOZ_LOG_TEST(tpLog, logLevel)) {
1094 0 : return;
1095 : }
1096 :
1097 : char prefix[256];
1098 :
1099 0 : switch (aLogType) {
1100 : case eLog_reflow:
1101 0 : SprintfLiteral(prefix, "(textperf-reflow) %p time-ms: %7.0f", aPresShell, aTime);
1102 0 : break;
1103 : case eLog_loaddone:
1104 0 : SprintfLiteral(prefix, "(textperf-loaddone) %p time-ms: %7.0f", aPresShell, aTime);
1105 0 : break;
1106 : default:
1107 0 : MOZ_ASSERT(aLogType == eLog_totals, "unknown textperf log type");
1108 0 : SprintfLiteral(prefix, "(textperf-totals) %p", aPresShell);
1109 : }
1110 :
1111 0 : double hitRatio = 0.0;
1112 0 : uint32_t lookups = aCounts.wordCacheHit + aCounts.wordCacheMiss;
1113 0 : if (lookups) {
1114 0 : hitRatio = double(aCounts.wordCacheHit) / double(lookups);
1115 : }
1116 :
1117 0 : if (aLogType == eLog_loaddone) {
1118 0 : MOZ_LOG(tpLog, logLevel,
1119 : ("%s reflow: %d chars: %d "
1120 : "[%s] "
1121 : "content-textruns: %d chrome-textruns: %d "
1122 : "max-textrun-len: %d "
1123 : "word-cache-lookups: %d word-cache-hit-ratio: %4.3f "
1124 : "word-cache-space: %d word-cache-long: %d "
1125 : "pref-fallbacks: %d system-fallbacks: %d "
1126 : "textruns-const: %d textruns-destr: %d "
1127 : "generic-lookups: %d "
1128 : "cumulative-textruns-destr: %d\n",
1129 : prefix, aTextPerf->reflowCount, aCounts.numChars,
1130 : (aURL ? aURL : ""),
1131 : aCounts.numContentTextRuns, aCounts.numChromeTextRuns,
1132 : aCounts.maxTextRunLen,
1133 : lookups, hitRatio,
1134 : aCounts.wordCacheSpaceRules, aCounts.wordCacheLong,
1135 : aCounts.fallbackPrefs, aCounts.fallbackSystem,
1136 : aCounts.textrunConst, aCounts.textrunDestr,
1137 : aCounts.genericLookups,
1138 : aTextPerf->cumulative.textrunDestr));
1139 : } else {
1140 0 : MOZ_LOG(tpLog, logLevel,
1141 : ("%s reflow: %d chars: %d "
1142 : "content-textruns: %d chrome-textruns: %d "
1143 : "max-textrun-len: %d "
1144 : "word-cache-lookups: %d word-cache-hit-ratio: %4.3f "
1145 : "word-cache-space: %d word-cache-long: %d "
1146 : "pref-fallbacks: %d system-fallbacks: %d "
1147 : "textruns-const: %d textruns-destr: %d "
1148 : "generic-lookups: %d "
1149 : "cumulative-textruns-destr: %d\n",
1150 : prefix, aTextPerf->reflowCount, aCounts.numChars,
1151 : aCounts.numContentTextRuns, aCounts.numChromeTextRuns,
1152 : aCounts.maxTextRunLen,
1153 : lookups, hitRatio,
1154 : aCounts.wordCacheSpaceRules, aCounts.wordCacheLong,
1155 : aCounts.fallbackPrefs, aCounts.fallbackSystem,
1156 : aCounts.textrunConst, aCounts.textrunDestr,
1157 : aCounts.genericLookups,
1158 : aTextPerf->cumulative.textrunDestr));
1159 : }
1160 : }
1161 :
1162 : void
1163 4 : PresShell::Destroy()
1164 : {
1165 : // Do not add code before this line please!
1166 4 : if (mHaveShutDown) {
1167 : // If we never got a root frame the root view could exist now still.
1168 : // In that case assert that it has no children and no frame.
1169 0 : MOZ_RELEASE_ASSERT(!mViewManager || !mViewManager->GetRootView() ||
1170 : (!mViewManager->GetRootView()->GetFrame() &&
1171 : !mViewManager->GetRootView()->GetFirstChild()));
1172 0 : MOZ_RELEASE_ASSERT(!mFrameConstructor || !mFrameConstructor->GetRootFrame());
1173 0 : return;
1174 : }
1175 :
1176 4 : NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
1177 : "destroy called on presshell while scripts not blocked");
1178 :
1179 : // dump out cumulative text perf metrics
1180 : gfxTextPerfMetrics* tp;
1181 4 : if (mPresContext && (tp = mPresContext->GetTextPerfMetrics())) {
1182 0 : tp->Accumulate();
1183 0 : if (tp->cumulative.numChars > 0) {
1184 0 : LogTextPerfStats(tp, this, tp->cumulative, 0.0, eLog_totals, nullptr);
1185 : }
1186 : }
1187 4 : if (mPresContext) {
1188 4 : const bool mayFlushUserFontSet = false;
1189 4 : gfxUserFontSet* fs = mPresContext->GetUserFontSet(mayFlushUserFontSet);
1190 4 : if (fs) {
1191 : uint32_t fontCount;
1192 : uint64_t fontSize;
1193 0 : fs->GetLoadStatistics(fontCount, fontSize);
1194 0 : Telemetry::Accumulate(Telemetry::WEBFONT_PER_PAGE, fontCount);
1195 0 : Telemetry::Accumulate(Telemetry::WEBFONT_SIZE_PER_PAGE,
1196 0 : uint32_t(fontSize/1024));
1197 : } else {
1198 4 : Telemetry::Accumulate(Telemetry::WEBFONT_PER_PAGE, 0);
1199 4 : Telemetry::Accumulate(Telemetry::WEBFONT_SIZE_PER_PAGE, 0);
1200 : }
1201 : }
1202 :
1203 : #ifdef MOZ_REFLOW_PERF
1204 4 : DumpReflows();
1205 4 : if (mReflowCountMgr) {
1206 4 : delete mReflowCountMgr;
1207 4 : mReflowCountMgr = nullptr;
1208 : }
1209 : #endif
1210 :
1211 4 : if (mZoomConstraintsClient) {
1212 2 : mZoomConstraintsClient->Destroy();
1213 2 : mZoomConstraintsClient = nullptr;
1214 : }
1215 4 : if (mMobileViewportManager) {
1216 0 : mMobileViewportManager->Destroy();
1217 0 : mMobileViewportManager = nullptr;
1218 : }
1219 :
1220 : #ifdef ACCESSIBILITY
1221 4 : if (mDocAccessible) {
1222 : #ifdef DEBUG
1223 0 : if (a11y::logging::IsEnabled(a11y::logging::eDocDestroy))
1224 0 : a11y::logging::DocDestroy("presshell destroyed", mDocument);
1225 : #endif
1226 :
1227 0 : mDocAccessible->Shutdown();
1228 0 : mDocAccessible = nullptr;
1229 : }
1230 : #endif // ACCESSIBILITY
1231 :
1232 4 : MaybeReleaseCapturingContent();
1233 :
1234 4 : if (gKeyDownTarget && gKeyDownTarget->OwnerDoc() == mDocument) {
1235 0 : NS_RELEASE(gKeyDownTarget);
1236 : }
1237 :
1238 4 : if (mContentToScrollTo) {
1239 0 : mContentToScrollTo->DeleteProperty(nsGkAtoms::scrolling);
1240 0 : mContentToScrollTo = nullptr;
1241 : }
1242 :
1243 4 : if (mPresContext) {
1244 : // We need to notify the destroying the nsPresContext to ESM for
1245 : // suppressing to use from ESM.
1246 4 : mPresContext->EventStateManager()->NotifyDestroyPresContext(mPresContext);
1247 : }
1248 :
1249 4 : if (nsStyleSheetService* ss = nsStyleSheetService::GetInstance()) {
1250 4 : ss->UnregisterPresShell(this);
1251 : }
1252 :
1253 : {
1254 8 : nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
1255 4 : if (os) {
1256 : #ifdef MOZ_XUL
1257 4 : os->RemoveObserver(this, "chrome-flush-skin-caches");
1258 : #endif
1259 4 : os->RemoveObserver(this, "memory-pressure");
1260 4 : os->RemoveObserver(this, NS_WIDGET_WAKE_OBSERVER_TOPIC);
1261 : }
1262 : }
1263 :
1264 : // If our paint suppression timer is still active, kill it.
1265 4 : if (mPaintSuppressionTimer) {
1266 0 : mPaintSuppressionTimer->Cancel();
1267 0 : mPaintSuppressionTimer = nullptr;
1268 : }
1269 :
1270 : // Same for our reflow continuation timer
1271 4 : if (mReflowContinueTimer) {
1272 0 : mReflowContinueTimer->Cancel();
1273 0 : mReflowContinueTimer = nullptr;
1274 : }
1275 :
1276 4 : if (mDelayedPaintTimer) {
1277 0 : mDelayedPaintTimer->Cancel();
1278 0 : mDelayedPaintTimer = nullptr;
1279 : }
1280 :
1281 4 : mSynthMouseMoveEvent.Revoke();
1282 :
1283 4 : mUpdateApproximateFrameVisibilityEvent.Revoke();
1284 :
1285 4 : ClearApproximatelyVisibleFramesList(Some(OnNonvisible::DISCARD_IMAGES));
1286 :
1287 4 : if (mCaret) {
1288 4 : mCaret->Terminate();
1289 4 : mCaret = nullptr;
1290 : }
1291 :
1292 4 : if (mSelection) {
1293 8 : RefPtr<nsFrameSelection> frameSelection = mSelection;
1294 4 : frameSelection->DisconnectFromPresShell();
1295 : }
1296 :
1297 4 : if (mAccessibleCaretEventHub) {
1298 0 : mAccessibleCaretEventHub->Terminate();
1299 0 : mAccessibleCaretEventHub = nullptr;
1300 : }
1301 :
1302 : // release our pref style sheet, if we have one still
1303 4 : RemovePreferenceStyles();
1304 :
1305 4 : mIsDestroying = true;
1306 :
1307 : // We can't release all the event content in
1308 : // mCurrentEventContentStack here since there might be code on the
1309 : // stack that will release the event content too. Double release
1310 : // bad!
1311 :
1312 : // The frames will be torn down, so remove them from the current
1313 : // event frame stack (since they'd be dangling references if we'd
1314 : // leave them in) and null out the mCurrentEventFrame pointer as
1315 : // well.
1316 :
1317 4 : mCurrentEventFrame = nullptr;
1318 :
1319 4 : int32_t i, count = mCurrentEventFrameStack.Length();
1320 4 : for (i = 0; i < count; i++) {
1321 0 : mCurrentEventFrameStack[i] = nullptr;
1322 : }
1323 :
1324 4 : mFramesToDirty.Clear();
1325 :
1326 4 : if (mViewManager) {
1327 : // Clear the view manager's weak pointer back to |this| in case it
1328 : // was leaked.
1329 4 : mViewManager->SetPresShell(nullptr);
1330 4 : mViewManager = nullptr;
1331 : }
1332 :
1333 : // mFrameArena will be destroyed soon. Clear out any ArenaRefPtrs
1334 : // pointing to objects in the arena now. This is done:
1335 : //
1336 : // (a) before mFrameArena's destructor runs so that our
1337 : // mAllocatedPointers becomes empty and doesn't trip the assertion
1338 : // in ~PresShell,
1339 : // (b) before the mPresContext->DetachShell() below, so
1340 : // that when we clear the ArenaRefPtrs they'll still be able to
1341 : // get back to this PresShell to deregister themselves (e.g. note
1342 : // how nsStyleContext::Arena returns the PresShell got from its
1343 : // rule node's nsPresContext, which would return null if we'd already
1344 : // called mPresContext->DetachShell()), and
1345 : // (c) before the mStyleSet->BeginShutdown() call just below, so that
1346 : // the nsStyleContexts don't complain they're being destroyed later
1347 : // than the rule tree is.
1348 4 : mFrameArena.ClearArenaRefPtrs();
1349 :
1350 4 : mStyleSet->BeginShutdown();
1351 4 : nsRefreshDriver* rd = GetPresContext()->RefreshDriver();
1352 :
1353 : // This shell must be removed from the document before the frame
1354 : // hierarchy is torn down to avoid finding deleted frames through
1355 : // this presshell while the frames are being torn down
1356 4 : if (mDocument) {
1357 4 : NS_ASSERTION(mDocument->GetShell() == this, "Wrong shell?");
1358 4 : mDocument->DeleteShell();
1359 :
1360 4 : if (mDocument->HasAnimationController()) {
1361 0 : mDocument->GetAnimationController()->NotifyRefreshDriverDestroying(rd);
1362 : }
1363 4 : for (DocumentTimeline* timeline : mDocument->Timelines()) {
1364 0 : timeline->NotifyRefreshDriverDestroying(rd);
1365 : }
1366 : }
1367 :
1368 4 : if (mPresContext) {
1369 4 : mPresContext->AnimationManager()->ClearEventQueue();
1370 4 : mPresContext->TransitionManager()->ClearEventQueue();
1371 : }
1372 :
1373 : // Revoke any pending events. We need to do this and cancel pending reflows
1374 : // before we destroy the frame manager, since apparently frame destruction
1375 : // sometimes spins the event queue when plug-ins are involved(!).
1376 4 : rd->RemoveLayoutFlushObserver(this);
1377 :
1378 4 : if (rd->GetPresContext() == GetPresContext()) {
1379 4 : rd->RevokeViewManagerFlush();
1380 : }
1381 :
1382 4 : mResizeEvent.Revoke();
1383 4 : if (mAsyncResizeTimerIsActive) {
1384 0 : mAsyncResizeEventTimer->Cancel();
1385 0 : mAsyncResizeTimerIsActive = false;
1386 : }
1387 :
1388 4 : CancelAllPendingReflows();
1389 4 : CancelPostedReflowCallbacks();
1390 :
1391 : // Destroy the frame manager. This will destroy the frame hierarchy
1392 4 : mFrameConstructor->WillDestroyFrameTree();
1393 :
1394 4 : NS_WARNING_ASSERTION(!mAutoWeakFrames && mWeakFrames.IsEmpty(),
1395 : "Weak frames alive after destroying FrameManager");
1396 4 : while (mAutoWeakFrames) {
1397 0 : mAutoWeakFrames->Clear(this);
1398 : }
1399 8 : nsTArray<WeakFrame*> toRemove(mWeakFrames.Count());
1400 4 : for (auto iter = mWeakFrames.Iter(); !iter.Done(); iter.Next()) {
1401 0 : toRemove.AppendElement(iter.Get()->GetKey());
1402 : }
1403 4 : for (WeakFrame* weakFrame : toRemove) {
1404 0 : weakFrame->Clear(this);
1405 : }
1406 :
1407 : // Let the style set do its cleanup.
1408 4 : mStyleSet->Shutdown();
1409 :
1410 4 : if (mPresContext) {
1411 : // We hold a reference to the pres context, and it holds a weak link back
1412 : // to us. To avoid the pres context having a dangling reference, set its
1413 : // pres shell to nullptr
1414 4 : mPresContext->DetachShell();
1415 :
1416 : // Clear the link handler (weak reference) as well
1417 4 : mPresContext->SetLinkHandler(nullptr);
1418 : }
1419 :
1420 4 : mHaveShutDown = true;
1421 :
1422 4 : mTouchManager.Destroy();
1423 : }
1424 :
1425 : nsRefreshDriver*
1426 56 : nsIPresShell::GetRefreshDriver() const
1427 : {
1428 56 : return mPresContext ? mPresContext->RefreshDriver() : nullptr;
1429 : }
1430 :
1431 : void
1432 3 : nsIPresShell::SetAuthorStyleDisabled(bool aStyleDisabled)
1433 : {
1434 3 : if (aStyleDisabled != mStyleSet->GetAuthorStyleDisabled()) {
1435 0 : mStyleSet->SetAuthorStyleDisabled(aStyleDisabled);
1436 0 : RestyleForCSSRuleChanges();
1437 :
1438 : nsCOMPtr<nsIObserverService> observerService =
1439 0 : mozilla::services::GetObserverService();
1440 0 : if (observerService) {
1441 0 : observerService->NotifyObservers(mDocument,
1442 : "author-style-disabled-changed",
1443 0 : nullptr);
1444 : }
1445 : }
1446 3 : }
1447 :
1448 : bool
1449 7 : nsIPresShell::GetAuthorStyleDisabled() const
1450 : {
1451 7 : return mStyleSet->GetAuthorStyleDisabled();
1452 : }
1453 :
1454 : void
1455 28 : PresShell::UpdatePreferenceStyles()
1456 : {
1457 28 : if (!mDocument) {
1458 25 : return;
1459 : }
1460 :
1461 : // If the document doesn't have a window there's no need to notify
1462 : // its presshell about changes to preferences since the document is
1463 : // in a state where it doesn't matter any more (see
1464 : // nsDocumentViewer::Close()).
1465 28 : if (!mDocument->GetWindow()) {
1466 21 : return;
1467 : }
1468 :
1469 : // Documents in chrome shells do not have any preference style rules applied.
1470 7 : if (nsContentUtils::IsInChromeDocshell(mDocument)) {
1471 4 : return;
1472 : }
1473 :
1474 : // We need to pass in mPresContext so that if the nsLayoutStylesheetCache
1475 : // needs to recreate the pref style sheet, it has somewhere to get the
1476 : // pref styling information from. All pres contexts for
1477 : // IsChromeOriginImage() == false will have the same pref styling information,
1478 : // and similarly for IsChromeOriginImage() == true, so it doesn't really
1479 : // matter which pres context we pass in when it does need to be recreated.
1480 : // (See nsPresContext::GetDocumentColorPreferences for how whether we
1481 : // are a chrome origin image affects some pref styling information.)
1482 3 : auto cache = nsLayoutStylesheetCache::For(mStyleSet->BackendType());
1483 : RefPtr<StyleSheet> newPrefSheet =
1484 3 : mPresContext->IsChromeOriginImage() ?
1485 0 : cache->ChromePreferenceSheet(mPresContext) :
1486 6 : cache->ContentPreferenceSheet(mPresContext);
1487 :
1488 3 : if (mPrefStyleSheet == newPrefSheet) {
1489 0 : return;
1490 : }
1491 :
1492 3 : mStyleSet->BeginUpdate();
1493 :
1494 3 : RemovePreferenceStyles();
1495 :
1496 3 : mStyleSet->AppendStyleSheet(SheetType::User, newPrefSheet);
1497 3 : mPrefStyleSheet = newPrefSheet;
1498 :
1499 3 : mStyleSet->EndUpdate();
1500 : }
1501 :
1502 : void
1503 7 : PresShell::RemovePreferenceStyles()
1504 : {
1505 7 : if (mPrefStyleSheet) {
1506 2 : mStyleSet->RemoveStyleSheet(SheetType::User, mPrefStyleSheet);
1507 2 : mPrefStyleSheet = nullptr;
1508 : }
1509 7 : }
1510 :
1511 : void
1512 0 : PresShell::AddUserSheet(StyleSheet* aSheet)
1513 : {
1514 : // Make sure this does what nsDocumentViewer::CreateStyleSet does wrt
1515 : // ordering. We want this new sheet to come after all the existing stylesheet
1516 : // service sheets, but before other user sheets; see nsIStyleSheetService.idl
1517 : // for the ordering. Just remove and readd all the nsStyleSheetService
1518 : // sheets.
1519 : nsCOMPtr<nsIStyleSheetService> dummy =
1520 0 : do_GetService(NS_STYLESHEETSERVICE_CONTRACTID);
1521 :
1522 0 : mStyleSet->BeginUpdate();
1523 :
1524 0 : nsStyleSheetService* sheetService = nsStyleSheetService::gInstance;
1525 : nsTArray<RefPtr<StyleSheet>>& userSheets =
1526 0 : *sheetService->UserStyleSheets(mStyleSet->BackendType());
1527 : // Iterate forwards when removing so the searches for RemoveStyleSheet are as
1528 : // short as possible.
1529 0 : for (StyleSheet* sheet : userSheets) {
1530 0 : mStyleSet->RemoveStyleSheet(SheetType::User, sheet);
1531 : }
1532 :
1533 : // Now iterate backwards, so that the order of userSheets will be the same as
1534 : // the order of sheets from it in the style set.
1535 0 : for (StyleSheet* sheet : Reversed(userSheets)) {
1536 0 : mStyleSet->PrependStyleSheet(SheetType::User, sheet);
1537 : }
1538 :
1539 0 : mStyleSet->EndUpdate();
1540 0 : RestyleForCSSRuleChanges();
1541 0 : }
1542 :
1543 : void
1544 0 : PresShell::AddAgentSheet(StyleSheet* aSheet)
1545 : {
1546 : // Make sure this does what nsDocumentViewer::CreateStyleSet does
1547 : // wrt ordering.
1548 0 : mStyleSet->AppendStyleSheet(SheetType::Agent, aSheet);
1549 0 : RestyleForCSSRuleChanges();
1550 0 : }
1551 :
1552 : void
1553 0 : PresShell::AddAuthorSheet(StyleSheet* aSheet)
1554 : {
1555 : // Document specific "additional" Author sheets should be stronger than the
1556 : // ones added with the StyleSheetService.
1557 : StyleSheet* firstAuthorSheet =
1558 0 : mDocument->GetFirstAdditionalAuthorSheet();
1559 0 : if (firstAuthorSheet) {
1560 0 : mStyleSet->InsertStyleSheetBefore(SheetType::Doc, aSheet, firstAuthorSheet);
1561 : } else {
1562 0 : mStyleSet->AppendStyleSheet(SheetType::Doc, aSheet);
1563 : }
1564 :
1565 0 : RestyleForCSSRuleChanges();
1566 0 : }
1567 :
1568 : void
1569 0 : PresShell::RemoveSheet(SheetType aType, StyleSheet* aSheet)
1570 : {
1571 0 : mStyleSet->RemoveStyleSheet(aType, aSheet);
1572 0 : RestyleForCSSRuleChanges();
1573 0 : }
1574 :
1575 : NS_IMETHODIMP
1576 31 : PresShell::SetDisplaySelection(int16_t aToggle)
1577 : {
1578 62 : RefPtr<nsFrameSelection> frameSelection = mSelection;
1579 31 : frameSelection->SetDisplaySelection(aToggle);
1580 62 : return NS_OK;
1581 : }
1582 :
1583 : NS_IMETHODIMP
1584 3 : PresShell::GetDisplaySelection(int16_t *aToggle)
1585 : {
1586 6 : RefPtr<nsFrameSelection> frameSelection = mSelection;
1587 3 : *aToggle = frameSelection->GetDisplaySelection();
1588 6 : return NS_OK;
1589 : }
1590 :
1591 : NS_IMETHODIMP
1592 31 : PresShell::GetSelection(RawSelectionType aRawSelectionType,
1593 : nsISelection **aSelection)
1594 : {
1595 31 : if (!aSelection || !mSelection)
1596 0 : return NS_ERROR_NULL_POINTER;
1597 :
1598 62 : RefPtr<nsFrameSelection> frameSelection = mSelection;
1599 : nsCOMPtr<nsISelection> selection =
1600 62 : frameSelection->GetSelection(ToSelectionType(aRawSelectionType));
1601 :
1602 31 : if (!selection) {
1603 0 : return NS_ERROR_INVALID_ARG;
1604 : }
1605 :
1606 31 : selection.forget(aSelection);
1607 31 : return NS_OK;
1608 : }
1609 :
1610 : Selection*
1611 38 : PresShell::GetCurrentSelection(SelectionType aSelectionType)
1612 : {
1613 38 : if (!mSelection)
1614 0 : return nullptr;
1615 :
1616 76 : RefPtr<nsFrameSelection> frameSelection = mSelection;
1617 38 : return frameSelection->GetSelection(aSelectionType);
1618 : }
1619 :
1620 : already_AddRefed<nsISelectionController>
1621 3 : PresShell::GetSelectionControllerForFocusedContent(nsIContent** aFocusedContent)
1622 : {
1623 3 : if (aFocusedContent) {
1624 3 : *aFocusedContent = nullptr;
1625 : }
1626 :
1627 3 : if (mDocument) {
1628 5 : nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
1629 : nsCOMPtr<nsIContent> focusedContent =
1630 : nsFocusManager::GetFocusedDescendant(mDocument->GetWindow(), false,
1631 5 : getter_AddRefs(focusedWindow));
1632 3 : if (focusedContent) {
1633 1 : nsIFrame* frame = focusedContent->GetPrimaryFrame();
1634 1 : if (frame) {
1635 1 : nsCOMPtr<nsISelectionController> selectionController;
1636 1 : frame->GetSelectionController(mPresContext,
1637 2 : getter_AddRefs(selectionController));
1638 1 : if (selectionController) {
1639 1 : if (aFocusedContent) {
1640 1 : focusedContent.forget(aFocusedContent);
1641 : }
1642 1 : return selectionController.forget();
1643 : }
1644 : }
1645 : }
1646 : }
1647 4 : nsCOMPtr<nsISelectionController> self(this);
1648 2 : return self.forget();
1649 : }
1650 :
1651 : NS_IMETHODIMP
1652 0 : PresShell::ScrollSelectionIntoView(RawSelectionType aRawSelectionType,
1653 : SelectionRegion aRegion,
1654 : int16_t aFlags)
1655 : {
1656 0 : if (!mSelection)
1657 0 : return NS_ERROR_NULL_POINTER;
1658 :
1659 0 : RefPtr<nsFrameSelection> frameSelection = mSelection;
1660 0 : return frameSelection->ScrollSelectionIntoView(
1661 0 : ToSelectionType(aRawSelectionType), aRegion, aFlags);
1662 : }
1663 :
1664 : NS_IMETHODIMP
1665 3 : PresShell::RepaintSelection(RawSelectionType aRawSelectionType)
1666 : {
1667 3 : if (!mSelection)
1668 0 : return NS_ERROR_NULL_POINTER;
1669 :
1670 6 : RefPtr<nsFrameSelection> frameSelection = mSelection;
1671 3 : return frameSelection->RepaintSelection(ToSelectionType(aRawSelectionType));
1672 : }
1673 :
1674 : // Make shell be a document observer
1675 : void
1676 28 : PresShell::BeginObservingDocument()
1677 : {
1678 28 : if (mDocument && !mIsDestroying) {
1679 28 : mDocument->AddObserver(this);
1680 28 : if (mIsDocumentGone) {
1681 : NS_WARNING("Adding a presshell that was disconnected from the document "
1682 0 : "as a document observer? Sounds wrong...");
1683 0 : mIsDocumentGone = false;
1684 : }
1685 : }
1686 28 : }
1687 :
1688 : // Make shell stop being a document observer
1689 : void
1690 4 : PresShell::EndObservingDocument()
1691 : {
1692 : // XXXbz do we need to tell the frame constructor that the document
1693 : // is gone, perhaps? Except for printing it's NOT gone, sometimes.
1694 4 : mIsDocumentGone = true;
1695 4 : if (mDocument) {
1696 4 : mDocument->RemoveObserver(this);
1697 : }
1698 4 : }
1699 :
1700 : #ifdef DEBUG_kipp
1701 : char* nsPresShell_ReflowStackPointerTop;
1702 : #endif
1703 :
1704 72 : class XBLConstructorRunner : public Runnable
1705 : {
1706 : public:
1707 24 : explicit XBLConstructorRunner(nsIDocument* aDocument)
1708 24 : : Runnable("XBLConstructorRunner")
1709 24 : , mDocument(aDocument)
1710 : {
1711 24 : }
1712 :
1713 24 : NS_IMETHOD Run() override
1714 : {
1715 24 : mDocument->BindingManager()->ProcessAttachedQueue();
1716 24 : return NS_OK;
1717 : }
1718 :
1719 : private:
1720 : nsCOMPtr<nsIDocument> mDocument;
1721 : };
1722 :
1723 : nsresult
1724 24 : PresShell::Initialize(nscoord aWidth, nscoord aHeight)
1725 : {
1726 24 : if (mIsDestroying) {
1727 0 : return NS_OK;
1728 : }
1729 :
1730 24 : if (!mDocument) {
1731 : // Nothing to do
1732 0 : return NS_OK;
1733 : }
1734 :
1735 24 : NS_ASSERTION(!mDidInitialize, "Why are we being called?");
1736 :
1737 48 : nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
1738 24 : mDidInitialize = true;
1739 :
1740 : #ifdef DEBUG
1741 24 : if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) {
1742 0 : if (mDocument) {
1743 0 : nsIURI *uri = mDocument->GetDocumentURI();
1744 0 : if (uri) {
1745 0 : printf("*** PresShell::Initialize (this=%p, url='%s')\n",
1746 0 : (void*)this, uri->GetSpecOrDefault().get());
1747 : }
1748 : }
1749 : }
1750 : #endif
1751 :
1752 : // XXX Do a full invalidate at the beginning so that invalidates along
1753 : // the way don't have region accumulation issues?
1754 :
1755 24 : mPresContext->SetVisibleArea(nsRect(0, 0, aWidth, aHeight));
1756 :
1757 : // Get the root frame from the frame manager
1758 : // XXXbz it would be nice to move this somewhere else... like frame manager
1759 : // Init(), say. But we need to make sure our views are all set up by the
1760 : // time we do this!
1761 24 : nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
1762 24 : NS_ASSERTION(!rootFrame, "How did that happen, exactly?");
1763 24 : if (!rootFrame) {
1764 48 : nsAutoScriptBlocker scriptBlocker;
1765 24 : mFrameConstructor->BeginUpdate();
1766 24 : rootFrame = mFrameConstructor->ConstructRootFrame();
1767 24 : mFrameConstructor->SetRootFrame(rootFrame);
1768 24 : mFrameConstructor->EndUpdate();
1769 : }
1770 :
1771 24 : NS_ENSURE_STATE(!mHaveShutDown);
1772 :
1773 24 : if (!rootFrame) {
1774 0 : return NS_ERROR_OUT_OF_MEMORY;
1775 : }
1776 :
1777 24 : nsIFrame* invalidateFrame = nullptr;
1778 48 : for (nsIFrame* f = rootFrame; f; f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
1779 24 : if (f->GetStateBits() & NS_FRAME_NO_COMPONENT_ALPHA) {
1780 0 : invalidateFrame = f;
1781 0 : f->RemoveStateBits(NS_FRAME_NO_COMPONENT_ALPHA);
1782 : }
1783 48 : nsCOMPtr<nsIPresShell> shell;
1784 48 : if (f->IsSubDocumentFrame() &&
1785 : (shell = static_cast<nsSubDocumentFrame*>(f)
1786 24 : ->GetSubdocumentPresShellForPainting(0)) &&
1787 0 : shell->GetPresContext()->IsRootContentDocument()) {
1788 : // Root content documents build a 'force active' layer, and component alpha flattening
1789 : // can't be propagated across that so no need to invalidate above this frame.
1790 0 : break;
1791 : }
1792 :
1793 :
1794 : }
1795 24 : if (invalidateFrame) {
1796 0 : invalidateFrame->InvalidateFrameSubtree();
1797 : }
1798 :
1799 24 : Element *root = mDocument->GetRootElement();
1800 :
1801 24 : if (root) {
1802 : {
1803 48 : nsAutoCauseReflowNotifier reflowNotifier(this);
1804 24 : mFrameConstructor->BeginUpdate();
1805 :
1806 : // Have the style sheet processor construct frame for the root
1807 : // content object down
1808 24 : mFrameConstructor->ContentInserted(nullptr, root, nullptr, false);
1809 24 : VERIFY_STYLE_TREE;
1810 :
1811 : // Something in mFrameConstructor->ContentInserted may have caused
1812 : // Destroy() to get called, bug 337586.
1813 24 : NS_ENSURE_STATE(!mHaveShutDown);
1814 :
1815 24 : mFrameConstructor->EndUpdate();
1816 : }
1817 :
1818 : // nsAutoCauseReflowNotifier (which sets up a script blocker) going out of
1819 : // scope may have killed us too
1820 24 : NS_ENSURE_STATE(!mHaveShutDown);
1821 :
1822 : // Run the XBL binding constructors for any new frames we've constructed.
1823 : // (Do this in a script runner, since our caller might have a script
1824 : // blocker on the stack.)
1825 48 : nsContentUtils::AddScriptRunner(new XBLConstructorRunner(mDocument));
1826 : }
1827 :
1828 24 : NS_ASSERTION(rootFrame, "How did that happen?");
1829 :
1830 : // Note: when the frame was created above it had the NS_FRAME_IS_DIRTY bit
1831 : // set, but XBL processing could have caused a reflow which clears it.
1832 24 : if (MOZ_LIKELY(rootFrame->GetStateBits() & NS_FRAME_IS_DIRTY)) {
1833 : // Unset the DIRTY bits so that FrameNeedsReflow() will work right.
1834 24 : rootFrame->RemoveStateBits(NS_FRAME_IS_DIRTY |
1835 24 : NS_FRAME_HAS_DIRTY_CHILDREN);
1836 24 : NS_ASSERTION(!mDirtyRoots.Contains(rootFrame),
1837 : "Why is the root in mDirtyRoots already?");
1838 24 : FrameNeedsReflow(rootFrame, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
1839 24 : NS_ASSERTION(mDirtyRoots.Contains(rootFrame),
1840 : "Should be in mDirtyRoots now");
1841 24 : NS_ASSERTION(mObservingLayoutFlushes, "Why no reflow scheduled?");
1842 : }
1843 :
1844 : // Restore our root scroll position now if we're getting here after EndLoad
1845 : // got called, since this is our one chance to do it. Note that we need not
1846 : // have reflowed for this to work; when the scrollframe is finally reflowed
1847 : // it'll pick up the position we store in it here.
1848 24 : if (!mDocumentLoading) {
1849 1 : RestoreRootScrollPosition();
1850 : }
1851 :
1852 : // For printing, we just immediately unsuppress.
1853 24 : if (!mPresContext->IsPaginated()) {
1854 : // Kick off a one-shot timer based off our pref value. When this timer
1855 : // fires, if painting is still locked down, then we will go ahead and
1856 : // trigger a full invalidate and allow painting to proceed normally.
1857 24 : mPaintingSuppressed = true;
1858 : // Don't suppress painting if the document isn't loading.
1859 24 : nsIDocument::ReadyState readyState = mDocument->GetReadyStateEnum();
1860 24 : if (readyState != nsIDocument::READYSTATE_COMPLETE) {
1861 24 : mPaintSuppressionTimer = do_CreateInstance("@mozilla.org/timer;1");
1862 : }
1863 24 : if (!mPaintSuppressionTimer) {
1864 0 : mPaintingSuppressed = false;
1865 : } else {
1866 : // Initialize the timer.
1867 :
1868 : // Default to PAINTLOCK_EVENT_DELAY if we can't get the pref value.
1869 : int32_t delay =
1870 : Preferences::GetInt("nglayout.initialpaint.delay",
1871 24 : PAINTLOCK_EVENT_DELAY);
1872 :
1873 24 : mPaintSuppressionTimer->SetTarget(
1874 24 : mDocument->EventTargetFor(TaskCategory::Other));
1875 48 : mPaintSuppressionTimer->InitWithNamedFuncCallback(
1876 : sPaintSuppressionCallback, this, delay, nsITimer::TYPE_ONE_SHOT,
1877 48 : "PresShell::sPaintSuppressionCallback");
1878 : }
1879 : }
1880 :
1881 : // If we get here and painting is not suppressed, then we can paint anytime
1882 : // and we should fire the before-first-paint notification
1883 24 : if (!mPaintingSuppressed) {
1884 0 : ScheduleBeforeFirstPaint();
1885 : }
1886 :
1887 24 : return NS_OK; //XXX this needs to be real. MMP
1888 : }
1889 :
1890 : void
1891 22 : PresShell::sPaintSuppressionCallback(nsITimer *aTimer, void* aPresShell)
1892 : {
1893 44 : RefPtr<PresShell> self = static_cast<PresShell*>(aPresShell);
1894 22 : if (self)
1895 22 : self->UnsuppressPainting();
1896 22 : }
1897 :
1898 : void
1899 0 : PresShell::AsyncResizeEventCallback(nsITimer* aTimer, void* aPresShell)
1900 : {
1901 0 : static_cast<PresShell*>(aPresShell)->FireResizeEvent();
1902 0 : }
1903 :
1904 : nsresult
1905 22 : PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight, nscoord aOldWidth, nscoord aOldHeight)
1906 : {
1907 22 : if (mZoomConstraintsClient) {
1908 : // If we have a ZoomConstraintsClient and the available screen area
1909 : // changed, then we might need to disable double-tap-to-zoom, so notify
1910 : // the ZCC to update itself.
1911 2 : mZoomConstraintsClient->ScreenSizeChanged();
1912 : }
1913 22 : if (mMobileViewportManager) {
1914 : // If we have a mobile viewport manager, request a reflow from it. It can
1915 : // recompute the final CSS viewport and trigger a call to
1916 : // ResizeReflowIgnoreOverride if it changed.
1917 0 : mMobileViewportManager->RequestReflow();
1918 0 : return NS_OK;
1919 : }
1920 :
1921 22 : return ResizeReflowIgnoreOverride(aWidth, aHeight, aOldWidth, aOldHeight);
1922 : }
1923 :
1924 : nsresult
1925 22 : PresShell::ResizeReflowIgnoreOverride(nscoord aWidth, nscoord aHeight, nscoord aOldWidth, nscoord aOldHeight)
1926 : {
1927 22 : NS_PRECONDITION(!mIsReflowing, "Shouldn't be in reflow here!");
1928 :
1929 : // If we don't have a root frame yet, that means we haven't had our initial
1930 : // reflow... If that's the case, and aWidth or aHeight is unconstrained,
1931 : // ignore them altogether.
1932 22 : nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
1933 22 : if (!rootFrame && aHeight == NS_UNCONSTRAINEDSIZE) {
1934 : // We can't do the work needed for SizeToContent without a root
1935 : // frame, and we want to return before setting the visible area.
1936 0 : return NS_ERROR_NOT_AVAILABLE;
1937 : }
1938 :
1939 22 : mPresContext->SetVisibleArea(nsRect(0, 0, aWidth, aHeight));
1940 :
1941 : // There isn't anything useful we can do if the initial reflow hasn't happened.
1942 22 : if (!rootFrame) {
1943 2 : return NS_OK;
1944 : }
1945 :
1946 20 : WritingMode wm = rootFrame->GetWritingMode();
1947 20 : NS_PRECONDITION((wm.IsVertical() ? aHeight : aWidth) != NS_UNCONSTRAINEDSIZE,
1948 : "shouldn't use unconstrained isize anymore");
1949 :
1950 20 : const bool isBSizeChanging = wm.IsVertical()
1951 20 : ? aOldWidth != aWidth
1952 20 : : aOldHeight != aHeight;
1953 :
1954 40 : RefPtr<nsViewManager> viewManager = mViewManager;
1955 40 : nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
1956 :
1957 20 : if (!GetPresContext()->SuppressingResizeReflow()) {
1958 : // Have to make sure that the content notifications are flushed before we
1959 : // start messing with the frame model; otherwise we can get content doubling.
1960 20 : mDocument->FlushPendingNotifications(FlushType::ContentAndNotify);
1961 :
1962 : // Make sure style is up to date
1963 : {
1964 40 : nsAutoScriptBlocker scriptBlocker;
1965 20 : mPresContext->RestyleManager()->ProcessPendingRestyles();
1966 : }
1967 :
1968 20 : rootFrame = mFrameConstructor->GetRootFrame();
1969 20 : if (!mIsDestroying && rootFrame) {
1970 : // XXX Do a full invalidate at the beginning so that invalidates along
1971 : // the way don't have region accumulation issues?
1972 :
1973 20 : if (isBSizeChanging) {
1974 : // For BSize changes driven by style, RestyleManager handles this.
1975 : // For height:auto BSizes (i.e. layout-controlled), descendant
1976 : // intrinsic sizes can't depend on them. So the only other case is
1977 : // viewport-controlled BSizes which we handle here.
1978 20 : nsLayoutUtils::MarkIntrinsicISizesDirtyIfDependentOnBSize(rootFrame);
1979 : }
1980 :
1981 : {
1982 40 : nsAutoCauseReflowNotifier crNotifier(this);
1983 20 : WillDoReflow();
1984 :
1985 : // Kick off a top-down reflow
1986 40 : AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Reflow);
1987 40 : nsViewManager::AutoDisableRefresh refreshBlocker(viewManager);
1988 :
1989 20 : mDirtyRoots.RemoveElement(rootFrame);
1990 20 : DoReflow(rootFrame, true);
1991 : }
1992 :
1993 20 : DidDoReflow(true);
1994 : }
1995 : }
1996 :
1997 20 : rootFrame = mFrameConstructor->GetRootFrame();
1998 20 : if (rootFrame) {
1999 20 : wm = rootFrame->GetWritingMode();
2000 20 : if (wm.IsVertical()) {
2001 0 : if (aWidth == NS_UNCONSTRAINEDSIZE) {
2002 0 : mPresContext->SetVisibleArea(
2003 0 : nsRect(0, 0, rootFrame->GetRect().width, aHeight));
2004 : }
2005 : } else {
2006 20 : if (aHeight == NS_UNCONSTRAINEDSIZE) {
2007 0 : mPresContext->SetVisibleArea(
2008 0 : nsRect(0, 0, aWidth, rootFrame->GetRect().height));
2009 : }
2010 : }
2011 : }
2012 :
2013 40 : if (!mIsDestroying && !mResizeEvent.IsPending() &&
2014 20 : !mAsyncResizeTimerIsActive) {
2015 20 : if (mInResize) {
2016 0 : if (!mAsyncResizeEventTimer) {
2017 0 : mAsyncResizeEventTimer = do_CreateInstance("@mozilla.org/timer;1");
2018 : }
2019 0 : if (mAsyncResizeEventTimer) {
2020 0 : mAsyncResizeTimerIsActive = true;
2021 0 : mAsyncResizeEventTimer->SetTarget(
2022 0 : mDocument->EventTargetFor(TaskCategory::Other));
2023 0 : mAsyncResizeEventTimer->InitWithNamedFuncCallback(AsyncResizeEventCallback,
2024 : this, 15,
2025 : nsITimer::TYPE_ONE_SHOT,
2026 0 : "AsyncResizeEventCallback");
2027 : }
2028 : } else {
2029 40 : RefPtr<nsRunnableMethod<PresShell>> event = NewRunnableMethod(
2030 40 : "PresShell::FireResizeEvent", this, &PresShell::FireResizeEvent);
2031 60 : nsresult rv = mDocument->Dispatch("PresShell::FireResizeEvent",
2032 : TaskCategory::Other,
2033 60 : do_AddRef(event));
2034 20 : if (NS_SUCCEEDED(rv)) {
2035 20 : mResizeEvent = event;
2036 20 : SetNeedStyleFlush();
2037 : }
2038 : }
2039 : }
2040 :
2041 20 : return NS_OK; //XXX this needs to be real. MMP
2042 : }
2043 :
2044 : void
2045 20 : PresShell::FireResizeEvent()
2046 : {
2047 20 : if (mAsyncResizeTimerIsActive) {
2048 0 : mAsyncResizeTimerIsActive = false;
2049 0 : mAsyncResizeEventTimer->Cancel();
2050 : }
2051 20 : mResizeEvent.Revoke();
2052 :
2053 20 : if (mIsDocumentGone)
2054 0 : return;
2055 :
2056 : //Send resize event from here.
2057 40 : WidgetEvent event(true, mozilla::eResize);
2058 20 : nsEventStatus status = nsEventStatus_eIgnore;
2059 :
2060 20 : if (nsPIDOMWindowOuter* window = mDocument->GetWindow()) {
2061 4 : nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
2062 2 : mInResize = true;
2063 2 : EventDispatcher::Dispatch(window, mPresContext, &event, nullptr, &status);
2064 2 : mInResize = false;
2065 : }
2066 : }
2067 :
2068 : void
2069 4 : PresShell::SetIgnoreFrameDestruction(bool aIgnore)
2070 : {
2071 4 : if (mDocument) {
2072 : // We need to tell the ImageLoader to drop all its references to frames
2073 : // because they're about to go away and it won't get notifications of that.
2074 4 : mDocument->StyleImageLoader()->ClearFrames(mPresContext);
2075 : }
2076 4 : mIgnoreFrameDestruction = aIgnore;
2077 4 : }
2078 :
2079 : void
2080 126 : PresShell::NotifyDestroyingFrame(nsIFrame* aFrame)
2081 : {
2082 : // We must remove these from FrameLayerBuilder::DisplayItemData::mFrameList here,
2083 : // otherwise the DisplayItemData destructor will use the destroyed frame when it
2084 : // tries to remove it from the (array) value of this property.
2085 126 : FrameLayerBuilder::RemoveFrameFromLayerManager(aFrame, aFrame->DisplayItemData());
2086 126 : aFrame->DisplayItemData().Clear();
2087 :
2088 126 : if (!mIgnoreFrameDestruction) {
2089 126 : if (aFrame->HasImageRequest()) {
2090 2 : mDocument->StyleImageLoader()->DropRequestsForFrame(aFrame);
2091 : }
2092 :
2093 126 : mFrameConstructor->NotifyDestroyingFrame(aFrame);
2094 :
2095 249 : for (int32_t idx = mDirtyRoots.Length(); idx; ) {
2096 123 : --idx;
2097 123 : if (mDirtyRoots[idx] == aFrame) {
2098 0 : mDirtyRoots.RemoveElementAt(idx);
2099 : }
2100 : }
2101 :
2102 : // Remove frame properties
2103 126 : aFrame->DeleteAllProperties();
2104 :
2105 126 : if (aFrame == mCurrentEventFrame) {
2106 0 : mCurrentEventContent = aFrame->GetContent();
2107 0 : mCurrentEventFrame = nullptr;
2108 : }
2109 :
2110 : #ifdef DEBUG
2111 126 : if (aFrame == mDrawEventTargetFrame) {
2112 0 : mDrawEventTargetFrame = nullptr;
2113 : }
2114 : #endif
2115 :
2116 126 : for (unsigned int i=0; i < mCurrentEventFrameStack.Length(); i++) {
2117 0 : if (aFrame == mCurrentEventFrameStack.ElementAt(i)) {
2118 : //One of our stack frames was deleted. Get its content so that when we
2119 : //pop it we can still get its new frame from its content
2120 0 : nsIContent *currentEventContent = aFrame->GetContent();
2121 0 : mCurrentEventContentStack.ReplaceObjectAt(currentEventContent, i);
2122 0 : mCurrentEventFrameStack[i] = nullptr;
2123 : }
2124 : }
2125 :
2126 126 : mFramesToDirty.RemoveEntry(aFrame);
2127 : }
2128 126 : }
2129 :
2130 36 : already_AddRefed<nsCaret> PresShell::GetCaret() const
2131 : {
2132 72 : RefPtr<nsCaret> caret = mCaret;
2133 72 : return caret.forget();
2134 : }
2135 :
2136 61 : already_AddRefed<AccessibleCaretEventHub> PresShell::GetAccessibleCaretEventHub() const
2137 : {
2138 122 : RefPtr<AccessibleCaretEventHub> eventHub = mAccessibleCaretEventHub;
2139 122 : return eventHub.forget();
2140 : }
2141 :
2142 0 : void PresShell::SetCaret(nsCaret *aNewCaret)
2143 : {
2144 0 : mCaret = aNewCaret;
2145 0 : }
2146 :
2147 0 : void PresShell::RestoreCaret()
2148 : {
2149 0 : mCaret = mOriginalCaret;
2150 0 : }
2151 :
2152 0 : NS_IMETHODIMP PresShell::SetCaretEnabled(bool aInEnable)
2153 : {
2154 0 : bool oldEnabled = mCaretEnabled;
2155 :
2156 0 : mCaretEnabled = aInEnable;
2157 :
2158 0 : if (mCaretEnabled != oldEnabled)
2159 : {
2160 0 : MOZ_ASSERT(mCaret);
2161 0 : if (mCaret) {
2162 0 : mCaret->SetVisible(mCaretEnabled);
2163 : }
2164 : }
2165 :
2166 0 : return NS_OK;
2167 : }
2168 :
2169 0 : NS_IMETHODIMP PresShell::SetCaretReadOnly(bool aReadOnly)
2170 : {
2171 0 : if (mCaret)
2172 0 : mCaret->SetCaretReadOnly(aReadOnly);
2173 0 : return NS_OK;
2174 : }
2175 :
2176 0 : NS_IMETHODIMP PresShell::GetCaretEnabled(bool *aOutEnabled)
2177 : {
2178 0 : NS_ENSURE_ARG_POINTER(aOutEnabled);
2179 0 : *aOutEnabled = mCaretEnabled;
2180 0 : return NS_OK;
2181 : }
2182 :
2183 0 : NS_IMETHODIMP PresShell::SetCaretVisibilityDuringSelection(bool aVisibility)
2184 : {
2185 0 : if (mCaret)
2186 0 : mCaret->SetVisibilityDuringSelection(aVisibility);
2187 0 : return NS_OK;
2188 : }
2189 :
2190 0 : NS_IMETHODIMP PresShell::GetCaretVisible(bool *aOutIsVisible)
2191 : {
2192 0 : *aOutIsVisible = false;
2193 0 : if (mCaret) {
2194 0 : *aOutIsVisible = mCaret->IsVisible();
2195 : }
2196 0 : return NS_OK;
2197 : }
2198 :
2199 0 : NS_IMETHODIMP PresShell::SetSelectionFlags(int16_t aInEnable)
2200 : {
2201 0 : mSelectionFlags = aInEnable;
2202 0 : return NS_OK;
2203 : }
2204 :
2205 0 : NS_IMETHODIMP PresShell::GetSelectionFlags(int16_t *aOutEnable)
2206 : {
2207 0 : if (!aOutEnable)
2208 0 : return NS_ERROR_INVALID_ARG;
2209 0 : *aOutEnable = mSelectionFlags;
2210 0 : return NS_OK;
2211 : }
2212 :
2213 : //implementation of nsISelectionController
2214 :
2215 : NS_IMETHODIMP
2216 0 : PresShell::PhysicalMove(int16_t aDirection, int16_t aAmount, bool aExtend)
2217 : {
2218 0 : RefPtr<nsFrameSelection> frameSelection = mSelection;
2219 0 : return frameSelection->PhysicalMove(aDirection, aAmount, aExtend);
2220 : }
2221 :
2222 : NS_IMETHODIMP
2223 0 : PresShell::CharacterMove(bool aForward, bool aExtend)
2224 : {
2225 0 : RefPtr<nsFrameSelection> frameSelection = mSelection;
2226 0 : return frameSelection->CharacterMove(aForward, aExtend);
2227 : }
2228 :
2229 : NS_IMETHODIMP
2230 0 : PresShell::CharacterExtendForDelete()
2231 : {
2232 0 : RefPtr<nsFrameSelection> frameSelection = mSelection;
2233 0 : return frameSelection->CharacterExtendForDelete();
2234 : }
2235 :
2236 : NS_IMETHODIMP
2237 0 : PresShell::CharacterExtendForBackspace()
2238 : {
2239 0 : RefPtr<nsFrameSelection> frameSelection = mSelection;
2240 0 : return frameSelection->CharacterExtendForBackspace();
2241 : }
2242 :
2243 : NS_IMETHODIMP
2244 0 : PresShell::WordMove(bool aForward, bool aExtend)
2245 : {
2246 0 : RefPtr<nsFrameSelection> frameSelection = mSelection;
2247 0 : nsresult result = frameSelection->WordMove(aForward, aExtend);
2248 : // if we can't go down/up any more we must then move caret completely to
2249 : // end/beginning respectively.
2250 0 : if (NS_FAILED(result))
2251 0 : result = CompleteMove(aForward, aExtend);
2252 0 : return result;
2253 : }
2254 :
2255 : NS_IMETHODIMP
2256 0 : PresShell::WordExtendForDelete(bool aForward)
2257 : {
2258 0 : RefPtr<nsFrameSelection> frameSelection = mSelection;
2259 0 : return frameSelection->WordExtendForDelete(aForward);
2260 : }
2261 :
2262 : NS_IMETHODIMP
2263 0 : PresShell::LineMove(bool aForward, bool aExtend)
2264 : {
2265 0 : RefPtr<nsFrameSelection> frameSelection = mSelection;
2266 0 : nsresult result = frameSelection->LineMove(aForward, aExtend);
2267 : // if we can't go down/up any more we must then move caret completely to
2268 : // end/beginning respectively.
2269 0 : if (NS_FAILED(result))
2270 0 : result = CompleteMove(aForward,aExtend);
2271 0 : return result;
2272 : }
2273 :
2274 : NS_IMETHODIMP
2275 0 : PresShell::IntraLineMove(bool aForward, bool aExtend)
2276 : {
2277 0 : RefPtr<nsFrameSelection> frameSelection = mSelection;
2278 0 : return frameSelection->IntraLineMove(aForward, aExtend);
2279 : }
2280 :
2281 :
2282 :
2283 : NS_IMETHODIMP
2284 0 : PresShell::PageMove(bool aForward, bool aExtend)
2285 : {
2286 : nsIScrollableFrame *scrollableFrame =
2287 0 : GetScrollableFrameToScroll(nsIPresShell::eVertical);
2288 0 : if (!scrollableFrame)
2289 0 : return NS_OK;
2290 :
2291 0 : RefPtr<nsFrameSelection> frameSelection = mSelection;
2292 0 : frameSelection->CommonPageMove(aForward, aExtend, scrollableFrame);
2293 : // After ScrollSelectionIntoView(), the pending notifications might be
2294 : // flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
2295 : return ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL,
2296 : nsISelectionController::SELECTION_FOCUS_REGION,
2297 : nsISelectionController::SCROLL_SYNCHRONOUS |
2298 0 : nsISelectionController::SCROLL_FOR_CARET_MOVE);
2299 : }
2300 :
2301 :
2302 :
2303 : NS_IMETHODIMP
2304 0 : PresShell::ScrollPage(bool aForward)
2305 : {
2306 : nsIScrollableFrame* scrollFrame =
2307 0 : GetScrollableFrameToScroll(nsIPresShell::eVertical);
2308 0 : if (scrollFrame) {
2309 : mozilla::Telemetry::Accumulate(mozilla::Telemetry::SCROLL_INPUT_METHODS,
2310 0 : (uint32_t) ScrollInputMethod::MainThreadScrollPage);
2311 0 : scrollFrame->ScrollBy(nsIntPoint(0, aForward ? 1 : -1),
2312 : nsIScrollableFrame::PAGES,
2313 : nsIScrollableFrame::SMOOTH,
2314 : nullptr, nullptr,
2315 : nsIScrollableFrame::NOT_MOMENTUM,
2316 0 : nsIScrollableFrame::ENABLE_SNAP);
2317 : }
2318 0 : return NS_OK;
2319 : }
2320 :
2321 : NS_IMETHODIMP
2322 0 : PresShell::ScrollLine(bool aForward)
2323 : {
2324 : nsIScrollableFrame* scrollFrame =
2325 0 : GetScrollableFrameToScroll(nsIPresShell::eVertical);
2326 0 : if (scrollFrame) {
2327 : mozilla::Telemetry::Accumulate(mozilla::Telemetry::SCROLL_INPUT_METHODS,
2328 0 : (uint32_t) ScrollInputMethod::MainThreadScrollLine);
2329 :
2330 : int32_t lineCount = Preferences::GetInt("toolkit.scrollbox.verticalScrollDistance",
2331 0 : NS_DEFAULT_VERTICAL_SCROLL_DISTANCE);
2332 0 : scrollFrame->ScrollBy(nsIntPoint(0, aForward ? lineCount : -lineCount),
2333 : nsIScrollableFrame::LINES,
2334 : nsIScrollableFrame::SMOOTH,
2335 : nullptr, nullptr,
2336 : nsIScrollableFrame::NOT_MOMENTUM,
2337 0 : nsIScrollableFrame::ENABLE_SNAP);
2338 : }
2339 0 : return NS_OK;
2340 : }
2341 :
2342 : NS_IMETHODIMP
2343 0 : PresShell::ScrollCharacter(bool aRight)
2344 : {
2345 : nsIScrollableFrame* scrollFrame =
2346 0 : GetScrollableFrameToScroll(nsIPresShell::eHorizontal);
2347 0 : if (scrollFrame) {
2348 : mozilla::Telemetry::Accumulate(mozilla::Telemetry::SCROLL_INPUT_METHODS,
2349 0 : (uint32_t) ScrollInputMethod::MainThreadScrollCharacter);
2350 : int32_t h = Preferences::GetInt("toolkit.scrollbox.horizontalScrollDistance",
2351 0 : NS_DEFAULT_HORIZONTAL_SCROLL_DISTANCE);
2352 0 : scrollFrame->ScrollBy(nsIntPoint(aRight ? h : -h, 0),
2353 : nsIScrollableFrame::LINES,
2354 : nsIScrollableFrame::SMOOTH,
2355 : nullptr, nullptr,
2356 : nsIScrollableFrame::NOT_MOMENTUM,
2357 0 : nsIScrollableFrame::ENABLE_SNAP);
2358 : }
2359 0 : return NS_OK;
2360 : }
2361 :
2362 : NS_IMETHODIMP
2363 0 : PresShell::CompleteScroll(bool aForward)
2364 : {
2365 : nsIScrollableFrame* scrollFrame =
2366 0 : GetScrollableFrameToScroll(nsIPresShell::eVertical);
2367 0 : if (scrollFrame) {
2368 : mozilla::Telemetry::Accumulate(mozilla::Telemetry::SCROLL_INPUT_METHODS,
2369 0 : (uint32_t) ScrollInputMethod::MainThreadCompleteScroll);
2370 0 : scrollFrame->ScrollBy(nsIntPoint(0, aForward ? 1 : -1),
2371 : nsIScrollableFrame::WHOLE,
2372 : nsIScrollableFrame::SMOOTH,
2373 : nullptr, nullptr,
2374 : nsIScrollableFrame::NOT_MOMENTUM,
2375 0 : nsIScrollableFrame::ENABLE_SNAP);
2376 : }
2377 0 : return NS_OK;
2378 : }
2379 :
2380 : NS_IMETHODIMP
2381 0 : PresShell::CompleteMove(bool aForward, bool aExtend)
2382 : {
2383 : // Beware! This may flush notifications via synchronous
2384 : // ScrollSelectionIntoView.
2385 0 : RefPtr<nsFrameSelection> frameSelection = mSelection;
2386 0 : nsIContent* limiter = frameSelection->GetAncestorLimiter();
2387 0 : nsIFrame* frame = limiter ? limiter->GetPrimaryFrame()
2388 0 : : FrameConstructor()->GetRootElementFrame();
2389 0 : if (!frame)
2390 0 : return NS_ERROR_FAILURE;
2391 : nsIFrame::CaretPosition pos =
2392 0 : frame->GetExtremeCaretPosition(!aForward);
2393 0 : frameSelection->HandleClick(pos.mResultContent, pos.mContentOffset,
2394 0 : pos.mContentOffset, aExtend, false,
2395 : aForward ? CARET_ASSOCIATE_AFTER :
2396 0 : CARET_ASSOCIATE_BEFORE);
2397 0 : if (limiter) {
2398 : // HandleClick resets ancestorLimiter, so set it again.
2399 0 : frameSelection->SetAncestorLimiter(limiter);
2400 : }
2401 :
2402 : // After ScrollSelectionIntoView(), the pending notifications might be
2403 : // flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
2404 : return ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL,
2405 : nsISelectionController::SELECTION_FOCUS_REGION,
2406 : nsISelectionController::SCROLL_SYNCHRONOUS |
2407 0 : nsISelectionController::SCROLL_FOR_CARET_MOVE);
2408 : }
2409 :
2410 : NS_IMETHODIMP
2411 0 : PresShell::SelectAll()
2412 : {
2413 0 : RefPtr<nsFrameSelection> frameSelection = mSelection;
2414 0 : return frameSelection->SelectAll();
2415 : }
2416 :
2417 : static void
2418 0 : DoCheckVisibility(nsPresContext* aPresContext,
2419 : nsIContent* aNode,
2420 : int16_t aStartOffset,
2421 : int16_t aEndOffset,
2422 : bool* aRetval)
2423 : {
2424 0 : nsIFrame* frame = aNode->GetPrimaryFrame();
2425 0 : if (!frame) {
2426 : // No frame to look at so it must not be visible.
2427 0 : return;
2428 : }
2429 :
2430 : // Start process now to go through all frames to find startOffset. Then check
2431 : // chars after that to see if anything until EndOffset is visible.
2432 0 : bool finished = false;
2433 0 : frame->CheckVisibility(aPresContext, aStartOffset, aEndOffset, true,
2434 0 : &finished, aRetval);
2435 : // Don't worry about other return value.
2436 : }
2437 :
2438 : NS_IMETHODIMP
2439 0 : PresShell::CheckVisibility(nsIDOMNode *node, int16_t startOffset, int16_t EndOffset, bool *_retval)
2440 : {
2441 0 : if (!node || startOffset>EndOffset || !_retval || startOffset<0 || EndOffset<0)
2442 0 : return NS_ERROR_INVALID_ARG;
2443 0 : *_retval = false; //initialize return parameter
2444 0 : nsCOMPtr<nsIContent> content(do_QueryInterface(node));
2445 0 : if (!content)
2446 0 : return NS_ERROR_FAILURE;
2447 :
2448 0 : DoCheckVisibility(mPresContext, content, startOffset, EndOffset, _retval);
2449 0 : return NS_OK;
2450 : }
2451 :
2452 : nsresult
2453 0 : PresShell::CheckVisibilityContent(nsIContent* aNode, int16_t aStartOffset,
2454 : int16_t aEndOffset, bool* aRetval)
2455 : {
2456 0 : if (!aNode || aStartOffset > aEndOffset || !aRetval ||
2457 0 : aStartOffset < 0 || aEndOffset < 0) {
2458 0 : return NS_ERROR_INVALID_ARG;
2459 : }
2460 :
2461 0 : *aRetval = false;
2462 0 : DoCheckVisibility(mPresContext, aNode, aStartOffset, aEndOffset, aRetval);
2463 0 : return NS_OK;
2464 : }
2465 :
2466 : //end implementations nsISelectionController
2467 :
2468 : nsIFrame*
2469 0 : nsIPresShell::GetRootFrameExternal() const
2470 : {
2471 0 : return mFrameConstructor->GetRootFrame();
2472 : }
2473 :
2474 : nsIFrame*
2475 1159 : nsIPresShell::GetRootScrollFrame() const
2476 : {
2477 1159 : nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
2478 : // Ensure root frame is a viewport frame
2479 1159 : if (!rootFrame || !rootFrame->IsViewportFrame())
2480 1 : return nullptr;
2481 1158 : nsIFrame* theFrame = rootFrame->PrincipalChildList().FirstChild();
2482 1158 : if (!theFrame || !theFrame->IsScrollFrame())
2483 765 : return nullptr;
2484 393 : return theFrame;
2485 : }
2486 :
2487 : nsIScrollableFrame*
2488 128 : nsIPresShell::GetRootScrollFrameAsScrollable() const
2489 : {
2490 128 : nsIFrame* frame = GetRootScrollFrame();
2491 128 : if (!frame)
2492 61 : return nullptr;
2493 67 : nsIScrollableFrame* scrollableFrame = do_QueryFrame(frame);
2494 67 : NS_ASSERTION(scrollableFrame,
2495 : "All scroll frames must implement nsIScrollableFrame");
2496 67 : return scrollableFrame;
2497 : }
2498 :
2499 : nsIScrollableFrame*
2500 0 : nsIPresShell::GetRootScrollFrameAsScrollableExternal() const
2501 : {
2502 0 : return GetRootScrollFrameAsScrollable();
2503 : }
2504 :
2505 : nsIPageSequenceFrame*
2506 0 : PresShell::GetPageSequenceFrame() const
2507 : {
2508 0 : nsIFrame* frame = mFrameConstructor->GetPageSequenceFrame();
2509 0 : return do_QueryFrame(frame);
2510 : }
2511 :
2512 : nsCanvasFrame*
2513 53 : PresShell::GetCanvasFrame() const
2514 : {
2515 53 : nsIFrame* frame = mFrameConstructor->GetDocElementContainingBlock();
2516 53 : return do_QueryFrame(frame);
2517 : }
2518 :
2519 : void
2520 618 : PresShell::BeginUpdate(nsIDocument *aDocument, nsUpdateType aUpdateType)
2521 : {
2522 : #ifdef DEBUG
2523 618 : mUpdateCount++;
2524 : #endif
2525 618 : mFrameConstructor->BeginUpdate();
2526 :
2527 618 : if (aUpdateType & UPDATE_STYLE)
2528 62 : mStyleSet->BeginUpdate();
2529 618 : }
2530 :
2531 : void
2532 618 : PresShell::EndUpdate(nsIDocument *aDocument, nsUpdateType aUpdateType)
2533 : {
2534 : #ifdef DEBUG
2535 618 : NS_PRECONDITION(0 != mUpdateCount, "too many EndUpdate's");
2536 618 : --mUpdateCount;
2537 : #endif
2538 :
2539 618 : if (aUpdateType & UPDATE_STYLE) {
2540 62 : mStyleSet->EndUpdate();
2541 62 : if (mStyleSet->StyleSheetsHaveChanged()) {
2542 54 : RestyleForCSSRuleChanges();
2543 : }
2544 : }
2545 :
2546 618 : mFrameConstructor->EndUpdate();
2547 618 : }
2548 :
2549 : void
2550 25 : PresShell::RestoreRootScrollPosition()
2551 : {
2552 25 : nsIScrollableFrame* scrollableFrame = GetRootScrollFrameAsScrollable();
2553 25 : if (scrollableFrame) {
2554 23 : scrollableFrame->ScrollToRestoredPosition();
2555 : }
2556 25 : }
2557 :
2558 : void
2559 4 : PresShell::MaybeReleaseCapturingContent()
2560 : {
2561 8 : RefPtr<nsFrameSelection> frameSelection = FrameSelection();
2562 4 : if (frameSelection) {
2563 4 : frameSelection->SetDragState(false);
2564 : }
2565 4 : if (gCaptureInfo.mContent &&
2566 4 : gCaptureInfo.mContent->OwnerDoc() == mDocument) {
2567 0 : SetCapturingContent(nullptr, 0);
2568 : }
2569 4 : }
2570 :
2571 : void
2572 23 : PresShell::BeginLoad(nsIDocument *aDocument)
2573 : {
2574 23 : mDocumentLoading = true;
2575 :
2576 23 : gfxTextPerfMetrics *tp = nullptr;
2577 23 : if (mPresContext) {
2578 23 : tp = mPresContext->GetTextPerfMetrics();
2579 : }
2580 :
2581 23 : bool shouldLog = MOZ_LOG_TEST(gLog, LogLevel::Debug);
2582 23 : if (shouldLog || tp) {
2583 0 : mLoadBegin = TimeStamp::Now();
2584 : }
2585 :
2586 23 : if (shouldLog) {
2587 0 : nsIURI* uri = mDocument->GetDocumentURI();
2588 0 : MOZ_LOG(gLog, LogLevel::Debug,
2589 : ("(presshell) %p load begin [%s]\n",
2590 : this, uri ? uri->GetSpecOrDefault().get() : ""));
2591 : }
2592 23 : }
2593 :
2594 : void
2595 24 : PresShell::EndLoad(nsIDocument *aDocument)
2596 : {
2597 24 : NS_PRECONDITION(aDocument == mDocument, "Wrong document");
2598 :
2599 24 : RestoreRootScrollPosition();
2600 :
2601 24 : mDocumentLoading = false;
2602 24 : }
2603 :
2604 : void
2605 4 : PresShell::LoadComplete()
2606 : {
2607 4 : gfxTextPerfMetrics *tp = nullptr;
2608 4 : if (mPresContext) {
2609 4 : tp = mPresContext->GetTextPerfMetrics();
2610 : }
2611 :
2612 : // log load
2613 4 : bool shouldLog = MOZ_LOG_TEST(gLog, LogLevel::Debug);
2614 4 : if (shouldLog || tp) {
2615 0 : TimeDuration loadTime = TimeStamp::Now() - mLoadBegin;
2616 0 : nsIURI* uri = mDocument->GetDocumentURI();
2617 0 : nsAutoCString spec;
2618 0 : if (uri) {
2619 0 : spec = uri->GetSpecOrDefault();
2620 : }
2621 0 : if (shouldLog) {
2622 0 : MOZ_LOG(gLog, LogLevel::Debug,
2623 : ("(presshell) %p load done time-ms: %9.2f [%s]\n",
2624 : this, loadTime.ToMilliseconds(), spec.get()));
2625 : }
2626 0 : if (tp) {
2627 0 : tp->Accumulate();
2628 0 : if (tp->cumulative.numChars > 0) {
2629 0 : LogTextPerfStats(tp, this, tp->cumulative, loadTime.ToMilliseconds(),
2630 0 : eLog_loaddone, spec.get());
2631 : }
2632 : }
2633 : }
2634 4 : }
2635 :
2636 : #ifdef DEBUG
2637 : void
2638 111 : PresShell::VerifyHasDirtyRootAncestor(nsIFrame* aFrame)
2639 : {
2640 : // XXXbz due to bug 372769, can't actually assert anything here...
2641 111 : return;
2642 :
2643 : // XXXbz shouldn't need this part; remove it once FrameNeedsReflow
2644 : // handles the root frame correctly.
2645 : if (!aFrame->GetParent()) {
2646 : return;
2647 : }
2648 :
2649 : // Make sure that there is a reflow root ancestor of |aFrame| that's
2650 : // in mDirtyRoots already.
2651 : while (aFrame && (aFrame->GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN)) {
2652 : if (((aFrame->GetStateBits() & NS_FRAME_REFLOW_ROOT) ||
2653 : !aFrame->GetParent()) &&
2654 : mDirtyRoots.Contains(aFrame)) {
2655 : return;
2656 : }
2657 :
2658 : aFrame = aFrame->GetParent();
2659 : }
2660 : NS_NOTREACHED("Frame has dirty bits set but isn't scheduled to be "
2661 : "reflowed?");
2662 : }
2663 : #endif
2664 :
2665 : void
2666 158 : PresShell::FrameNeedsReflow(nsIFrame *aFrame, IntrinsicDirty aIntrinsicDirty,
2667 : nsFrameState aBitToAdd,
2668 : ReflowRootHandling aRootHandling)
2669 : {
2670 158 : NS_PRECONDITION(aBitToAdd == NS_FRAME_IS_DIRTY ||
2671 : aBitToAdd == NS_FRAME_HAS_DIRTY_CHILDREN ||
2672 : !aBitToAdd,
2673 : "Unexpected bits being added");
2674 158 : NS_PRECONDITION(!(aIntrinsicDirty == eStyleChange &&
2675 : aBitToAdd == NS_FRAME_HAS_DIRTY_CHILDREN),
2676 : "bits don't correspond to style change reason");
2677 :
2678 158 : NS_ASSERTION(!mIsReflowing, "can't mark frame dirty during reflow");
2679 :
2680 : // If we've not yet done the initial reflow, then don't bother
2681 : // enqueuing a reflow command yet.
2682 158 : if (! mDidInitialize)
2683 0 : return;
2684 :
2685 : // If we're already destroying, don't bother with this either.
2686 158 : if (mIsDestroying)
2687 0 : return;
2688 :
2689 : #ifdef DEBUG
2690 : //printf("gShellCounter: %d\n", gShellCounter++);
2691 158 : if (mInVerifyReflow)
2692 0 : return;
2693 :
2694 158 : if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) {
2695 0 : printf("\nPresShell@%p: frame %p needs reflow\n", (void*)this, (void*)aFrame);
2696 0 : if (VERIFY_REFLOW_REALLY_NOISY_RC & gVerifyReflowFlags) {
2697 0 : printf("Current content model:\n");
2698 0 : Element *rootElement = mDocument->GetRootElement();
2699 0 : if (rootElement) {
2700 0 : rootElement->List(stdout, 0);
2701 : }
2702 : }
2703 : }
2704 : #endif
2705 :
2706 316 : AutoTArray<nsIFrame*, 4> subtrees;
2707 158 : subtrees.AppendElement(aFrame);
2708 :
2709 164 : do {
2710 164 : nsIFrame *subtreeRoot = subtrees.ElementAt(subtrees.Length() - 1);
2711 164 : subtrees.RemoveElementAt(subtrees.Length() - 1);
2712 :
2713 : // Grab |wasDirty| now so we can go ahead and update the bits on
2714 : // subtreeRoot.
2715 164 : bool wasDirty = NS_SUBTREE_DIRTY(subtreeRoot);
2716 164 : subtreeRoot->AddStateBits(aBitToAdd);
2717 :
2718 : // Determine whether we need to keep looking for the next ancestor
2719 : // reflow root if subtreeRoot itself is a reflow root.
2720 : bool targetNeedsReflowFromParent;
2721 164 : switch (aRootHandling) {
2722 : case ePositionOrSizeChange:
2723 31 : targetNeedsReflowFromParent = true;
2724 31 : break;
2725 : case eNoPositionOrSizeChange:
2726 1 : targetNeedsReflowFromParent = false;
2727 1 : break;
2728 : case eInferFromBitToAdd:
2729 132 : targetNeedsReflowFromParent = (aBitToAdd == NS_FRAME_IS_DIRTY);
2730 132 : break;
2731 : }
2732 :
2733 : #define FRAME_IS_REFLOW_ROOT(_f) \
2734 : ((_f->GetStateBits() & NS_FRAME_REFLOW_ROOT) && \
2735 : (_f != subtreeRoot || !targetNeedsReflowFromParent))
2736 :
2737 :
2738 : // Mark the intrinsic widths as dirty on the frame, all of its ancestors,
2739 : // and all of its descendants, if needed:
2740 :
2741 164 : if (aIntrinsicDirty != nsIPresShell::eResize) {
2742 : // Mark argument and all ancestors dirty. (Unless we hit a reflow
2743 : // root that should contain the reflow. That root could be
2744 : // subtreeRoot itself if it's not dirty, or it could be some
2745 : // ancestor of subtreeRoot.)
2746 2596 : for (nsIFrame *a = subtreeRoot;
2747 1298 : a && !FRAME_IS_REFLOW_ROOT(a);
2748 : a = a->GetParent())
2749 1161 : a->MarkIntrinsicISizesDirty();
2750 : }
2751 :
2752 164 : if (aIntrinsicDirty == eStyleChange) {
2753 : // Mark all descendants dirty (using an nsTArray stack rather than
2754 : // recursion).
2755 : // Note that ReflowInput::InitResizeFlags has some similar
2756 : // code; see comments there for how and why it differs.
2757 172 : AutoTArray<nsIFrame*, 32> stack;
2758 86 : stack.AppendElement(subtreeRoot);
2759 :
2760 263 : do {
2761 263 : nsIFrame *f = stack.ElementAt(stack.Length() - 1);
2762 263 : stack.RemoveElementAt(stack.Length() - 1);
2763 :
2764 263 : if (f->IsPlaceholderFrame()) {
2765 6 : nsIFrame *oof = nsPlaceholderFrame::GetRealFrameForPlaceholder(f);
2766 6 : if (!nsLayoutUtils::IsProperAncestorFrame(subtreeRoot, oof)) {
2767 : // We have another distinct subtree we need to mark.
2768 6 : subtrees.AppendElement(oof);
2769 : }
2770 : }
2771 :
2772 526 : nsIFrame::ChildListIterator lists(f);
2773 525 : for (; !lists.IsDone(); lists.Next()) {
2774 308 : for (nsIFrame* kid : lists.CurrentList()) {
2775 177 : kid->MarkIntrinsicISizesDirty();
2776 177 : stack.AppendElement(kid);
2777 : }
2778 : }
2779 263 : } while (stack.Length() != 0);
2780 : }
2781 :
2782 : // Skip setting dirty bits up the tree if we weren't given a bit to add.
2783 164 : if (!aBitToAdd) {
2784 1 : continue;
2785 : }
2786 :
2787 : // Set NS_FRAME_HAS_DIRTY_CHILDREN bits (via nsIFrame::ChildIsDirty)
2788 : // up the tree until we reach either a frame that's already dirty or
2789 : // a reflow root.
2790 163 : nsIFrame *f = subtreeRoot;
2791 : for (;;) {
2792 483 : if (FRAME_IS_REFLOW_ROOT(f) || !f->GetParent()) {
2793 : // we've hit a reflow root or the root frame
2794 54 : if (!wasDirty) {
2795 52 : mDirtyRoots.AppendElement(f);
2796 52 : SetNeedLayoutFlush();
2797 : }
2798 : #ifdef DEBUG
2799 : else {
2800 2 : VerifyHasDirtyRootAncestor(f);
2801 : }
2802 : #endif
2803 :
2804 54 : break;
2805 : }
2806 :
2807 429 : nsIFrame *child = f;
2808 429 : f = f->GetParent();
2809 429 : wasDirty = NS_SUBTREE_DIRTY(f);
2810 429 : f->ChildIsDirty(child);
2811 429 : NS_ASSERTION(f->GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN,
2812 : "ChildIsDirty didn't do its job");
2813 429 : if (wasDirty) {
2814 : // This frame was already marked dirty.
2815 : #ifdef DEBUG
2816 109 : VerifyHasDirtyRootAncestor(f);
2817 : #endif
2818 109 : break;
2819 : }
2820 320 : }
2821 164 : } while (subtrees.Length() != 0);
2822 :
2823 158 : MaybeScheduleReflow();
2824 : }
2825 :
2826 : void
2827 0 : PresShell::FrameNeedsToContinueReflow(nsIFrame *aFrame)
2828 : {
2829 0 : NS_ASSERTION(mIsReflowing, "Must be in reflow when marking path dirty.");
2830 0 : NS_PRECONDITION(mCurrentReflowRoot, "Must have a current reflow root here");
2831 0 : NS_ASSERTION(aFrame == mCurrentReflowRoot ||
2832 : nsLayoutUtils::IsProperAncestorFrame(mCurrentReflowRoot, aFrame),
2833 : "Frame passed in is not the descendant of mCurrentReflowRoot");
2834 0 : NS_ASSERTION(aFrame->GetStateBits() & NS_FRAME_IN_REFLOW,
2835 : "Frame passed in not in reflow?");
2836 :
2837 0 : mFramesToDirty.PutEntry(aFrame);
2838 0 : }
2839 :
2840 : already_AddRefed<nsIContent>
2841 0 : nsIPresShell::GetContentForScrolling() const
2842 : {
2843 0 : nsCOMPtr<nsIContent> focusedContent;
2844 0 : nsIFocusManager* fm = nsFocusManager::GetFocusManager();
2845 0 : if (fm && mDocument) {
2846 0 : nsCOMPtr<nsIDOMElement> focusedElement;
2847 0 : fm->GetFocusedElementForWindow(mDocument->GetWindow(), false, nullptr,
2848 0 : getter_AddRefs(focusedElement));
2849 0 : focusedContent = do_QueryInterface(focusedElement);
2850 : }
2851 0 : if (!focusedContent && mSelection) {
2852 : nsISelection* domSelection =
2853 0 : mSelection->GetSelection(SelectionType::eNormal);
2854 0 : if (domSelection) {
2855 0 : nsCOMPtr<nsIDOMNode> focusedNode;
2856 0 : domSelection->GetFocusNode(getter_AddRefs(focusedNode));
2857 0 : focusedContent = do_QueryInterface(focusedNode);
2858 : }
2859 : }
2860 0 : return focusedContent.forget();
2861 : }
2862 :
2863 : nsIScrollableFrame*
2864 0 : nsIPresShell::GetScrollableFrameToScrollForContent(
2865 : nsIContent* aContent,
2866 : nsIPresShell::ScrollDirection aDirection)
2867 : {
2868 0 : nsIScrollableFrame* scrollFrame = nullptr;
2869 0 : if (aContent) {
2870 0 : nsIFrame* startFrame = aContent->GetPrimaryFrame();
2871 0 : if (startFrame) {
2872 0 : scrollFrame = startFrame->GetScrollTargetFrame();
2873 0 : if (scrollFrame) {
2874 0 : startFrame = scrollFrame->GetScrolledFrame();
2875 : }
2876 0 : if (aDirection == nsIPresShell::eEither) {
2877 : scrollFrame =
2878 0 : nsLayoutUtils::GetNearestScrollableFrame(startFrame);
2879 : } else {
2880 : scrollFrame =
2881 0 : nsLayoutUtils::GetNearestScrollableFrameForDirection(startFrame,
2882 : aDirection == eVertical ? nsLayoutUtils::eVertical :
2883 0 : nsLayoutUtils::eHorizontal);
2884 : }
2885 : }
2886 : }
2887 0 : if (!scrollFrame) {
2888 0 : scrollFrame = GetRootScrollFrameAsScrollable();
2889 : }
2890 0 : return scrollFrame;
2891 : }
2892 :
2893 : nsIScrollableFrame*
2894 0 : nsIPresShell::GetScrollableFrameToScroll(nsIPresShell::ScrollDirection aDirection)
2895 : {
2896 0 : nsCOMPtr<nsIContent> content = GetContentForScrolling();
2897 0 : return GetScrollableFrameToScrollForContent(content.get(), aDirection);
2898 : }
2899 :
2900 : void
2901 4 : PresShell::CancelAllPendingReflows()
2902 : {
2903 4 : mDirtyRoots.Clear();
2904 :
2905 4 : if (mObservingLayoutFlushes) {
2906 0 : GetPresContext()->RefreshDriver()->RemoveLayoutFlushObserver(this);
2907 0 : mObservingLayoutFlushes = false;
2908 : }
2909 :
2910 4 : ASSERT_REFLOW_SCHEDULED_STATE();
2911 4 : }
2912 :
2913 : void
2914 0 : PresShell::DestroyFramesFor(nsIContent* aContent,
2915 : nsIContent** aDestroyedFramesFor)
2916 : {
2917 0 : MOZ_ASSERT(aContent);
2918 0 : NS_ENSURE_TRUE_VOID(mPresContext);
2919 0 : if (!mDidInitialize) {
2920 0 : return;
2921 : }
2922 :
2923 0 : nsAutoScriptBlocker scriptBlocker;
2924 :
2925 : // Mark ourselves as not safe to flush while we're doing frame destruction.
2926 0 : ++mChangeNestCount;
2927 :
2928 0 : nsCSSFrameConstructor* fc = FrameConstructor();
2929 0 : fc->BeginUpdate();
2930 0 : fc->DestroyFramesFor(aContent, aDestroyedFramesFor);
2931 0 : fc->EndUpdate();
2932 :
2933 0 : --mChangeNestCount;
2934 : }
2935 :
2936 : void
2937 0 : PresShell::CreateFramesFor(nsIContent* aContent)
2938 : {
2939 0 : NS_ENSURE_TRUE_VOID(mPresContext);
2940 0 : if (!mDidInitialize) {
2941 : // Nothing to do here. In fact, if we proceed and aContent is the
2942 : // root we will crash.
2943 0 : return;
2944 : }
2945 :
2946 : // Don't call RecreateFramesForContent since that is not exported and we want
2947 : // to keep the number of entrypoints down.
2948 :
2949 0 : NS_ASSERTION(mViewManager, "Should have view manager");
2950 0 : MOZ_ASSERT(aContent);
2951 :
2952 : // Have to make sure that the content notifications are flushed before we
2953 : // start messing with the frame model; otherwise we can get content doubling.
2954 0 : mDocument->FlushPendingNotifications(FlushType::ContentAndNotify);
2955 :
2956 0 : nsAutoScriptBlocker scriptBlocker;
2957 :
2958 : // Mark ourselves as not safe to flush while we're doing frame construction.
2959 0 : ++mChangeNestCount;
2960 :
2961 0 : nsCSSFrameConstructor* fc = FrameConstructor();
2962 0 : nsILayoutHistoryState* layoutState = fc->GetLastCapturedLayoutHistoryState();
2963 0 : fc->BeginUpdate();
2964 0 : fc->ContentInserted(aContent->GetParent(), aContent, layoutState, false);
2965 0 : fc->EndUpdate();
2966 :
2967 0 : --mChangeNestCount;
2968 : }
2969 :
2970 : void
2971 0 : nsIPresShell::PostRecreateFramesFor(Element* aElement)
2972 : {
2973 0 : if (MOZ_UNLIKELY(!mDidInitialize)) {
2974 : // Nothing to do here. In fact, if we proceed and aElement is the root, we
2975 : // will crash.
2976 0 : return;
2977 : }
2978 :
2979 0 : mPresContext->RestyleManager()->PostRestyleEvent(aElement, nsRestyleHint(0),
2980 0 : nsChangeHint_ReconstructFrame);
2981 : }
2982 :
2983 : void
2984 16 : nsIPresShell::RestyleForAnimation(Element* aElement, nsRestyleHint aHint)
2985 : {
2986 : // Now that we no longer have separate non-animation and animation
2987 : // restyles, this method having a distinct identity is less important,
2988 : // but it still seems useful to offer as a "more public" API and as a
2989 : // chokepoint for these restyles to go through.
2990 16 : mPresContext->RestyleManager()->PostRestyleEvent(aElement, aHint,
2991 16 : nsChangeHint(0));
2992 16 : }
2993 :
2994 : void
2995 21 : nsIPresShell::SetForwardingContainer(const WeakPtr<nsDocShell> &aContainer)
2996 : {
2997 21 : mForwardingContainer = aContainer;
2998 21 : }
2999 :
3000 : void
3001 5 : PresShell::ClearFrameRefs(nsIFrame* aFrame)
3002 : {
3003 5 : mPresContext->EventStateManager()->ClearFrameRefs(aFrame);
3004 :
3005 5 : AutoWeakFrame* weakFrame = mAutoWeakFrames;
3006 5 : while (weakFrame) {
3007 0 : AutoWeakFrame* prev = weakFrame->GetPreviousWeakFrame();
3008 0 : if (weakFrame->GetFrame() == aFrame) {
3009 : // This removes weakFrame from mAutoWeakFrames.
3010 0 : weakFrame->Clear(this);
3011 : }
3012 0 : weakFrame = prev;
3013 : }
3014 :
3015 10 : AutoTArray<WeakFrame*, 4> toRemove;
3016 5 : for (auto iter = mWeakFrames.Iter(); !iter.Done(); iter.Next()) {
3017 0 : WeakFrame* weakFrame = iter.Get()->GetKey();
3018 0 : if (weakFrame->GetFrame() == aFrame) {
3019 0 : toRemove.AppendElement(weakFrame);
3020 : }
3021 : }
3022 5 : for (WeakFrame* weakFrame : toRemove) {
3023 0 : weakFrame->Clear(this);
3024 : }
3025 5 : }
3026 :
3027 : already_AddRefed<gfxContext>
3028 97 : PresShell::CreateReferenceRenderingContext()
3029 : {
3030 97 : nsDeviceContext* devCtx = mPresContext->DeviceContext();
3031 194 : RefPtr<gfxContext> rc;
3032 97 : if (mPresContext->IsScreen()) {
3033 97 : rc = gfxContext::CreateOrNull(gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget());
3034 : } else {
3035 : // We assume the devCtx has positive width and height for this call.
3036 : // However, width and height, may be outside of the reasonable range
3037 : // so rc may still be null.
3038 0 : rc = devCtx->CreateReferenceRenderingContext();
3039 : }
3040 :
3041 194 : return rc ? rc.forget() : nullptr;
3042 : }
3043 :
3044 : nsresult
3045 2 : PresShell::GoToAnchor(const nsAString& aAnchorName, bool aScroll,
3046 : uint32_t aAdditionalScrollFlags)
3047 : {
3048 2 : if (!mDocument) {
3049 0 : return NS_ERROR_FAILURE;
3050 : }
3051 :
3052 2 : const Element *root = mDocument->GetRootElement();
3053 2 : if (root && root->IsSVGElement(nsGkAtoms::svg)) {
3054 : // We need to execute this even if there is an empty anchor name
3055 : // so that any existing SVG fragment identifier effect is removed
3056 2 : if (SVGFragmentIdentifier::ProcessFragmentIdentifier(mDocument, aAnchorName)) {
3057 0 : return NS_OK;
3058 : }
3059 : }
3060 :
3061 : // Hold a reference to the ESM in case event dispatch tears us down.
3062 4 : RefPtr<EventStateManager> esm = mPresContext->EventStateManager();
3063 :
3064 2 : if (aAnchorName.IsEmpty()) {
3065 0 : NS_ASSERTION(!aScroll, "can't scroll to empty anchor name");
3066 0 : esm->SetContentState(nullptr, NS_EVENT_STATE_URLTARGET);
3067 0 : return NS_OK;
3068 : }
3069 :
3070 4 : nsCOMPtr<nsIDOMHTMLDocument> htmlDoc = do_QueryInterface(mDocument);
3071 2 : nsresult rv = NS_OK;
3072 4 : nsCOMPtr<nsIContent> content;
3073 :
3074 : // Search for an element with a matching "id" attribute
3075 2 : if (mDocument) {
3076 2 : content = mDocument->GetElementById(aAnchorName);
3077 : }
3078 :
3079 : // Search for an anchor element with a matching "name" attribute
3080 2 : if (!content && htmlDoc) {
3081 0 : nsCOMPtr<nsIDOMNodeList> list;
3082 : // Find a matching list of named nodes
3083 0 : rv = htmlDoc->GetElementsByName(aAnchorName, getter_AddRefs(list));
3084 0 : if (NS_SUCCEEDED(rv) && list) {
3085 : uint32_t i;
3086 : // Loop through the named nodes looking for the first anchor
3087 0 : for (i = 0; true; i++) {
3088 0 : nsCOMPtr<nsIDOMNode> node;
3089 0 : rv = list->Item(i, getter_AddRefs(node));
3090 0 : if (!node) { // End of list
3091 0 : break;
3092 : }
3093 : // Ensure it's an anchor element
3094 0 : content = do_QueryInterface(node);
3095 0 : if (content) {
3096 0 : if (content->IsHTMLElement(nsGkAtoms::a)) {
3097 0 : break;
3098 : }
3099 0 : content = nullptr;
3100 : }
3101 0 : }
3102 : }
3103 : }
3104 :
3105 : // Search for anchor in the HTML namespace with a matching name
3106 2 : if (!content && !htmlDoc)
3107 : {
3108 0 : nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(mDocument);
3109 0 : nsCOMPtr<nsIDOMNodeList> list;
3110 0 : NS_NAMED_LITERAL_STRING(nameSpace, "http://www.w3.org/1999/xhtml");
3111 : // Get the list of anchor elements
3112 0 : rv = doc->GetElementsByTagNameNS(nameSpace, NS_LITERAL_STRING("a"), getter_AddRefs(list));
3113 0 : if (NS_SUCCEEDED(rv) && list) {
3114 : uint32_t i;
3115 : // Loop through the named nodes looking for the first anchor
3116 0 : for (i = 0; true; i++) {
3117 0 : nsCOMPtr<nsIDOMNode> node;
3118 0 : rv = list->Item(i, getter_AddRefs(node));
3119 0 : if (!node) { // End of list
3120 0 : break;
3121 : }
3122 : // Compare the name attribute
3123 0 : nsCOMPtr<nsIDOMElement> element = do_QueryInterface(node);
3124 0 : nsAutoString value;
3125 0 : if (element && NS_SUCCEEDED(element->GetAttribute(NS_LITERAL_STRING("name"), value))) {
3126 0 : if (value.Equals(aAnchorName)) {
3127 0 : content = do_QueryInterface(element);
3128 0 : break;
3129 : }
3130 : }
3131 0 : }
3132 : }
3133 : }
3134 :
3135 2 : esm->SetContentState(content, NS_EVENT_STATE_URLTARGET);
3136 :
3137 : #ifdef ACCESSIBILITY
3138 2 : nsIContent *anchorTarget = content;
3139 : #endif
3140 :
3141 2 : nsIScrollableFrame* rootScroll = GetRootScrollFrameAsScrollable();
3142 2 : if (rootScroll && rootScroll->DidHistoryRestore()) {
3143 : // Scroll position restored from history trumps scrolling to anchor.
3144 0 : aScroll = false;
3145 0 : rootScroll->ClearDidHistoryRestore();
3146 : }
3147 :
3148 2 : if (content) {
3149 2 : if (aScroll) {
3150 0 : rv = ScrollContentIntoView(content,
3151 : ScrollAxis(SCROLL_TOP, SCROLL_ALWAYS),
3152 : ScrollAxis(),
3153 0 : ANCHOR_SCROLL_FLAGS | aAdditionalScrollFlags);
3154 0 : NS_ENSURE_SUCCESS(rv, rv);
3155 :
3156 0 : nsIScrollableFrame* rootScroll = GetRootScrollFrameAsScrollable();
3157 0 : if (rootScroll) {
3158 0 : mLastAnchorScrolledTo = content;
3159 0 : mLastAnchorScrollPositionY = rootScroll->GetScrollPosition().y;
3160 : }
3161 : }
3162 :
3163 : // Should we select the target? This action is controlled by a
3164 : // preference: the default is to not select.
3165 2 : bool selectAnchor = Preferences::GetBool("layout.selectanchor");
3166 :
3167 : // Even if select anchor pref is false, we must still move the
3168 : // caret there. That way tabbing will start from the new
3169 : // location
3170 6 : RefPtr<nsIDOMRange> jumpToRange = new nsRange(mDocument);
3171 6 : while (content && content->GetFirstChild()) {
3172 2 : content = content->GetFirstChild();
3173 : }
3174 4 : nsCOMPtr<nsIDOMNode> node(do_QueryInterface(content));
3175 2 : NS_ASSERTION(node, "No nsIDOMNode for descendant of anchor");
3176 2 : jumpToRange->SelectNodeContents(node);
3177 : // Select the anchor
3178 4 : RefPtr<Selection> sel = mSelection->GetSelection(SelectionType::eNormal);
3179 2 : if (sel) {
3180 2 : sel->RemoveAllRanges();
3181 2 : sel->AddRange(jumpToRange);
3182 2 : if (!selectAnchor) {
3183 : // Use a caret (collapsed selection) at the start of the anchor
3184 2 : sel->CollapseToStart();
3185 : }
3186 : }
3187 : // Selection is at anchor.
3188 : // Now focus the document itself if focus is on an element within it.
3189 2 : nsPIDOMWindowOuter *win = mDocument->GetWindow();
3190 :
3191 2 : nsIFocusManager* fm = nsFocusManager::GetFocusManager();
3192 2 : if (fm && win) {
3193 0 : nsCOMPtr<mozIDOMWindowProxy> focusedWindow;
3194 0 : fm->GetFocusedWindow(getter_AddRefs(focusedWindow));
3195 0 : if (SameCOMIdentity(win, focusedWindow)) {
3196 0 : fm->ClearFocus(focusedWindow);
3197 : }
3198 : }
3199 :
3200 : // If the target is an animation element, activate the animation
3201 2 : if (content->IsNodeOfType(nsINode::eANIMATION)) {
3202 0 : SVGContentUtils::ActivateByHyperlink(content.get());
3203 : }
3204 : } else {
3205 0 : rv = NS_ERROR_FAILURE;
3206 0 : NS_NAMED_LITERAL_STRING(top, "top");
3207 0 : if (nsContentUtils::EqualsIgnoreASCIICase(aAnchorName, top)) {
3208 : // Scroll to the top/left if aAnchorName is "top" and there is no element
3209 : // with such a name or id.
3210 0 : rv = NS_OK;
3211 0 : nsIScrollableFrame* sf = GetRootScrollFrameAsScrollable();
3212 : // Check |aScroll| after setting |rv| so we set |rv| to the same
3213 : // thing whether or not |aScroll| is true.
3214 0 : if (aScroll && sf) {
3215 : // Scroll to the top of the page
3216 0 : sf->ScrollTo(nsPoint(0, 0), nsIScrollableFrame::INSTANT);
3217 : }
3218 : }
3219 : }
3220 :
3221 : #ifdef ACCESSIBILITY
3222 2 : if (anchorTarget) {
3223 2 : nsAccessibilityService* accService = AccService();
3224 2 : if (accService)
3225 0 : accService->NotifyOfAnchorJumpTo(anchorTarget);
3226 : }
3227 : #endif
3228 :
3229 2 : return rv;
3230 : }
3231 :
3232 : nsresult
3233 0 : PresShell::ScrollToAnchor()
3234 : {
3235 0 : if (!mLastAnchorScrolledTo) {
3236 0 : return NS_OK;
3237 : }
3238 0 : NS_ASSERTION(mDidInitialize, "should have done initial reflow by now");
3239 :
3240 0 : nsIScrollableFrame* rootScroll = GetRootScrollFrameAsScrollable();
3241 0 : if (!rootScroll ||
3242 0 : mLastAnchorScrollPositionY != rootScroll->GetScrollPosition().y) {
3243 0 : return NS_OK;
3244 : }
3245 0 : nsresult rv = ScrollContentIntoView(mLastAnchorScrolledTo,
3246 : ScrollAxis(SCROLL_TOP, SCROLL_ALWAYS),
3247 : ScrollAxis(),
3248 0 : ANCHOR_SCROLL_FLAGS);
3249 0 : mLastAnchorScrolledTo = nullptr;
3250 0 : return rv;
3251 : }
3252 :
3253 : /*
3254 : * Helper (per-continuation) for ScrollContentIntoView.
3255 : *
3256 : * @param aContainerFrame [in] the frame which aRect is relative to
3257 : * @param aFrame [in] Frame whose bounds should be unioned
3258 : * @param aUseWholeLineHeightForInlines [in] if true, then for inline frames
3259 : * we should include the top of the line in the added rectangle
3260 : * @param aRect [inout] rect into which its bounds should be unioned
3261 : * @param aHaveRect [inout] whether aRect contains data yet
3262 : * @param aPrevBlock [inout] the block aLines is a line iterator for
3263 : * @param aLines [inout] the line iterator we're using
3264 : * @param aCurLine [inout] the line to start looking from in this iterator
3265 : */
3266 : static void
3267 0 : AccumulateFrameBounds(nsIFrame* aContainerFrame,
3268 : nsIFrame* aFrame,
3269 : bool aUseWholeLineHeightForInlines,
3270 : nsRect& aRect,
3271 : bool& aHaveRect,
3272 : nsIFrame*& aPrevBlock,
3273 : nsAutoLineIterator& aLines,
3274 : int32_t& aCurLine)
3275 : {
3276 0 : nsIFrame* frame = aFrame;
3277 0 : nsRect frameBounds = nsRect(nsPoint(0, 0), aFrame->GetSize());
3278 :
3279 : // If this is an inline frame and either the bounds height is 0 (quirks
3280 : // layout model) or aUseWholeLineHeightForInlines is set, we need to
3281 : // change the top of the bounds to include the whole line.
3282 0 : if (frameBounds.height == 0 || aUseWholeLineHeightForInlines) {
3283 0 : nsIFrame *prevFrame = aFrame;
3284 0 : nsIFrame *f = aFrame;
3285 :
3286 0 : while (f && f->IsFrameOfType(nsIFrame::eLineParticipant) &&
3287 0 : !f->IsTransformed() && !f->IsAbsPosContainingBlock()) {
3288 0 : prevFrame = f;
3289 0 : f = prevFrame->GetParent();
3290 : }
3291 :
3292 0 : if (f != aFrame && f && f->IsBlockFrame()) {
3293 : // find the line containing aFrame and increase the top of |offset|.
3294 0 : if (f != aPrevBlock) {
3295 0 : aLines = f->GetLineIterator();
3296 0 : aPrevBlock = f;
3297 0 : aCurLine = 0;
3298 : }
3299 0 : if (aLines) {
3300 0 : int32_t index = aLines->FindLineContaining(prevFrame, aCurLine);
3301 0 : if (index >= 0) {
3302 0 : aCurLine = index;
3303 : nsIFrame *trash1;
3304 : int32_t trash2;
3305 0 : nsRect lineBounds;
3306 :
3307 0 : if (NS_SUCCEEDED(aLines->GetLine(index, &trash1, &trash2,
3308 : lineBounds))) {
3309 0 : frameBounds += frame->GetOffsetTo(f);
3310 0 : frame = f;
3311 0 : if (lineBounds.y < frameBounds.y) {
3312 0 : frameBounds.height = frameBounds.YMost() - lineBounds.y;
3313 0 : frameBounds.y = lineBounds.y;
3314 : }
3315 : }
3316 : }
3317 : }
3318 : }
3319 : }
3320 :
3321 : nsRect transformedBounds = nsLayoutUtils::TransformFrameRectToAncestor(frame,
3322 0 : frameBounds, aContainerFrame);
3323 :
3324 0 : if (aHaveRect) {
3325 : // We can't use nsRect::UnionRect since it drops empty rects on
3326 : // the floor, and we need to include them. (Thus we need
3327 : // aHaveRect to know when to drop the initial value on the floor.)
3328 0 : aRect.UnionRectEdges(aRect, transformedBounds);
3329 : } else {
3330 0 : aHaveRect = true;
3331 0 : aRect = transformedBounds;
3332 : }
3333 0 : }
3334 :
3335 : static bool
3336 1 : ComputeNeedToScroll(nsIPresShell::WhenToScroll aWhenToScroll,
3337 : nscoord aLineSize,
3338 : nscoord aRectMin,
3339 : nscoord aRectMax,
3340 : nscoord aViewMin,
3341 : nscoord aViewMax) {
3342 : // See how the rect should be positioned vertically
3343 1 : if (nsIPresShell::SCROLL_ALWAYS == aWhenToScroll) {
3344 : // The caller wants the frame as visible as possible
3345 0 : return true;
3346 1 : } else if (nsIPresShell::SCROLL_IF_NOT_VISIBLE == aWhenToScroll) {
3347 : // Scroll only if no part of the frame is visible in this view
3348 0 : return aRectMax - aLineSize <= aViewMin ||
3349 0 : aRectMin + aLineSize >= aViewMax;
3350 1 : } else if (nsIPresShell::SCROLL_IF_NOT_FULLY_VISIBLE == aWhenToScroll) {
3351 : // Scroll only if part of the frame is hidden and more can fit in view
3352 1 : return !(aRectMin >= aViewMin && aRectMax <= aViewMax) &&
3353 1 : std::min(aViewMax, aRectMax) - std::max(aRectMin, aViewMin) < aViewMax - aViewMin;
3354 : }
3355 0 : return false;
3356 : }
3357 :
3358 : static nscoord
3359 0 : ComputeWhereToScroll(int16_t aWhereToScroll,
3360 : nscoord aOriginalCoord,
3361 : nscoord aRectMin,
3362 : nscoord aRectMax,
3363 : nscoord aViewMin,
3364 : nscoord aViewMax,
3365 : nscoord* aRangeMin,
3366 : nscoord* aRangeMax) {
3367 0 : nscoord resultCoord = aOriginalCoord;
3368 : // Allow the scroll operation to land anywhere that
3369 : // makes the whole rectangle visible.
3370 0 : if (nsIPresShell::SCROLL_MINIMUM == aWhereToScroll) {
3371 0 : if (aRectMin < aViewMin) {
3372 : // Scroll up so the frame's top edge is visible
3373 0 : resultCoord = aRectMin;
3374 0 : } else if (aRectMax > aViewMax) {
3375 : // Scroll down so the frame's bottom edge is visible. Make sure the
3376 : // frame's top edge is still visible
3377 0 : resultCoord = aOriginalCoord + aRectMax - aViewMax;
3378 0 : if (resultCoord > aRectMin) {
3379 0 : resultCoord = aRectMin;
3380 : }
3381 : }
3382 : } else {
3383 : nscoord frameAlignCoord =
3384 0 : NSToCoordRound(aRectMin + (aRectMax - aRectMin) * (aWhereToScroll / 100.0f));
3385 0 : resultCoord = NSToCoordRound(frameAlignCoord - (aViewMax - aViewMin) * (
3386 0 : aWhereToScroll / 100.0f));
3387 : }
3388 0 : nscoord scrollPortLength = aViewMax - aViewMin;
3389 : // Force the scroll range to extend to include resultCoord.
3390 0 : *aRangeMin = std::min(resultCoord, aRectMax - scrollPortLength);
3391 0 : *aRangeMax = std::max(resultCoord, aRectMin);
3392 0 : return resultCoord;
3393 : }
3394 :
3395 : /**
3396 : * This function takes a scrollable frame, a rect in the coordinate system
3397 : * of the scrolled frame, and a desired percentage-based scroll
3398 : * position and attempts to scroll the rect to that position in the
3399 : * scrollport.
3400 : *
3401 : * This needs to work even if aRect has a width or height of zero.
3402 : */
3403 1 : static void ScrollToShowRect(nsIScrollableFrame* aFrameAsScrollable,
3404 : const nsRect& aRect,
3405 : nsIPresShell::ScrollAxis aVertical,
3406 : nsIPresShell::ScrollAxis aHorizontal,
3407 : uint32_t aFlags)
3408 : {
3409 1 : nsPoint scrollPt = aFrameAsScrollable->GetScrollPosition();
3410 : nsRect visibleRect(scrollPt,
3411 2 : aFrameAsScrollable->GetScrollPositionClampingScrollPortSize());
3412 :
3413 1 : nsSize lineSize;
3414 : // Don't call GetLineScrollAmount unless we actually need it. Not only
3415 : // does this save time, but it's not safe to call GetLineScrollAmount
3416 : // during reflow (because it depends on font size inflation and doesn't
3417 : // use the in-reflow-safe font-size inflation path). If we did call it,
3418 : // it would assert and possible give the wrong result.
3419 2 : if (aVertical.mWhenToScroll == nsIPresShell::SCROLL_IF_NOT_VISIBLE ||
3420 1 : aHorizontal.mWhenToScroll == nsIPresShell::SCROLL_IF_NOT_VISIBLE) {
3421 0 : lineSize = aFrameAsScrollable->GetLineScrollAmount();
3422 : }
3423 2 : ScrollbarStyles ss = aFrameAsScrollable->GetScrollbarStyles();
3424 2 : nsRect allowedRange(scrollPt, nsSize(0, 0));
3425 1 : bool needToScroll = false;
3426 1 : uint32_t directions = aFrameAsScrollable->GetPerceivedScrollingDirections();
3427 :
3428 2 : if (((aFlags & nsIPresShell::SCROLL_OVERFLOW_HIDDEN) ||
3429 2 : ss.mVertical != NS_STYLE_OVERFLOW_HIDDEN) &&
3430 2 : (!aVertical.mOnlyIfPerceivedScrollableDirection ||
3431 1 : (directions & nsIScrollableFrame::VERTICAL))) {
3432 :
3433 0 : if (ComputeNeedToScroll(aVertical.mWhenToScroll,
3434 : lineSize.height,
3435 0 : aRect.y,
3436 : aRect.YMost(),
3437 : visibleRect.y,
3438 : visibleRect.YMost())) {
3439 : nscoord maxHeight;
3440 0 : scrollPt.y = ComputeWhereToScroll(aVertical.mWhereToScroll,
3441 : scrollPt.y,
3442 0 : aRect.y,
3443 : aRect.YMost(),
3444 : visibleRect.y,
3445 : visibleRect.YMost(),
3446 : &allowedRange.y, &maxHeight);
3447 0 : allowedRange.height = maxHeight - allowedRange.y;
3448 0 : needToScroll = true;
3449 : }
3450 : }
3451 :
3452 2 : if (((aFlags & nsIPresShell::SCROLL_OVERFLOW_HIDDEN) ||
3453 2 : ss.mHorizontal != NS_STYLE_OVERFLOW_HIDDEN) &&
3454 1 : (!aHorizontal.mOnlyIfPerceivedScrollableDirection ||
3455 0 : (directions & nsIScrollableFrame::HORIZONTAL))) {
3456 :
3457 2 : if (ComputeNeedToScroll(aHorizontal.mWhenToScroll,
3458 : lineSize.width,
3459 1 : aRect.x,
3460 : aRect.XMost(),
3461 : visibleRect.x,
3462 : visibleRect.XMost())) {
3463 : nscoord maxWidth;
3464 0 : scrollPt.x = ComputeWhereToScroll(aHorizontal.mWhereToScroll,
3465 : scrollPt.x,
3466 0 : aRect.x,
3467 : aRect.XMost(),
3468 : visibleRect.x,
3469 : visibleRect.XMost(),
3470 : &allowedRange.x, &maxWidth);
3471 0 : allowedRange.width = maxWidth - allowedRange.x;
3472 0 : needToScroll = true;
3473 : }
3474 : }
3475 :
3476 : // If we don't need to scroll, then don't try since it might cancel
3477 : // a current smooth scroll operation.
3478 1 : if (needToScroll) {
3479 0 : nsIScrollableFrame::ScrollMode scrollMode = nsIScrollableFrame::INSTANT;
3480 0 : bool autoBehaviorIsSmooth = (aFrameAsScrollable->GetScrollbarStyles().mScrollBehavior
3481 0 : == NS_STYLE_SCROLL_BEHAVIOR_SMOOTH);
3482 0 : bool smoothScroll = (aFlags & nsIPresShell::SCROLL_SMOOTH) ||
3483 0 : ((aFlags & nsIPresShell::SCROLL_SMOOTH_AUTO) && autoBehaviorIsSmooth);
3484 0 : if (gfxPrefs::ScrollBehaviorEnabled() && smoothScroll) {
3485 0 : scrollMode = nsIScrollableFrame::SMOOTH_MSD;
3486 : }
3487 0 : aFrameAsScrollable->ScrollTo(scrollPt, scrollMode, &allowedRange);
3488 : }
3489 1 : }
3490 :
3491 : nsresult
3492 1 : PresShell::ScrollContentIntoView(nsIContent* aContent,
3493 : nsIPresShell::ScrollAxis aVertical,
3494 : nsIPresShell::ScrollAxis aHorizontal,
3495 : uint32_t aFlags)
3496 : {
3497 1 : NS_ENSURE_TRUE(aContent, NS_ERROR_NULL_POINTER);
3498 2 : nsCOMPtr<nsIDocument> composedDoc = aContent->GetComposedDoc();
3499 1 : NS_ENSURE_STATE(composedDoc);
3500 :
3501 1 : NS_ASSERTION(mDidInitialize, "should have done initial reflow by now");
3502 :
3503 1 : if (mContentToScrollTo) {
3504 0 : mContentToScrollTo->DeleteProperty(nsGkAtoms::scrolling);
3505 : }
3506 1 : mContentToScrollTo = aContent;
3507 1 : ScrollIntoViewData* data = new ScrollIntoViewData();
3508 1 : data->mContentScrollVAxis = aVertical;
3509 1 : data->mContentScrollHAxis = aHorizontal;
3510 1 : data->mContentToScrollToFlags = aFlags;
3511 1 : if (NS_FAILED(mContentToScrollTo->SetProperty(nsGkAtoms::scrolling, data,
3512 : nsINode::DeleteProperty<PresShell::ScrollIntoViewData>))) {
3513 0 : mContentToScrollTo = nullptr;
3514 : }
3515 :
3516 : // Flush layout and attempt to scroll in the process.
3517 1 : if (nsIPresShell* shell = composedDoc->GetShell()) {
3518 1 : shell->SetNeedLayoutFlush();
3519 : }
3520 1 : composedDoc->FlushPendingNotifications(FlushType::InterruptibleLayout);
3521 :
3522 : // If mContentToScrollTo is non-null, that means we interrupted the reflow
3523 : // (or suppressed it altogether because we're suppressing interruptible
3524 : // flushes right now) and won't necessarily get the position correct, but do
3525 : // a best-effort scroll here. The other option would be to do this inside
3526 : // FlushPendingNotifications, but I'm not sure the repeated scrolling that
3527 : // could trigger if reflows keep getting interrupted would be more desirable
3528 : // than a single best-effort scroll followed by one final scroll on the first
3529 : // completed reflow.
3530 1 : if (mContentToScrollTo) {
3531 0 : DoScrollContentIntoView();
3532 : }
3533 1 : return NS_OK;
3534 : }
3535 :
3536 : void
3537 1 : PresShell::DoScrollContentIntoView()
3538 : {
3539 1 : NS_ASSERTION(mDidInitialize, "should have done initial reflow by now");
3540 :
3541 1 : nsIFrame* frame = mContentToScrollTo->GetPrimaryFrame();
3542 1 : if (!frame) {
3543 0 : mContentToScrollTo->DeleteProperty(nsGkAtoms::scrolling);
3544 0 : mContentToScrollTo = nullptr;
3545 0 : return;
3546 : }
3547 :
3548 1 : if (frame->GetStateBits() & NS_FRAME_FIRST_REFLOW) {
3549 : // The reflow flush before this scroll got interrupted, and this frame's
3550 : // coords and size are all zero, and it has no content showing anyway.
3551 : // Don't bother scrolling to it. We'll try again when we finish up layout.
3552 0 : return;
3553 : }
3554 :
3555 : // Make sure we skip 'frame' ... if it's scrollable, we should use its
3556 : // scrollable ancestor as the container.
3557 : nsIFrame* container = nsLayoutUtils::GetClosestFrameOfType(
3558 1 : frame->GetParent(), LayoutFrameType::Scroll);
3559 1 : if (!container) {
3560 : // nothing can be scrolled
3561 1 : return;
3562 : }
3563 :
3564 : ScrollIntoViewData* data = static_cast<ScrollIntoViewData*>(
3565 0 : mContentToScrollTo->GetProperty(nsGkAtoms::scrolling));
3566 0 : if (MOZ_UNLIKELY(!data)) {
3567 0 : mContentToScrollTo = nullptr;
3568 0 : return;
3569 : }
3570 :
3571 : // This is a two-step process.
3572 : // Step 1: Find the bounds of the rect we want to scroll into view. For
3573 : // example, for an inline frame we may want to scroll in the whole
3574 : // line, or we may want to scroll multiple lines into view.
3575 : // Step 2: Walk container frame and its ancestors and scroll them
3576 : // appropriately.
3577 : // frameBounds is relative to container. We're assuming
3578 : // that scrollframes don't split so every continuation of frame will
3579 : // be a descendant of container. (Things would still mostly work
3580 : // even if that assumption was false.)
3581 0 : nsRect frameBounds;
3582 0 : bool haveRect = false;
3583 : bool useWholeLineHeightForInlines =
3584 0 : data->mContentScrollVAxis.mWhenToScroll != nsIPresShell::SCROLL_IF_NOT_FULLY_VISIBLE;
3585 : // Reuse the same line iterator across calls to AccumulateFrameBounds. We set
3586 : // it every time we detect a new block (stored in prevBlock).
3587 0 : nsIFrame* prevBlock = nullptr;
3588 0 : nsAutoLineIterator lines;
3589 : // The last line we found a continuation on in |lines|. We assume that later
3590 : // continuations cannot come on earlier lines.
3591 0 : int32_t curLine = 0;
3592 0 : do {
3593 0 : AccumulateFrameBounds(container, frame, useWholeLineHeightForInlines,
3594 0 : frameBounds, haveRect, prevBlock, lines, curLine);
3595 0 : } while ((frame = frame->GetNextContinuation()));
3596 :
3597 0 : ScrollFrameRectIntoView(container, frameBounds, data->mContentScrollVAxis,
3598 : data->mContentScrollHAxis,
3599 0 : data->mContentToScrollToFlags);
3600 : }
3601 :
3602 : bool
3603 1 : PresShell::ScrollFrameRectIntoView(nsIFrame* aFrame,
3604 : const nsRect& aRect,
3605 : nsIPresShell::ScrollAxis aVertical,
3606 : nsIPresShell::ScrollAxis aHorizontal,
3607 : uint32_t aFlags)
3608 : {
3609 1 : bool didScroll = false;
3610 : // This function needs to work even if rect has a width or height of 0.
3611 2 : nsRect rect = aRect;
3612 1 : nsIFrame* container = aFrame;
3613 : // Walk up the frame hierarchy scrolling the rect into view and
3614 : // keeping rect relative to container
3615 2 : do {
3616 3 : nsIScrollableFrame* sf = do_QueryFrame(container);
3617 3 : if (sf) {
3618 1 : nsPoint oldPosition = sf->GetScrollPosition();
3619 1 : nsRect targetRect = rect;
3620 1 : if (container->StyleDisplay()->mOverflowClipBox ==
3621 : NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX) {
3622 1 : nsMargin padding = container->GetUsedPadding();
3623 1 : targetRect.Inflate(padding);
3624 : }
3625 2 : ScrollToShowRect(sf, targetRect - sf->GetScrolledFrame()->GetPosition(),
3626 1 : aVertical, aHorizontal, aFlags);
3627 1 : nsPoint newPosition = sf->LastScrollDestination();
3628 : // If the scroll position increased, that means our content moved up,
3629 : // so our rect's offset should decrease
3630 1 : rect += oldPosition - newPosition;
3631 :
3632 1 : if (oldPosition != newPosition) {
3633 0 : didScroll = true;
3634 : }
3635 :
3636 : // only scroll one container when this flag is set
3637 1 : if (aFlags & nsIPresShell::SCROLL_FIRST_ANCESTOR_ONLY) {
3638 1 : break;
3639 : }
3640 : }
3641 : nsIFrame* parent;
3642 2 : if (container->IsTransformed()) {
3643 0 : container->GetTransformMatrix(nullptr, &parent);
3644 0 : rect = nsLayoutUtils::TransformFrameRectToAncestor(container, rect, parent);
3645 : } else {
3646 2 : rect += container->GetPosition();
3647 2 : parent = container->GetParent();
3648 : }
3649 2 : if (!parent && !(aFlags & nsIPresShell::SCROLL_NO_PARENT_FRAMES)) {
3650 0 : nsPoint extraOffset(0,0);
3651 0 : parent = nsLayoutUtils::GetCrossDocParentFrame(container, &extraOffset);
3652 0 : if (parent) {
3653 0 : int32_t APD = container->PresContext()->AppUnitsPerDevPixel();
3654 0 : int32_t parentAPD = parent->PresContext()->AppUnitsPerDevPixel();
3655 0 : rect = rect.ScaleToOtherAppUnitsRoundOut(APD, parentAPD);
3656 0 : rect += extraOffset;
3657 : }
3658 : }
3659 2 : container = parent;
3660 2 : } while (container);
3661 :
3662 2 : return didScroll;
3663 : }
3664 :
3665 : nsRectVisibility
3666 0 : PresShell::GetRectVisibility(nsIFrame* aFrame,
3667 : const nsRect &aRect,
3668 : nscoord aMinTwips) const
3669 : {
3670 0 : NS_ASSERTION(aFrame->PresContext() == GetPresContext(),
3671 : "prescontext mismatch?");
3672 0 : nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
3673 0 : NS_ASSERTION(rootFrame,
3674 : "How can someone have a frame for this presshell when there's no root?");
3675 0 : nsIScrollableFrame* sf = GetRootScrollFrameAsScrollable();
3676 0 : nsRect scrollPortRect;
3677 0 : if (sf) {
3678 0 : scrollPortRect = sf->GetScrollPortRect();
3679 0 : nsIFrame* f = do_QueryFrame(sf);
3680 0 : scrollPortRect += f->GetOffsetTo(rootFrame);
3681 : } else {
3682 0 : scrollPortRect = nsRect(nsPoint(0,0), rootFrame->GetSize());
3683 : }
3684 :
3685 0 : nsRect r = aRect + aFrame->GetOffsetTo(rootFrame);
3686 : // If aRect is entirely visible then we don't need to ensure that
3687 : // at least aMinTwips of it is visible
3688 0 : if (scrollPortRect.Contains(r))
3689 0 : return nsRectVisibility_kVisible;
3690 :
3691 0 : nsRect insetRect = scrollPortRect;
3692 0 : insetRect.Deflate(aMinTwips, aMinTwips);
3693 0 : if (r.YMost() <= insetRect.y)
3694 0 : return nsRectVisibility_kAboveViewport;
3695 0 : if (r.y >= insetRect.YMost())
3696 0 : return nsRectVisibility_kBelowViewport;
3697 0 : if (r.XMost() <= insetRect.x)
3698 0 : return nsRectVisibility_kLeftOfViewport;
3699 0 : if (r.x >= insetRect.XMost())
3700 0 : return nsRectVisibility_kRightOfViewport;
3701 :
3702 0 : return nsRectVisibility_kVisible;
3703 : }
3704 :
3705 : void
3706 245 : PresShell::ScheduleViewManagerFlush(PaintType aType)
3707 : {
3708 245 : if (aType == PAINT_DELAYED_COMPRESS) {
3709 : // Delay paint for 1 second.
3710 : static const uint32_t kPaintDelayPeriod = 1000;
3711 11 : if (!mDelayedPaintTimer) {
3712 : nsTimerCallbackFunc
3713 3 : PaintTimerCallBack = [](nsITimer* aTimer, void* aClosure) {
3714 : // The passed-in PresShell is always alive here. Because if PresShell
3715 : // died, mDelayedPaintTimer->Cancel() would be called during the
3716 : // destruction and this callback would never be invoked.
3717 1 : auto self = static_cast<PresShell*>(aClosure);
3718 1 : self->SetNextPaintCompressed();
3719 1 : self->ScheduleViewManagerFlush();
3720 4 : };
3721 :
3722 1 : mDelayedPaintTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
3723 1 : mDelayedPaintTimer->SetTarget(
3724 1 : mDocument->EventTargetFor(TaskCategory::Other));
3725 1 : mDelayedPaintTimer->InitWithNamedFuncCallback(PaintTimerCallBack,
3726 : this,
3727 : kPaintDelayPeriod,
3728 : nsITimer::TYPE_ONE_SHOT,
3729 1 : "PaintTimerCallBack");
3730 : }
3731 11 : return;
3732 : }
3733 :
3734 234 : nsPresContext* presContext = GetPresContext();
3735 234 : if (presContext) {
3736 234 : presContext->RefreshDriver()->ScheduleViewManagerFlush();
3737 : }
3738 234 : SetNeedLayoutFlush();
3739 : }
3740 :
3741 : bool
3742 0 : FlushLayoutRecursive(nsIDocument* aDocument,
3743 : void* aData = nullptr)
3744 : {
3745 0 : MOZ_ASSERT(!aData);
3746 0 : nsCOMPtr<nsIDocument> kungFuDeathGrip(aDocument);
3747 0 : aDocument->EnumerateSubDocuments(FlushLayoutRecursive, nullptr);
3748 0 : aDocument->FlushPendingNotifications(FlushType::Layout);
3749 0 : return true;
3750 : }
3751 :
3752 : void
3753 0 : PresShell::DispatchSynthMouseMove(WidgetGUIEvent* aEvent,
3754 : bool aFlushOnHoverChange)
3755 : {
3756 0 : AutoProfilerTracing tracing("Paint", "DispatchSynthMouseMove");
3757 0 : RestyleManager* restyleManager = mPresContext->RestyleManager();
3758 : uint32_t hoverGenerationBefore =
3759 0 : restyleManager->GetHoverGeneration();
3760 : nsEventStatus status;
3761 0 : nsView* targetView = nsView::GetViewFor(aEvent->mWidget);
3762 0 : if (!targetView)
3763 0 : return;
3764 0 : targetView->GetViewManager()->DispatchEvent(aEvent, targetView, &status);
3765 0 : if (MOZ_UNLIKELY(mIsDestroying)) {
3766 0 : return;
3767 : }
3768 0 : if (aFlushOnHoverChange &&
3769 0 : hoverGenerationBefore != restyleManager->GetHoverGeneration()) {
3770 : // Flush so that the resulting reflow happens now so that our caller
3771 : // can suppress any synthesized mouse moves caused by that reflow.
3772 : // This code only ever runs for the root document, but :hover changes
3773 : // can happen in descendant documents too, so make sure we flush
3774 : // all of them.
3775 0 : FlushLayoutRecursive(mDocument);
3776 : }
3777 : }
3778 :
3779 : void
3780 11 : PresShell::ClearMouseCaptureOnView(nsView* aView)
3781 : {
3782 11 : if (gCaptureInfo.mContent) {
3783 0 : if (aView) {
3784 : // if a view was specified, ensure that the captured content is within
3785 : // this view.
3786 0 : nsIFrame* frame = gCaptureInfo.mContent->GetPrimaryFrame();
3787 0 : if (frame) {
3788 0 : nsView* view = frame->GetClosestView();
3789 : // if there is no view, capturing won't be handled any more, so
3790 : // just release the capture.
3791 0 : if (view) {
3792 0 : do {
3793 0 : if (view == aView) {
3794 0 : gCaptureInfo.mContent = nullptr;
3795 : // the view containing the captured content likely disappeared so
3796 : // disable capture for now.
3797 0 : gCaptureInfo.mAllowed = false;
3798 0 : break;
3799 : }
3800 :
3801 0 : view = view->GetParent();
3802 0 : } while (view);
3803 : // return if the view wasn't found
3804 0 : return;
3805 : }
3806 : }
3807 : }
3808 :
3809 0 : gCaptureInfo.mContent = nullptr;
3810 : }
3811 :
3812 : // disable mouse capture until the next mousedown as a dialog has opened
3813 : // or a drag has started. Otherwise, someone could start capture during
3814 : // the modal dialog or drag.
3815 11 : gCaptureInfo.mAllowed = false;
3816 : }
3817 :
3818 : void
3819 0 : nsIPresShell::ClearMouseCapture(nsIFrame* aFrame)
3820 : {
3821 0 : if (!gCaptureInfo.mContent) {
3822 0 : gCaptureInfo.mAllowed = false;
3823 0 : return;
3824 : }
3825 :
3826 : // null frame argument means clear the capture
3827 0 : if (!aFrame) {
3828 0 : gCaptureInfo.mContent = nullptr;
3829 0 : gCaptureInfo.mAllowed = false;
3830 0 : return;
3831 : }
3832 :
3833 0 : nsIFrame* capturingFrame = gCaptureInfo.mContent->GetPrimaryFrame();
3834 0 : if (!capturingFrame) {
3835 0 : gCaptureInfo.mContent = nullptr;
3836 0 : gCaptureInfo.mAllowed = false;
3837 0 : return;
3838 : }
3839 :
3840 0 : if (nsLayoutUtils::IsAncestorFrameCrossDoc(aFrame, capturingFrame)) {
3841 0 : gCaptureInfo.mContent = nullptr;
3842 0 : gCaptureInfo.mAllowed = false;
3843 : }
3844 : }
3845 :
3846 : nsresult
3847 25 : PresShell::CaptureHistoryState(nsILayoutHistoryState** aState)
3848 : {
3849 25 : NS_PRECONDITION(nullptr != aState, "null state pointer");
3850 :
3851 : // We actually have to mess with the docshell here, since we want to
3852 : // store the state back in it.
3853 : // XXXbz this isn't really right, since this is being called in the
3854 : // content viewer's Hide() method... by that point the docshell's
3855 : // state could be wrong. We should sort out a better ownership
3856 : // model for the layout history state.
3857 50 : nsCOMPtr<nsIDocShell> docShell(mPresContext->GetDocShell());
3858 25 : if (!docShell)
3859 21 : return NS_ERROR_FAILURE;
3860 :
3861 8 : nsCOMPtr<nsILayoutHistoryState> historyState;
3862 4 : docShell->GetLayoutHistoryState(getter_AddRefs(historyState));
3863 4 : if (!historyState) {
3864 : // Create the document state object
3865 4 : historyState = NS_NewLayoutHistoryState();
3866 4 : docShell->SetLayoutHistoryState(historyState);
3867 : }
3868 :
3869 4 : *aState = historyState;
3870 4 : NS_IF_ADDREF(*aState);
3871 :
3872 : // Capture frame state for the entire frame hierarchy
3873 4 : nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
3874 4 : if (!rootFrame) return NS_OK;
3875 :
3876 3 : mFrameConstructor->CaptureFrameState(rootFrame, historyState);
3877 :
3878 3 : return NS_OK;
3879 : }
3880 :
3881 : void
3882 24 : PresShell::ScheduleBeforeFirstPaint()
3883 : {
3884 24 : if (!mDocument->IsResourceDoc()) {
3885 : // Notify observers that a new page is about to be drawn. Execute this
3886 : // as soon as it is safe to run JS, which is guaranteed to be before we
3887 : // go back to the event loop and actually draw the page.
3888 6 : nsContentUtils::AddScriptRunner(new nsBeforeFirstPaintDispatcher(mDocument));
3889 : }
3890 24 : }
3891 :
3892 : void
3893 24 : PresShell::UnsuppressAndInvalidate()
3894 : {
3895 : // Note: We ignore the EnsureVisible check for resource documents, because
3896 : // they won't have a docshell, so they'll always fail EnsureVisible.
3897 48 : if ((!mDocument->IsResourceDoc() && !mPresContext->EnsureVisible()) ||
3898 24 : mHaveShutDown) {
3899 : // No point; we're about to be torn down anyway.
3900 0 : return;
3901 : }
3902 :
3903 24 : ScheduleBeforeFirstPaint();
3904 :
3905 24 : mPaintingSuppressed = false;
3906 24 : nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
3907 24 : if (rootFrame) {
3908 : // let's assume that outline on a root frame is not supported
3909 24 : rootFrame->InvalidateFrame();
3910 : }
3911 :
3912 : // now that painting is unsuppressed, focus may be set on the document
3913 24 : if (nsPIDOMWindowOuter* win = mDocument->GetWindow())
3914 3 : win->SetReadyForFocus();
3915 :
3916 24 : if (!mHaveShutDown) {
3917 24 : SynthesizeMouseMove(false);
3918 24 : ScheduleApproximateFrameVisibilityUpdateNow();
3919 : }
3920 : }
3921 :
3922 : void
3923 28 : PresShell::UnsuppressPainting()
3924 : {
3925 28 : if (mPaintSuppressionTimer) {
3926 24 : mPaintSuppressionTimer->Cancel();
3927 24 : mPaintSuppressionTimer = nullptr;
3928 : }
3929 :
3930 28 : if (mIsDocumentGone || !mPaintingSuppressed)
3931 4 : return;
3932 :
3933 : // If we have reflows pending, just wait until we process
3934 : // the reflows and get all the frames where we want them
3935 : // before actually unlocking the painting. Otherwise
3936 : // go ahead and unlock now.
3937 24 : if (!mDirtyRoots.IsEmpty())
3938 20 : mShouldUnsuppressPainting = true;
3939 : else
3940 4 : UnsuppressAndInvalidate();
3941 : }
3942 :
3943 : // Post a request to handle an arbitrary callback after reflow has finished.
3944 : nsresult
3945 184 : PresShell::PostReflowCallback(nsIReflowCallback* aCallback)
3946 : {
3947 184 : void* result = AllocateByObjectID(eArenaObjectID_nsCallbackEventRequest,
3948 184 : sizeof(nsCallbackEventRequest));
3949 184 : nsCallbackEventRequest* request = (nsCallbackEventRequest*)result;
3950 :
3951 184 : request->callback = aCallback;
3952 184 : request->next = nullptr;
3953 :
3954 184 : if (mLastCallbackEventRequest) {
3955 118 : mLastCallbackEventRequest = mLastCallbackEventRequest->next = request;
3956 : } else {
3957 66 : mFirstCallbackEventRequest = request;
3958 66 : mLastCallbackEventRequest = request;
3959 : }
3960 :
3961 184 : return NS_OK;
3962 : }
3963 :
3964 : void
3965 0 : PresShell::CancelReflowCallback(nsIReflowCallback* aCallback)
3966 : {
3967 0 : nsCallbackEventRequest* before = nullptr;
3968 0 : nsCallbackEventRequest* node = mFirstCallbackEventRequest;
3969 0 : while(node)
3970 : {
3971 0 : nsIReflowCallback* callback = node->callback;
3972 :
3973 0 : if (callback == aCallback)
3974 : {
3975 0 : nsCallbackEventRequest* toFree = node;
3976 0 : if (node == mFirstCallbackEventRequest) {
3977 0 : node = node->next;
3978 0 : mFirstCallbackEventRequest = node;
3979 0 : NS_ASSERTION(before == nullptr, "impossible");
3980 : } else {
3981 0 : node = node->next;
3982 0 : before->next = node;
3983 : }
3984 :
3985 0 : if (toFree == mLastCallbackEventRequest) {
3986 0 : mLastCallbackEventRequest = before;
3987 : }
3988 :
3989 0 : FreeByObjectID(eArenaObjectID_nsCallbackEventRequest, toFree);
3990 : } else {
3991 0 : before = node;
3992 0 : node = node->next;
3993 : }
3994 : }
3995 0 : }
3996 :
3997 : void
3998 4 : PresShell::CancelPostedReflowCallbacks()
3999 : {
4000 4 : while (mFirstCallbackEventRequest) {
4001 0 : nsCallbackEventRequest* node = mFirstCallbackEventRequest;
4002 0 : mFirstCallbackEventRequest = node->next;
4003 0 : if (!mFirstCallbackEventRequest) {
4004 0 : mLastCallbackEventRequest = nullptr;
4005 : }
4006 0 : nsIReflowCallback* callback = node->callback;
4007 0 : FreeByObjectID(eArenaObjectID_nsCallbackEventRequest, node);
4008 0 : if (callback) {
4009 0 : callback->ReflowCallbackCanceled();
4010 : }
4011 : }
4012 4 : }
4013 :
4014 : void
4015 68 : PresShell::HandlePostedReflowCallbacks(bool aInterruptible)
4016 : {
4017 68 : bool shouldFlush = false;
4018 :
4019 436 : while (mFirstCallbackEventRequest) {
4020 184 : nsCallbackEventRequest* node = mFirstCallbackEventRequest;
4021 184 : mFirstCallbackEventRequest = node->next;
4022 184 : if (!mFirstCallbackEventRequest) {
4023 66 : mLastCallbackEventRequest = nullptr;
4024 : }
4025 184 : nsIReflowCallback* callback = node->callback;
4026 184 : FreeByObjectID(eArenaObjectID_nsCallbackEventRequest, node);
4027 184 : if (callback) {
4028 184 : if (callback->ReflowFinished()) {
4029 25 : shouldFlush = true;
4030 : }
4031 : }
4032 : }
4033 :
4034 : FlushType flushType =
4035 68 : aInterruptible ? FlushType::InterruptibleLayout : FlushType::Layout;
4036 68 : if (shouldFlush && !mIsDestroying) {
4037 6 : FlushPendingNotifications(flushType);
4038 : }
4039 68 : }
4040 :
4041 : bool
4042 179 : PresShell::IsSafeToFlush() const
4043 : {
4044 : // Not safe if we are reflowing or in the middle of frame construction
4045 358 : bool isSafeToFlush = !mIsReflowing &&
4046 358 : !mChangeNestCount;
4047 :
4048 179 : if (isSafeToFlush) {
4049 : // Not safe if we are painting
4050 179 : nsViewManager* viewManager = GetViewManager();
4051 179 : if (viewManager) {
4052 179 : bool isPainting = false;
4053 179 : viewManager->IsPainting(isPainting);
4054 179 : if (isPainting) {
4055 0 : isSafeToFlush = false;
4056 : }
4057 : }
4058 : }
4059 :
4060 179 : return isSafeToFlush;
4061 : }
4062 :
4063 :
4064 : void
4065 67 : PresShell::DoFlushPendingNotifications(FlushType aType)
4066 : {
4067 : // by default, flush animations if aType >= FlushType::Style
4068 67 : mozilla::ChangesToFlush flush(aType, aType >= FlushType::Style);
4069 67 : FlushPendingNotifications(flush);
4070 67 : }
4071 :
4072 : void
4073 122 : PresShell::DoFlushPendingNotifications(mozilla::ChangesToFlush aFlush)
4074 : {
4075 : // Per our API contract, hold a strong ref to ourselves until we return.
4076 244 : nsCOMPtr<nsIPresShell> kungFuDeathGrip = this;
4077 :
4078 : /**
4079 : * VERY IMPORTANT: If you add some sort of new flushing to this
4080 : * method, make sure to add the relevant SetNeedLayoutFlush or
4081 : * SetNeedStyleFlush calls on the shell.
4082 : */
4083 122 : FlushType flushType = aFlush.mFlushType;
4084 :
4085 122 : MOZ_ASSERT(NeedFlush(flushType), "Why did we get called?");
4086 :
4087 : static const EnumeratedArray<FlushType,
4088 : FlushType::Count,
4089 : const char*> flushTypeNames = {
4090 : "",
4091 : "Content",
4092 : "ContentAndNotify",
4093 : // As far as the profiler is concerned, EnsurePresShellInitAndFrames and
4094 : // Frames are the same
4095 : "Style",
4096 : "Style",
4097 : "InterruptibleLayout",
4098 : "Layout",
4099 : "Display"
4100 122 : };
4101 :
4102 244 : AUTO_PROFILER_LABEL_DYNAMIC("PresShell::DoFlushPendingNotifications",
4103 : GRAPHICS, flushTypeNames[flushType]);
4104 :
4105 : #ifdef ACCESSIBILITY
4106 : #ifdef DEBUG
4107 122 : nsAccessibilityService* accService = GetAccService();
4108 122 : if (accService) {
4109 0 : NS_ASSERTION(!accService->IsProcessingRefreshDriverNotification(),
4110 : "Flush during accessible tree update!");
4111 : }
4112 : #endif
4113 : #endif
4114 :
4115 122 : NS_ASSERTION(flushType >= FlushType::Frames, "Why did we get called?");
4116 :
4117 122 : mNeedStyleFlush = false;
4118 122 : mNeedThrottledAnimationFlush =
4119 122 : mNeedThrottledAnimationFlush && !aFlush.mFlushAnimations;
4120 122 : mNeedLayoutFlush =
4121 122 : mNeedLayoutFlush && (flushType < FlushType::InterruptibleLayout);
4122 :
4123 122 : bool isSafeToFlush = IsSafeToFlush();
4124 :
4125 : // If layout could possibly trigger scripts, then it's only safe to flush if
4126 : // it's safe to run script.
4127 : bool hasHadScriptObject;
4128 122 : if (mDocument->GetScriptHandlingObject(hasHadScriptObject) ||
4129 : hasHadScriptObject) {
4130 83 : isSafeToFlush = isSafeToFlush && nsContentUtils::IsSafeToRunScript();
4131 : }
4132 :
4133 122 : NS_ASSERTION(!isSafeToFlush || mViewManager, "Must have view manager");
4134 : // Make sure the view manager stays alive.
4135 244 : RefPtr<nsViewManager> viewManager = mViewManager;
4136 122 : bool didStyleFlush = false;
4137 122 : bool didLayoutFlush = false;
4138 122 : if (isSafeToFlush && viewManager) {
4139 : // Record that we are in a flush, so that our optimization in
4140 : // nsDocument::FlushPendingNotifications doesn't skip any re-entrant
4141 : // calls to us. Otherwise, we might miss some needed flushes, since
4142 : // we clear mNeedStyleFlush / mNeedLayoutFlush here at the top of
4143 : // the function but we might not have done the work yet.
4144 244 : AutoRestore<bool> guard(mInFlush);
4145 122 : mInFlush = true;
4146 :
4147 122 : if (mResizeEvent.IsPending()) {
4148 20 : FireResizeEvent();
4149 20 : if (mIsDestroying) {
4150 0 : return;
4151 : }
4152 : }
4153 :
4154 : // We need to make sure external resource documents are flushed too (for
4155 : // example, svg filters that reference a filter in an external document
4156 : // need the frames in the external document to be constructed for the
4157 : // filter to work). We only need external resources to be flushed when the
4158 : // main document is flushing >= FlushType::Frames, so we flush external
4159 : // resources here instead of nsDocument::FlushPendingNotifications.
4160 122 : mDocument->FlushExternalResources(flushType);
4161 :
4162 : // Force flushing of any pending content notifications that might have
4163 : // queued up while our event was pending. That will ensure that we don't
4164 : // construct frames for content right now that's still waiting to be
4165 : // notified on,
4166 122 : mDocument->FlushPendingNotifications(FlushType::ContentAndNotify);
4167 :
4168 : // Process pending restyles, since any flush of the presshell wants
4169 : // up-to-date style data.
4170 122 : if (!mIsDestroying) {
4171 122 : viewManager->FlushDelayedResize(false);
4172 122 : mPresContext->FlushPendingMediaFeatureValuesChanged();
4173 :
4174 : // Flush any pending update of the user font set, since that could
4175 : // cause style changes (for updating ex/ch units, and to cause a
4176 : // reflow).
4177 122 : mDocument->FlushUserFontSet();
4178 :
4179 122 : mPresContext->FlushCounterStyles();
4180 :
4181 : // Flush any requested SMIL samples.
4182 122 : if (mDocument->HasAnimationController()) {
4183 106 : mDocument->GetAnimationController()->FlushResampleRequests();
4184 : }
4185 :
4186 122 : if (aFlush.mFlushAnimations && mPresContext->EffectCompositor()) {
4187 67 : mPresContext->EffectCompositor()->PostRestyleForThrottledAnimations();
4188 : }
4189 :
4190 : // The FlushResampleRequests() above flushed style changes.
4191 122 : if (!mIsDestroying) {
4192 244 : nsAutoScriptBlocker scriptBlocker;
4193 122 : mPresContext->RestyleManager()->ProcessPendingRestyles();
4194 : }
4195 : }
4196 :
4197 : // Process whatever XBL constructors those restyles queued up. This
4198 : // ensures that onload doesn't fire too early and that we won't do extra
4199 : // reflows after those constructors run.
4200 122 : if (!mIsDestroying) {
4201 122 : mDocument->BindingManager()->ProcessAttachedQueue();
4202 : }
4203 :
4204 : // Now those constructors or events might have posted restyle
4205 : // events. At the same time, we still need up-to-date style data.
4206 : // In particular, reflow depends on style being completely up to
4207 : // date. If it's not, then style context reparenting, which can
4208 : // happen during reflow, might suddenly pick up the new rules and
4209 : // we'll end up with frames whose style doesn't match the frame
4210 : // type.
4211 122 : if (!mIsDestroying) {
4212 244 : nsAutoScriptBlocker scriptBlocker;
4213 122 : mPresContext->RestyleManager()->ProcessPendingRestyles();
4214 : }
4215 :
4216 122 : didStyleFlush = true;
4217 :
4218 :
4219 : // There might be more pending constructors now, but we're not going to
4220 : // worry about them. They can't be triggered during reflow, so we should
4221 : // be good.
4222 :
4223 244 : if (flushType >= (mSuppressInterruptibleReflows
4224 122 : ? FlushType::Layout
4225 105 : : FlushType::InterruptibleLayout) &&
4226 105 : !mIsDestroying) {
4227 105 : didLayoutFlush = true;
4228 105 : mFrameConstructor->RecalcQuotesAndCounters();
4229 105 : viewManager->FlushDelayedResize(true);
4230 210 : if (ProcessReflowCommands(flushType < FlushType::Layout) &&
4231 105 : mContentToScrollTo) {
4232 : // We didn't get interrupted. Go ahead and scroll to our content
4233 1 : DoScrollContentIntoView();
4234 1 : if (mContentToScrollTo) {
4235 1 : mContentToScrollTo->DeleteProperty(nsGkAtoms::scrolling);
4236 1 : mContentToScrollTo = nullptr;
4237 : }
4238 : }
4239 : }
4240 :
4241 122 : if (flushType >= FlushType::Layout) {
4242 56 : if (!mIsDestroying) {
4243 56 : viewManager->UpdateWidgetGeometry();
4244 : }
4245 : }
4246 : }
4247 :
4248 122 : if (!didStyleFlush && flushType >= FlushType::Style && !mIsDestroying) {
4249 0 : SetNeedStyleFlush();
4250 0 : if (aFlush.mFlushAnimations) {
4251 0 : SetNeedThrottledAnimationFlush();
4252 : }
4253 : }
4254 :
4255 122 : if (!didLayoutFlush && flushType >= FlushType::InterruptibleLayout &&
4256 0 : !mIsDestroying) {
4257 : // We suppressed this flush either due to it not being safe to flush,
4258 : // or due to mSuppressInterruptibleReflows. Either way, the
4259 : // mNeedLayoutFlush flag needs to be re-set.
4260 0 : SetNeedLayoutFlush();
4261 : }
4262 : }
4263 :
4264 : void
4265 1 : PresShell::CharacterDataChanged(nsIDocument *aDocument,
4266 : nsIContent* aContent,
4267 : CharacterDataChangeInfo* aInfo)
4268 : {
4269 1 : NS_PRECONDITION(!mIsDocumentGone, "Unexpected CharacterDataChanged");
4270 1 : NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
4271 :
4272 2 : nsAutoCauseReflowNotifier crNotifier(this);
4273 :
4274 : // Call this here so it only happens for real content mutations and
4275 : // not cases when the frame constructor calls its own methods to force
4276 : // frame reconstruction.
4277 1 : nsIContent *container = aContent->GetParent();
4278 : uint32_t selectorFlags =
4279 1 : container ? (container->GetFlags() & NODE_ALL_SELECTOR_FLAGS) : 0;
4280 1 : if (selectorFlags != 0 && !aContent->IsRootOfAnonymousSubtree()) {
4281 0 : Element* element = container->AsElement();
4282 0 : if (aInfo->mAppend && !aContent->GetNextSibling())
4283 0 : mPresContext->RestyleManager()->RestyleForAppend(element, aContent);
4284 : else
4285 0 : mPresContext->RestyleManager()->RestyleForInsertOrChange(element, aContent);
4286 : }
4287 :
4288 1 : mFrameConstructor->CharacterDataChanged(aContent, aInfo);
4289 1 : VERIFY_STYLE_TREE;
4290 1 : }
4291 :
4292 : void
4293 55 : PresShell::ContentStateChanged(nsIDocument* aDocument,
4294 : nsIContent* aContent,
4295 : EventStates aStateMask)
4296 : {
4297 55 : NS_PRECONDITION(!mIsDocumentGone, "Unexpected ContentStateChanged");
4298 55 : NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
4299 :
4300 55 : if (mDidInitialize) {
4301 102 : nsAutoCauseReflowNotifier crNotifier(this);
4302 51 : mPresContext->RestyleManager()->ContentStateChanged(aContent, aStateMask);
4303 51 : VERIFY_STYLE_TREE;
4304 : }
4305 55 : }
4306 :
4307 : void
4308 4 : PresShell::DocumentStatesChanged(nsIDocument* aDocument,
4309 : EventStates aStateMask)
4310 : {
4311 4 : NS_PRECONDITION(!mIsDocumentGone, "Unexpected DocumentStatesChanged");
4312 4 : NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
4313 :
4314 4 : nsStyleSet* geckoSet = mStyleSet->GetAsGecko();
4315 4 : if (!geckoSet) {
4316 : // XXXheycam ServoStyleSets don't support document state selectors,
4317 : // but these are only used in chrome documents, which we are not
4318 : // aiming to support yet.
4319 : NS_WARNING("stylo: ServoStyleSets cannot respond to document state "
4320 0 : "changes yet (only matters for chrome documents). See bug 1290285.");
4321 :
4322 6 : } else if (mDidInitialize &&
4323 2 : geckoSet->HasDocumentStateDependentStyle(mDocument->GetRootElement(),
4324 : aStateMask)) {
4325 1 : mPresContext->RestyleManager()->PostRestyleEvent(mDocument->GetRootElement(),
4326 : eRestyle_Subtree,
4327 1 : nsChangeHint(0));
4328 1 : VERIFY_STYLE_TREE;
4329 : }
4330 :
4331 4 : if (aStateMask.HasState(NS_DOCUMENT_STATE_WINDOW_INACTIVE)) {
4332 4 : nsIFrame* root = mFrameConstructor->GetRootFrame();
4333 4 : if (root) {
4334 2 : root->SchedulePaint();
4335 : }
4336 : }
4337 4 : }
4338 :
4339 : void
4340 332 : PresShell::AttributeWillChange(nsIDocument* aDocument,
4341 : Element* aElement,
4342 : int32_t aNameSpaceID,
4343 : nsIAtom* aAttribute,
4344 : int32_t aModType,
4345 : const nsAttrValue* aNewValue)
4346 : {
4347 332 : NS_PRECONDITION(!mIsDocumentGone, "Unexpected AttributeWillChange");
4348 332 : NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
4349 :
4350 : // XXXwaterson it might be more elegant to wait until after the
4351 : // initial reflow to begin observing the document. That would
4352 : // squelch any other inappropriate notifications as well.
4353 332 : if (mDidInitialize) {
4354 652 : nsAutoCauseReflowNotifier crNotifier(this);
4355 326 : mPresContext->RestyleManager()->AttributeWillChange(aElement, aNameSpaceID,
4356 : aAttribute, aModType,
4357 326 : aNewValue);
4358 326 : VERIFY_STYLE_TREE;
4359 : }
4360 332 : }
4361 :
4362 : void
4363 328 : PresShell::AttributeChanged(nsIDocument* aDocument,
4364 : Element* aElement,
4365 : int32_t aNameSpaceID,
4366 : nsIAtom* aAttribute,
4367 : int32_t aModType,
4368 : const nsAttrValue* aOldValue)
4369 : {
4370 328 : NS_PRECONDITION(!mIsDocumentGone, "Unexpected AttributeChanged");
4371 328 : NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
4372 :
4373 : // XXXwaterson it might be more elegant to wait until after the
4374 : // initial reflow to begin observing the document. That would
4375 : // squelch any other inappropriate notifications as well.
4376 328 : if (mDidInitialize) {
4377 644 : nsAutoCauseReflowNotifier crNotifier(this);
4378 322 : mPresContext->RestyleManager()->AttributeChanged(aElement, aNameSpaceID,
4379 : aAttribute, aModType,
4380 322 : aOldValue);
4381 322 : VERIFY_STYLE_TREE;
4382 : }
4383 328 : }
4384 :
4385 : // nsIMutationObserver callbacks have this terrible API where aContainer is
4386 : // null in the case that the container is the document (since nsIDocument is
4387 : // not an nsIContent), and callees are supposed to figure this out and use the
4388 : // document instead. It would be nice to fix that API to just pass a single
4389 : // nsINode* parameter in place of the nsIDocument*, nsIContent* pair, but
4390 : // there are quite a lot of consumers. So we fix things up locally with this
4391 : // routine for now.
4392 : static inline nsINode*
4393 56 : RealContainer(nsIDocument* aDocument, nsIContent* aContainer, nsIContent* aContent)
4394 : {
4395 56 : MOZ_ASSERT(aDocument);
4396 56 : MOZ_ASSERT(!aContainer || aContainer->OwnerDoc() == aDocument);
4397 56 : MOZ_ASSERT(aContent->OwnerDoc() == aDocument);
4398 56 : MOZ_ASSERT(aContainer || aContent->GetParentNode() == aDocument);
4399 56 : if (!aContainer) {
4400 26 : return aDocument;
4401 : }
4402 30 : return aContainer;
4403 : }
4404 :
4405 : void
4406 102 : PresShell::ContentAppended(nsIDocument *aDocument,
4407 : nsIContent* aContainer,
4408 : nsIContent* aFirstNewContent,
4409 : int32_t aNewIndexInContainer)
4410 : {
4411 102 : NS_PRECONDITION(!mIsDocumentGone, "Unexpected ContentAppended");
4412 102 : NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
4413 :
4414 : // We never call ContentAppended with a document as the container, so we can
4415 : // assert that we have an nsIContent container.
4416 102 : MOZ_ASSERT(aContainer);
4417 102 : MOZ_ASSERT(aContainer->IsElement() ||
4418 : aContainer->IsNodeOfType(nsINode::eDOCUMENT_FRAGMENT));
4419 102 : if (!mDidInitialize) {
4420 46 : return;
4421 : }
4422 :
4423 112 : nsAutoCauseReflowNotifier crNotifier(this);
4424 :
4425 : // Call this here so it only happens for real content mutations and
4426 : // not cases when the frame constructor calls its own methods to force
4427 : // frame reconstruction.
4428 56 : mPresContext->RestyleManager()->ContentAppended(aContainer, aFirstNewContent);
4429 :
4430 56 : mFrameConstructor->ContentAppended(aContainer, aFirstNewContent, true);
4431 :
4432 56 : VERIFY_STYLE_TREE;
4433 : }
4434 :
4435 : void
4436 45 : PresShell::ContentInserted(nsIDocument* aDocument,
4437 : nsIContent* aMaybeContainer,
4438 : nsIContent* aChild,
4439 : int32_t aIndexInContainer)
4440 : {
4441 45 : NS_PRECONDITION(!mIsDocumentGone, "Unexpected ContentInserted");
4442 45 : NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
4443 45 : nsINode* container = RealContainer(aDocument, aMaybeContainer, aChild);
4444 :
4445 45 : if (!mDidInitialize) {
4446 26 : return;
4447 : }
4448 :
4449 38 : nsAutoCauseReflowNotifier crNotifier(this);
4450 :
4451 : // Call this here so it only happens for real content mutations and
4452 : // not cases when the frame constructor calls its own methods to force
4453 : // frame reconstruction.
4454 19 : mPresContext->RestyleManager()->ContentInserted(container, aChild);
4455 :
4456 19 : mFrameConstructor->ContentInserted(aMaybeContainer, aChild, nullptr, true);
4457 :
4458 19 : if (aChild->NodeType() == nsIDOMNode::DOCUMENT_TYPE_NODE) {
4459 0 : MOZ_ASSERT(container == aDocument);
4460 0 : NotifyFontSizeInflationEnabledIsDirty();
4461 : }
4462 :
4463 19 : VERIFY_STYLE_TREE;
4464 : }
4465 :
4466 : void
4467 11 : PresShell::ContentRemoved(nsIDocument *aDocument,
4468 : nsIContent* aMaybeContainer,
4469 : nsIContent* aChild,
4470 : int32_t aIndexInContainer,
4471 : nsIContent* aPreviousSibling)
4472 : {
4473 11 : NS_PRECONDITION(!mIsDocumentGone, "Unexpected ContentRemoved");
4474 11 : NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
4475 11 : nsINode* container = RealContainer(aDocument, aMaybeContainer, aChild);
4476 :
4477 : // Notify the ESM that the content has been removed, so that
4478 : // it can clean up any state related to the content.
4479 :
4480 : // XXX_jwir3: There is no null check for aDocument necessary, since, even
4481 : // though by nsIMutationObserver, aDocument could be null, the
4482 : // precondition check that mDocument == aDocument ensures that
4483 : // aDocument will not be null (since mDocument can't be null unless
4484 : // we're still intializing).
4485 11 : mPresContext->EventStateManager()->ContentRemoved(aDocument, aChild);
4486 :
4487 22 : nsAutoCauseReflowNotifier crNotifier(this);
4488 :
4489 : // Call this here so it only happens for real content mutations and
4490 : // not cases when the frame constructor calls its own methods to force
4491 : // frame reconstruction.
4492 11 : nsIContent* oldNextSibling = container->GetChildAt(aIndexInContainer);
4493 :
4494 11 : mPresContext->RestyleManager()->ContentRemoved(container, aChild, oldNextSibling);
4495 :
4496 : // After removing aChild from tree we should save information about live ancestor
4497 11 : if (mPointerEventTarget) {
4498 2 : if (nsContentUtils::ContentIsDescendantOf(mPointerEventTarget, aChild)) {
4499 0 : mPointerEventTarget = aMaybeContainer;
4500 : }
4501 : }
4502 :
4503 : // We should check that aChild does not contain pointer capturing elements.
4504 : // If it does we should release the pointer capture for the elements.
4505 11 : for (auto iter = sPointerCaptureList->Iter(); !iter.Done(); iter.Next()) {
4506 0 : nsIPresShell::PointerCaptureInfo* data = iter.UserData();
4507 0 : if (data && data->mPendingContent &&
4508 0 : nsContentUtils::ContentIsDescendantOf(data->mPendingContent, aChild)) {
4509 0 : nsIPresShell::ReleasePointerCapturingContent(iter.Key());
4510 : }
4511 : }
4512 :
4513 : bool didReconstruct;
4514 11 : mFrameConstructor->ContentRemoved(aMaybeContainer, aChild, oldNextSibling,
4515 : nsCSSFrameConstructor::REMOVE_CONTENT,
4516 11 : &didReconstruct);
4517 :
4518 :
4519 11 : if (aChild->NodeType() == nsIDOMNode::DOCUMENT_TYPE_NODE) {
4520 0 : MOZ_ASSERT(container == aDocument);
4521 0 : NotifyFontSizeInflationEnabledIsDirty();
4522 : }
4523 :
4524 11 : VERIFY_STYLE_TREE;
4525 11 : }
4526 :
4527 : void
4528 0 : PresShell::NotifyCounterStylesAreDirty()
4529 : {
4530 0 : nsAutoCauseReflowNotifier reflowNotifier(this);
4531 0 : mFrameConstructor->BeginUpdate();
4532 0 : mFrameConstructor->NotifyCounterStylesAreDirty();
4533 0 : mFrameConstructor->EndUpdate();
4534 0 : }
4535 :
4536 : void
4537 0 : PresShell::ReconstructFrames()
4538 : {
4539 0 : NS_PRECONDITION(!mFrameConstructor->GetRootFrame() || mDidInitialize,
4540 : "Must not have root frame before initial reflow");
4541 0 : if (!mDidInitialize || mIsDestroying) {
4542 : // Nothing to do here
4543 0 : return;
4544 : }
4545 :
4546 0 : nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
4547 :
4548 : // Have to make sure that the content notifications are flushed before we
4549 : // start messing with the frame model; otherwise we can get content doubling.
4550 0 : mDocument->FlushPendingNotifications(FlushType::ContentAndNotify);
4551 :
4552 0 : if (mIsDestroying) {
4553 0 : return;
4554 : }
4555 :
4556 0 : nsAutoCauseReflowNotifier crNotifier(this);
4557 0 : mFrameConstructor->BeginUpdate();
4558 0 : mFrameConstructor->ReconstructDocElementHierarchy();
4559 0 : VERIFY_STYLE_TREE;
4560 0 : mFrameConstructor->EndUpdate();
4561 : }
4562 :
4563 : void
4564 54 : nsIPresShell::RestyleForCSSRuleChanges()
4565 : {
4566 54 : if (mIsDestroying) {
4567 : // We don't want to mess with restyles at this point
4568 0 : return;
4569 : }
4570 :
4571 54 : mDocument->RebuildUserFontSet();
4572 :
4573 54 : if (mPresContext) {
4574 54 : mPresContext->RebuildCounterStyles();
4575 : }
4576 :
4577 54 : if (!mDidInitialize) {
4578 : // Nothing to do here, since we have no frames yet
4579 31 : return;
4580 : }
4581 :
4582 23 : mStyleSet->InvalidateStyleForCSSRuleChanges();
4583 : }
4584 :
4585 : void
4586 48 : PresShell::RecordStyleSheetChange(StyleSheet* aStyleSheet,
4587 : StyleSheet::ChangeType aChangeType)
4588 : {
4589 : // too bad we can't check that the update is UPDATE_STYLE
4590 48 : NS_ASSERTION(mUpdateCount != 0, "must be in an update");
4591 48 : MOZ_ASSERT(aStyleSheet->IsServo() == mStyleSet->IsServo());
4592 :
4593 48 : mStyleSet->RecordStyleSheetChange(aStyleSheet, aChangeType);
4594 48 : }
4595 :
4596 : void
4597 46 : PresShell::StyleSheetAdded(StyleSheet* aStyleSheet,
4598 : bool aDocumentSheet)
4599 : {
4600 : // We only care when enabled sheets are added
4601 46 : NS_PRECONDITION(aStyleSheet, "Must have a style sheet!");
4602 :
4603 46 : if (aStyleSheet->IsApplicable() && aStyleSheet->HasRules()) {
4604 35 : RecordStyleSheetChange(aStyleSheet, StyleSheet::ChangeType::Added);
4605 : }
4606 46 : }
4607 :
4608 : void
4609 0 : PresShell::StyleSheetRemoved(StyleSheet* aStyleSheet,
4610 : bool aDocumentSheet)
4611 : {
4612 : // We only care when enabled sheets are removed
4613 0 : NS_PRECONDITION(aStyleSheet, "Must have a style sheet!");
4614 :
4615 0 : if (aStyleSheet->IsApplicable() && aStyleSheet->HasRules()) {
4616 0 : RecordStyleSheetChange(aStyleSheet, StyleSheet::ChangeType::Removed);
4617 : }
4618 0 : }
4619 :
4620 : void
4621 13 : PresShell::StyleSheetApplicableStateChanged(StyleSheet* aStyleSheet)
4622 : {
4623 13 : if (aStyleSheet->HasRules()) {
4624 : RecordStyleSheetChange(
4625 13 : aStyleSheet, StyleSheet::ChangeType::ApplicableStateChanged);
4626 : }
4627 13 : }
4628 :
4629 : void
4630 0 : PresShell::StyleRuleChanged(StyleSheet* aStyleSheet, css::Rule* aStyleRule)
4631 : {
4632 0 : RecordStyleSheetChange(aStyleSheet, StyleSheet::ChangeType::RuleChanged);
4633 0 : }
4634 :
4635 : void
4636 0 : PresShell::StyleRuleAdded(StyleSheet* aStyleSheet, css::Rule* aStyleRule)
4637 : {
4638 0 : RecordStyleSheetChange(aStyleSheet, StyleSheet::ChangeType::RuleAdded);
4639 0 : }
4640 :
4641 : void
4642 0 : PresShell::StyleRuleRemoved(StyleSheet* aStyleSheet, css::Rule* aStyleRule)
4643 : {
4644 0 : RecordStyleSheetChange(aStyleSheet, StyleSheet::ChangeType::RuleRemoved);
4645 0 : }
4646 :
4647 : nsresult
4648 18 : PresShell::RenderDocument(const nsRect& aRect, uint32_t aFlags,
4649 : nscolor aBackgroundColor,
4650 : gfxContext* aThebesContext)
4651 : {
4652 18 : NS_ENSURE_TRUE(!(aFlags & RENDER_IS_UNTRUSTED), NS_ERROR_NOT_IMPLEMENTED);
4653 :
4654 18 : nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext();
4655 18 : if (rootPresContext) {
4656 18 : rootPresContext->FlushWillPaintObservers();
4657 18 : if (mIsDestroying)
4658 0 : return NS_OK;
4659 : }
4660 :
4661 36 : nsAutoScriptBlocker blockScripts;
4662 :
4663 : // Set up the rectangle as the path in aThebesContext
4664 : gfxRect r(0, 0,
4665 18 : nsPresContext::AppUnitsToFloatCSSPixels(aRect.width),
4666 36 : nsPresContext::AppUnitsToFloatCSSPixels(aRect.height));
4667 18 : aThebesContext->NewPath();
4668 : #ifdef MOZ_GFX_OPTIMIZE_MOBILE
4669 : aThebesContext->Rectangle(r, true);
4670 : #else
4671 18 : aThebesContext->Rectangle(r);
4672 : #endif
4673 :
4674 18 : nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
4675 18 : if (!rootFrame) {
4676 : // Nothing to paint, just fill the rect
4677 0 : aThebesContext->SetColor(Color::FromABGR(aBackgroundColor));
4678 0 : aThebesContext->Fill();
4679 0 : return NS_OK;
4680 : }
4681 :
4682 36 : gfxContextAutoSaveRestore save(aThebesContext);
4683 :
4684 18 : MOZ_ASSERT(aThebesContext->CurrentOp() == CompositionOp::OP_OVER);
4685 :
4686 18 : aThebesContext->Clip();
4687 :
4688 18 : nsDeviceContext* devCtx = mPresContext->DeviceContext();
4689 :
4690 18 : gfxPoint offset(-nsPresContext::AppUnitsToFloatCSSPixels(aRect.x),
4691 36 : -nsPresContext::AppUnitsToFloatCSSPixels(aRect.y));
4692 18 : gfxFloat scale = gfxFloat(devCtx->AppUnitsPerDevPixel())/nsPresContext::AppUnitsPerCSSPixel();
4693 :
4694 : // Since canvas APIs use floats to set up their matrices, we may have some
4695 : // slight rounding errors here. We use NudgeToIntegers() here to adjust
4696 : // matrix components that are integers up to the accuracy of floats to be
4697 : // those integers.
4698 36 : gfxMatrix newTM = aThebesContext->CurrentMatrix().PreTranslate(offset).
4699 18 : PreScale(scale, scale).
4700 18 : NudgeToIntegers();
4701 18 : aThebesContext->SetMatrix(newTM);
4702 :
4703 36 : AutoSaveRestoreRenderingState _(this);
4704 :
4705 18 : bool wouldFlushRetainedLayers = false;
4706 18 : PaintFrameFlags flags = PaintFrameFlags::PAINT_IGNORE_SUPPRESSION;
4707 18 : if (aThebesContext->CurrentMatrix().HasNonIntegerTranslation()) {
4708 3 : flags |= PaintFrameFlags::PAINT_IN_TRANSFORM;
4709 : }
4710 18 : if (!(aFlags & RENDER_ASYNC_DECODE_IMAGES)) {
4711 0 : flags |= PaintFrameFlags::PAINT_SYNC_DECODE_IMAGES;
4712 : }
4713 18 : if (aFlags & RENDER_USE_WIDGET_LAYERS) {
4714 : // We only support using widget layers on display root's with widgets.
4715 0 : nsView* view = rootFrame->GetView();
4716 0 : if (view && view->GetWidget() &&
4717 0 : nsLayoutUtils::GetDisplayRootFrame(rootFrame) == rootFrame) {
4718 0 : LayerManager* layerManager = view->GetWidget()->GetLayerManager();
4719 : // ClientLayerManagers or WebRenderLayerManagers in content processes
4720 : // don't support taking snapshots.
4721 0 : if (layerManager &&
4722 0 : (!layerManager->AsKnowsCompositor() ||
4723 0 : XRE_IsParentProcess())) {
4724 0 : flags |= PaintFrameFlags::PAINT_WIDGET_LAYERS;
4725 : }
4726 : }
4727 : }
4728 18 : if (!(aFlags & RENDER_CARET)) {
4729 18 : wouldFlushRetainedLayers = true;
4730 18 : flags |= PaintFrameFlags::PAINT_HIDE_CARET;
4731 : }
4732 18 : if (aFlags & RENDER_IGNORE_VIEWPORT_SCROLLING) {
4733 18 : wouldFlushRetainedLayers = !IgnoringViewportScrolling();
4734 18 : mRenderFlags = ChangeFlag(mRenderFlags, true, STATE_IGNORING_VIEWPORT_SCROLLING);
4735 : }
4736 18 : if (aFlags & RENDER_DRAWWINDOW_NOT_FLUSHING) {
4737 0 : mRenderFlags = ChangeFlag(mRenderFlags, true, STATE_DRAWWINDOW_NOT_FLUSHING);
4738 : }
4739 18 : if (aFlags & RENDER_DOCUMENT_RELATIVE) {
4740 : // XXX be smarter about this ... drawWindow might want a rect
4741 : // that's "pretty close" to what our retained layer tree covers.
4742 : // In that case, it wouldn't disturb normal rendering too much,
4743 : // and we should allow it.
4744 0 : wouldFlushRetainedLayers = true;
4745 0 : flags |= PaintFrameFlags::PAINT_DOCUMENT_RELATIVE;
4746 : }
4747 :
4748 : // Don't let drawWindow blow away our retained layer tree
4749 18 : if ((flags & PaintFrameFlags::PAINT_WIDGET_LAYERS) && wouldFlushRetainedLayers) {
4750 0 : flags &= ~PaintFrameFlags::PAINT_WIDGET_LAYERS;
4751 : }
4752 :
4753 36 : nsLayoutUtils::PaintFrame(aThebesContext, rootFrame, nsRegion(aRect),
4754 : aBackgroundColor,
4755 : nsDisplayListBuilderMode::PAINTING,
4756 36 : flags);
4757 :
4758 18 : return NS_OK;
4759 : }
4760 :
4761 : /*
4762 : * Clip the display list aList to a range. Returns the clipped
4763 : * rectangle surrounding the range.
4764 : */
4765 : nsRect
4766 0 : PresShell::ClipListToRange(nsDisplayListBuilder *aBuilder,
4767 : nsDisplayList* aList,
4768 : nsRange* aRange)
4769 : {
4770 : // iterate though the display items and add up the bounding boxes of each.
4771 : // This will allow the total area of the frames within the range to be
4772 : // determined. To do this, remove an item from the bottom of the list, check
4773 : // whether it should be part of the range, and if so, append it to the top
4774 : // of the temporary list tmpList. If the item is a text frame at the end of
4775 : // the selection range, clip it to the portion of the text frame that is
4776 : // part of the selection. Then, append the wrapper to the top of the list.
4777 : // Otherwise, just delete the item and don't append it.
4778 0 : nsRect surfaceRect;
4779 0 : nsDisplayList tmpList;
4780 :
4781 : nsDisplayItem* i;
4782 0 : while ((i = aList->RemoveBottom())) {
4783 : // itemToInsert indiciates the item that should be inserted into the
4784 : // temporary list. If null, no item should be inserted.
4785 0 : nsDisplayItem* itemToInsert = nullptr;
4786 0 : nsIFrame* frame = i->Frame();
4787 0 : nsIContent* content = frame->GetContent();
4788 0 : if (content) {
4789 0 : bool atStart = (content == aRange->GetStartContainer());
4790 0 : bool atEnd = (content == aRange->GetEndContainer());
4791 0 : if ((atStart || atEnd) && frame->IsTextFrame()) {
4792 : int32_t frameStartOffset, frameEndOffset;
4793 0 : frame->GetOffsets(frameStartOffset, frameEndOffset);
4794 :
4795 : int32_t hilightStart =
4796 0 : atStart ? std::max(aRange->StartOffset(), frameStartOffset) : frameStartOffset;
4797 : int32_t hilightEnd =
4798 0 : atEnd ? std::min(aRange->EndOffset(), frameEndOffset) : frameEndOffset;
4799 0 : if (hilightStart < hilightEnd) {
4800 : // determine the location of the start and end edges of the range.
4801 0 : nsPoint startPoint, endPoint;
4802 0 : frame->GetPointFromOffset(hilightStart, &startPoint);
4803 0 : frame->GetPointFromOffset(hilightEnd, &endPoint);
4804 :
4805 : // The clip rectangle is determined by taking the the start and
4806 : // end points of the range, offset from the reference frame.
4807 : // Because of rtl, the end point may be to the left of (or above,
4808 : // in vertical mode) the start point, so x (or y) is set to the
4809 : // lower of the values.
4810 0 : nsRect textRect(aBuilder->ToReferenceFrame(frame), frame->GetSize());
4811 0 : if (frame->GetWritingMode().IsVertical()) {
4812 0 : nscoord y = std::min(startPoint.y, endPoint.y);
4813 0 : textRect.y += y;
4814 0 : textRect.height = std::max(startPoint.y, endPoint.y) - y;
4815 : } else {
4816 0 : nscoord x = std::min(startPoint.x, endPoint.x);
4817 0 : textRect.x += x;
4818 0 : textRect.width = std::max(startPoint.x, endPoint.x) - x;
4819 : }
4820 0 : surfaceRect.UnionRect(surfaceRect, textRect);
4821 :
4822 0 : DisplayItemClip newClip;
4823 0 : newClip.SetTo(textRect);
4824 0 : DisplayItemClipChain newClipChain = { newClip, i->GetActiveScrolledRoot(), nullptr };
4825 0 : i->IntersectClip(aBuilder, &newClipChain);
4826 0 : itemToInsert = i;
4827 : }
4828 : }
4829 : // Don't try to descend into subdocuments.
4830 : // If this ever changes we'd need to add handling for subdocuments with
4831 : // different zoom levels.
4832 0 : else if (content->GetUncomposedDoc() ==
4833 0 : aRange->GetStartContainer()->GetUncomposedDoc()) {
4834 : // if the node is within the range, append it to the temporary list
4835 : bool before, after;
4836 : nsresult rv =
4837 0 : nsRange::CompareNodeToRange(content, aRange, &before, &after);
4838 0 : if (NS_SUCCEEDED(rv) && !before && !after) {
4839 0 : itemToInsert = i;
4840 : bool snap;
4841 0 : surfaceRect.UnionRect(surfaceRect, i->GetBounds(aBuilder, &snap));
4842 : }
4843 : }
4844 : }
4845 :
4846 : // insert the item into the list if necessary. If the item has a child
4847 : // list, insert that as well
4848 0 : nsDisplayList* sublist = i->GetSameCoordinateSystemChildren();
4849 0 : if (itemToInsert || sublist) {
4850 0 : tmpList.AppendToTop(itemToInsert ? itemToInsert : i);
4851 : // if the item is a list, iterate over it as well
4852 0 : if (sublist)
4853 : surfaceRect.UnionRect(surfaceRect,
4854 0 : ClipListToRange(aBuilder, sublist, aRange));
4855 : }
4856 : else {
4857 : // otherwise, just delete the item and don't readd it to the list
4858 0 : i->~nsDisplayItem();
4859 : }
4860 : }
4861 :
4862 : // now add all the items back onto the original list again
4863 0 : aList->AppendToTop(&tmpList);
4864 :
4865 0 : return surfaceRect;
4866 : }
4867 :
4868 : #ifdef DEBUG
4869 : #include <stdio.h>
4870 :
4871 : static bool gDumpRangePaintList = false;
4872 : #endif
4873 :
4874 : UniquePtr<RangePaintInfo>
4875 0 : PresShell::CreateRangePaintInfo(nsIDOMRange* aRange,
4876 : nsRect& aSurfaceRect,
4877 : bool aForPrimarySelection)
4878 : {
4879 0 : nsRange* range = static_cast<nsRange*>(aRange);
4880 : nsIFrame* ancestorFrame;
4881 0 : nsIFrame* rootFrame = GetRootFrame();
4882 :
4883 : // If the start or end of the range is the document, just use the root
4884 : // frame, otherwise get the common ancestor of the two endpoints of the
4885 : // range.
4886 0 : nsINode* startContainer = range->GetStartContainer();
4887 0 : nsINode* endContainer = range->GetEndContainer();
4888 0 : nsIDocument* doc = startContainer->GetComposedDoc();
4889 0 : if (startContainer == doc || endContainer == doc) {
4890 0 : ancestorFrame = rootFrame;
4891 : } else {
4892 : nsINode* ancestor =
4893 0 : nsContentUtils::GetCommonAncestor(startContainer, endContainer);
4894 0 : NS_ASSERTION(!ancestor || ancestor->IsNodeOfType(nsINode::eCONTENT),
4895 : "common ancestor is not content");
4896 0 : if (!ancestor || !ancestor->IsNodeOfType(nsINode::eCONTENT))
4897 0 : return nullptr;
4898 :
4899 0 : nsIContent* ancestorContent = static_cast<nsIContent*>(ancestor);
4900 0 : ancestorFrame = ancestorContent->GetPrimaryFrame();
4901 :
4902 : // XXX deal with ancestorFrame being null due to display:contents
4903 :
4904 : // use the nearest ancestor frame that includes all continuations as the
4905 : // root for building the display list
4906 0 : while (ancestorFrame &&
4907 0 : nsLayoutUtils::GetNextContinuationOrIBSplitSibling(ancestorFrame))
4908 0 : ancestorFrame = ancestorFrame->GetParent();
4909 : }
4910 :
4911 0 : if (!ancestorFrame) {
4912 0 : return nullptr;
4913 : }
4914 :
4915 : // get a display list containing the range
4916 0 : auto info = MakeUnique<RangePaintInfo>(range, ancestorFrame);
4917 0 : info->mBuilder.SetIncludeAllOutOfFlows();
4918 0 : if (aForPrimarySelection) {
4919 0 : info->mBuilder.SetSelectedFramesOnly();
4920 : }
4921 0 : info->mBuilder.EnterPresShell(ancestorFrame);
4922 :
4923 0 : nsCOMPtr<nsIContentIterator> iter = NS_NewContentSubtreeIterator();
4924 0 : nsresult rv = iter->Init(range);
4925 0 : if (NS_FAILED(rv)) {
4926 0 : return nullptr;
4927 : }
4928 :
4929 0 : auto BuildDisplayListForNode = [&] (nsINode* aNode) {
4930 0 : if (MOZ_UNLIKELY(!aNode->IsContent())) {
4931 0 : return;
4932 : }
4933 0 : nsIFrame* frame = aNode->AsContent()->GetPrimaryFrame();
4934 : // XXX deal with frame being null due to display:contents
4935 0 : for (; frame; frame = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(frame)) {
4936 0 : frame->BuildDisplayListForStackingContext(&info->mBuilder,
4937 0 : frame->GetVisualOverflowRect(), &info->mList);
4938 : }
4939 0 : };
4940 0 : if (startContainer->NodeType() == nsIDOMNode::TEXT_NODE) {
4941 0 : BuildDisplayListForNode(startContainer);
4942 : }
4943 0 : for (; !iter->IsDone(); iter->Next()) {
4944 0 : nsCOMPtr<nsINode> node = iter->GetCurrentNode();
4945 0 : BuildDisplayListForNode(node);
4946 : }
4947 0 : if (endContainer != startContainer &&
4948 0 : endContainer->NodeType() == nsIDOMNode::TEXT_NODE) {
4949 0 : BuildDisplayListForNode(endContainer);
4950 : }
4951 :
4952 : #ifdef DEBUG
4953 0 : if (gDumpRangePaintList) {
4954 0 : fprintf(stderr, "CreateRangePaintInfo --- before ClipListToRange:\n");
4955 0 : nsFrame::PrintDisplayList(&(info->mBuilder), info->mList);
4956 : }
4957 : #endif
4958 :
4959 0 : nsRect rangeRect = ClipListToRange(&info->mBuilder, &info->mList, range);
4960 :
4961 0 : info->mBuilder.LeavePresShell(ancestorFrame, &info->mList);
4962 :
4963 : #ifdef DEBUG
4964 0 : if (gDumpRangePaintList) {
4965 0 : fprintf(stderr, "CreateRangePaintInfo --- after ClipListToRange:\n");
4966 0 : nsFrame::PrintDisplayList(&(info->mBuilder), info->mList);
4967 : }
4968 : #endif
4969 :
4970 : // determine the offset of the reference frame for the display list
4971 : // to the root frame. This will allow the coordinates used when painting
4972 : // to all be offset from the same point
4973 0 : info->mRootOffset = ancestorFrame->GetOffsetTo(rootFrame);
4974 0 : rangeRect.MoveBy(info->mRootOffset);
4975 0 : aSurfaceRect.UnionRect(aSurfaceRect, rangeRect);
4976 :
4977 0 : return info;
4978 : }
4979 :
4980 : already_AddRefed<SourceSurface>
4981 0 : PresShell::PaintRangePaintInfo(const nsTArray<UniquePtr<RangePaintInfo>>& aItems,
4982 : nsISelection* aSelection,
4983 : nsIntRegion* aRegion,
4984 : nsRect aArea,
4985 : const LayoutDeviceIntPoint aPoint,
4986 : LayoutDeviceIntRect* aScreenRect,
4987 : uint32_t aFlags)
4988 : {
4989 0 : nsPresContext* pc = GetPresContext();
4990 0 : if (!pc || aArea.width == 0 || aArea.height == 0)
4991 0 : return nullptr;
4992 :
4993 : // use the rectangle to create the surface
4994 0 : nsIntRect pixelArea = aArea.ToOutsidePixels(pc->AppUnitsPerDevPixel());
4995 :
4996 : // if the image should not be resized, the scale, relative to the original image, must be 1
4997 0 : float scale = 1.0;
4998 : nsIntRect rootScreenRect =
4999 0 : GetRootFrame()->GetScreenRectInAppUnits().ToNearestPixels(
5000 0 : pc->AppUnitsPerDevPixel());
5001 :
5002 0 : nsRect maxSize;
5003 0 : pc->DeviceContext()->GetClientRect(maxSize);
5004 :
5005 : // check if the image should be resized
5006 0 : bool resize = aFlags & RENDER_AUTO_SCALE;
5007 :
5008 0 : if (resize) {
5009 : // check if image-resizing-algorithm should be used
5010 0 : if (aFlags & RENDER_IS_IMAGE) {
5011 : // get max screensize
5012 0 : nscoord maxWidth = pc->AppUnitsToDevPixels(maxSize.width);
5013 0 : nscoord maxHeight = pc->AppUnitsToDevPixels(maxSize.height);
5014 : // resize image relative to the screensize
5015 : // get best height/width relative to screensize
5016 0 : float bestHeight = float(maxHeight)*RELATIVE_SCALEFACTOR;
5017 0 : float bestWidth = float(maxWidth)*RELATIVE_SCALEFACTOR;
5018 : // get scalefactor to reach bestWidth
5019 0 : scale = bestWidth / float(pixelArea.width);
5020 : // get the worst height (height when width is perfect)
5021 0 : float worstHeight = float(pixelArea.height)*scale;
5022 : // get the difference of best and worst height
5023 0 : float difference = bestHeight - worstHeight;
5024 : // half the difference and add it to worstHeight,
5025 : // then get scalefactor to reach this
5026 0 : scale = (worstHeight + difference / 2) / float(pixelArea.height);
5027 : } else {
5028 : // get half of max screensize
5029 0 : nscoord maxWidth = pc->AppUnitsToDevPixels(maxSize.width >> 1);
5030 0 : nscoord maxHeight = pc->AppUnitsToDevPixels(maxSize.height >> 1);
5031 0 : if (pixelArea.width > maxWidth || pixelArea.height > maxHeight) {
5032 0 : scale = 1.0;
5033 : // divide the maximum size by the image size in both directions. Whichever
5034 : // direction produces the smallest result determines how much should be
5035 : // scaled.
5036 0 : if (pixelArea.width > maxWidth)
5037 0 : scale = std::min(scale, float(maxWidth) / pixelArea.width);
5038 0 : if (pixelArea.height > maxHeight)
5039 0 : scale = std::min(scale, float(maxHeight) / pixelArea.height);
5040 : }
5041 : }
5042 :
5043 :
5044 0 : pixelArea.width = NSToIntFloor(float(pixelArea.width) * scale);
5045 0 : pixelArea.height = NSToIntFloor(float(pixelArea.height) * scale);
5046 0 : if (!pixelArea.width || !pixelArea.height)
5047 0 : return nullptr;
5048 :
5049 : // adjust the screen position based on the rescaled size
5050 0 : nscoord left = rootScreenRect.x + pixelArea.x;
5051 0 : nscoord top = rootScreenRect.y + pixelArea.y;
5052 0 : aScreenRect->x = NSToIntFloor(aPoint.x - float(aPoint.x - left) * scale);
5053 0 : aScreenRect->y = NSToIntFloor(aPoint.y - float(aPoint.y - top) * scale);
5054 : }
5055 : else {
5056 : // move aScreenRect to the position of the surface in screen coordinates
5057 0 : aScreenRect->MoveTo(rootScreenRect.x + pixelArea.x, rootScreenRect.y + pixelArea.y);
5058 : }
5059 0 : aScreenRect->width = pixelArea.width;
5060 0 : aScreenRect->height = pixelArea.height;
5061 :
5062 : RefPtr<DrawTarget> dt =
5063 0 : gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
5064 0 : IntSize(pixelArea.width, pixelArea.height),
5065 0 : SurfaceFormat::B8G8R8A8);
5066 0 : if (!dt || !dt->IsValid()) {
5067 0 : return nullptr;
5068 : }
5069 :
5070 0 : RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(dt);
5071 0 : MOZ_ASSERT(ctx); // already checked the draw target above
5072 :
5073 0 : if (aRegion) {
5074 0 : RefPtr<PathBuilder> builder = dt->CreatePathBuilder(FillRule::FILL_WINDING);
5075 :
5076 : // Convert aRegion from CSS pixels to dev pixels
5077 : nsIntRegion region =
5078 0 : aRegion->ToAppUnits(nsPresContext::AppUnitsPerCSSPixel())
5079 0 : .ToOutsidePixels(pc->AppUnitsPerDevPixel());
5080 0 : for (auto iter = region.RectIter(); !iter.Done(); iter.Next()) {
5081 0 : const nsIntRect& rect = iter.Get();
5082 :
5083 0 : builder->MoveTo(rect.TopLeft());
5084 0 : builder->LineTo(rect.TopRight());
5085 0 : builder->LineTo(rect.BottomRight());
5086 0 : builder->LineTo(rect.BottomLeft());
5087 0 : builder->LineTo(rect.TopLeft());
5088 : }
5089 :
5090 0 : RefPtr<Path> path = builder->Finish();
5091 0 : ctx->Clip(path);
5092 : }
5093 :
5094 0 : gfxMatrix initialTM = ctx->CurrentMatrix();
5095 :
5096 0 : if (resize)
5097 0 : initialTM.PreScale(scale, scale);
5098 :
5099 : // translate so that points are relative to the surface area
5100 : gfxPoint surfaceOffset =
5101 0 : nsLayoutUtils::PointToGfxPoint(-aArea.TopLeft(), pc->AppUnitsPerDevPixel());
5102 0 : initialTM.PreTranslate(surfaceOffset);
5103 :
5104 : // temporarily hide the selection so that text is drawn normally. If a
5105 : // selection is being rendered, use that, otherwise use the presshell's
5106 : // selection.
5107 0 : RefPtr<nsFrameSelection> frameSelection;
5108 0 : if (aSelection) {
5109 0 : frameSelection = aSelection->AsSelection()->GetFrameSelection();
5110 : }
5111 : else {
5112 0 : frameSelection = FrameSelection();
5113 : }
5114 0 : int16_t oldDisplaySelection = frameSelection->GetDisplaySelection();
5115 0 : frameSelection->SetDisplaySelection(nsISelectionController::SELECTION_HIDDEN);
5116 :
5117 : // next, paint each range in the selection
5118 0 : for (const UniquePtr<RangePaintInfo>& rangeInfo : aItems) {
5119 : // the display lists paint relative to the offset from the reference
5120 : // frame, so account for that translation too:
5121 : gfxPoint rootOffset =
5122 0 : nsLayoutUtils::PointToGfxPoint(rangeInfo->mRootOffset,
5123 0 : pc->AppUnitsPerDevPixel());
5124 0 : ctx->SetMatrix(gfxMatrix(initialTM).PreTranslate(rootOffset));
5125 0 : aArea.MoveBy(-rangeInfo->mRootOffset.x, -rangeInfo->mRootOffset.y);
5126 0 : nsRegion visible(aArea);
5127 : RefPtr<LayerManager> layerManager =
5128 0 : rangeInfo->mList.PaintRoot(&rangeInfo->mBuilder, ctx,
5129 0 : nsDisplayList::PAINT_DEFAULT);
5130 0 : aArea.MoveBy(rangeInfo->mRootOffset.x, rangeInfo->mRootOffset.y);
5131 : }
5132 :
5133 : // restore the old selection display state
5134 0 : frameSelection->SetDisplaySelection(oldDisplaySelection);
5135 :
5136 0 : return dt->Snapshot();
5137 : }
5138 :
5139 : already_AddRefed<SourceSurface>
5140 0 : PresShell::RenderNode(nsIDOMNode* aNode,
5141 : nsIntRegion* aRegion,
5142 : const LayoutDeviceIntPoint aPoint,
5143 : LayoutDeviceIntRect* aScreenRect,
5144 : uint32_t aFlags)
5145 : {
5146 : // area will hold the size of the surface needed to draw the node, measured
5147 : // from the root frame.
5148 0 : nsRect area;
5149 0 : nsTArray<UniquePtr<RangePaintInfo>> rangeItems;
5150 :
5151 : // nothing to draw if the node isn't in a document
5152 0 : nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
5153 0 : if (!node->IsInUncomposedDoc())
5154 0 : return nullptr;
5155 :
5156 0 : RefPtr<nsRange> range = new nsRange(node);
5157 0 : if (NS_FAILED(range->SelectNode(aNode)))
5158 0 : return nullptr;
5159 :
5160 0 : UniquePtr<RangePaintInfo> info = CreateRangePaintInfo(range, area, false);
5161 0 : if (info && !rangeItems.AppendElement(Move(info))) {
5162 0 : return nullptr;
5163 : }
5164 :
5165 0 : if (aRegion) {
5166 : // combine the area with the supplied region
5167 0 : nsIntRect rrectPixels = aRegion->GetBounds();
5168 :
5169 0 : nsRect rrect = ToAppUnits(rrectPixels, nsPresContext::AppUnitsPerCSSPixel());
5170 0 : area.IntersectRect(area, rrect);
5171 :
5172 0 : nsPresContext* pc = GetPresContext();
5173 0 : if (!pc)
5174 0 : return nullptr;
5175 :
5176 : // move the region so that it is offset from the topleft corner of the surface
5177 0 : aRegion->MoveBy(-nsPresContext::AppUnitsToIntCSSPixels(area.x),
5178 0 : -nsPresContext::AppUnitsToIntCSSPixels(area.y));
5179 : }
5180 :
5181 : return PaintRangePaintInfo(rangeItems, nullptr, aRegion, area, aPoint,
5182 0 : aScreenRect, aFlags);
5183 : }
5184 :
5185 : already_AddRefed<SourceSurface>
5186 0 : PresShell::RenderSelection(nsISelection* aSelection,
5187 : const LayoutDeviceIntPoint aPoint,
5188 : LayoutDeviceIntRect* aScreenRect,
5189 : uint32_t aFlags)
5190 : {
5191 : // area will hold the size of the surface needed to draw the selection,
5192 : // measured from the root frame.
5193 0 : nsRect area;
5194 0 : nsTArray<UniquePtr<RangePaintInfo>> rangeItems;
5195 :
5196 : // iterate over each range and collect them into the rangeItems array.
5197 : // This is done so that the size of selection can be determined so as
5198 : // to allocate a surface area
5199 : int32_t numRanges;
5200 0 : aSelection->GetRangeCount(&numRanges);
5201 0 : NS_ASSERTION(numRanges > 0, "RenderSelection called with no selection");
5202 :
5203 0 : for (int32_t r = 0; r < numRanges; r++)
5204 : {
5205 0 : nsCOMPtr<nsIDOMRange> range;
5206 0 : aSelection->GetRangeAt(r, getter_AddRefs(range));
5207 :
5208 0 : UniquePtr<RangePaintInfo> info = CreateRangePaintInfo(range, area, true);
5209 0 : if (info && !rangeItems.AppendElement(Move(info))) {
5210 0 : return nullptr;
5211 : }
5212 : }
5213 :
5214 : return PaintRangePaintInfo(rangeItems, aSelection, nullptr, area, aPoint,
5215 0 : aScreenRect, aFlags);
5216 : }
5217 :
5218 : void
5219 0 : PresShell::AddPrintPreviewBackgroundItem(nsDisplayListBuilder& aBuilder,
5220 : nsDisplayList& aList,
5221 : nsIFrame* aFrame,
5222 : const nsRect& aBounds)
5223 : {
5224 : aList.AppendNewToBottom(new (&aBuilder)
5225 0 : nsDisplaySolidColor(&aBuilder, aFrame, aBounds, NS_RGB(115, 115, 115)));
5226 0 : }
5227 :
5228 : static bool
5229 2 : AddCanvasBackgroundColor(const nsDisplayList& aList, nsIFrame* aCanvasFrame,
5230 : nscolor aColor, bool aCSSBackgroundColor)
5231 : {
5232 6 : for (nsDisplayItem* i = aList.GetBottom(); i; i = i->GetAbove()) {
5233 10 : if (i->Frame() == aCanvasFrame &&
5234 4 : i->GetType() == nsDisplayItem::TYPE_CANVAS_BACKGROUND_COLOR) {
5235 2 : nsDisplayCanvasBackgroundColor* bg = static_cast<nsDisplayCanvasBackgroundColor*>(i);
5236 2 : bg->SetExtraBackgroundColor(aColor);
5237 2 : return true;
5238 : }
5239 4 : nsDisplayList* sublist = i->GetSameCoordinateSystemChildren();
5240 4 : if (sublist &&
5241 4 : !(i->GetType() == nsDisplayItem::TYPE_BLEND_CONTAINER && !aCSSBackgroundColor) &&
5242 0 : AddCanvasBackgroundColor(*sublist, aCanvasFrame, aColor, aCSSBackgroundColor))
5243 0 : return true;
5244 : }
5245 0 : return false;
5246 : }
5247 :
5248 : void
5249 44 : PresShell::AddCanvasBackgroundColorItem(nsDisplayListBuilder& aBuilder,
5250 : nsDisplayList& aList,
5251 : nsIFrame* aFrame,
5252 : const nsRect& aBounds,
5253 : nscolor aBackstopColor,
5254 : uint32_t aFlags)
5255 : {
5256 44 : if (aBounds.IsEmpty()) {
5257 0 : return;
5258 : }
5259 : // We don't want to add an item for the canvas background color if the frame
5260 : // (sub)tree we are painting doesn't include any canvas frames. There isn't
5261 : // an easy way to check this directly, but if we check if the root of the
5262 : // (sub)tree we are painting is a canvas frame that should cover us in all
5263 : // cases (it will usually be a viewport frame when we have a canvas frame in
5264 : // the (sub)tree).
5265 88 : if (!(aFlags & nsIPresShell::FORCE_DRAW) &&
5266 44 : !nsCSSRendering::IsCanvasFrame(aFrame)) {
5267 0 : return;
5268 : }
5269 :
5270 44 : nscolor bgcolor = NS_ComposeColors(aBackstopColor, mCanvasBackgroundColor);
5271 44 : if (NS_GET_A(bgcolor) == 0)
5272 18 : return;
5273 :
5274 : // To make layers work better, we want to avoid having a big non-scrolled
5275 : // color background behind a scrolled transparent background. Instead,
5276 : // we'll try to move the color background into the scrolled content
5277 : // by making nsDisplayCanvasBackground paint it.
5278 : // If we're only adding an unscrolled item, then pretend that we've
5279 : // already done it.
5280 26 : bool addedScrollingBackgroundColor = (aFlags & APPEND_UNSCROLLED_ONLY);
5281 26 : if (!aFrame->GetParent() && !addedScrollingBackgroundColor) {
5282 : nsIScrollableFrame* sf =
5283 26 : aFrame->PresContext()->PresShell()->GetRootScrollFrameAsScrollable();
5284 26 : if (sf) {
5285 2 : nsCanvasFrame* canvasFrame = do_QueryFrame(sf->GetScrolledFrame());
5286 2 : if (canvasFrame && canvasFrame->IsVisibleForPainting(&aBuilder)) {
5287 : addedScrollingBackgroundColor =
5288 2 : AddCanvasBackgroundColor(aList, canvasFrame, bgcolor, mHasCSSBackgroundColor);
5289 : }
5290 : }
5291 : }
5292 :
5293 : // With async scrolling, we'd like to have two instances of the background
5294 : // color: one that scrolls with the content (for the reasons stated above),
5295 : // and one underneath which does not scroll with the content, but which can
5296 : // be shown during checkerboarding and overscroll.
5297 : // We can only do that if the color is opaque.
5298 52 : bool forceUnscrolledItem = nsLayoutUtils::UsesAsyncScrolling(aFrame) &&
5299 52 : NS_GET_A(bgcolor) == 255;
5300 26 : if ((aFlags & ADD_FOR_SUBDOC) && gfxPrefs::LayoutUseContainersForRootFrames()) {
5301 : // If we're using ContainerLayers for a subdoc, then any items we add here will
5302 : // still be scrolled (since we're inside the container at this point), so don't
5303 : // bother and we will do it manually later.
5304 0 : forceUnscrolledItem = false;
5305 : }
5306 :
5307 26 : if (!addedScrollingBackgroundColor || forceUnscrolledItem) {
5308 : aList.AppendNewToBottom(
5309 26 : new (&aBuilder) nsDisplaySolidColor(&aBuilder, aFrame, aBounds, bgcolor));
5310 : }
5311 : }
5312 :
5313 2 : static bool IsTransparentContainerElement(nsPresContext* aPresContext)
5314 : {
5315 4 : nsCOMPtr<nsIDocShell> docShell = aPresContext->GetDocShell();
5316 2 : if (!docShell) {
5317 0 : return false;
5318 : }
5319 :
5320 4 : nsCOMPtr<nsPIDOMWindowOuter> pwin = docShell->GetWindow();
5321 2 : if (!pwin)
5322 0 : return false;
5323 4 : nsCOMPtr<Element> containerElement = pwin->GetFrameElementInternal();
5324 :
5325 2 : TabChild* tab = TabChild::GetFrom(docShell);
5326 2 : if (tab) {
5327 : // Check if presShell is the top PresShell. Only the top can
5328 : // influence the canvas background color.
5329 4 : nsCOMPtr<nsIPresShell> presShell = aPresContext->GetPresShell();
5330 4 : nsCOMPtr<nsIPresShell> topPresShell = tab->GetPresShell();
5331 2 : if (presShell != topPresShell) {
5332 0 : tab = nullptr;
5333 : }
5334 : }
5335 :
5336 0 : return (containerElement &&
5337 2 : containerElement->HasAttr(kNameSpaceID_None, nsGkAtoms::transparent))
5338 4 : || (tab && tab->IsTransparent());
5339 : }
5340 :
5341 26 : nscolor PresShell::GetDefaultBackgroundColorToDraw()
5342 : {
5343 26 : if (!mPresContext || !mPresContext->GetBackgroundColorDraw()) {
5344 0 : return NS_RGB(255,255,255);
5345 : }
5346 26 : return mPresContext->DefaultBackgroundColor();
5347 : }
5348 :
5349 53 : void PresShell::UpdateCanvasBackground()
5350 : {
5351 : // If we have a frame tree and it has style information that
5352 : // specifies the background color of the canvas, update our local
5353 : // cache of that color.
5354 53 : nsIFrame* rootStyleFrame = FrameConstructor()->GetRootElementStyleFrame();
5355 53 : if (rootStyleFrame) {
5356 : nsStyleContext* bgStyle =
5357 53 : nsCSSRendering::FindRootFrameBackground(rootStyleFrame);
5358 : // XXX We should really be passing the canvasframe, not the root element
5359 : // style frame but we don't have access to the canvasframe here. It isn't
5360 : // a problem because only a few frames can return something other than true
5361 : // and none of them would be a canvas frame or root element style frame.
5362 : bool drawBackgroundImage;
5363 : bool drawBackgroundColor;
5364 53 : mCanvasBackgroundColor =
5365 53 : nsCSSRendering::DetermineBackgroundColor(mPresContext, bgStyle,
5366 : rootStyleFrame,
5367 : drawBackgroundImage,
5368 : drawBackgroundColor);
5369 53 : mHasCSSBackgroundColor = drawBackgroundColor;
5370 55 : if (mPresContext->IsRootContentDocument() &&
5371 2 : !IsTransparentContainerElement(mPresContext)) {
5372 2 : mCanvasBackgroundColor =
5373 2 : NS_ComposeColors(GetDefaultBackgroundColorToDraw(), mCanvasBackgroundColor);
5374 : }
5375 : }
5376 :
5377 : // If the root element of the document (ie html) has style 'display: none'
5378 : // then the document's background color does not get drawn; cache the
5379 : // color we actually draw.
5380 53 : if (!FrameConstructor()->GetRootElementFrame()) {
5381 0 : mCanvasBackgroundColor = GetDefaultBackgroundColorToDraw();
5382 : }
5383 53 : }
5384 :
5385 28 : nscolor PresShell::ComputeBackstopColor(nsView* aDisplayRoot)
5386 : {
5387 28 : nsIWidget* widget = aDisplayRoot->GetWidget();
5388 52 : if (widget && (widget->GetTransparencyMode() != eTransparencyOpaque ||
5389 24 : widget->WidgetPaintsBackground())) {
5390 : // Within a transparent widget, so the backstop color must be
5391 : // totally transparent.
5392 4 : return NS_RGBA(0,0,0,0);
5393 : }
5394 : // Within an opaque widget (or no widget at all), so the backstop
5395 : // color must be totally opaque. The user's default background
5396 : // as reported by the prescontext is guaranteed to be opaque.
5397 24 : return GetDefaultBackgroundColorToDraw();
5398 : }
5399 :
5400 : struct PaintParams {
5401 : nscolor mBackgroundColor;
5402 : };
5403 :
5404 0 : LayerManager* PresShell::GetLayerManager()
5405 : {
5406 0 : NS_ASSERTION(mViewManager, "Should have view manager");
5407 :
5408 0 : nsView* rootView = mViewManager->GetRootView();
5409 0 : if (rootView) {
5410 0 : if (nsIWidget* widget = rootView->GetWidget()) {
5411 0 : return widget->GetLayerManager();
5412 : }
5413 : }
5414 0 : return nullptr;
5415 : }
5416 :
5417 0 : bool PresShell::AsyncPanZoomEnabled()
5418 : {
5419 0 : NS_ASSERTION(mViewManager, "Should have view manager");
5420 0 : nsView* rootView = mViewManager->GetRootView();
5421 0 : if (rootView) {
5422 0 : if (nsIWidget* widget = rootView->GetWidget()) {
5423 0 : return widget->AsyncPanZoomEnabled();
5424 : }
5425 : }
5426 0 : return gfxPlatform::AsyncPanZoomEnabled();
5427 : }
5428 :
5429 0 : void PresShell::SetIgnoreViewportScrolling(bool aIgnore)
5430 : {
5431 0 : if (IgnoringViewportScrolling() == aIgnore) {
5432 0 : return;
5433 : }
5434 0 : RenderingState state(this);
5435 0 : state.mRenderFlags = ChangeFlag(state.mRenderFlags, aIgnore,
5436 : STATE_IGNORING_VIEWPORT_SCROLLING);
5437 0 : SetRenderingState(state);
5438 : }
5439 :
5440 0 : nsresult PresShell::SetResolutionImpl(float aResolution, bool aScaleToResolution)
5441 : {
5442 0 : if (!(aResolution > 0.0)) {
5443 0 : return NS_ERROR_ILLEGAL_VALUE;
5444 : }
5445 0 : if (aResolution == mResolution.valueOr(0.0)) {
5446 0 : MOZ_ASSERT(mResolution.isSome());
5447 0 : return NS_OK;
5448 : }
5449 0 : RenderingState state(this);
5450 0 : state.mResolution = Some(aResolution);
5451 0 : SetRenderingState(state);
5452 0 : mScaleToResolution = aScaleToResolution;
5453 0 : if (mMobileViewportManager) {
5454 0 : mMobileViewportManager->ResolutionUpdated();
5455 : }
5456 :
5457 0 : return NS_OK;
5458 : }
5459 :
5460 44 : bool PresShell::ScaleToResolution() const
5461 : {
5462 44 : return mScaleToResolution;
5463 : }
5464 :
5465 90 : float PresShell::GetCumulativeResolution()
5466 : {
5467 90 : float resolution = GetResolution();
5468 90 : nsPresContext* parentCtx = GetPresContext()->GetParentPresContext();
5469 90 : if (parentCtx) {
5470 0 : resolution *= parentCtx->PresShell()->GetCumulativeResolution();
5471 : }
5472 90 : return resolution;
5473 : }
5474 :
5475 80 : float PresShell::GetCumulativeNonRootScaleResolution()
5476 : {
5477 80 : float resolution = 1.0;
5478 80 : nsIPresShell* currentShell = this;
5479 240 : while (currentShell) {
5480 80 : nsPresContext* currentCtx = currentShell->GetPresContext();
5481 80 : if (currentCtx != currentCtx->GetRootPresContext()) {
5482 0 : resolution *= currentShell->ScaleToResolution() ? currentShell->GetResolution() : 1.0f;
5483 : }
5484 80 : nsPresContext* parentCtx = currentCtx->GetParentPresContext();
5485 80 : if (parentCtx) {
5486 0 : currentShell = parentCtx->PresShell();
5487 : } else {
5488 80 : currentShell = nullptr;
5489 : }
5490 : }
5491 80 : return resolution;
5492 : }
5493 :
5494 0 : void PresShell::SetRestoreResolution(float aResolution,
5495 : LayoutDeviceIntSize aDisplaySize)
5496 : {
5497 0 : if (mMobileViewportManager) {
5498 0 : mMobileViewportManager->SetRestoreResolution(aResolution, aDisplaySize);
5499 : }
5500 0 : }
5501 :
5502 0 : void PresShell::SetRenderingState(const RenderingState& aState)
5503 : {
5504 0 : if (mRenderFlags != aState.mRenderFlags) {
5505 : // Rendering state changed in a way that forces us to flush any
5506 : // retained layers we might already have.
5507 0 : LayerManager* manager = GetLayerManager();
5508 0 : if (manager) {
5509 0 : FrameLayerBuilder::InvalidateAllLayers(manager);
5510 : }
5511 : }
5512 :
5513 0 : mRenderFlags = aState.mRenderFlags;
5514 0 : mResolution = aState.mResolution;
5515 0 : }
5516 :
5517 136 : void PresShell::SynthesizeMouseMove(bool aFromScroll)
5518 : {
5519 136 : if (!sSynthMouseMove)
5520 0 : return;
5521 :
5522 136 : if (mPaintingSuppressed || !mIsActive || !mPresContext) {
5523 51 : return;
5524 : }
5525 :
5526 85 : if (!mPresContext->IsRoot()) {
5527 0 : nsIPresShell* rootPresShell = GetRootPresShell();
5528 0 : if (rootPresShell) {
5529 0 : rootPresShell->SynthesizeMouseMove(aFromScroll);
5530 : }
5531 0 : return;
5532 : }
5533 :
5534 85 : if (mMouseLocation == nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE))
5535 81 : return;
5536 :
5537 4 : if (!mSynthMouseMoveEvent.IsPending()) {
5538 : RefPtr<nsSynthMouseMoveEvent> ev =
5539 2 : new nsSynthMouseMoveEvent(this, aFromScroll);
5540 :
5541 1 : if (!GetPresContext()->RefreshDriver()
5542 1 : ->AddRefreshObserver(ev, FlushType::Display)) {
5543 0 : NS_WARNING("failed to dispatch nsSynthMouseMoveEvent");
5544 0 : return;
5545 : }
5546 :
5547 1 : mSynthMouseMoveEvent = ev;
5548 : }
5549 : }
5550 :
5551 : /**
5552 : * Find the first floating view with a widget in a postorder traversal of the
5553 : * view tree that contains the point. Thus more deeply nested floating views
5554 : * are preferred over their ancestors, and floating views earlier in the
5555 : * view hierarchy (i.e., added later) are preferred over their siblings.
5556 : * This is adequate for finding the "topmost" floating view under a point,
5557 : * given that floating views don't supporting having a specific z-index.
5558 : *
5559 : * We cannot exit early when aPt is outside the view bounds, because floating
5560 : * views aren't necessarily included in their parent's bounds, so this could
5561 : * traverse the entire view hierarchy --- use carefully.
5562 : */
5563 0 : static nsView* FindFloatingViewContaining(nsView* aView, nsPoint aPt)
5564 : {
5565 0 : if (aView->GetVisibility() == nsViewVisibility_kHide)
5566 : // No need to look into descendants.
5567 0 : return nullptr;
5568 :
5569 0 : nsIFrame* frame = aView->GetFrame();
5570 0 : if (frame) {
5571 0 : if (!frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) ||
5572 0 : !frame->PresContext()->PresShell()->IsActive()) {
5573 0 : return nullptr;
5574 : }
5575 : }
5576 :
5577 0 : for (nsView* v = aView->GetFirstChild(); v; v = v->GetNextSibling()) {
5578 0 : nsView* r = FindFloatingViewContaining(v, v->ConvertFromParentCoords(aPt));
5579 0 : if (r)
5580 0 : return r;
5581 : }
5582 :
5583 0 : if (aView->GetFloating() && aView->HasWidget() &&
5584 0 : aView->GetDimensions().Contains(aPt))
5585 0 : return aView;
5586 :
5587 0 : return nullptr;
5588 : }
5589 :
5590 : /*
5591 : * This finds the first view containing the given point in a postorder
5592 : * traversal of the view tree that contains the point, assuming that the
5593 : * point is not in a floating view. It assumes that only floating views
5594 : * extend outside the bounds of their parents.
5595 : *
5596 : * This methods should only be called if FindFloatingViewContaining
5597 : * returns null.
5598 : */
5599 0 : static nsView* FindViewContaining(nsView* aView, nsPoint aPt)
5600 : {
5601 0 : if (!aView->GetDimensions().Contains(aPt) ||
5602 0 : aView->GetVisibility() == nsViewVisibility_kHide) {
5603 0 : return nullptr;
5604 : }
5605 :
5606 0 : nsIFrame* frame = aView->GetFrame();
5607 0 : if (frame) {
5608 0 : if (!frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) ||
5609 0 : !frame->PresContext()->PresShell()->IsActive()) {
5610 0 : return nullptr;
5611 : }
5612 : }
5613 :
5614 0 : for (nsView* v = aView->GetFirstChild(); v; v = v->GetNextSibling()) {
5615 0 : nsView* r = FindViewContaining(v, v->ConvertFromParentCoords(aPt));
5616 0 : if (r)
5617 0 : return r;
5618 : }
5619 :
5620 0 : return aView;
5621 : }
5622 :
5623 : void
5624 1 : PresShell::ProcessSynthMouseMoveEvent(bool aFromScroll)
5625 : {
5626 : // If drag session has started, we shouldn't synthesize mousemove event.
5627 1 : nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
5628 1 : if (dragSession) {
5629 0 : mSynthMouseMoveEvent.Forget();
5630 0 : return;
5631 : }
5632 :
5633 : // allow new event to be posted while handling this one only if the
5634 : // source of the event is a scroll (to prevent infinite reflow loops)
5635 1 : if (aFromScroll) {
5636 0 : mSynthMouseMoveEvent.Forget();
5637 : }
5638 :
5639 1 : nsView* rootView = mViewManager ? mViewManager->GetRootView() : nullptr;
5640 3 : if (mMouseLocation == nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE) ||
5641 3 : !rootView || !rootView->HasWidget() || !mPresContext) {
5642 1 : mSynthMouseMoveEvent.Forget();
5643 1 : return;
5644 : }
5645 :
5646 0 : NS_ASSERTION(mPresContext->IsRoot(), "Only a root pres shell should be here");
5647 :
5648 : // Hold a ref to ourselves so DispatchEvent won't destroy us (since
5649 : // we need to access members after we call DispatchEvent).
5650 0 : nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
5651 :
5652 : #ifdef DEBUG_MOUSE_LOCATION
5653 : printf("[ps=%p]synthesizing mouse move to (%d,%d)\n",
5654 : this, mMouseLocation.x, mMouseLocation.y);
5655 : #endif
5656 :
5657 0 : int32_t APD = mPresContext->AppUnitsPerDevPixel();
5658 :
5659 : // We need a widget to put in the event we are going to dispatch so we look
5660 : // for a view that has a widget and the mouse location is over. We first look
5661 : // for floating views, if there isn't one we use the root view. |view| holds
5662 : // that view.
5663 0 : nsView* view = nullptr;
5664 :
5665 : // The appunits per devpixel ratio of |view|.
5666 : int32_t viewAPD;
5667 :
5668 : // mRefPoint will be mMouseLocation relative to the widget of |view|, the
5669 : // widget we will put in the event we dispatch, in viewAPD appunits
5670 0 : nsPoint refpoint(0, 0);
5671 :
5672 : // We always dispatch the event to the pres shell that contains the view that
5673 : // the mouse is over. pointVM is the VM of that pres shell.
5674 0 : nsViewManager *pointVM = nullptr;
5675 :
5676 : // This could be a bit slow (traverses entire view hierarchy)
5677 : // but it's OK to do it once per synthetic mouse event
5678 0 : view = FindFloatingViewContaining(rootView, mMouseLocation);
5679 0 : if (!view) {
5680 0 : view = rootView;
5681 0 : nsView *pointView = FindViewContaining(rootView, mMouseLocation);
5682 : // pointView can be null in situations related to mouse capture
5683 0 : pointVM = (pointView ? pointView : view)->GetViewManager();
5684 0 : refpoint = mMouseLocation + rootView->ViewToWidgetOffset();
5685 0 : viewAPD = APD;
5686 : } else {
5687 0 : pointVM = view->GetViewManager();
5688 0 : nsIFrame* frame = view->GetFrame();
5689 0 : NS_ASSERTION(frame, "floating views can't be anonymous");
5690 0 : viewAPD = frame->PresContext()->AppUnitsPerDevPixel();
5691 0 : refpoint = mMouseLocation.ScaleToOtherAppUnits(APD, viewAPD);
5692 0 : refpoint -= view->GetOffsetTo(rootView);
5693 0 : refpoint += view->ViewToWidgetOffset();
5694 : }
5695 0 : NS_ASSERTION(view->GetWidget(), "view should have a widget here");
5696 : WidgetMouseEvent event(true, eMouseMove, view->GetWidget(),
5697 0 : WidgetMouseEvent::eSynthesized);
5698 : event.mRefPoint =
5699 0 : LayoutDeviceIntPoint::FromAppUnitsToNearest(refpoint, viewAPD);
5700 0 : event.mTime = PR_IntervalNow();
5701 : // XXX set event.mModifiers ?
5702 : // XXX mnakano I think that we should get the latest information from widget.
5703 :
5704 0 : nsCOMPtr<nsIPresShell> shell = pointVM->GetPresShell();
5705 0 : if (shell) {
5706 : // Since this gets run in a refresh tick there isn't an InputAPZContext on
5707 : // the stack from the nsBaseWidget. We need to simulate one with at least
5708 : // the correct target guid, so that the correct callback transform gets
5709 : // applied if this event goes to a child process. The input block id is set
5710 : // to 0 because this is a synthetic event which doesn't really belong to any
5711 : // input block. Same for the APZ response field.
5712 0 : InputAPZContext apzContext(mMouseEventTargetGuid, 0, nsEventStatus_eIgnore);
5713 0 : shell->DispatchSynthMouseMove(&event, !aFromScroll);
5714 : }
5715 :
5716 0 : if (!aFromScroll) {
5717 0 : mSynthMouseMoveEvent.Forget();
5718 : }
5719 : }
5720 :
5721 : static void
5722 0 : AddFrameToVisibleRegions(nsIFrame* aFrame,
5723 : nsViewManager* aViewManager,
5724 : Maybe<VisibleRegions>& aVisibleRegions)
5725 : {
5726 0 : if (!aVisibleRegions) {
5727 0 : return;
5728 : }
5729 :
5730 0 : MOZ_ASSERT(aFrame);
5731 0 : MOZ_ASSERT(aViewManager);
5732 :
5733 : // Retrieve the view ID for this frame (which we obtain from the enclosing
5734 : // scrollable frame).
5735 : nsIScrollableFrame* scrollableFrame =
5736 : nsLayoutUtils::GetNearestScrollableFrame(aFrame,
5737 : nsLayoutUtils::SCROLLABLE_ONLY_ASYNC_SCROLLABLE |
5738 0 : nsLayoutUtils::SCROLLABLE_ALWAYS_MATCH_ROOT);
5739 0 : if (!scrollableFrame) {
5740 0 : return;
5741 : }
5742 :
5743 0 : nsIFrame* scrollableFrameAsFrame = do_QueryFrame(scrollableFrame);
5744 0 : MOZ_ASSERT(scrollableFrameAsFrame);
5745 :
5746 0 : nsIContent* scrollableFrameContent = scrollableFrameAsFrame->GetContent();
5747 0 : if (!scrollableFrameContent) {
5748 0 : return;
5749 : }
5750 :
5751 : ViewID viewID;
5752 0 : if (!nsLayoutUtils::FindIDFor(scrollableFrameContent, &viewID)) {
5753 0 : return ;
5754 : }
5755 :
5756 : // Update the visible region for the appropriate view ID.
5757 0 : nsRect frameRectInScrolledFrameSpace = aFrame->GetVisualOverflowRect();
5758 : nsLayoutUtils::TransformResult result =
5759 0 : nsLayoutUtils::TransformRect(aFrame,
5760 0 : scrollableFrame->GetScrolledFrame(),
5761 0 : frameRectInScrolledFrameSpace);
5762 0 : if (result != nsLayoutUtils::TransformResult::TRANSFORM_SUCCEEDED) {
5763 0 : return;
5764 : }
5765 :
5766 0 : CSSIntRegion* regionForView = aVisibleRegions->LookupOrAdd(viewID);
5767 0 : MOZ_ASSERT(regionForView);
5768 :
5769 0 : regionForView->OrWith(CSSPixel::FromAppUnitsRounded(frameRectInScrolledFrameSpace));
5770 : }
5771 :
5772 : /* static */ void
5773 0 : PresShell::MarkFramesInListApproximatelyVisible(const nsDisplayList& aList,
5774 : Maybe<VisibleRegions>& aVisibleRegions)
5775 : {
5776 0 : for (nsDisplayItem* item = aList.GetBottom(); item; item = item->GetAbove()) {
5777 0 : nsDisplayList* sublist = item->GetChildren();
5778 0 : if (sublist) {
5779 0 : MarkFramesInListApproximatelyVisible(*sublist, aVisibleRegions);
5780 0 : continue;
5781 : }
5782 :
5783 0 : nsIFrame* frame = item->Frame();
5784 0 : MOZ_ASSERT(frame);
5785 :
5786 0 : if (!frame->TrackingVisibility()) {
5787 0 : continue;
5788 : }
5789 :
5790 : // Use the presshell containing the frame.
5791 0 : auto* presShell = static_cast<PresShell*>(frame->PresContext()->PresShell());
5792 0 : MOZ_ASSERT(!presShell->AssumeAllFramesVisible());
5793 0 : if (presShell->mApproximatelyVisibleFrames.EnsureInserted(frame)) {
5794 : // The frame was added to mApproximatelyVisibleFrames, so increment its visible count.
5795 0 : frame->IncApproximateVisibleCount();
5796 : }
5797 :
5798 0 : AddFrameToVisibleRegions(frame, presShell->mViewManager, aVisibleRegions);
5799 : }
5800 0 : }
5801 :
5802 : static void
5803 1 : NotifyCompositorOfVisibleRegionsChange(PresShell* aPresShell,
5804 : const Maybe<VisibleRegions>& aRegions)
5805 : {
5806 1 : if (!aRegions) {
5807 1 : return;
5808 : }
5809 :
5810 0 : MOZ_ASSERT(aPresShell);
5811 :
5812 : // Retrieve the layers ID and pres shell ID.
5813 0 : TabChild* tabChild = TabChild::GetFrom(aPresShell);
5814 0 : if (!tabChild) {
5815 0 : return;
5816 : }
5817 :
5818 0 : const uint64_t layersId = tabChild->LayersId();
5819 0 : const uint32_t presShellId = aPresShell->GetPresShellId();
5820 :
5821 : // Retrieve the CompositorBridgeChild.
5822 0 : LayerManager* layerManager = aPresShell->GetLayerManager();
5823 0 : if (!layerManager) {
5824 0 : return;
5825 : }
5826 :
5827 0 : ClientLayerManager* clientLayerManager = layerManager->AsClientLayerManager();
5828 0 : if (!clientLayerManager) {
5829 0 : return;
5830 : }
5831 :
5832 0 : CompositorBridgeChild* compositorChild = clientLayerManager->GetCompositorBridgeChild();
5833 0 : if (!compositorChild) {
5834 0 : return;
5835 : }
5836 :
5837 : // Clear the old approximately visible regions associated with this document.
5838 0 : compositorChild->SendClearApproximatelyVisibleRegions(layersId, presShellId);
5839 :
5840 : // Send the new approximately visible regions to the compositor.
5841 0 : for (auto iter = aRegions->ConstIter(); !iter.Done(); iter.Next()) {
5842 0 : const ViewID viewId = iter.Key();
5843 0 : const CSSIntRegion* region = iter.UserData();
5844 0 : MOZ_ASSERT(region);
5845 :
5846 0 : const ScrollableLayerGuid guid(layersId, presShellId, viewId);
5847 :
5848 0 : compositorChild->SendNotifyApproximatelyVisibleRegion(guid, *region);
5849 : }
5850 : }
5851 :
5852 : /* static */ void
5853 5 : PresShell::DecApproximateVisibleCount(VisibleFrames& aFrames,
5854 : const Maybe<OnNonvisible>& aNonvisibleAction
5855 : /* = Nothing() */)
5856 : {
5857 5 : for (auto iter = aFrames.Iter(); !iter.Done(); iter.Next()) {
5858 0 : nsIFrame* frame = iter.Get()->GetKey();
5859 : // Decrement the frame's visible count if we're still tracking its
5860 : // visibility. (We may not be, if the frame disabled visibility tracking
5861 : // after we added it to the visible frames list.)
5862 0 : if (frame->TrackingVisibility()) {
5863 0 : frame->DecApproximateVisibleCount(aNonvisibleAction);
5864 : }
5865 : }
5866 5 : }
5867 :
5868 : void
5869 0 : PresShell::RebuildApproximateFrameVisibilityDisplayList(const nsDisplayList& aList)
5870 : {
5871 0 : MOZ_ASSERT(!mApproximateFrameVisibilityVisited, "already visited?");
5872 0 : mApproximateFrameVisibilityVisited = true;
5873 :
5874 : // Remove the entries of the mApproximatelyVisibleFrames hashtable and put
5875 : // them in oldApproxVisibleFrames.
5876 0 : VisibleFrames oldApproximatelyVisibleFrames;
5877 0 : mApproximatelyVisibleFrames.SwapElements(oldApproximatelyVisibleFrames);
5878 :
5879 : // If we're visualizing visible regions, create a VisibleRegions object to
5880 : // store information about them. The functions we call will populate this
5881 : // object and send it to the compositor only if it's Some(), so we don't
5882 : // need to check the prefs everywhere.
5883 0 : Maybe<VisibleRegions> visibleRegions;
5884 0 : if (gfxPrefs::APZMinimap() && gfxPrefs::APZMinimapVisibilityEnabled()) {
5885 0 : visibleRegions.emplace();
5886 : }
5887 :
5888 0 : MarkFramesInListApproximatelyVisible(aList, visibleRegions);
5889 :
5890 0 : DecApproximateVisibleCount(oldApproximatelyVisibleFrames);
5891 :
5892 0 : NotifyCompositorOfVisibleRegionsChange(this, visibleRegions);
5893 0 : }
5894 :
5895 : /* static */ void
5896 1 : PresShell::ClearApproximateFrameVisibilityVisited(nsView* aView, bool aClear)
5897 : {
5898 1 : nsViewManager* vm = aView->GetViewManager();
5899 1 : if (aClear) {
5900 1 : PresShell* presShell = static_cast<PresShell*>(vm->GetPresShell());
5901 1 : if (!presShell->mApproximateFrameVisibilityVisited) {
5902 0 : presShell->ClearApproximatelyVisibleFramesList();
5903 : }
5904 1 : presShell->mApproximateFrameVisibilityVisited = false;
5905 : }
5906 1 : for (nsView* v = aView->GetFirstChild(); v; v = v->GetNextSibling()) {
5907 0 : ClearApproximateFrameVisibilityVisited(v, v->GetViewManager() != vm);
5908 : }
5909 1 : }
5910 :
5911 : void
5912 4 : PresShell::ClearApproximatelyVisibleFramesList(const Maybe<OnNonvisible>& aNonvisibleAction
5913 : /* = Nothing() */)
5914 : {
5915 4 : DecApproximateVisibleCount(mApproximatelyVisibleFrames, aNonvisibleAction);
5916 4 : mApproximatelyVisibleFrames.Clear();
5917 4 : }
5918 :
5919 : void
5920 4 : PresShell::MarkFramesInSubtreeApproximatelyVisible(nsIFrame* aFrame,
5921 : const nsRect& aRect,
5922 : Maybe<VisibleRegions>& aVisibleRegions,
5923 : bool aRemoveOnly /* = false */)
5924 : {
5925 4 : MOZ_ASSERT(aFrame->PresContext()->PresShell() == this, "wrong presshell");
5926 :
5927 8 : if (aFrame->TrackingVisibility() &&
5928 4 : aFrame->StyleVisibility()->IsVisible() &&
5929 0 : (!aRemoveOnly || aFrame->GetVisibility() == Visibility::APPROXIMATELY_VISIBLE)) {
5930 0 : MOZ_ASSERT(!AssumeAllFramesVisible());
5931 0 : if (mApproximatelyVisibleFrames.EnsureInserted(aFrame)) {
5932 : // The frame was added to mApproximatelyVisibleFrames, so increment its visible count.
5933 0 : aFrame->IncApproximateVisibleCount();
5934 : }
5935 :
5936 0 : AddFrameToVisibleRegions(aFrame, mViewManager, aVisibleRegions);
5937 : }
5938 :
5939 4 : nsSubDocumentFrame* subdocFrame = do_QueryFrame(aFrame);
5940 4 : if (subdocFrame) {
5941 : nsIPresShell* presShell = subdocFrame->GetSubdocumentPresShellForPainting(
5942 0 : nsSubDocumentFrame::IGNORE_PAINT_SUPPRESSION);
5943 0 : if (presShell && !presShell->AssumeAllFramesVisible()) {
5944 0 : nsRect rect = aRect;
5945 0 : nsIFrame* root = presShell->GetRootFrame();
5946 0 : if (root) {
5947 0 : rect.MoveBy(aFrame->GetOffsetToCrossDoc(root));
5948 : } else {
5949 0 : rect.MoveBy(-aFrame->GetContentRectRelativeToSelf().TopLeft());
5950 : }
5951 0 : rect = rect.ScaleToOtherAppUnitsRoundOut(
5952 : aFrame->PresContext()->AppUnitsPerDevPixel(),
5953 : presShell->GetPresContext()->AppUnitsPerDevPixel());
5954 :
5955 0 : presShell->RebuildApproximateFrameVisibility(&rect);
5956 : }
5957 0 : return;
5958 : }
5959 :
5960 8 : nsRect rect = aRect;
5961 :
5962 4 : nsIScrollableFrame* scrollFrame = do_QueryFrame(aFrame);
5963 4 : if (scrollFrame) {
5964 1 : bool ignoreDisplayPort = false;
5965 1 : if (nsLayoutUtils::IsMissingDisplayPortBaseRect(aFrame->GetContent())) {
5966 : // We can properly set the base rect for root scroll frames on top level
5967 : // and root content documents. Otherwise the base rect we compute might
5968 : // be way too big without the limiting that
5969 : // ScrollFrameHelper::DecideScrollableLayer does, so we just ignore the
5970 : // displayport in that case.
5971 0 : nsPresContext* pc = aFrame->PresContext();
5972 0 : if (scrollFrame->IsRootScrollFrameOfDocument() &&
5973 0 : (pc->IsRootContentDocument() || !pc->GetParentPresContext())) {
5974 : nsRect baseRect =
5975 0 : nsRect(nsPoint(0, 0), nsLayoutUtils::CalculateCompositionSizeForFrame(aFrame));
5976 0 : nsLayoutUtils::SetDisplayPortBase(aFrame->GetContent(), baseRect);
5977 : } else {
5978 0 : ignoreDisplayPort = true;
5979 : }
5980 : }
5981 :
5982 1 : scrollFrame->NotifyApproximateFrameVisibilityUpdate(ignoreDisplayPort);
5983 :
5984 2 : nsRect displayPort;
5985 2 : bool usingDisplayport = !ignoreDisplayPort &&
5986 1 : nsLayoutUtils::GetDisplayPortForVisibilityTesting(
5987 1 : aFrame->GetContent(), &displayPort, RelativeTo::ScrollFrame);
5988 1 : if (usingDisplayport) {
5989 1 : rect = displayPort;
5990 : } else {
5991 0 : rect = rect.Intersect(scrollFrame->GetScrollPortRect());
5992 : }
5993 1 : rect = scrollFrame->ExpandRectToNearlyVisible(rect);
5994 : }
5995 :
5996 4 : bool preserves3DChildren = aFrame->Extend3DContext();
5997 :
5998 : // We assume all frames in popups are visible, so we skip them here.
5999 : const nsIFrame::ChildListIDs skip(nsIFrame::kPopupList |
6000 4 : nsIFrame::kSelectPopupList);
6001 16 : for (nsIFrame::ChildListIterator childLists(aFrame);
6002 12 : !childLists.IsDone(); childLists.Next()) {
6003 4 : if (skip.Contains(childLists.CurrentID())) {
6004 0 : continue;
6005 : }
6006 :
6007 11 : for (nsIFrame* child : childLists.CurrentList()) {
6008 10 : nsRect r = rect - child->GetPosition();
6009 7 : if (!r.IntersectRect(r, child->GetVisualOverflowRect())) {
6010 4 : continue;
6011 : }
6012 3 : if (child->IsTransformed()) {
6013 : // for children of a preserve3d element we just pass down the same dirty rect
6014 0 : if (!preserves3DChildren || !child->Combines3DTransformWithAncestors()) {
6015 0 : const nsRect overflow = child->GetVisualOverflowRectRelativeToSelf();
6016 0 : nsRect out;
6017 0 : if (nsDisplayTransform::UntransformRect(r, overflow, child, &out)) {
6018 0 : r = out;
6019 : } else {
6020 0 : r.SetEmpty();
6021 : }
6022 : }
6023 : }
6024 3 : MarkFramesInSubtreeApproximatelyVisible(child, r, aVisibleRegions);
6025 : }
6026 : }
6027 : }
6028 :
6029 : void
6030 1 : PresShell::RebuildApproximateFrameVisibility(nsRect* aRect,
6031 : bool aRemoveOnly /* = false */)
6032 : {
6033 1 : MOZ_ASSERT(!mApproximateFrameVisibilityVisited, "already visited?");
6034 1 : mApproximateFrameVisibilityVisited = true;
6035 :
6036 1 : nsIFrame* rootFrame = GetRootFrame();
6037 1 : if (!rootFrame) {
6038 0 : return;
6039 : }
6040 :
6041 : // Remove the entries of the mApproximatelyVisibleFrames hashtable and put
6042 : // them in oldApproximatelyVisibleFrames.
6043 2 : VisibleFrames oldApproximatelyVisibleFrames;
6044 1 : mApproximatelyVisibleFrames.SwapElements(oldApproximatelyVisibleFrames);
6045 :
6046 : // If we're visualizing visible regions, create a VisibleRegions object to
6047 : // store information about them. The functions we call will populate this
6048 : // object and send it to the compositor only if it's Some(), so we don't
6049 : // need to check the prefs everywhere.
6050 2 : Maybe<VisibleRegions> visibleRegions;
6051 1 : if (gfxPrefs::APZMinimap() && gfxPrefs::APZMinimapVisibilityEnabled()) {
6052 0 : visibleRegions.emplace();
6053 : }
6054 :
6055 2 : nsRect vis(nsPoint(0, 0), rootFrame->GetSize());
6056 1 : if (aRect) {
6057 0 : vis = *aRect;
6058 : }
6059 :
6060 1 : MarkFramesInSubtreeApproximatelyVisible(rootFrame, vis, visibleRegions, aRemoveOnly);
6061 :
6062 1 : DecApproximateVisibleCount(oldApproximatelyVisibleFrames);
6063 :
6064 1 : NotifyCompositorOfVisibleRegionsChange(this, visibleRegions);
6065 : }
6066 :
6067 : void
6068 1 : PresShell::UpdateApproximateFrameVisibility()
6069 : {
6070 1 : DoUpdateApproximateFrameVisibility(/* aRemoveOnly = */ false);
6071 1 : }
6072 :
6073 : void
6074 1 : PresShell::DoUpdateApproximateFrameVisibility(bool aRemoveOnly)
6075 : {
6076 1 : MOZ_ASSERT(!mPresContext || mPresContext->IsRootContentDocument(),
6077 : "Updating approximate frame visibility on a non-root content document?");
6078 :
6079 1 : mUpdateApproximateFrameVisibilityEvent.Revoke();
6080 :
6081 1 : if (mHaveShutDown || mIsDestroying) {
6082 0 : return;
6083 : }
6084 :
6085 : // call update on that frame
6086 1 : nsIFrame* rootFrame = GetRootFrame();
6087 1 : if (!rootFrame) {
6088 0 : ClearApproximatelyVisibleFramesList(Some(OnNonvisible::DISCARD_IMAGES));
6089 0 : return;
6090 : }
6091 :
6092 1 : RebuildApproximateFrameVisibility(/* aRect = */ nullptr, aRemoveOnly);
6093 1 : ClearApproximateFrameVisibilityVisited(rootFrame->GetView(), true);
6094 :
6095 : #ifdef DEBUG_FRAME_VISIBILITY_DISPLAY_LIST
6096 : // This can be used to debug the frame walker by comparing beforeFrameList
6097 : // and mApproximatelyVisibleFrames in RebuildFrameVisibilityDisplayList to see if
6098 : // they produce the same results (mApproximatelyVisibleFrames holds the frames the
6099 : // display list thinks are visible, beforeFrameList holds the frames the
6100 : // frame walker thinks are visible).
6101 : nsDisplayListBuilder builder(rootFrame, nsDisplayListBuilderMode::FRAME_VISIBILITY, false);
6102 : nsRect updateRect(nsPoint(0, 0), rootFrame->GetSize());
6103 : nsIFrame* rootScroll = GetRootScrollFrame();
6104 : if (rootScroll) {
6105 : nsIContent* content = rootScroll->GetContent();
6106 : if (content) {
6107 : Unused << nsLayoutUtils::GetDisplayPortForVisibilityTesting(content, &updateRect,
6108 : RelativeTo::ScrollFrame);
6109 : }
6110 :
6111 : if (IgnoringViewportScrolling()) {
6112 : builder.SetIgnoreScrollFrame(rootScroll);
6113 : }
6114 : }
6115 : builder.IgnorePaintSuppression();
6116 : builder.EnterPresShell(rootFrame);
6117 : nsDisplayList list;
6118 : rootFrame->BuildDisplayListForStackingContext(&builder, updateRect, &list);
6119 : builder.LeavePresShell(rootFrame, &list);
6120 :
6121 : RebuildApproximateFrameVisibilityDisplayList(list);
6122 :
6123 : ClearApproximateFrameVisibilityVisited(rootFrame->GetView(), true);
6124 :
6125 : list.DeleteAll();
6126 : #endif
6127 : }
6128 :
6129 : bool
6130 824 : PresShell::AssumeAllFramesVisible()
6131 : {
6132 : static bool sFrameVisibilityEnabled = true;
6133 : static bool sFrameVisibilityPrefCached = false;
6134 :
6135 824 : if (!sFrameVisibilityPrefCached) {
6136 : Preferences::AddBoolVarCache(&sFrameVisibilityEnabled,
6137 2 : "layout.framevisibility.enabled", true);
6138 2 : sFrameVisibilityPrefCached = true;
6139 : }
6140 :
6141 824 : if (!sFrameVisibilityEnabled || !mPresContext || !mDocument) {
6142 0 : return true;
6143 : }
6144 :
6145 : // We assume all frames are visible in print, print preview, chrome, and
6146 : // resource docs and don't keep track of them.
6147 2472 : if (mPresContext->Type() == nsPresContext::eContext_PrintPreview ||
6148 1648 : mPresContext->Type() == nsPresContext::eContext_Print ||
6149 1912 : mPresContext->IsChrome() ||
6150 264 : mDocument->IsResourceDoc()) {
6151 808 : return true;
6152 : }
6153 :
6154 : // If we're assuming all frames are visible in the top level content
6155 : // document, we need to in subdocuments as well. Otherwise we can get in a
6156 : // situation where things like animations won't work in subdocuments because
6157 : // their frames appear not to be visible, since we won't schedule an image
6158 : // visibility update if the top level content document is assuming all
6159 : // frames are visible.
6160 : //
6161 : // Note that it's not safe to call IsRootContentDocument() if we're
6162 : // currently being destroyed, so we have to check that first.
6163 32 : if (!mHaveShutDown && !mIsDestroying &&
6164 16 : !mPresContext->IsRootContentDocument()) {
6165 : nsPresContext* presContext =
6166 0 : mPresContext->GetToplevelContentDocumentPresContext();
6167 0 : if (presContext && presContext->PresShell()->AssumeAllFramesVisible()) {
6168 0 : return true;
6169 : }
6170 : }
6171 :
6172 16 : return false;
6173 : }
6174 :
6175 : void
6176 0 : PresShell::ScheduleApproximateFrameVisibilityUpdateSoon()
6177 : {
6178 0 : if (AssumeAllFramesVisible()) {
6179 0 : return;
6180 : }
6181 :
6182 0 : if (!mPresContext) {
6183 0 : return;
6184 : }
6185 :
6186 0 : nsRefreshDriver* refreshDriver = mPresContext->RefreshDriver();
6187 0 : if (!refreshDriver) {
6188 0 : return;
6189 : }
6190 :
6191 : // Ask the refresh driver to update frame visibility soon.
6192 0 : refreshDriver->ScheduleFrameVisibilityUpdate();
6193 : }
6194 :
6195 : void
6196 32 : PresShell::ScheduleApproximateFrameVisibilityUpdateNow()
6197 : {
6198 32 : if (AssumeAllFramesVisible()) {
6199 60 : return;
6200 : }
6201 :
6202 3 : if (!mPresContext->IsRootContentDocument()) {
6203 0 : nsPresContext* presContext = mPresContext->GetToplevelContentDocumentPresContext();
6204 0 : if (!presContext)
6205 0 : return;
6206 0 : MOZ_ASSERT(presContext->IsRootContentDocument(),
6207 : "Didn't get a root prescontext from GetToplevelContentDocumentPresContext?");
6208 0 : presContext->PresShell()->ScheduleApproximateFrameVisibilityUpdateNow();
6209 0 : return;
6210 : }
6211 :
6212 3 : if (mHaveShutDown || mIsDestroying) {
6213 0 : return;
6214 : }
6215 :
6216 3 : if (mUpdateApproximateFrameVisibilityEvent.IsPending()) {
6217 2 : return;
6218 : }
6219 :
6220 : RefPtr<nsRunnableMethod<PresShell>> event =
6221 2 : NewRunnableMethod("PresShell::UpdateApproximateFrameVisibility",
6222 : this,
6223 2 : &PresShell::UpdateApproximateFrameVisibility);
6224 : nsresult rv =
6225 3 : mDocument->Dispatch("PresShell::UpdateApproximateFrameVisibility",
6226 : TaskCategory::Other,
6227 3 : do_AddRef(event));
6228 :
6229 1 : if (NS_SUCCEEDED(rv)) {
6230 1 : mUpdateApproximateFrameVisibilityEvent = event;
6231 : }
6232 : }
6233 :
6234 : void
6235 0 : PresShell::EnsureFrameInApproximatelyVisibleList(nsIFrame* aFrame)
6236 : {
6237 0 : if (!aFrame->TrackingVisibility()) {
6238 0 : return;
6239 : }
6240 :
6241 0 : if (AssumeAllFramesVisible()) {
6242 0 : aFrame->IncApproximateVisibleCount();
6243 0 : return;
6244 : }
6245 :
6246 : #ifdef DEBUG
6247 : // Make sure it's in this pres shell.
6248 0 : nsCOMPtr<nsIContent> content = aFrame->GetContent();
6249 0 : if (content) {
6250 0 : PresShell* shell = static_cast<PresShell*>(content->OwnerDoc()->GetShell());
6251 0 : MOZ_ASSERT(!shell || shell == this, "wrong shell");
6252 : }
6253 : #endif
6254 :
6255 0 : if (mApproximatelyVisibleFrames.EnsureInserted(aFrame)) {
6256 : // We inserted a new entry.
6257 0 : aFrame->IncApproximateVisibleCount();
6258 : }
6259 : }
6260 :
6261 : void
6262 126 : PresShell::RemoveFrameFromApproximatelyVisibleList(nsIFrame* aFrame)
6263 : {
6264 : #ifdef DEBUG
6265 : // Make sure it's in this pres shell.
6266 126 : nsCOMPtr<nsIContent> content = aFrame->GetContent();
6267 126 : if (content) {
6268 126 : PresShell* shell = static_cast<PresShell*>(content->OwnerDoc()->GetShell());
6269 126 : MOZ_ASSERT(!shell || shell == this, "wrong shell");
6270 : }
6271 : #endif
6272 :
6273 126 : if (AssumeAllFramesVisible()) {
6274 126 : MOZ_ASSERT(mApproximatelyVisibleFrames.Count() == 0,
6275 : "Shouldn't have any frames in the table");
6276 126 : return;
6277 : }
6278 :
6279 0 : if (mApproximatelyVisibleFrames.EnsureRemoved(aFrame) &&
6280 0 : aFrame->TrackingVisibility()) {
6281 : // aFrame was in the hashtable, and we're still tracking its visibility,
6282 : // so we need to decrement its visible count.
6283 0 : aFrame->DecApproximateVisibleCount();
6284 : }
6285 : }
6286 :
6287 : class nsAutoNotifyDidPaint
6288 : {
6289 : public:
6290 29 : nsAutoNotifyDidPaint(PresShell* aShell, uint32_t aFlags)
6291 29 : : mShell(aShell), mFlags(aFlags)
6292 : {
6293 29 : }
6294 29 : ~nsAutoNotifyDidPaint()
6295 29 : {
6296 29 : if (mFlags & nsIPresShell::PAINT_COMPOSITE) {
6297 0 : mShell->GetPresContext()->NotifyDidPaintForSubtree();
6298 : }
6299 29 : }
6300 :
6301 : private:
6302 : PresShell* mShell;
6303 : uint32_t mFlags;
6304 : };
6305 :
6306 : void
6307 0 : PresShell::RecordShadowStyleChange(ShadowRoot* aShadowRoot)
6308 : {
6309 0 : mStyleSet->RecordShadowStyleChange(aShadowRoot);
6310 0 : }
6311 :
6312 : void
6313 29 : PresShell::Paint(nsView* aViewToPaint,
6314 : const nsRegion& aDirtyRegion,
6315 : uint32_t aFlags)
6316 : {
6317 29 : nsIURI* uri = mDocument->GetDocumentURI();
6318 29 : nsIDocument* contentRoot = GetPrimaryContentDocument();
6319 29 : if (contentRoot) {
6320 4 : uri = contentRoot->GetDocumentURI();
6321 : }
6322 31 : nsCString uriString = uri ? uri->GetSpecOrDefault() : NS_LITERAL_CSTRING("N/A");
6323 31 : AUTO_PROFILER_LABEL_DYNAMIC("PresShell::Paint", GRAPHICS, uriString.get());
6324 :
6325 31 : Maybe<js::AutoAssertNoContentJS> nojs;
6326 :
6327 : // On Android, Flash can call into content JS during painting, so we can't
6328 : // assert there. However, we don't rely on this assertion on Android because
6329 : // we don't paint while JS is running.
6330 : #if !defined(MOZ_WIDGET_ANDROID)
6331 29 : if (!(aFlags & nsIPresShell::PAINT_COMPOSITE)) {
6332 : // We need to allow content JS when the flag is set since we may trigger
6333 : // MozAfterPaint events in content in those cases.
6334 29 : nojs.emplace(dom::danger::GetJSContext());
6335 : }
6336 : #endif
6337 :
6338 29 : NS_ASSERTION(!mIsDestroying, "painting a destroyed PresShell");
6339 29 : NS_ASSERTION(aViewToPaint, "null view");
6340 :
6341 29 : MOZ_ASSERT(!mApproximateFrameVisibilityVisited, "Should have been cleared");
6342 :
6343 29 : if (!mIsActive) {
6344 0 : return;
6345 : }
6346 :
6347 29 : if (gfxPrefs::APZKeyboardEnabled()) {
6348 : // Update the focus target for async keyboard scrolling. This will be forwarded
6349 : // to APZ by nsDisplayList::PaintRoot. We need to to do this before we enter
6350 : // the paint phase because dispatching eVoid events can cause layout to happen.
6351 0 : mAPZFocusTarget = FocusTarget(this, mAPZFocusSequenceNumber);
6352 : }
6353 :
6354 29 : nsPresContext* presContext = GetPresContext();
6355 31 : AUTO_LAYOUT_PHASE_ENTRY_POINT(presContext, Paint);
6356 :
6357 29 : nsIFrame* frame = aViewToPaint->GetFrame();
6358 :
6359 : LayerManager* layerManager =
6360 29 : aViewToPaint->GetWidget()->GetLayerManager();
6361 29 : NS_ASSERTION(layerManager, "Must be in paint event");
6362 29 : bool shouldInvalidate = layerManager->NeedsWidgetInvalidation();
6363 :
6364 31 : nsAutoNotifyDidPaint notifyDidPaint(this, aFlags);
6365 :
6366 : // Whether or not we should set first paint when painting is suppressed
6367 : // is debatable. For now we'll do it because B2G relied on first paint
6368 : // to configure the viewport and we only want to do that when we have
6369 : // real content to paint. See Bug 798245
6370 29 : if (mIsFirstPaint && !mPaintingSuppressed) {
6371 3 : layerManager->SetIsFirstPaint();
6372 3 : mIsFirstPaint = false;
6373 : }
6374 :
6375 29 : if (!layerManager->BeginTransaction()) {
6376 0 : return;
6377 : }
6378 :
6379 : // Send an updated focus target with this transaction. Be sure to do this
6380 : // before we paint in the case this is an empty transaction.
6381 29 : layerManager->SetFocusTarget(mAPZFocusTarget);
6382 :
6383 29 : if (frame) {
6384 : // Try to do an empty transaction, if the frame tree does not
6385 : // need to be updated. Do not try to do an empty transaction on
6386 : // a non-retained layer manager (like the BasicLayerManager that
6387 : // draws the window title bar on Mac), because a) it won't work
6388 : // and b) below we don't want to clear NS_FRAME_UPDATE_LAYER_TREE,
6389 : // that will cause us to forget to update the real layer manager!
6390 :
6391 27 : if (!(aFlags & PAINT_LAYERS)) {
6392 0 : if (layerManager->EndEmptyTransaction()) {
6393 0 : return;
6394 : }
6395 0 : NS_WARNING("Must complete empty transaction when compositing!");
6396 : }
6397 :
6398 81 : if (!(aFlags & PAINT_SYNC_DECODE_IMAGES) &&
6399 28 : !(frame->GetStateBits() & NS_FRAME_UPDATE_LAYER_TREE) &&
6400 1 : !mNextPaintCompressed) {
6401 : NotifySubDocInvalidationFunc computeInvalidFunc =
6402 1 : presContext->MayHavePaintEventListenerInSubDocument() ? nsPresContext::NotifySubDocInvalidation : 0;
6403 1 : bool computeInvalidRect = computeInvalidFunc ||
6404 1 : (layerManager->GetBackendType() == LayersBackend::LAYERS_BASIC);
6405 :
6406 1 : UniquePtr<LayerProperties> props;
6407 1 : if (computeInvalidRect) {
6408 1 : props = Move(LayerProperties::CloneFrom(layerManager->GetRoot()));
6409 : }
6410 :
6411 1 : MaybeSetupTransactionIdAllocator(layerManager, presContext);
6412 :
6413 1 : if (layerManager->EndEmptyTransaction((aFlags & PAINT_COMPOSITE) ?
6414 1 : LayerManager::END_DEFAULT : LayerManager::END_NO_COMPOSITE)) {
6415 2 : nsIntRegion invalid;
6416 1 : if (props) {
6417 1 : invalid = props->ComputeDifferences(layerManager->GetRoot(), computeInvalidFunc);
6418 : } else {
6419 0 : LayerProperties::ClearInvalidations(layerManager->GetRoot());
6420 : }
6421 1 : if (props) {
6422 1 : if (!invalid.IsEmpty()) {
6423 0 : nsIntRect bounds = invalid.GetBounds();
6424 : nsRect rect(presContext->DevPixelsToAppUnits(bounds.x),
6425 : presContext->DevPixelsToAppUnits(bounds.y),
6426 : presContext->DevPixelsToAppUnits(bounds.width),
6427 0 : presContext->DevPixelsToAppUnits(bounds.height));
6428 0 : if (shouldInvalidate) {
6429 0 : aViewToPaint->GetViewManager()->InvalidateViewNoSuppression(aViewToPaint, rect);
6430 : }
6431 0 : presContext->NotifyInvalidation(layerManager->GetLastTransactionId(), bounds);
6432 : }
6433 0 : } else if (shouldInvalidate) {
6434 0 : aViewToPaint->GetViewManager()->InvalidateView(aViewToPaint);
6435 : }
6436 :
6437 1 : frame->UpdatePaintCountForPaintedPresShells();
6438 1 : return;
6439 : }
6440 : }
6441 26 : frame->RemoveStateBits(NS_FRAME_UPDATE_LAYER_TREE);
6442 : }
6443 28 : if (frame) {
6444 26 : frame->ClearPresShellsFromLastPaint();
6445 : }
6446 :
6447 28 : nscolor bgcolor = ComputeBackstopColor(aViewToPaint);
6448 56 : PaintFrameFlags flags = PaintFrameFlags::PAINT_WIDGET_LAYERS |
6449 28 : PaintFrameFlags::PAINT_EXISTING_TRANSACTION;
6450 28 : if (!(aFlags & PAINT_COMPOSITE)) {
6451 28 : flags |= PaintFrameFlags::PAINT_NO_COMPOSITE;
6452 : }
6453 28 : if (aFlags & PAINT_SYNC_DECODE_IMAGES) {
6454 0 : flags |= PaintFrameFlags::PAINT_SYNC_DECODE_IMAGES;
6455 : }
6456 28 : if (mNextPaintCompressed) {
6457 1 : flags |= PaintFrameFlags::PAINT_COMPRESSED;
6458 1 : mNextPaintCompressed = false;
6459 : }
6460 :
6461 28 : if (frame) {
6462 : // We can paint directly into the widget using its layer manager.
6463 : nsLayoutUtils::PaintFrame(nullptr, frame, aDirtyRegion, bgcolor,
6464 26 : nsDisplayListBuilderMode::PAINTING, flags);
6465 26 : return;
6466 : }
6467 :
6468 4 : RefPtr<ColorLayer> root = layerManager->CreateColorLayer();
6469 2 : if (root) {
6470 2 : nsPresContext* pc = GetPresContext();
6471 : nsIntRect bounds =
6472 2 : pc->GetVisibleArea().ToOutsidePixels(pc->AppUnitsPerDevPixel());
6473 2 : bgcolor = NS_ComposeColors(bgcolor, mCanvasBackgroundColor);
6474 2 : root->SetColor(Color::FromABGR(bgcolor));
6475 2 : root->SetVisibleRegion(LayerIntRegion::FromUnknownRegion(bounds));
6476 2 : layerManager->SetRoot(root);
6477 : }
6478 2 : MaybeSetupTransactionIdAllocator(layerManager, presContext);
6479 2 : layerManager->EndTransaction(nullptr, nullptr, (aFlags & PAINT_COMPOSITE) ?
6480 4 : LayerManager::END_DEFAULT : LayerManager::END_NO_COMPOSITE);
6481 : }
6482 :
6483 : // static
6484 : void
6485 0 : nsIPresShell::SetCapturingContent(nsIContent* aContent, uint8_t aFlags)
6486 : {
6487 : // If capture was set for pointer lock, don't unlock unless we are coming
6488 : // out of pointer lock explicitly.
6489 0 : if (!aContent && gCaptureInfo.mPointerLock &&
6490 0 : !(aFlags & CAPTURE_POINTERLOCK)) {
6491 0 : return;
6492 : }
6493 :
6494 0 : gCaptureInfo.mContent = nullptr;
6495 :
6496 : // only set capturing content if allowed or the CAPTURE_IGNOREALLOWED or
6497 : // CAPTURE_POINTERLOCK flags are used.
6498 0 : if ((aFlags & CAPTURE_IGNOREALLOWED) || gCaptureInfo.mAllowed ||
6499 0 : (aFlags & CAPTURE_POINTERLOCK)) {
6500 0 : if (aContent) {
6501 0 : gCaptureInfo.mContent = aContent;
6502 : }
6503 : // CAPTURE_POINTERLOCK is the same as CAPTURE_RETARGETTOELEMENT & CAPTURE_IGNOREALLOWED
6504 0 : gCaptureInfo.mRetargetToElement = ((aFlags & CAPTURE_RETARGETTOELEMENT) != 0) ||
6505 0 : ((aFlags & CAPTURE_POINTERLOCK) != 0);
6506 0 : gCaptureInfo.mPreventDrag = (aFlags & CAPTURE_PREVENTDRAG) != 0;
6507 0 : gCaptureInfo.mPointerLock = (aFlags & CAPTURE_POINTERLOCK) != 0;
6508 : }
6509 : }
6510 :
6511 : /* static */ void
6512 0 : nsIPresShell::SetPointerCapturingContent(uint32_t aPointerId,
6513 : nsIContent* aContent)
6514 : {
6515 0 : MOZ_ASSERT(aContent != nullptr);
6516 :
6517 0 : if (nsIDOMMouseEvent::MOZ_SOURCE_MOUSE == GetPointerType(aPointerId)) {
6518 0 : SetCapturingContent(aContent, CAPTURE_PREVENTDRAG);
6519 : }
6520 :
6521 0 : PointerCaptureInfo* pointerCaptureInfo = GetPointerCaptureInfo(aPointerId);
6522 0 : if (pointerCaptureInfo) {
6523 0 : pointerCaptureInfo->mPendingContent = aContent;
6524 : } else {
6525 0 : sPointerCaptureList->Put(aPointerId, new PointerCaptureInfo(aContent));
6526 : }
6527 0 : }
6528 :
6529 : /* static */ nsIPresShell::PointerCaptureInfo*
6530 14 : nsIPresShell::GetPointerCaptureInfo(uint32_t aPointerId)
6531 : {
6532 14 : PointerCaptureInfo* pointerCaptureInfo = nullptr;
6533 14 : sPointerCaptureList->Get(aPointerId, &pointerCaptureInfo);
6534 14 : return pointerCaptureInfo;
6535 : }
6536 :
6537 : /* static */ void
6538 0 : nsIPresShell::ReleasePointerCapturingContent(uint32_t aPointerId)
6539 : {
6540 0 : if (nsIDOMMouseEvent::MOZ_SOURCE_MOUSE == GetPointerType(aPointerId)) {
6541 0 : SetCapturingContent(nullptr, CAPTURE_PREVENTDRAG);
6542 : }
6543 :
6544 0 : PointerCaptureInfo* pointerCaptureInfo = GetPointerCaptureInfo(aPointerId);
6545 0 : if (pointerCaptureInfo) {
6546 0 : pointerCaptureInfo->mPendingContent = nullptr;
6547 : }
6548 0 : }
6549 :
6550 : /* static */ nsIContent*
6551 10 : nsIPresShell::GetPointerCapturingContent(uint32_t aPointerId)
6552 : {
6553 10 : PointerCaptureInfo* pointerCaptureInfo = GetPointerCaptureInfo(aPointerId);
6554 10 : if (pointerCaptureInfo) {
6555 0 : return pointerCaptureInfo->mOverrideContent;
6556 : }
6557 10 : return nullptr;
6558 : }
6559 :
6560 : /* static */ void
6561 4 : nsIPresShell::CheckPointerCaptureState(const WidgetPointerEvent* aPointerEvent)
6562 : {
6563 : PointerCaptureInfo* captureInfo =
6564 4 : GetPointerCaptureInfo(aPointerEvent->pointerId);
6565 :
6566 4 : if (captureInfo &&
6567 0 : captureInfo->mPendingContent != captureInfo->mOverrideContent) {
6568 : // cache captureInfo->mPendingContent since it may be changed in the pointer
6569 : // event listener
6570 0 : nsIContent* pendingContent = captureInfo->mPendingContent.get();
6571 0 : if (captureInfo->mOverrideContent) {
6572 0 : DispatchGotOrLostPointerCaptureEvent(/* aIsGotCapture */ false,
6573 : aPointerEvent,
6574 0 : captureInfo->mOverrideContent);
6575 : }
6576 0 : if (pendingContent) {
6577 : DispatchGotOrLostPointerCaptureEvent(/* aIsGotCapture */ true,
6578 0 : aPointerEvent, pendingContent);
6579 : }
6580 :
6581 0 : captureInfo->mOverrideContent = pendingContent;
6582 0 : if (captureInfo->Empty()) {
6583 0 : sPointerCaptureList->Remove(aPointerEvent->pointerId);
6584 : }
6585 : }
6586 4 : }
6587 :
6588 : /* static */ uint16_t
6589 0 : nsIPresShell::GetPointerType(uint32_t aPointerId)
6590 : {
6591 0 : PointerInfo* pointerInfo = nullptr;
6592 0 : if (sActivePointersIds->Get(aPointerId, &pointerInfo) && pointerInfo) {
6593 0 : return pointerInfo->mPointerType;
6594 : }
6595 0 : return nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN;
6596 : }
6597 :
6598 : /* static */ bool
6599 0 : nsIPresShell::GetPointerPrimaryState(uint32_t aPointerId)
6600 : {
6601 0 : PointerInfo* pointerInfo = nullptr;
6602 0 : if (sActivePointersIds->Get(aPointerId, &pointerInfo) && pointerInfo) {
6603 0 : return pointerInfo->mPrimaryState;
6604 : }
6605 0 : return false;
6606 : }
6607 :
6608 : /* static */ bool
6609 0 : nsIPresShell::GetPointerInfo(uint32_t aPointerId, bool& aActiveState)
6610 : {
6611 0 : PointerInfo* pointerInfo = nullptr;
6612 0 : if (sActivePointersIds->Get(aPointerId, &pointerInfo) && pointerInfo) {
6613 0 : aActiveState = pointerInfo->mActiveState;
6614 0 : return true;
6615 : }
6616 0 : return false;
6617 : }
6618 :
6619 : void
6620 10 : PresShell::UpdateActivePointerState(WidgetGUIEvent* aEvent)
6621 : {
6622 10 : switch (aEvent->mMessage) {
6623 : case eMouseEnterIntoWidget:
6624 : // In this case we have to know information about available mouse pointers
6625 1 : if (WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent()) {
6626 1 : sActivePointersIds->Put(mouseEvent->pointerId,
6627 3 : new PointerInfo(false, mouseEvent->inputSource,
6628 3 : true));
6629 : }
6630 1 : break;
6631 : case ePointerDown:
6632 : // In this case we switch pointer to active state
6633 0 : if (WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent()) {
6634 0 : sActivePointersIds->Put(pointerEvent->pointerId,
6635 0 : new PointerInfo(true, pointerEvent->inputSource,
6636 0 : pointerEvent->mIsPrimary));
6637 : }
6638 0 : break;
6639 : case ePointerUp:
6640 : // In this case we remove information about pointer or turn off active state
6641 0 : if (WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent()) {
6642 0 : if(pointerEvent->inputSource != nsIDOMMouseEvent::MOZ_SOURCE_TOUCH) {
6643 0 : sActivePointersIds->Put(pointerEvent->pointerId,
6644 0 : new PointerInfo(false,
6645 0 : pointerEvent->inputSource,
6646 0 : pointerEvent->mIsPrimary));
6647 : } else {
6648 0 : sActivePointersIds->Remove(pointerEvent->pointerId);
6649 : }
6650 : }
6651 0 : break;
6652 : case eMouseExitFromWidget:
6653 : // In this case we have to remove information about disappeared mouse
6654 : // pointers
6655 1 : if (WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent()) {
6656 1 : sActivePointersIds->Remove(mouseEvent->pointerId);
6657 : }
6658 1 : break;
6659 : default:
6660 8 : break;
6661 : }
6662 10 : }
6663 :
6664 : nsIContent*
6665 231 : PresShell::GetCurrentEventContent()
6666 : {
6667 280 : if (mCurrentEventContent &&
6668 280 : mCurrentEventContent->GetComposedDoc() != mDocument) {
6669 0 : mCurrentEventContent = nullptr;
6670 0 : mCurrentEventFrame = nullptr;
6671 : }
6672 231 : return mCurrentEventContent;
6673 : }
6674 :
6675 : nsIFrame*
6676 223 : PresShell::GetCurrentEventFrame()
6677 : {
6678 223 : if (MOZ_UNLIKELY(mIsDestroying)) {
6679 0 : return nullptr;
6680 : }
6681 :
6682 : // GetCurrentEventContent() makes sure the content is still in the
6683 : // same document that this pres shell belongs to. If not, then the
6684 : // frame shouldn't get an event, nor should we even assume its safe
6685 : // to try and find the frame.
6686 223 : nsIContent* content = GetCurrentEventContent();
6687 223 : if (!mCurrentEventFrame && content) {
6688 0 : mCurrentEventFrame = content->GetPrimaryFrame();
6689 0 : MOZ_ASSERT(!mCurrentEventFrame ||
6690 : mCurrentEventFrame->PresContext()->GetPresShell() == this);
6691 : }
6692 223 : return mCurrentEventFrame;
6693 : }
6694 :
6695 : nsIFrame*
6696 178 : PresShell::GetEventTargetFrame()
6697 : {
6698 178 : return GetCurrentEventFrame();
6699 : }
6700 :
6701 : already_AddRefed<nsIContent>
6702 8 : PresShell::GetEventTargetContent(WidgetEvent* aEvent)
6703 : {
6704 16 : nsCOMPtr<nsIContent> content = GetCurrentEventContent();
6705 8 : if (!content) {
6706 0 : nsIFrame* currentEventFrame = GetCurrentEventFrame();
6707 0 : if (currentEventFrame) {
6708 0 : currentEventFrame->GetContentForEvent(aEvent, getter_AddRefs(content));
6709 0 : NS_ASSERTION(!content || content->GetComposedDoc() == mDocument,
6710 : "handing out content from a different doc");
6711 : }
6712 : }
6713 16 : return content.forget();
6714 : }
6715 :
6716 : void
6717 10 : PresShell::PushCurrentEventInfo(nsIFrame* aFrame, nsIContent* aContent)
6718 : {
6719 10 : if (mCurrentEventFrame || mCurrentEventContent) {
6720 0 : mCurrentEventFrameStack.InsertElementAt(0, mCurrentEventFrame);
6721 0 : mCurrentEventContentStack.InsertObjectAt(mCurrentEventContent, 0);
6722 : }
6723 10 : mCurrentEventFrame = aFrame;
6724 10 : mCurrentEventContent = aContent;
6725 10 : }
6726 :
6727 : void
6728 10 : PresShell::PopCurrentEventInfo()
6729 : {
6730 10 : mCurrentEventFrame = nullptr;
6731 10 : mCurrentEventContent = nullptr;
6732 :
6733 10 : if (0 != mCurrentEventFrameStack.Length()) {
6734 0 : mCurrentEventFrame = mCurrentEventFrameStack.ElementAt(0);
6735 0 : mCurrentEventFrameStack.RemoveElementAt(0);
6736 0 : mCurrentEventContent = mCurrentEventContentStack.ObjectAt(0);
6737 0 : mCurrentEventContentStack.RemoveObjectAt(0);
6738 :
6739 : // Don't use it if it has moved to a different document.
6740 0 : if (mCurrentEventContent &&
6741 0 : mCurrentEventContent->GetComposedDoc() != mDocument) {
6742 0 : mCurrentEventContent = nullptr;
6743 0 : mCurrentEventFrame = nullptr;
6744 : }
6745 : }
6746 10 : }
6747 :
6748 0 : bool PresShell::InZombieDocument(nsIContent *aContent)
6749 : {
6750 : // If a content node points to a null document, or the document is not
6751 : // attached to a window, then it is possibly in a zombie document,
6752 : // about to be replaced by a newly loading document.
6753 : // Such documents cannot handle DOM events.
6754 : // It might actually be in a node not attached to any document,
6755 : // in which case there is not parent presshell to retarget it to.
6756 0 : nsIDocument* doc = aContent->GetComposedDoc();
6757 0 : return !doc || !doc->GetWindow();
6758 : }
6759 :
6760 : already_AddRefed<nsPIDOMWindowOuter>
6761 0 : PresShell::GetRootWindow()
6762 : {
6763 0 : nsCOMPtr<nsPIDOMWindowOuter> window = mDocument->GetWindow();
6764 0 : if (window) {
6765 0 : nsCOMPtr<nsPIDOMWindowOuter> rootWindow = window->GetPrivateRoot();
6766 0 : NS_ASSERTION(rootWindow, "nsPIDOMWindow::GetPrivateRoot() returns NULL");
6767 0 : return rootWindow.forget();
6768 : }
6769 :
6770 : // If we don't have DOM window, we're zombie, we should find the root window
6771 : // with our parent shell.
6772 0 : nsCOMPtr<nsIPresShell> parent = GetParentPresShellForEventHandling();
6773 0 : NS_ENSURE_TRUE(parent, nullptr);
6774 0 : return parent->GetRootWindow();
6775 : }
6776 :
6777 : already_AddRefed<nsPIDOMWindowOuter>
6778 0 : PresShell::GetFocusedDOMWindowInOurWindow()
6779 : {
6780 0 : nsCOMPtr<nsPIDOMWindowOuter> rootWindow = GetRootWindow();
6781 0 : NS_ENSURE_TRUE(rootWindow, nullptr);
6782 0 : nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
6783 0 : nsFocusManager::GetFocusedDescendant(rootWindow, true,
6784 0 : getter_AddRefs(focusedWindow));
6785 0 : return focusedWindow.forget();
6786 : }
6787 :
6788 : already_AddRefed<nsIPresShell>
6789 0 : PresShell::GetParentPresShellForEventHandling()
6790 : {
6791 0 : NS_ENSURE_TRUE(mPresContext, nullptr);
6792 :
6793 : // Now, find the parent pres shell and send the event there
6794 0 : nsCOMPtr<nsIDocShellTreeItem> treeItem = mPresContext->GetDocShell();
6795 0 : if (!treeItem) {
6796 0 : treeItem = mForwardingContainer.get();
6797 : }
6798 :
6799 : // Might have gone away, or never been around to start with
6800 0 : NS_ENSURE_TRUE(treeItem, nullptr);
6801 :
6802 0 : nsCOMPtr<nsIDocShellTreeItem> parentTreeItem;
6803 0 : treeItem->GetParent(getter_AddRefs(parentTreeItem));
6804 0 : nsCOMPtr<nsIDocShell> parentDocShell = do_QueryInterface(parentTreeItem);
6805 0 : NS_ENSURE_TRUE(parentDocShell && treeItem != parentTreeItem, nullptr);
6806 :
6807 0 : nsCOMPtr<nsIPresShell> parentPresShell = parentDocShell->GetPresShell();
6808 0 : return parentPresShell.forget();
6809 : }
6810 :
6811 : nsresult
6812 0 : PresShell::RetargetEventToParent(WidgetGUIEvent* aEvent,
6813 : nsEventStatus* aEventStatus)
6814 : {
6815 : // Send this events straight up to the parent pres shell.
6816 : // We do this for keystroke events in zombie documents or if either a frame
6817 : // or a root content is not present.
6818 : // That way at least the UI key bindings can work.
6819 :
6820 0 : nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
6821 0 : nsCOMPtr<nsIPresShell> parentPresShell = GetParentPresShellForEventHandling();
6822 0 : NS_ENSURE_TRUE(parentPresShell, NS_ERROR_FAILURE);
6823 :
6824 : // Fake the event as though it's from the parent pres shell's root frame.
6825 0 : return parentPresShell->HandleEvent(parentPresShell->GetRootFrame(), aEvent, true, aEventStatus);
6826 : }
6827 :
6828 : void
6829 0 : PresShell::DisableNonTestMouseEvents(bool aDisable)
6830 : {
6831 0 : sDisableNonTestMouseEvents = aDisable;
6832 0 : }
6833 :
6834 : void
6835 10 : PresShell::RecordMouseLocation(WidgetGUIEvent* aEvent)
6836 : {
6837 10 : if (!mPresContext)
6838 0 : return;
6839 :
6840 10 : if (!mPresContext->IsRoot()) {
6841 0 : PresShell* rootPresShell = GetRootPresShell();
6842 0 : if (rootPresShell) {
6843 0 : rootPresShell->RecordMouseLocation(aEvent);
6844 : }
6845 0 : return;
6846 : }
6847 :
6848 24 : if ((aEvent->mMessage == eMouseMove &&
6849 10 : aEvent->AsMouseEvent()->mReason == WidgetMouseEvent::eReal) ||
6850 11 : aEvent->mMessage == eMouseEnterIntoWidget ||
6851 20 : aEvent->mMessage == eMouseDown ||
6852 5 : aEvent->mMessage == eMouseUp) {
6853 5 : nsIFrame* rootFrame = GetRootFrame();
6854 5 : if (!rootFrame) {
6855 0 : nsView* rootView = mViewManager->GetRootView();
6856 0 : mMouseLocation = nsLayoutUtils::TranslateWidgetToView(mPresContext,
6857 : aEvent->mWidget, aEvent->mRefPoint, rootView);
6858 0 : mMouseEventTargetGuid = InputAPZContext::GetTargetLayerGuid();
6859 : } else {
6860 5 : mMouseLocation =
6861 10 : nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, rootFrame);
6862 5 : mMouseEventTargetGuid = InputAPZContext::GetTargetLayerGuid();
6863 : }
6864 : #ifdef DEBUG_MOUSE_LOCATION
6865 : if (aEvent->mMessage == eMouseEnterIntoWidget) {
6866 : printf("[ps=%p]got mouse enter for %p\n",
6867 : this, aEvent->mWidget);
6868 : }
6869 : printf("[ps=%p]setting mouse location to (%d,%d)\n",
6870 : this, mMouseLocation.x, mMouseLocation.y);
6871 : #endif
6872 5 : if (aEvent->mMessage == eMouseEnterIntoWidget) {
6873 1 : SynthesizeMouseMove(false);
6874 : }
6875 5 : } else if (aEvent->mMessage == eMouseExitFromWidget) {
6876 : // Although we only care about the mouse moving into an area for which this
6877 : // pres shell doesn't receive mouse move events, we don't check which widget
6878 : // the mouse exit was for since this seems to vary by platform. Hopefully
6879 : // this won't matter at all since we'll get the mouse move or enter after
6880 : // the mouse exit when the mouse moves from one of our widgets into another.
6881 1 : mMouseLocation = nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
6882 1 : mMouseEventTargetGuid = InputAPZContext::GetTargetLayerGuid();
6883 : #ifdef DEBUG_MOUSE_LOCATION
6884 : printf("[ps=%p]got mouse exit for %p\n",
6885 : this, aEvent->mWidget);
6886 : printf("[ps=%p]clearing mouse location\n",
6887 : this);
6888 : #endif
6889 : }
6890 : }
6891 :
6892 0 : nsIFrame* GetNearestFrameContainingPresShell(nsIPresShell* aPresShell)
6893 : {
6894 0 : nsView* view = aPresShell->GetViewManager()->GetRootView();
6895 0 : while (view && !view->GetFrame()) {
6896 0 : view = view->GetParent();
6897 : }
6898 :
6899 0 : nsIFrame* frame = nullptr;
6900 0 : if (view) {
6901 0 : frame = view->GetFrame();
6902 : }
6903 :
6904 0 : return frame;
6905 : }
6906 :
6907 : static bool
6908 20 : FlushThrottledStyles(nsIDocument *aDocument, void *aData)
6909 : {
6910 20 : nsIPresShell* shell = aDocument->GetShell();
6911 20 : if (shell && shell->IsVisible()) {
6912 10 : nsPresContext* presContext = shell->GetPresContext();
6913 10 : if (presContext) {
6914 10 : presContext->RestyleManager()->UpdateOnlyAnimationStyles();
6915 : }
6916 : }
6917 :
6918 20 : aDocument->EnumerateSubDocuments(FlushThrottledStyles, nullptr);
6919 20 : return true;
6920 : }
6921 :
6922 : /*
6923 : * This function handles the preventDefault behavior of pointerdown. When user
6924 : * preventDefault on pointerdown, We have to mark the active pointer to prevent
6925 : * sebsequent mouse events (except mouse transition events) and default
6926 : * behaviors.
6927 : *
6928 : * We add mPreventMouseEventByContent flag in PointerInfo to represent the
6929 : * active pointer won't firing compatible mouse events. It's set to true when
6930 : * content preventDefault on pointerdown
6931 : */
6932 : static void
6933 4 : PostHandlePointerEventsPreventDefault(WidgetPointerEvent* aPointerEvent,
6934 : WidgetGUIEvent* aMouseOrTouchEvent)
6935 : {
6936 4 : if (!aPointerEvent->mIsPrimary || aPointerEvent->mMessage != ePointerDown ||
6937 0 : !aPointerEvent->DefaultPreventedByContent()) {
6938 8 : return;
6939 : }
6940 0 : nsIPresShell::PointerInfo* pointerInfo = nullptr;
6941 0 : if (!sActivePointersIds->Get(aPointerEvent->pointerId, &pointerInfo) ||
6942 0 : !pointerInfo) {
6943 : // We already added the PointerInfo for active pointer when
6944 : // PresShell::HandleEvent handling pointerdown event.
6945 : #ifdef DEBUG
6946 0 : MOZ_CRASH("Got ePointerDown w/o active pointer info!!");
6947 : #endif // #ifdef DEBUG
6948 : return;
6949 : }
6950 : // PreventDefault only applied for active pointers.
6951 0 : if (!pointerInfo->mActiveState) {
6952 0 : return;
6953 : }
6954 0 : aMouseOrTouchEvent->PreventDefault(false);
6955 0 : pointerInfo->mPreventMouseEventByContent = true;
6956 : }
6957 :
6958 : /*
6959 : * This function handles the case when content had called preventDefault on the
6960 : * active pointer. In that case we have to prevent firing subsequent mouse
6961 : * to content. We check the flag PointerInfo::mPreventMouseEventByContent and
6962 : * call PreventDefault(false) to stop default behaviors and stop firing mouse
6963 : * events to content and chrome.
6964 : *
6965 : * note: mouse transition events are excluded
6966 : * note: we have to clean mPreventMouseEventByContent on pointerup for those
6967 : * devices support hover
6968 : * note: we don't suppress firing mouse events to chrome and system group
6969 : * handlers because they may implement default behaviors
6970 : */
6971 : static void
6972 4 : PreHandlePointerEventsPreventDefault(WidgetPointerEvent* aPointerEvent,
6973 : WidgetGUIEvent* aMouseOrTouchEvent)
6974 : {
6975 4 : if (!aPointerEvent->mIsPrimary || aPointerEvent->mMessage == ePointerDown) {
6976 4 : return;
6977 : }
6978 4 : nsIPresShell::PointerInfo* pointerInfo = nullptr;
6979 8 : if (!sActivePointersIds->Get(aPointerEvent->pointerId, &pointerInfo) ||
6980 4 : !pointerInfo) {
6981 : // The PointerInfo for active pointer should be added for normal cases. But
6982 : // in some cases, we may receive mouse events before adding PointerInfo in
6983 : // sActivePointersIds. (e.g. receive mousemove before eMouseEnterIntoWidget
6984 : // or change preference 'dom.w3c_pointer_events.enabled' from off to on).
6985 : // In these cases, we could ignore them because they are not the events
6986 : // between a DefaultPrevented pointerdown and the corresponding pointerup.
6987 0 : return;
6988 : }
6989 4 : if (!pointerInfo->mPreventMouseEventByContent) {
6990 4 : return;
6991 : }
6992 0 : aMouseOrTouchEvent->PreventDefault(false);
6993 0 : if (aPointerEvent->mMessage == ePointerUp) {
6994 0 : pointerInfo->mPreventMouseEventByContent = false;
6995 : }
6996 : }
6997 :
6998 : static nsresult
6999 10 : DispatchPointerFromMouseOrTouch(PresShell* aShell,
7000 : nsIFrame* aFrame,
7001 : WidgetGUIEvent* aEvent,
7002 : bool aDontRetargetEvents,
7003 : nsEventStatus* aStatus,
7004 : nsIContent** aTargetContent)
7005 : {
7006 10 : EventMessage pointerMessage = eVoidEvent;
7007 10 : if (aEvent->mClass == eMouseEventClass) {
7008 6 : WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
7009 : // 1. If it is not mouse then it is likely will come as touch event
7010 : // 2. We don't synthesize pointer events for those events that are not
7011 : // dispatched to DOM.
7012 12 : if (!mouseEvent->convertToPointer ||
7013 6 : !aEvent->IsAllowedToDispatchDOMEvent()) {
7014 2 : return NS_OK;
7015 : }
7016 6 : int16_t button = mouseEvent->button;
7017 6 : switch (mouseEvent->mMessage) {
7018 : case eMouseMove:
7019 4 : button = WidgetMouseEvent::eNoButton;
7020 4 : pointerMessage = ePointerMove;
7021 4 : break;
7022 : case eMouseUp:
7023 0 : pointerMessage = mouseEvent->buttons ? ePointerMove : ePointerUp;
7024 0 : break;
7025 : case eMouseDown:
7026 0 : pointerMessage =
7027 0 : mouseEvent->buttons & ~nsContentUtils::GetButtonsFlagForButton(button) ?
7028 : ePointerMove : ePointerDown;
7029 0 : break;
7030 : default:
7031 2 : return NS_OK;
7032 : }
7033 :
7034 8 : WidgetPointerEvent event(*mouseEvent);
7035 4 : event.pointerId = mouseEvent->pointerId;
7036 4 : event.inputSource = mouseEvent->inputSource;
7037 4 : event.mMessage = pointerMessage;
7038 4 : event.button = button;
7039 4 : event.buttons = mouseEvent->buttons;
7040 4 : event.pressure = event.buttons ?
7041 0 : mouseEvent->pressure ? mouseEvent->pressure : 0.5f :
7042 : 0.0f;
7043 4 : event.convertToPointer = mouseEvent->convertToPointer = false;
7044 4 : PreHandlePointerEventsPreventDefault(&event, aEvent);
7045 4 : aShell->HandleEvent(aFrame, &event, aDontRetargetEvents, aStatus,
7046 4 : aTargetContent);
7047 4 : PostHandlePointerEventsPreventDefault(&event, aEvent);
7048 4 : } else if (aEvent->mClass == eTouchEventClass) {
7049 0 : WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
7050 0 : int16_t button = WidgetMouseEvent::eLeftButton;
7051 0 : int16_t buttons = WidgetMouseEvent::eLeftButtonFlag;
7052 : // loop over all touches and dispatch pointer events on each touch
7053 : // copy the event
7054 0 : switch (touchEvent->mMessage) {
7055 : case eTouchMove:
7056 0 : pointerMessage = ePointerMove;
7057 0 : button = WidgetMouseEvent::eNoButton;
7058 0 : break;
7059 : case eTouchEnd:
7060 0 : pointerMessage = ePointerUp;
7061 0 : buttons = WidgetMouseEvent::eNoButtonFlag;
7062 0 : break;
7063 : case eTouchStart:
7064 0 : pointerMessage = ePointerDown;
7065 0 : break;
7066 : case eTouchCancel:
7067 : case eTouchPointerCancel:
7068 0 : pointerMessage = ePointerCancel;
7069 0 : break;
7070 : default:
7071 0 : return NS_OK;
7072 : }
7073 :
7074 0 : for (uint32_t i = 0; i < touchEvent->mTouches.Length(); ++i) {
7075 0 : mozilla::dom::Touch* touch = touchEvent->mTouches[i];
7076 0 : if (!TouchManager::ShouldConvertTouchToPointer(touch, touchEvent)) {
7077 0 : continue;
7078 : }
7079 :
7080 0 : WidgetPointerEvent event(touchEvent->IsTrusted(), pointerMessage,
7081 0 : touchEvent->mWidget);
7082 0 : event.mIsPrimary = i == 0;
7083 0 : event.pointerId = touch->Identifier();
7084 0 : event.mRefPoint = touch->mRefPoint;
7085 0 : event.mModifiers = touchEvent->mModifiers;
7086 0 : event.mWidth = touch->RadiusX();
7087 0 : event.mHeight = touch->RadiusY();
7088 0 : event.tiltX = touch->tiltX;
7089 0 : event.tiltY = touch->tiltY;
7090 0 : event.mTime = touchEvent->mTime;
7091 0 : event.mTimeStamp = touchEvent->mTimeStamp;
7092 0 : event.mFlags = touchEvent->mFlags;
7093 0 : event.button = button;
7094 0 : event.buttons = buttons;
7095 0 : event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
7096 0 : event.convertToPointer = touch->convertToPointer = false;
7097 0 : PreHandlePointerEventsPreventDefault(&event, aEvent);
7098 0 : aShell->HandleEvent(aFrame, &event, aDontRetargetEvents, aStatus,
7099 0 : aTargetContent);
7100 0 : PostHandlePointerEventsPreventDefault(&event, aEvent);
7101 : }
7102 : }
7103 8 : return NS_OK;
7104 : }
7105 :
7106 : class ReleasePointerCaptureCaller final
7107 : {
7108 : public:
7109 10 : ReleasePointerCaptureCaller()
7110 10 : : mPointerEvent(nullptr)
7111 : {
7112 10 : }
7113 10 : ~ReleasePointerCaptureCaller()
7114 10 : {
7115 10 : if (mPointerEvent) {
7116 0 : nsIPresShell::ReleasePointerCapturingContent(mPointerEvent->pointerId);
7117 0 : nsIPresShell::CheckPointerCaptureState(mPointerEvent);
7118 : }
7119 10 : }
7120 :
7121 0 : void SetTarget(const WidgetPointerEvent* aPointerEvent)
7122 : {
7123 0 : MOZ_ASSERT(aPointerEvent);
7124 0 : mPointerEvent = aPointerEvent;
7125 0 : }
7126 :
7127 : private:
7128 : // This is synchronously used inside PresShell::HandleEvent.
7129 : const WidgetPointerEvent* mPointerEvent;
7130 : };
7131 :
7132 : bool
7133 0 : PresShell::CanDispatchEvent(const WidgetGUIEvent* aEvent) const
7134 : {
7135 : bool rv =
7136 0 : mPresContext && !mHaveShutDown && nsContentUtils::IsSafeToRunScript();
7137 0 : if (aEvent) {
7138 0 : rv &= (aEvent && aEvent->mWidget && !aEvent->mWidget->Destroyed());
7139 : }
7140 0 : return rv;
7141 : }
7142 :
7143 : nsresult
7144 10 : PresShell::HandleEvent(nsIFrame* aFrame,
7145 : WidgetGUIEvent* aEvent,
7146 : bool aDontRetargetEvents,
7147 : nsEventStatus* aEventStatus,
7148 : nsIContent** aTargetContent)
7149 : {
7150 : #ifdef MOZ_TASK_TRACER
7151 : Maybe<AutoSourceEvent> taskTracerEvent;
7152 : if (MOZ_UNLIKELY(IsStartLogging())) {
7153 : // Make touch events, mouse events and hardware key events to be
7154 : // the source events of TaskTracer, and originate the rest
7155 : // correlation tasks from here.
7156 : SourceEventType type = SourceEventType::Unknown;
7157 : if (aEvent->AsTouchEvent()) {
7158 : type = SourceEventType::Touch;
7159 : } else if (aEvent->AsMouseEvent()) {
7160 : type = SourceEventType::Mouse;
7161 : } else if (aEvent->AsKeyboardEvent()) {
7162 : type = SourceEventType::Key;
7163 : }
7164 : taskTracerEvent.emplace(type);
7165 : }
7166 : #endif
7167 :
7168 10 : NS_ASSERTION(aFrame, "aFrame should be not null");
7169 :
7170 : // Update the latest focus sequence number with this new sequence number
7171 10 : if (mAPZFocusSequenceNumber < aEvent->mFocusSequenceNumber) {
7172 6 : mAPZFocusSequenceNumber = aEvent->mFocusSequenceNumber;
7173 : }
7174 :
7175 10 : if (sPointerEventEnabled) {
7176 20 : AutoWeakFrame weakFrame(aFrame);
7177 20 : nsCOMPtr<nsIContent> targetContent;
7178 10 : DispatchPointerFromMouseOrTouch(this, aFrame, aEvent, aDontRetargetEvents,
7179 : aEventStatus,
7180 20 : getter_AddRefs(targetContent));
7181 10 : if (!weakFrame.IsAlive()) {
7182 0 : if (targetContent) {
7183 0 : aFrame = targetContent->GetPrimaryFrame();
7184 0 : if (!aFrame) {
7185 0 : PushCurrentEventInfo(aFrame, targetContent);
7186 0 : nsresult rv = HandleEventInternal(aEvent, aEventStatus, true);
7187 0 : PopCurrentEventInfo();
7188 0 : return rv;
7189 : }
7190 : } else {
7191 0 : return NS_OK;
7192 : }
7193 : }
7194 : }
7195 :
7196 10 : if (mIsDestroying ||
7197 0 : (sDisableNonTestMouseEvents && !aEvent->mFlags.mIsSynthesizedForTests &&
7198 0 : aEvent->HasMouseEventMessage())) {
7199 0 : return NS_OK;
7200 : }
7201 :
7202 10 : RecordMouseLocation(aEvent);
7203 :
7204 10 : if (AccessibleCaretEnabled(mDocument->GetDocShell())) {
7205 : // We have to target the focus window because regardless of where the
7206 : // touch goes, we want to access the copy paste manager.
7207 0 : nsCOMPtr<nsPIDOMWindowOuter> window = GetFocusedDOMWindowInOurWindow();
7208 : nsCOMPtr<nsIDocument> retargetEventDoc =
7209 0 : window ? window->GetExtantDoc() : nullptr;
7210 : nsCOMPtr<nsIPresShell> presShell =
7211 0 : retargetEventDoc ? retargetEventDoc->GetShell() : nullptr;
7212 :
7213 : RefPtr<AccessibleCaretEventHub> eventHub =
7214 0 : presShell ? presShell->GetAccessibleCaretEventHub() : nullptr;
7215 0 : if (eventHub && *aEventStatus != nsEventStatus_eConsumeNoDefault) {
7216 : // Don't dispatch event to AccessibleCaretEventHub when the event status
7217 : // is nsEventStatus_eConsumeNoDefault. This might be happened when content
7218 : // preventDefault on the pointer events. In such case, we also call
7219 : // preventDefault on mouse events to stop default behaviors.
7220 0 : *aEventStatus = eventHub->HandleEvent(aEvent);
7221 0 : if (*aEventStatus == nsEventStatus_eConsumeNoDefault) {
7222 : // If the event is consumed, cancel APZC panning by setting
7223 : // mMultipleActionsPrevented.
7224 0 : aEvent->mFlags.mMultipleActionsPrevented = true;
7225 0 : return NS_OK;
7226 : }
7227 : }
7228 : }
7229 :
7230 10 : if (sPointerEventEnabled) {
7231 10 : UpdateActivePointerState(aEvent);
7232 : }
7233 :
7234 10 : if (!nsContentUtils::IsSafeToRunScript() &&
7235 0 : aEvent->IsAllowedToDispatchDOMEvent()) {
7236 0 : if (aEvent->mClass == eCompositionEventClass) {
7237 0 : IMEStateManager::OnCompositionEventDiscarded(
7238 0 : aEvent->AsCompositionEvent());
7239 : }
7240 : #ifdef DEBUG
7241 0 : if (aEvent->IsIMERelatedEvent()) {
7242 0 : nsPrintfCString warning("%d event is discarded", aEvent->mMessage);
7243 0 : NS_WARNING(warning.get());
7244 : }
7245 : #endif
7246 0 : nsContentUtils::WarnScriptWasIgnored(GetDocument());
7247 0 : return NS_OK;
7248 : }
7249 :
7250 16 : nsIContent* capturingContent = ((aEvent->mClass == ePointerEventClass ||
7251 12 : aEvent->mClass == eWheelEventClass ||
7252 6 : aEvent->HasMouseEventMessage())
7253 20 : ? GetCapturingContent()
7254 10 : : nullptr);
7255 :
7256 20 : nsCOMPtr<nsIDocument> retargetEventDoc;
7257 10 : if (!aDontRetargetEvents) {
7258 : // key and IME related events should not cross top level window boundary.
7259 : // Basically, such input events should be fired only on focused widget.
7260 : // However, some IMEs might need to clean up composition after focused
7261 : // window is deactivated. And also some tests on MozMill want to test key
7262 : // handling on deactivated window because MozMill window can be activated
7263 : // during tests. So, there is no merit the events should be redirected to
7264 : // active window. So, the events should be handled on the last focused
7265 : // content in the last focused DOM window in same top level window.
7266 : // Note, if no DOM window has been focused yet, we can discard the events.
7267 10 : if (aEvent->IsTargetedAtFocusedWindow()) {
7268 0 : nsCOMPtr<nsPIDOMWindowOuter> window = GetFocusedDOMWindowInOurWindow();
7269 : // No DOM window in same top level window has not been focused yet,
7270 : // discard the events.
7271 0 : if (!window) {
7272 0 : return NS_OK;
7273 : }
7274 :
7275 0 : retargetEventDoc = window->GetExtantDoc();
7276 0 : if (!retargetEventDoc)
7277 0 : return NS_OK;
7278 10 : } else if (capturingContent) {
7279 : // if the mouse is being captured then retarget the mouse event at the
7280 : // document that is being captured.
7281 0 : retargetEventDoc = capturingContent->GetComposedDoc();
7282 : #ifdef ANDROID
7283 : } else if ((aEvent->mClass == eTouchEventClass) ||
7284 : (aEvent->mClass == eMouseEventClass) ||
7285 : (aEvent->mClass == eWheelEventClass)) {
7286 : retargetEventDoc = GetPrimaryContentDocument();
7287 : #endif
7288 : }
7289 :
7290 10 : if (retargetEventDoc) {
7291 0 : nsCOMPtr<nsIPresShell> presShell = retargetEventDoc->GetShell();
7292 0 : if (!presShell)
7293 0 : return NS_OK;
7294 :
7295 0 : if (presShell != this) {
7296 0 : nsIFrame* frame = presShell->GetRootFrame();
7297 0 : if (!frame) {
7298 0 : if (aEvent->mMessage == eQueryTextContent ||
7299 0 : aEvent->IsContentCommandEvent()) {
7300 0 : return NS_OK;
7301 : }
7302 :
7303 0 : frame = GetNearestFrameContainingPresShell(presShell);
7304 : }
7305 :
7306 0 : if (!frame)
7307 0 : return NS_OK;
7308 :
7309 0 : nsCOMPtr<nsIPresShell> shell = frame->PresContext()->GetPresShell();
7310 0 : return shell->HandleEvent(frame, aEvent, true, aEventStatus);
7311 : }
7312 : }
7313 : }
7314 :
7315 20 : if (aEvent->mClass == eKeyboardEventClass &&
7316 10 : mDocument && mDocument->EventHandlingSuppressed()) {
7317 0 : if (aEvent->mMessage == eKeyDown) {
7318 0 : mNoDelayedKeyEvents = true;
7319 0 : } else if (!mNoDelayedKeyEvents) {
7320 0 : DelayedEvent* event = new DelayedKeyEvent(aEvent->AsKeyboardEvent());
7321 0 : if (!mDelayedEvents.AppendElement(event)) {
7322 0 : delete event;
7323 : }
7324 : }
7325 0 : aEvent->mFlags.mIsSuppressedOrDelayed = true;
7326 0 : return NS_OK;
7327 : }
7328 :
7329 10 : nsIFrame* frame = aFrame;
7330 :
7331 10 : if (aEvent->IsUsingCoordinates()) {
7332 20 : ReleasePointerCaptureCaller releasePointerCaptureCaller;
7333 10 : if (mDocument) {
7334 10 : if (aEvent->mClass == eTouchEventClass) {
7335 0 : nsIDocument::UnlockPointer();
7336 : }
7337 :
7338 20 : AutoWeakFrame weakFrame(frame);
7339 : { // scope for scriptBlocker.
7340 20 : nsAutoScriptBlocker scriptBlocker;
7341 10 : FlushThrottledStyles(GetRootPresShell()->GetDocument(), nullptr);
7342 : }
7343 :
7344 :
7345 10 : if (!weakFrame.IsAlive()) {
7346 0 : frame = GetNearestFrameContainingPresShell(this);
7347 : }
7348 : }
7349 :
7350 10 : if (!frame) {
7351 0 : NS_WARNING("Nothing to handle this event!");
7352 0 : return NS_OK;
7353 : }
7354 :
7355 10 : nsPresContext* framePresContext = frame->PresContext();
7356 10 : nsPresContext* rootPresContext = framePresContext->GetRootPresContext();
7357 10 : NS_ASSERTION(rootPresContext == mPresContext->GetRootPresContext(),
7358 : "How did we end up outside the connected prescontext/viewmanager hierarchy?");
7359 : nsIFrame* popupFrame =
7360 10 : nsLayoutUtils::GetPopupFrameForEventCoordinates(rootPresContext, aEvent);
7361 : // If a remote browser is currently capturing input break out if we
7362 : // detect a chrome generated popup.
7363 10 : if (popupFrame && capturingContent &&
7364 0 : EventStateManager::IsRemoteTarget(capturingContent)) {
7365 0 : capturingContent = nullptr;
7366 : }
7367 : // If the popupFrame is an ancestor of the 'frame', the frame should
7368 : // handle the event, otherwise, the popup should handle it.
7369 10 : if (popupFrame &&
7370 0 : !nsContentUtils::ContentIsCrossDocDescendantOf(
7371 0 : framePresContext->GetPresShell()->GetDocument(),
7372 0 : popupFrame->GetContent())) {
7373 :
7374 : // If we aren't starting our event dispatch from the root frame of the
7375 : // root prescontext, then someone must be capturing the mouse. In that
7376 : // case we only want to use the popup list if the capture is
7377 : // inside the popup.
7378 0 : if (framePresContext == rootPresContext &&
7379 0 : frame == mFrameConstructor->GetRootFrame()) {
7380 0 : frame = popupFrame;
7381 0 : } else if (capturingContent &&
7382 0 : nsContentUtils::ContentIsDescendantOf(
7383 0 : capturingContent, popupFrame->GetContent())) {
7384 0 : frame = popupFrame;
7385 : }
7386 : }
7387 :
7388 10 : bool captureRetarget = false;
7389 10 : if (capturingContent) {
7390 : // If a capture is active, determine if the docshell is visible. If not,
7391 : // clear the capture and target the mouse event normally instead. This
7392 : // would occur if the mouse button is held down while a tab change occurs.
7393 : // If the docshell is visible, look for a scrolling container.
7394 : bool vis;
7395 : nsCOMPtr<nsIBaseWindow> baseWin =
7396 0 : do_QueryInterface(mPresContext->GetContainerWeak());
7397 0 : if (baseWin && NS_SUCCEEDED(baseWin->GetVisibility(&vis)) && vis) {
7398 0 : captureRetarget = gCaptureInfo.mRetargetToElement;
7399 0 : if (!captureRetarget) {
7400 : // A check was already done above to ensure that capturingContent is
7401 : // in this presshell.
7402 0 : NS_ASSERTION(capturingContent->GetComposedDoc() == GetDocument(),
7403 : "Unexpected document");
7404 0 : nsIFrame* captureFrame = capturingContent->GetPrimaryFrame();
7405 0 : if (captureFrame) {
7406 0 : if (capturingContent->IsHTMLElement(nsGkAtoms::select)) {
7407 : // a dropdown <select> has a child in its selectPopupList and we should
7408 : // capture on that instead.
7409 0 : nsIFrame* childFrame = captureFrame->GetChildList(nsIFrame::kSelectPopupList).FirstChild();
7410 0 : if (childFrame) {
7411 0 : captureFrame = childFrame;
7412 : }
7413 : }
7414 :
7415 : // scrollable frames should use the scrolling container as
7416 : // the root instead of the document
7417 0 : nsIScrollableFrame* scrollFrame = do_QueryFrame(captureFrame);
7418 0 : if (scrollFrame) {
7419 0 : frame = scrollFrame->GetScrolledFrame();
7420 : }
7421 : }
7422 : }
7423 : }
7424 : else {
7425 0 : ClearMouseCapture(nullptr);
7426 0 : capturingContent = nullptr;
7427 : }
7428 : }
7429 :
7430 : // all touch events except for touchstart use a captured target
7431 10 : if (aEvent->mClass == eTouchEventClass && aEvent->mMessage != eTouchStart) {
7432 0 : captureRetarget = true;
7433 : }
7434 :
7435 10 : WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
7436 11 : bool isWindowLevelMouseExit = (aEvent->mMessage == eMouseExitFromWidget) &&
7437 11 : (mouseEvent && mouseEvent->mExitFrom == WidgetMouseEvent::eTopLevel);
7438 :
7439 : // Get the frame at the event point. However, don't do this if we're
7440 : // capturing and retargeting the event because the captured frame will
7441 : // be used instead below. Also keep using the root frame if we're dealing
7442 : // with a window-level mouse exit event since we want to start sending
7443 : // mouse out events at the root EventStateManager.
7444 10 : if (!captureRetarget && !isWindowLevelMouseExit) {
7445 9 : nsPoint eventPoint;
7446 9 : uint32_t flags = 0;
7447 9 : if (aEvent->mMessage == eTouchStart) {
7448 0 : if (gfxPrefs::APZAllowZooming()) {
7449 : // Setting this flag will skip the scrollbars on the root frame from
7450 : // participating in hit-testing, and we only want that to happen on
7451 : // zoomable platforms (for now).
7452 0 : flags |= INPUT_IGNORE_ROOT_SCROLL_FRAME;
7453 : }
7454 0 : WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
7455 : // if this is a continuing session, ensure that all these events are
7456 : // in the same document by taking the target of the events already in
7457 : // the capture list
7458 0 : nsCOMPtr<nsIContent> anyTarget;
7459 0 : if (touchEvent->mTouches.Length() > 1) {
7460 0 : anyTarget = TouchManager::GetAnyCapturedTouchTarget();
7461 : }
7462 :
7463 0 : for (int32_t i = touchEvent->mTouches.Length(); i; ) {
7464 0 : --i;
7465 0 : dom::Touch* touch = touchEvent->mTouches[i];
7466 :
7467 0 : int32_t id = touch->Identifier();
7468 0 : if (!TouchManager::HasCapturedTouch(id)) {
7469 : // find the target for this touch
7470 0 : eventPoint = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent,
7471 : touch->mRefPoint,
7472 : frame);
7473 : nsIFrame* target = FindFrameTargetedByInputEvent(aEvent,
7474 : frame,
7475 : eventPoint,
7476 0 : flags);
7477 0 : if (target && !anyTarget) {
7478 0 : target->GetContentForEvent(aEvent, getter_AddRefs(anyTarget));
7479 0 : while (anyTarget && !anyTarget->IsElement()) {
7480 0 : anyTarget = anyTarget->GetParent();
7481 : }
7482 0 : touch->SetTarget(anyTarget);
7483 : } else {
7484 0 : nsIFrame* newTargetFrame = nullptr;
7485 0 : for (nsIFrame* f = target; f;
7486 : f = nsLayoutUtils::GetParentOrPlaceholderForCrossDoc(f)) {
7487 0 : if (f->PresContext()->Document() == anyTarget->OwnerDoc()) {
7488 0 : newTargetFrame = f;
7489 0 : break;
7490 : }
7491 : // We must be in a subdocument so jump directly to the root frame.
7492 : // GetParentOrPlaceholderForCrossDoc gets called immediately to
7493 : // jump up to the containing document.
7494 0 : f = f->PresContext()->GetPresShell()->GetRootFrame();
7495 : }
7496 :
7497 : // if we couldn't find a target frame in the same document as
7498 : // anyTarget, remove the touch from the capture touch list, as
7499 : // well as the event->mTouches array. touchmove events that aren't
7500 : // in the captured touch list will be discarded
7501 0 : if (!newTargetFrame) {
7502 0 : touchEvent->mTouches.RemoveElementAt(i);
7503 : } else {
7504 0 : target = newTargetFrame;
7505 0 : nsCOMPtr<nsIContent> targetContent;
7506 0 : target->GetContentForEvent(aEvent, getter_AddRefs(targetContent));
7507 0 : while (targetContent && !targetContent->IsElement()) {
7508 0 : targetContent = targetContent->GetParent();
7509 : }
7510 0 : touch->SetTarget(targetContent);
7511 : }
7512 : }
7513 0 : if (target) {
7514 0 : frame = target;
7515 : }
7516 : } else {
7517 : // This touch is an old touch, we need to ensure that is not
7518 : // marked as changed and set its target correctly
7519 0 : touch->mChanged = false;
7520 0 : int32_t id = touch->Identifier();
7521 :
7522 0 : RefPtr<dom::Touch> oldTouch = TouchManager::GetCapturedTouch(id);
7523 0 : if (oldTouch) {
7524 0 : touch->SetTarget(oldTouch->mTarget);
7525 : }
7526 : }
7527 : }
7528 : } else {
7529 9 : eventPoint = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, frame);
7530 : }
7531 14 : if (mouseEvent && mouseEvent->mClass == eMouseEventClass &&
7532 5 : mouseEvent->mIgnoreRootScrollFrame) {
7533 0 : flags |= INPUT_IGNORE_ROOT_SCROLL_FRAME;
7534 : }
7535 : nsIFrame* target =
7536 9 : FindFrameTargetedByInputEvent(aEvent, frame, eventPoint, flags);
7537 9 : if (target) {
7538 9 : frame = target;
7539 : }
7540 : }
7541 :
7542 : // if a node is capturing the mouse, check if the event needs to be
7543 : // retargeted at the capturing content instead. This will be the case when
7544 : // capture retargeting is being used, no frame was found or the frame's
7545 : // content is not a descendant of the capturing content.
7546 10 : if (capturingContent &&
7547 0 : (gCaptureInfo.mRetargetToElement || !frame->GetContent() ||
7548 0 : !nsContentUtils::ContentIsCrossDocDescendantOf(frame->GetContent(),
7549 : capturingContent))) {
7550 : // A check was already done above to ensure that capturingContent is
7551 : // in this presshell.
7552 0 : NS_ASSERTION(capturingContent->GetComposedDoc() == GetDocument(),
7553 : "Unexpected document");
7554 0 : nsIFrame* capturingFrame = capturingContent->GetPrimaryFrame();
7555 0 : if (capturingFrame) {
7556 0 : frame = capturingFrame;
7557 : }
7558 : }
7559 :
7560 10 : if (aEvent->mClass == ePointerEventClass) {
7561 4 : if (WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent()) {
7562 : // Try to keep frame for following check, because
7563 : // frame can be damaged during CheckPointerCaptureState.
7564 8 : AutoWeakFrame frameKeeper(frame);
7565 : // Handle pending pointer capture before any pointer events except
7566 : // gotpointercapture / lostpointercapture.
7567 4 : CheckPointerCaptureState(pointerEvent);
7568 : // Prevent application crashes, in case damaged frame.
7569 4 : if (!frameKeeper.IsAlive()) {
7570 0 : frame = nullptr;
7571 : }
7572 : // Implicit pointer capture for touch
7573 4 : if (frame && sPointerEventImplicitCapture &&
7574 0 : pointerEvent->mMessage == ePointerDown &&
7575 0 : pointerEvent->inputSource == nsIDOMMouseEvent::MOZ_SOURCE_TOUCH) {
7576 0 : nsCOMPtr<nsIContent> targetContent;
7577 0 : frame->GetContentForEvent(aEvent, getter_AddRefs(targetContent));
7578 0 : while (targetContent && !targetContent->IsElement()) {
7579 0 : targetContent = targetContent->GetParent();
7580 : }
7581 0 : if (targetContent) {
7582 0 : SetPointerCapturingContent(pointerEvent->pointerId, targetContent);
7583 : }
7584 : }
7585 : }
7586 : }
7587 :
7588 : // Mouse events should be fired to the same target as their mapped pointer
7589 : // events
7590 16 : if ((aEvent->mClass == ePointerEventClass ||
7591 16 : aEvent->mClass == eMouseEventClass) &&
7592 20 : aEvent->mMessage != ePointerDown && aEvent->mMessage != eMouseDown) {
7593 10 : if (WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent()) {
7594 10 : uint32_t pointerId = mouseEvent->pointerId;
7595 : nsIContent* pointerCapturingContent =
7596 10 : GetPointerCapturingContent(pointerId);
7597 :
7598 10 : if (pointerCapturingContent) {
7599 0 : if (nsIFrame* capturingFrame = pointerCapturingContent->GetPrimaryFrame()) {
7600 0 : frame = capturingFrame;
7601 : }
7602 :
7603 0 : if (aEvent->mMessage == ePointerUp ||
7604 0 : aEvent->mMessage == ePointerCancel) {
7605 : // Implicitly releasing capture for given pointer.
7606 : // ePointerLostCapture should be send after ePointerUp or
7607 : // ePointerCancel.
7608 0 : WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent();
7609 0 : MOZ_ASSERT(pointerEvent);
7610 0 : releasePointerCaptureCaller.SetTarget(pointerEvent);
7611 : }
7612 : }
7613 : }
7614 : }
7615 :
7616 : // Suppress mouse event if it's being targeted at an element inside
7617 : // a document which needs events suppressed
7618 16 : if (aEvent->mClass == eMouseEventClass &&
7619 6 : frame->PresContext()->Document()->EventHandlingSuppressed()) {
7620 0 : if (aEvent->mMessage == eMouseDown) {
7621 0 : mNoDelayedMouseEvents = true;
7622 0 : } else if (!mNoDelayedMouseEvents && (aEvent->mMessage == eMouseUp ||
7623 : // contextmenu is triggered after right mouseup on Windows and right
7624 : // mousedown on other platforms.
7625 0 : aEvent->mMessage == eContextMenu)) {
7626 0 : DelayedEvent* event = new DelayedMouseEvent(aEvent->AsMouseEvent());
7627 0 : if (!mDelayedEvents.AppendElement(event)) {
7628 0 : delete event;
7629 : }
7630 : }
7631 0 : return NS_OK;
7632 : }
7633 :
7634 10 : if (!frame) {
7635 0 : NS_WARNING("Nothing to handle this event!");
7636 0 : return NS_OK;
7637 : }
7638 :
7639 : PresShell* shell =
7640 10 : static_cast<PresShell*>(frame->PresContext()->PresShell());
7641 10 : switch (aEvent->mMessage) {
7642 : case eTouchMove:
7643 : case eTouchCancel:
7644 : case eTouchEnd: {
7645 : // get the correct shell to dispatch to
7646 0 : WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
7647 0 : for (dom::Touch* touch : touchEvent->mTouches) {
7648 0 : if (!touch) {
7649 0 : break;
7650 : }
7651 :
7652 : RefPtr<dom::Touch> oldTouch =
7653 0 : TouchManager::GetCapturedTouch(touch->Identifier());
7654 0 : if (!oldTouch) {
7655 0 : break;
7656 : }
7657 :
7658 : nsCOMPtr<nsIContent> content =
7659 0 : do_QueryInterface(oldTouch->GetTarget());
7660 0 : if (!content) {
7661 0 : break;
7662 : }
7663 :
7664 0 : nsIFrame* contentFrame = content->GetPrimaryFrame();
7665 0 : if (!contentFrame) {
7666 0 : break;
7667 : }
7668 :
7669 : shell = static_cast<PresShell*>(
7670 0 : contentFrame->PresContext()->PresShell());
7671 0 : if (shell) {
7672 0 : break;
7673 : }
7674 : }
7675 0 : break;
7676 : }
7677 : default:
7678 10 : break;
7679 : }
7680 :
7681 : // Check if we have an active EventStateManager which isn't the
7682 : // EventStateManager of the current PresContext.
7683 : // If that is the case, and mouse is over some ancestor document,
7684 : // forward event handling to the active document.
7685 : // This way content can get mouse events even when
7686 : // mouse is over the chrome or outside the window.
7687 : //
7688 : // Note, currently for backwards compatibility we don't forward mouse events
7689 : // to the active document when mouse is over some subdocument.
7690 10 : if (EventStateManager* activeESM = EventStateManager::GetActiveEventStateManager()) {
7691 0 : if (aEvent->mClass == ePointerEventClass || aEvent->HasMouseEventMessage()) {
7692 0 : if (activeESM != shell->GetPresContext()->EventStateManager()) {
7693 0 : if (nsPresContext* activeContext = activeESM->GetPresContext()) {
7694 0 : if (nsIPresShell* activeShell = activeContext->GetPresShell()) {
7695 0 : if (nsContentUtils::ContentIsCrossDocDescendantOf(activeShell->GetDocument(),
7696 0 : shell->GetDocument())) {
7697 0 : shell = static_cast<PresShell*>(activeShell);
7698 0 : frame = shell->GetRootFrame();
7699 : }
7700 : }
7701 : }
7702 : }
7703 : }
7704 : }
7705 :
7706 : // Before HandlePositionedEvent we should save mPointerEventTarget in some
7707 : // cases
7708 20 : AutoWeakFrame weakFrame;
7709 14 : if (sPointerEventEnabled && aTargetContent &&
7710 4 : ePointerEventClass == aEvent->mClass) {
7711 4 : weakFrame = frame;
7712 4 : shell->mPointerEventTarget = frame->GetContent();
7713 4 : MOZ_ASSERT(!frame->GetContent() ||
7714 : shell->GetDocument() == frame->GetContent()->OwnerDoc());
7715 : }
7716 :
7717 : // Prevent deletion until we're done with event handling (bug 336582) and
7718 : // swap mPointerEventTarget to *aTargetContent
7719 20 : nsCOMPtr<nsIPresShell> kungFuDeathGrip(shell);
7720 : nsresult rv;
7721 10 : if (shell != this) {
7722 : // Handle the event in the correct shell.
7723 : // We pass the subshell's root frame as the frame to start from. This is
7724 : // the only correct alternative; if the event was captured then it
7725 : // must have been captured by us or some ancestor shell and we
7726 : // now ask the subshell to dispatch it normally.
7727 0 : rv = shell->HandlePositionedEvent(frame, aEvent, aEventStatus);
7728 : } else {
7729 10 : rv = HandlePositionedEvent(frame, aEvent, aEventStatus);
7730 : }
7731 :
7732 : // After HandlePositionedEvent we should reestablish
7733 : // content (which still live in tree) in some cases
7734 14 : if (sPointerEventEnabled && aTargetContent &&
7735 4 : ePointerEventClass == aEvent->mClass) {
7736 4 : if (!weakFrame.IsAlive()) {
7737 0 : shell->mPointerEventTarget.swap(*aTargetContent);
7738 : }
7739 : }
7740 :
7741 10 : return rv;
7742 : }
7743 :
7744 0 : nsresult rv = NS_OK;
7745 :
7746 0 : if (frame) {
7747 0 : PushCurrentEventInfo(nullptr, nullptr);
7748 :
7749 : // key and IME related events go to the focused frame in this DOM window.
7750 0 : if (aEvent->IsTargetedAtFocusedContent()) {
7751 0 : mCurrentEventContent = nullptr;
7752 :
7753 0 : nsCOMPtr<nsPIDOMWindowOuter> window = mDocument->GetWindow();
7754 0 : nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
7755 : nsCOMPtr<nsIContent> eventTarget =
7756 : nsFocusManager::GetFocusedDescendant(window, false,
7757 0 : getter_AddRefs(focusedWindow));
7758 :
7759 : // otherwise, if there is no focused content or the focused content has
7760 : // no frame, just use the root content. This ensures that key events
7761 : // still get sent to the window properly if nothing is focused or if a
7762 : // frame goes away while it is focused.
7763 0 : if (!eventTarget || !eventTarget->GetPrimaryFrame()) {
7764 0 : nsCOMPtr<nsIDOMHTMLDocument> htmlDoc = do_QueryInterface(mDocument);
7765 0 : if (htmlDoc) {
7766 0 : nsCOMPtr<nsIDOMHTMLElement> body;
7767 0 : htmlDoc->GetBody(getter_AddRefs(body));
7768 0 : eventTarget = do_QueryInterface(body);
7769 0 : if (!eventTarget) {
7770 0 : eventTarget = mDocument->GetRootElement();
7771 : }
7772 : } else {
7773 0 : eventTarget = mDocument->GetRootElement();
7774 : }
7775 : }
7776 :
7777 0 : if (aEvent->mMessage == eKeyDown) {
7778 0 : NS_IF_RELEASE(gKeyDownTarget);
7779 0 : NS_IF_ADDREF(gKeyDownTarget = eventTarget);
7780 : }
7781 0 : else if ((aEvent->mMessage == eKeyPress ||
7782 0 : aEvent->mMessage == eKeyUp) &&
7783 0 : gKeyDownTarget) {
7784 : // If a different element is now focused for the keypress/keyup event
7785 : // than what was focused during the keydown event, check if the new
7786 : // focused element is not in a chrome document any more, and if so,
7787 : // retarget the event back at the keydown target. This prevents a
7788 : // content area from grabbing the focus from chrome in-between key
7789 : // events.
7790 0 : if (eventTarget) {
7791 0 : bool keyDownIsChrome = nsContentUtils::IsChromeDoc(gKeyDownTarget->GetComposedDoc());
7792 0 : if (keyDownIsChrome != nsContentUtils::IsChromeDoc(eventTarget->GetComposedDoc()) ||
7793 0 : (keyDownIsChrome && TabParent::GetFrom(eventTarget))) {
7794 0 : eventTarget = gKeyDownTarget;
7795 : }
7796 : }
7797 :
7798 0 : if (aEvent->mMessage == eKeyUp) {
7799 0 : NS_RELEASE(gKeyDownTarget);
7800 : }
7801 : }
7802 :
7803 0 : mCurrentEventFrame = nullptr;
7804 0 : nsIDocument* targetDoc = eventTarget ? eventTarget->OwnerDoc() : nullptr;
7805 0 : if (targetDoc && targetDoc != mDocument) {
7806 0 : PopCurrentEventInfo();
7807 0 : nsCOMPtr<nsIPresShell> shell = targetDoc->GetShell();
7808 0 : if (shell) {
7809 0 : rv = static_cast<PresShell*>(shell.get())->
7810 0 : HandleRetargetedEvent(aEvent, aEventStatus, eventTarget);
7811 : }
7812 0 : return rv;
7813 : } else {
7814 0 : mCurrentEventContent = eventTarget;
7815 : }
7816 :
7817 0 : if (!GetCurrentEventContent() || !GetCurrentEventFrame() ||
7818 0 : InZombieDocument(mCurrentEventContent)) {
7819 0 : rv = RetargetEventToParent(aEvent, aEventStatus);
7820 0 : PopCurrentEventInfo();
7821 0 : return rv;
7822 : }
7823 : } else {
7824 0 : mCurrentEventFrame = frame;
7825 : }
7826 0 : if (GetCurrentEventFrame()) {
7827 0 : rv = HandleEventInternal(aEvent, aEventStatus, true);
7828 : }
7829 :
7830 : #ifdef DEBUG
7831 0 : ShowEventTargetDebug();
7832 : #endif
7833 0 : PopCurrentEventInfo();
7834 : } else {
7835 : // Activation events need to be dispatched even if no frame was found, since
7836 : // we don't want the focus to be out of sync.
7837 :
7838 0 : if (!NS_EVENT_NEEDS_FRAME(aEvent)) {
7839 0 : mCurrentEventFrame = nullptr;
7840 0 : return HandleEventInternal(aEvent, aEventStatus, true);
7841 : }
7842 0 : else if (aEvent->HasKeyEventMessage()) {
7843 : // Keypress events in new blank tabs should not be completely thrown away.
7844 : // Retarget them -- the parent chrome shell might make use of them.
7845 0 : return RetargetEventToParent(aEvent, aEventStatus);
7846 : }
7847 : }
7848 :
7849 0 : return rv;
7850 : }
7851 :
7852 : nsIDocument*
7853 29 : PresShell::GetPrimaryContentDocument()
7854 : {
7855 29 : nsPresContext* context = GetPresContext();
7856 29 : if (!context || !context->IsRoot()) {
7857 0 : return nullptr;
7858 : }
7859 :
7860 58 : nsCOMPtr<nsIDocShellTreeItem> shellAsTreeItem = context->GetDocShell();
7861 29 : if (!shellAsTreeItem) {
7862 0 : return nullptr;
7863 : }
7864 :
7865 58 : nsCOMPtr<nsIDocShellTreeOwner> owner;
7866 29 : shellAsTreeItem->GetTreeOwner(getter_AddRefs(owner));
7867 29 : if (!owner) {
7868 0 : return nullptr;
7869 : }
7870 :
7871 : // now get the primary content shell (active tab)
7872 58 : nsCOMPtr<nsIDocShellTreeItem> item;
7873 29 : owner->GetPrimaryContentShell(getter_AddRefs(item));
7874 58 : nsCOMPtr<nsIDocShell> childDocShell = do_QueryInterface(item);
7875 29 : if (!childDocShell) {
7876 25 : return nullptr;
7877 : }
7878 :
7879 4 : return childDocShell->GetDocument();
7880 : }
7881 :
7882 : #ifdef DEBUG
7883 : void
7884 10 : PresShell::ShowEventTargetDebug()
7885 : {
7886 10 : if (nsFrame::GetShowEventTargetFrameBorder() &&
7887 0 : GetCurrentEventFrame()) {
7888 0 : if (mDrawEventTargetFrame) {
7889 0 : mDrawEventTargetFrame->InvalidateFrame();
7890 : }
7891 :
7892 0 : mDrawEventTargetFrame = mCurrentEventFrame;
7893 0 : mDrawEventTargetFrame->InvalidateFrame();
7894 : }
7895 10 : }
7896 : #endif
7897 :
7898 : nsresult
7899 10 : PresShell::HandlePositionedEvent(nsIFrame* aTargetFrame,
7900 : WidgetGUIEvent* aEvent,
7901 : nsEventStatus* aEventStatus)
7902 : {
7903 10 : nsresult rv = NS_OK;
7904 :
7905 10 : PushCurrentEventInfo(nullptr, nullptr);
7906 :
7907 10 : mCurrentEventFrame = aTargetFrame;
7908 :
7909 10 : if (mCurrentEventFrame) {
7910 20 : nsCOMPtr<nsIContent> targetElement;
7911 20 : mCurrentEventFrame->GetContentForEvent(aEvent,
7912 20 : getter_AddRefs(targetElement));
7913 :
7914 : // If there is no content for this frame, target it anyway. Some
7915 : // frames can be targeted but do not have content, particularly
7916 : // windows with scrolling off.
7917 10 : if (targetElement) {
7918 : // Bug 103055, bug 185889: mouse events apply to *elements*, not all
7919 : // nodes. Thus we get the nearest element parent here.
7920 : // XXX we leave the frame the same even if we find an element
7921 : // parent, so that the text frame will receive the event (selection
7922 : // and friends are the ones who care about that anyway)
7923 : //
7924 : // We use weak pointers because during this tight loop, the node
7925 : // will *not* go away. And this happens on every mousemove.
7926 9 : while (targetElement && !targetElement->IsElement()) {
7927 0 : targetElement = targetElement->GetFlattenedTreeParent();
7928 : }
7929 :
7930 : // If we found an element, target it. Otherwise, target *nothing*.
7931 9 : if (!targetElement) {
7932 0 : mCurrentEventContent = nullptr;
7933 0 : mCurrentEventFrame = nullptr;
7934 9 : } else if (targetElement != mCurrentEventContent) {
7935 9 : mCurrentEventContent = targetElement;
7936 : }
7937 : }
7938 : }
7939 :
7940 10 : if (GetCurrentEventFrame()) {
7941 10 : rv = HandleEventInternal(aEvent, aEventStatus, true);
7942 : }
7943 :
7944 : #ifdef DEBUG
7945 10 : ShowEventTargetDebug();
7946 : #endif
7947 10 : PopCurrentEventInfo();
7948 10 : return rv;
7949 : }
7950 :
7951 : nsresult
7952 0 : PresShell::HandleEventWithTarget(WidgetEvent* aEvent, nsIFrame* aFrame,
7953 : nsIContent* aContent, nsEventStatus* aStatus)
7954 : {
7955 : #if DEBUG
7956 0 : MOZ_ASSERT(!aFrame || aFrame->PresContext()->GetPresShell() == this,
7957 : "wrong shell");
7958 0 : if (aContent) {
7959 0 : nsIDocument* doc = aContent->GetComposedDoc();
7960 0 : NS_ASSERTION(doc, "event for content that isn't in a document");
7961 : // NOTE: We don't require that the document still have a PresShell.
7962 : // See bug 1375940.
7963 : }
7964 : #endif
7965 0 : NS_ENSURE_STATE(!aContent || aContent->GetComposedDoc() == mDocument);
7966 :
7967 0 : PushCurrentEventInfo(aFrame, aContent);
7968 0 : nsresult rv = HandleEventInternal(aEvent, aStatus, false);
7969 0 : PopCurrentEventInfo();
7970 0 : return rv;
7971 : }
7972 :
7973 : nsresult
7974 10 : PresShell::HandleEventInternal(WidgetEvent* aEvent,
7975 : nsEventStatus* aStatus,
7976 : bool aIsHandlingNativeEvent)
7977 : {
7978 20 : RefPtr<EventStateManager> manager = mPresContext->EventStateManager();
7979 10 : nsresult rv = NS_OK;
7980 :
7981 10 : if (!NS_EVENT_NEEDS_FRAME(aEvent) || GetCurrentEventFrame() || GetCurrentEventContent()) {
7982 10 : bool touchIsNew = false;
7983 10 : bool isHandlingUserInput = false;
7984 :
7985 10 : if (mCurrentEventContent && aEvent->IsTargetedAtFocusedWindow()) {
7986 0 : nsFocusManager* fm = nsFocusManager::GetFocusManager();
7987 0 : if (fm) {
7988 0 : fm->FlushBeforeEventHandlingIfNeeded(mCurrentEventContent);
7989 : }
7990 : }
7991 :
7992 : // XXX How about IME events and input events for plugins?
7993 10 : if (aEvent->IsTrusted()) {
7994 10 : switch (aEvent->mMessage) {
7995 : case eKeyPress:
7996 : case eKeyDown:
7997 : case eKeyUp: {
7998 0 : nsIDocument* doc = GetCurrentEventContent() ?
7999 0 : mCurrentEventContent->OwnerDoc() : nullptr;
8000 0 : auto keyCode = aEvent->AsKeyboardEvent()->mKeyCode;
8001 0 : if (keyCode == NS_VK_ESCAPE) {
8002 0 : nsIDocument* root = nsContentUtils::GetRootDocument(doc);
8003 0 : if (root && root->GetFullscreenElement()) {
8004 : // Prevent default action on ESC key press when exiting
8005 : // DOM fullscreen mode. This prevents the browser ESC key
8006 : // handler from stopping all loads in the document, which
8007 : // would cause <video> loads to stop.
8008 : // XXX We need to claim the Escape key event which will be
8009 : // dispatched only into chrome is already consumed by
8010 : // content because we need to prevent its default here
8011 : // for some reasons (not sure) but we need to detect
8012 : // if a chrome event handler will call PreventDefault()
8013 : // again and check it later.
8014 0 : aEvent->PreventDefaultBeforeDispatch();
8015 0 : aEvent->mFlags.mOnlyChromeDispatch = true;
8016 :
8017 : // The event listeners in chrome can prevent this ESC behavior by
8018 : // calling prevent default on the preceding keydown/press events.
8019 0 : if (!mIsLastChromeOnlyEscapeKeyConsumed &&
8020 0 : aEvent->mMessage == eKeyUp) {
8021 : // ESC key released while in DOM fullscreen mode.
8022 : // Fully exit all browser windows and documents from
8023 : // fullscreen mode.
8024 0 : nsIDocument::AsyncExitFullscreen(nullptr);
8025 : }
8026 : }
8027 : nsCOMPtr<nsIDocument> pointerLockedDoc =
8028 0 : do_QueryReferent(EventStateManager::sPointerLockedDoc);
8029 0 : if (!mIsLastChromeOnlyEscapeKeyConsumed && pointerLockedDoc) {
8030 : // XXX See above comment to understand the reason why this needs
8031 : // to claim that the Escape key event is consumed by content
8032 : // even though it will be dispatched only into chrome.
8033 0 : aEvent->PreventDefaultBeforeDispatch();
8034 0 : aEvent->mFlags.mOnlyChromeDispatch = true;
8035 0 : if (aEvent->mMessage == eKeyUp) {
8036 0 : nsIDocument::UnlockPointer();
8037 : }
8038 : }
8039 : }
8040 0 : if (keyCode != NS_VK_ESCAPE && keyCode != NS_VK_SHIFT &&
8041 0 : keyCode != NS_VK_CONTROL && keyCode != NS_VK_ALT &&
8042 0 : keyCode != NS_VK_WIN && keyCode != NS_VK_META) {
8043 : // Allow keys other than ESC and modifiers be marked as a
8044 : // valid user input for triggering popup, fullscreen, and
8045 : // pointer lock.
8046 0 : isHandlingUserInput = true;
8047 0 : mPresContext->RecordInteractionTime(
8048 : nsPresContext::InteractionType::eKeyInteraction,
8049 0 : aEvent->mTimeStamp);
8050 : }
8051 :
8052 0 : Telemetry::AccumulateTimeDelta(Telemetry::INPUT_EVENT_QUEUED_KEYBOARD_MS, aEvent->mTimeStamp);
8053 0 : break;
8054 : }
8055 : case eMouseDown:
8056 : case eMouseUp:
8057 0 : Telemetry::AccumulateTimeDelta(Telemetry::INPUT_EVENT_QUEUED_CLICK_MS, aEvent->mTimeStamp);
8058 : MOZ_FALLTHROUGH;
8059 : case ePointerDown:
8060 : case ePointerUp:
8061 0 : isHandlingUserInput = true;
8062 0 : mPresContext->RecordInteractionTime(
8063 : nsPresContext::InteractionType::eClickInteraction,
8064 0 : aEvent->mTimeStamp);
8065 0 : break;
8066 :
8067 : case eMouseMove:
8068 4 : if (aEvent->mFlags.mHandledByAPZ) {
8069 4 : Telemetry::AccumulateTimeDelta(Telemetry::INPUT_EVENT_QUEUED_APZ_MOUSE_MOVE_MS, aEvent->mTimeStamp);
8070 : }
8071 4 : break;
8072 :
8073 : case eDrop: {
8074 0 : nsCOMPtr<nsIDragSession> session = nsContentUtils::GetDragSession();
8075 0 : if (session) {
8076 0 : bool onlyChromeDrop = false;
8077 0 : session->GetOnlyChromeDrop(&onlyChromeDrop);
8078 0 : if (onlyChromeDrop) {
8079 0 : aEvent->mFlags.mOnlyChromeDispatch = true;
8080 : }
8081 : }
8082 0 : break;
8083 : }
8084 :
8085 : case eWheel:
8086 0 : if (aEvent->mFlags.mHandledByAPZ) {
8087 0 : Telemetry::AccumulateTimeDelta(Telemetry::INPUT_EVENT_QUEUED_APZ_WHEEL_MS, aEvent->mTimeStamp);
8088 : }
8089 0 : break;
8090 :
8091 : case eTouchMove:
8092 0 : if (aEvent->mFlags.mHandledByAPZ) {
8093 0 : Telemetry::AccumulateTimeDelta(Telemetry::INPUT_EVENT_QUEUED_APZ_TOUCH_MOVE_MS, aEvent->mTimeStamp);
8094 : }
8095 0 : break;
8096 :
8097 : default:
8098 6 : break;
8099 : }
8100 :
8101 10 : if (!mTouchManager.PreHandleEvent(aEvent, aStatus,
8102 : touchIsNew, isHandlingUserInput,
8103 : mCurrentEventContent)) {
8104 0 : return NS_OK;
8105 : }
8106 : }
8107 :
8108 10 : if (aEvent->mMessage == eContextMenu) {
8109 0 : WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
8110 0 : if (mouseEvent->IsContextMenuKeyEvent() &&
8111 0 : !AdjustContextMenuKeyEvent(mouseEvent)) {
8112 0 : return NS_OK;
8113 : }
8114 0 : if (mouseEvent->IsShift()) {
8115 0 : aEvent->mFlags.mOnlyChromeDispatch = true;
8116 0 : aEvent->mFlags.mRetargetToNonNativeAnonymous = true;
8117 : }
8118 : }
8119 :
8120 : AutoHandlingUserInputStatePusher userInpStatePusher(isHandlingUserInput,
8121 20 : aEvent, mDocument);
8122 :
8123 10 : if (aEvent->IsTrusted() && aEvent->mMessage == eMouseMove) {
8124 4 : nsIPresShell::AllowMouseCapture(
8125 8 : EventStateManager::GetActiveEventStateManager() == manager);
8126 :
8127 4 : mPresContext->RecordInteractionTime(
8128 : nsPresContext::InteractionType::eMouseMoveInteraction,
8129 4 : aEvent->mTimeStamp);
8130 : }
8131 :
8132 : nsAutoPopupStatePusher popupStatePusher(
8133 20 : Event::GetEventPopupControlState(aEvent));
8134 :
8135 : // FIXME. If the event was reused, we need to clear the old target,
8136 : // bug 329430
8137 10 : aEvent->mTarget = nullptr;
8138 :
8139 10 : TimeStamp handlerStartTime = TimeStamp::Now();
8140 :
8141 : // 1. Give event to event manager for pre event state changes and
8142 : // generation of synthetic events.
8143 10 : rv = manager->PreHandleEvent(mPresContext, aEvent, mCurrentEventFrame,
8144 10 : mCurrentEventContent, aStatus);
8145 :
8146 : // 2. Give event to the DOM for third party and JS use.
8147 10 : if (NS_SUCCEEDED(rv)) {
8148 : bool wasHandlingKeyBoardEvent =
8149 10 : nsContentUtils::IsHandlingKeyBoardEvent();
8150 10 : if (aEvent->mClass == eKeyboardEventClass) {
8151 0 : nsContentUtils::SetIsHandlingKeyBoardEvent(true);
8152 : }
8153 10 : if (aEvent->IsAllowedToDispatchDOMEvent()) {
8154 10 : MOZ_ASSERT(nsContentUtils::IsSafeToRunScript(),
8155 : "Somebody changed aEvent to cause a DOM event!");
8156 20 : nsPresShellEventCB eventCB(this);
8157 10 : if (nsIFrame* target = GetCurrentEventFrame()) {
8158 10 : if (target->OnlySystemGroupDispatch(aEvent->mMessage)) {
8159 0 : aEvent->StopPropagation();
8160 : }
8161 : }
8162 10 : if (aEvent->mClass == eTouchEventClass) {
8163 0 : DispatchTouchEventToDOM(aEvent, aStatus, &eventCB, touchIsNew);
8164 : } else {
8165 10 : DispatchEventToDOM(aEvent, aStatus, &eventCB);
8166 : }
8167 : }
8168 :
8169 10 : nsContentUtils::SetIsHandlingKeyBoardEvent(wasHandlingKeyBoardEvent);
8170 :
8171 : // 3. Give event to event manager for post event state changes and
8172 : // generation of synthetic events.
8173 10 : if (!mIsDestroying && NS_SUCCEEDED(rv)) {
8174 10 : rv = manager->PostHandleEvent(mPresContext, aEvent,
8175 10 : GetCurrentEventFrame(), aStatus);
8176 : }
8177 : }
8178 :
8179 10 : if (!mIsDestroying && aIsHandlingNativeEvent) {
8180 : // Ensure that notifications to IME should be sent before getting next
8181 : // native event from the event queue.
8182 : // XXX Should we check the event message or event class instead of
8183 : // using aIsHandlingNativeEvent?
8184 10 : manager->TryToFlushPendingNotificationsToIME();
8185 : }
8186 :
8187 10 : switch (aEvent->mMessage) {
8188 : case eKeyPress:
8189 : case eKeyDown:
8190 : case eKeyUp: {
8191 0 : if (aEvent->AsKeyboardEvent()->mKeyCode == NS_VK_ESCAPE) {
8192 0 : if (aEvent->mMessage == eKeyUp) {
8193 : // Reset this flag after key up is handled.
8194 0 : mIsLastChromeOnlyEscapeKeyConsumed = false;
8195 : } else {
8196 0 : if (aEvent->mFlags.mOnlyChromeDispatch &&
8197 0 : aEvent->mFlags.mDefaultPreventedByChrome) {
8198 0 : mIsLastChromeOnlyEscapeKeyConsumed = true;
8199 : }
8200 : }
8201 : }
8202 0 : if (aEvent->mMessage == eKeyDown) {
8203 0 : mIsLastKeyDownCanceled = aEvent->mFlags.mDefaultPrevented;
8204 : }
8205 0 : break;
8206 : }
8207 : case eMouseUp:
8208 : // reset the capturing content now that the mouse button is up
8209 0 : SetCapturingContent(nullptr, 0);
8210 0 : break;
8211 : case eMouseMove:
8212 4 : nsIPresShell::AllowMouseCapture(false);
8213 4 : break;
8214 : default:
8215 6 : break;
8216 : }
8217 :
8218 10 : if (aEvent->IsTrusted() && aEvent->mTimeStamp > mLastOSWake) {
8219 10 : switch (aEvent->mMessage) {
8220 : case eKeyPress:
8221 : case eKeyDown:
8222 : case eKeyUp:
8223 0 : Telemetry::AccumulateTimeDelta(Telemetry::INPUT_EVENT_HANDLED_KEYBOARD_MS, handlerStartTime);
8224 0 : break;
8225 : case eMouseDown:
8226 0 : Telemetry::AccumulateTimeDelta(Telemetry::INPUT_EVENT_HANDLED_MOUSE_DOWN_MS, handlerStartTime);
8227 0 : break;
8228 : case eMouseUp:
8229 0 : Telemetry::AccumulateTimeDelta(Telemetry::INPUT_EVENT_HANDLED_MOUSE_UP_MS, handlerStartTime);
8230 0 : break;
8231 : case eMouseMove:
8232 4 : if (aEvent->mFlags.mHandledByAPZ) {
8233 4 : Telemetry::AccumulateTimeDelta(Telemetry::INPUT_EVENT_HANDLED_APZ_MOUSE_MOVE_MS, handlerStartTime);
8234 : }
8235 4 : break;
8236 : case eWheel:
8237 0 : if (aEvent->mFlags.mHandledByAPZ) {
8238 0 : Telemetry::AccumulateTimeDelta(Telemetry::INPUT_EVENT_HANDLED_APZ_WHEEL_MS, handlerStartTime);
8239 : }
8240 0 : break;
8241 : case eTouchMove:
8242 0 : if (aEvent->mFlags.mHandledByAPZ) {
8243 0 : Telemetry::AccumulateTimeDelta(Telemetry::INPUT_EVENT_HANDLED_APZ_TOUCH_MOVE_MS, handlerStartTime);
8244 : }
8245 0 : break;
8246 : default:
8247 6 : break;
8248 : }
8249 : }
8250 : }
8251 :
8252 30 : if (Telemetry::CanRecordBase() &&
8253 20 : !aEvent->mTimeStamp.IsNull() &&
8254 30 : aEvent->mTimeStamp > mLastOSWake &&
8255 10 : aEvent->AsInputEvent()) {
8256 10 : TimeStamp now = TimeStamp::Now();
8257 10 : double millis = (now - aEvent->mTimeStamp).ToMilliseconds();
8258 10 : Telemetry::Accumulate(Telemetry::INPUT_EVENT_RESPONSE_MS, millis);
8259 10 : if (mDocument && mDocument->GetReadyStateEnum() != nsIDocument::READYSTATE_COMPLETE) {
8260 0 : Telemetry::Accumulate(Telemetry::LOAD_INPUT_EVENT_RESPONSE_MS, millis);
8261 : }
8262 :
8263 10 : if (!sLastInputProcessed || sLastInputProcessed < aEvent->mTimeStamp) {
8264 3 : if (sLastInputProcessed) {
8265 : // This input event was created after we handled the last one.
8266 : // Accumulate the previous events' coalesced duration.
8267 2 : double lastMillis = (sLastInputProcessed - sLastInputCreated).ToMilliseconds();
8268 2 : Telemetry::Accumulate(Telemetry::INPUT_EVENT_RESPONSE_COALESCED_MS,
8269 2 : lastMillis);
8270 : }
8271 3 : sLastInputCreated = aEvent->mTimeStamp;
8272 7 : } else if (aEvent->mTimeStamp < sLastInputCreated) {
8273 : // This event was created before the last input. May be processing out
8274 : // of order, so coalesce backwards, too.
8275 0 : sLastInputCreated = aEvent->mTimeStamp;
8276 : }
8277 10 : sLastInputProcessed = now;
8278 : }
8279 :
8280 10 : return rv;
8281 : }
8282 :
8283 : /* static */ void
8284 0 : nsIPresShell::DispatchGotOrLostPointerCaptureEvent(
8285 : bool aIsGotCapture,
8286 : const WidgetPointerEvent* aPointerEvent,
8287 : nsIContent* aCaptureTarget)
8288 : {
8289 0 : nsIDocument* targetDoc = aCaptureTarget->OwnerDoc();
8290 0 : nsCOMPtr<nsIPresShell> shell = targetDoc->GetShell();
8291 0 : NS_ENSURE_TRUE_VOID(shell);
8292 :
8293 0 : if (!aIsGotCapture && !aCaptureTarget->IsInUncomposedDoc()) {
8294 : // If the capturing element was removed from the DOM tree, fire
8295 : // ePointerLostCapture at the document.
8296 0 : PointerEventInit init;
8297 0 : init.mPointerId = aPointerEvent->pointerId;
8298 0 : init.mBubbles = true;
8299 0 : init.mComposed = true;
8300 0 : ConvertPointerTypeToString(aPointerEvent->inputSource, init.mPointerType);
8301 0 : init.mIsPrimary = aPointerEvent->mIsPrimary;
8302 0 : RefPtr<mozilla::dom::PointerEvent> event;
8303 0 : event = PointerEvent::Constructor(aCaptureTarget,
8304 0 : NS_LITERAL_STRING("lostpointercapture"),
8305 0 : init);
8306 : bool dummy;
8307 0 : targetDoc->DispatchEvent(event->InternalDOMEvent(), &dummy);
8308 0 : return;
8309 : }
8310 0 : nsEventStatus status = nsEventStatus_eIgnore;
8311 0 : WidgetPointerEvent localEvent(aPointerEvent->IsTrusted(),
8312 : aIsGotCapture ? ePointerGotCapture :
8313 : ePointerLostCapture,
8314 0 : aPointerEvent->mWidget);
8315 0 : localEvent.AssignPointerEventData(*aPointerEvent, true);
8316 0 : nsresult rv = shell->HandleEventWithTarget(
8317 : &localEvent,
8318 : aCaptureTarget->GetPrimaryFrame(),
8319 0 : aCaptureTarget, &status);
8320 0 : NS_ENSURE_SUCCESS_VOID(rv);
8321 : }
8322 :
8323 : nsresult
8324 10 : PresShell::DispatchEventToDOM(WidgetEvent* aEvent,
8325 : nsEventStatus* aStatus,
8326 : nsPresShellEventCB* aEventCB)
8327 : {
8328 10 : nsresult rv = NS_OK;
8329 20 : nsCOMPtr<nsINode> eventTarget = mCurrentEventContent.get();
8330 10 : nsPresShellEventCB* eventCBPtr = aEventCB;
8331 10 : if (!eventTarget) {
8332 2 : nsCOMPtr<nsIContent> targetContent;
8333 1 : if (mCurrentEventFrame) {
8334 2 : rv = mCurrentEventFrame->
8335 2 : GetContentForEvent(aEvent, getter_AddRefs(targetContent));
8336 : }
8337 1 : if (NS_SUCCEEDED(rv) && targetContent) {
8338 0 : eventTarget = do_QueryInterface(targetContent);
8339 1 : } else if (mDocument) {
8340 1 : eventTarget = do_QueryInterface(mDocument);
8341 : // If we don't have any content, the callback wouldn't probably
8342 : // do nothing.
8343 1 : eventCBPtr = nullptr;
8344 : }
8345 : }
8346 10 : if (eventTarget) {
8347 10 : if (aEvent->mClass == eCompositionEventClass) {
8348 0 : IMEStateManager::DispatchCompositionEvent(eventTarget, mPresContext,
8349 0 : aEvent->AsCompositionEvent(),
8350 0 : aStatus, eventCBPtr);
8351 : } else {
8352 10 : EventDispatcher::Dispatch(eventTarget, mPresContext,
8353 10 : aEvent, nullptr, aStatus, eventCBPtr);
8354 : }
8355 : }
8356 20 : return rv;
8357 : }
8358 :
8359 : void
8360 0 : PresShell::DispatchTouchEventToDOM(WidgetEvent* aEvent,
8361 : nsEventStatus* aStatus,
8362 : nsPresShellEventCB* aEventCB,
8363 : bool aTouchIsNew)
8364 : {
8365 : // calling preventDefault on touchstart or the first touchmove for a
8366 : // point prevents mouse events. calling it on the touchend should
8367 : // prevent click dispatching.
8368 0 : bool canPrevent = (aEvent->mMessage == eTouchStart) ||
8369 0 : (aEvent->mMessage == eTouchMove && aTouchIsNew) ||
8370 0 : (aEvent->mMessage == eTouchEnd);
8371 0 : bool preventDefault = false;
8372 0 : nsEventStatus tmpStatus = nsEventStatus_eIgnore;
8373 0 : WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
8374 :
8375 : // loop over all touches and dispatch events on any that have changed
8376 0 : for (dom::Touch* touch : touchEvent->mTouches) {
8377 0 : if (!touch || !touch->mChanged) {
8378 0 : continue;
8379 : }
8380 :
8381 0 : nsCOMPtr<EventTarget> targetPtr = touch->mTarget;
8382 0 : nsCOMPtr<nsIContent> content = do_QueryInterface(targetPtr);
8383 0 : if (!content) {
8384 0 : continue;
8385 : }
8386 :
8387 0 : nsIDocument* doc = content->OwnerDoc();
8388 0 : nsIContent* capturingContent = GetCapturingContent();
8389 0 : if (capturingContent) {
8390 0 : if (capturingContent->OwnerDoc() != doc) {
8391 : // Wrong document, don't dispatch anything.
8392 0 : continue;
8393 : }
8394 0 : content = capturingContent;
8395 : }
8396 : // copy the event
8397 0 : WidgetTouchEvent newEvent(touchEvent->IsTrusted(),
8398 0 : touchEvent->mMessage, touchEvent->mWidget);
8399 0 : newEvent.AssignTouchEventData(*touchEvent, false);
8400 0 : newEvent.mTarget = targetPtr;
8401 :
8402 0 : RefPtr<PresShell> contentPresShell;
8403 0 : if (doc == mDocument) {
8404 0 : contentPresShell = static_cast<PresShell*>(doc->GetShell());
8405 0 : if (contentPresShell) {
8406 : //XXXsmaug huge hack. Pushing possibly capturing content,
8407 : // even though event target is something else.
8408 0 : contentPresShell->PushCurrentEventInfo(
8409 0 : content->GetPrimaryFrame(), content);
8410 : }
8411 : }
8412 :
8413 0 : nsIPresShell *presShell = doc->GetShell();
8414 0 : if (!presShell) {
8415 0 : continue;
8416 : }
8417 :
8418 0 : nsPresContext *context = presShell->GetPresContext();
8419 :
8420 0 : tmpStatus = nsEventStatus_eIgnore;
8421 : EventDispatcher::Dispatch(targetPtr, context,
8422 0 : &newEvent, nullptr, &tmpStatus, aEventCB);
8423 0 : if (nsEventStatus_eConsumeNoDefault == tmpStatus ||
8424 0 : newEvent.mFlags.mMultipleActionsPrevented) {
8425 0 : preventDefault = true;
8426 : }
8427 :
8428 0 : if (newEvent.mFlags.mMultipleActionsPrevented) {
8429 0 : touchEvent->mFlags.mMultipleActionsPrevented = true;
8430 : }
8431 :
8432 0 : if (contentPresShell) {
8433 0 : contentPresShell->PopCurrentEventInfo();
8434 : }
8435 : }
8436 :
8437 0 : if (preventDefault && canPrevent) {
8438 0 : *aStatus = nsEventStatus_eConsumeNoDefault;
8439 : } else {
8440 0 : *aStatus = nsEventStatus_eIgnore;
8441 : }
8442 0 : }
8443 :
8444 : // Dispatch event to content only (NOT full processing)
8445 : // See also HandleEventWithTarget which does full event processing.
8446 : nsresult
8447 0 : PresShell::HandleDOMEventWithTarget(nsIContent* aTargetContent,
8448 : WidgetEvent* aEvent,
8449 : nsEventStatus* aStatus)
8450 : {
8451 0 : nsresult rv = NS_OK;
8452 :
8453 0 : PushCurrentEventInfo(nullptr, aTargetContent);
8454 :
8455 : // Bug 41013: Check if the event should be dispatched to content.
8456 : // It's possible that we are in the middle of destroying the window
8457 : // and the js context is out of date. This check detects the case
8458 : // that caused a crash in bug 41013, but there may be a better way
8459 : // to handle this situation!
8460 0 : nsCOMPtr<nsISupports> container = mPresContext->GetContainerWeak();
8461 0 : if (container) {
8462 :
8463 : // Dispatch event to content
8464 0 : rv = EventDispatcher::Dispatch(aTargetContent, mPresContext, aEvent,
8465 0 : nullptr, aStatus);
8466 : }
8467 :
8468 0 : PopCurrentEventInfo();
8469 0 : return rv;
8470 : }
8471 :
8472 : // See the method above.
8473 : nsresult
8474 0 : PresShell::HandleDOMEventWithTarget(nsIContent* aTargetContent,
8475 : nsIDOMEvent* aEvent,
8476 : nsEventStatus* aStatus)
8477 : {
8478 0 : nsresult rv = NS_OK;
8479 :
8480 0 : PushCurrentEventInfo(nullptr, aTargetContent);
8481 0 : nsCOMPtr<nsISupports> container = mPresContext->GetContainerWeak();
8482 0 : if (container) {
8483 0 : rv = EventDispatcher::DispatchDOMEvent(aTargetContent, nullptr, aEvent,
8484 0 : mPresContext, aStatus);
8485 : }
8486 :
8487 0 : PopCurrentEventInfo();
8488 0 : return rv;
8489 : }
8490 :
8491 : bool
8492 0 : PresShell::AdjustContextMenuKeyEvent(WidgetMouseEvent* aEvent)
8493 : {
8494 : #ifdef MOZ_XUL
8495 : // if a menu is open, open the context menu relative to the active item on the menu.
8496 0 : nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
8497 0 : if (pm) {
8498 0 : nsIFrame* popupFrame = pm->GetTopPopup(ePopupTypeMenu);
8499 0 : if (popupFrame) {
8500 : nsIFrame* itemFrame =
8501 0 : (static_cast<nsMenuPopupFrame *>(popupFrame))->GetCurrentMenuItem();
8502 0 : if (!itemFrame)
8503 0 : itemFrame = popupFrame;
8504 :
8505 0 : nsCOMPtr<nsIWidget> widget = popupFrame->GetNearestWidget();
8506 0 : aEvent->mWidget = widget;
8507 0 : LayoutDeviceIntPoint widgetPoint = widget->WidgetToScreenOffset();
8508 0 : aEvent->mRefPoint = LayoutDeviceIntPoint::FromAppUnitsToNearest(
8509 0 : itemFrame->GetScreenRectInAppUnits().BottomLeft(),
8510 0 : itemFrame->PresContext()->AppUnitsPerDevPixel()) - widgetPoint;
8511 :
8512 0 : mCurrentEventContent = itemFrame->GetContent();
8513 0 : mCurrentEventFrame = itemFrame;
8514 :
8515 0 : return true;
8516 : }
8517 : }
8518 : #endif
8519 :
8520 : // If we're here because of the key-equiv for showing context menus, we
8521 : // have to twiddle with the NS event to make sure the context menu comes
8522 : // up in the upper left of the relevant content area before we create
8523 : // the DOM event. Since we never call InitMouseEvent() on the event,
8524 : // the client X/Y will be 0,0. We can make use of that if the widget is null.
8525 : // Use the root view manager's widget since it's most likely to have one,
8526 : // and the coordinates returned by GetCurrentItemAndPositionForElement
8527 : // are relative to the widget of the root of the root view manager.
8528 0 : nsRootPresContext* rootPC = mPresContext->GetRootPresContext();
8529 0 : aEvent->mRefPoint = LayoutDeviceIntPoint(0, 0);
8530 0 : if (rootPC) {
8531 : rootPC->PresShell()->GetViewManager()->
8532 0 : GetRootWidget(getter_AddRefs(aEvent->mWidget));
8533 :
8534 0 : if (aEvent->mWidget) {
8535 : // default the refpoint to the topleft of our document
8536 0 : nsPoint offset(0, 0);
8537 0 : nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
8538 0 : if (rootFrame) {
8539 0 : nsView* view = rootFrame->GetClosestView(&offset);
8540 0 : offset += view->GetOffsetToWidget(aEvent->mWidget);
8541 : aEvent->mRefPoint =
8542 0 : LayoutDeviceIntPoint::FromAppUnitsToNearest(offset, mPresContext->AppUnitsPerDevPixel());
8543 : }
8544 : }
8545 : } else {
8546 0 : aEvent->mWidget = nullptr;
8547 : }
8548 :
8549 : // see if we should use the caret position for the popup
8550 0 : LayoutDeviceIntPoint caretPoint;
8551 : // Beware! This may flush notifications via synchronous
8552 : // ScrollSelectionIntoView.
8553 0 : if (PrepareToUseCaretPosition(aEvent->mWidget, caretPoint)) {
8554 : // caret position is good
8555 0 : aEvent->mRefPoint = caretPoint;
8556 0 : return true;
8557 : }
8558 :
8559 : // If we're here because of the key-equiv for showing context menus, we
8560 : // have to reset the event target to the currently focused element. Get it
8561 : // from the focus controller.
8562 0 : nsCOMPtr<nsIDOMElement> currentFocus;
8563 0 : nsIFocusManager* fm = nsFocusManager::GetFocusManager();
8564 0 : if (fm)
8565 0 : fm->GetFocusedElement(getter_AddRefs(currentFocus));
8566 :
8567 : // Reset event coordinates relative to focused frame in view
8568 0 : if (currentFocus) {
8569 0 : nsCOMPtr<nsIContent> currentPointElement;
8570 0 : GetCurrentItemAndPositionForElement(currentFocus,
8571 0 : getter_AddRefs(currentPointElement),
8572 : aEvent->mRefPoint,
8573 0 : aEvent->mWidget);
8574 0 : if (currentPointElement) {
8575 0 : mCurrentEventContent = currentPointElement;
8576 0 : mCurrentEventFrame = nullptr;
8577 0 : GetCurrentEventFrame();
8578 : }
8579 : }
8580 :
8581 0 : return true;
8582 : }
8583 :
8584 : // PresShell::PrepareToUseCaretPosition
8585 : //
8586 : // This checks to see if we should use the caret position for popup context
8587 : // menus. Returns true if the caret position should be used, and the
8588 : // coordinates of that position is returned in aTargetPt. This function
8589 : // will also scroll the window as needed to make the caret visible.
8590 : //
8591 : // The event widget should be the widget that generated the event, and
8592 : // whose coordinate system the resulting event's mRefPoint should be
8593 : // relative to. The returned point is in device pixels realtive to the
8594 : // widget passed in.
8595 : bool
8596 0 : PresShell::PrepareToUseCaretPosition(nsIWidget* aEventWidget,
8597 : LayoutDeviceIntPoint& aTargetPt)
8598 : {
8599 : nsresult rv;
8600 :
8601 : // check caret visibility
8602 0 : RefPtr<nsCaret> caret = GetCaret();
8603 0 : NS_ENSURE_TRUE(caret, false);
8604 :
8605 0 : bool caretVisible = caret->IsVisible();
8606 0 : if (!caretVisible)
8607 0 : return false;
8608 :
8609 : // caret selection, this is a temporary weak reference, so no refcounting is
8610 : // needed
8611 0 : nsISelection* domSelection = caret->GetSelection();
8612 0 : NS_ENSURE_TRUE(domSelection, false);
8613 :
8614 : // since the match could be an anonymous textnode inside a
8615 : // <textarea> or text <input>, we need to get the outer frame
8616 : // note: frames are not refcounted
8617 0 : nsIFrame* frame = nullptr; // may be nullptr
8618 0 : nsCOMPtr<nsIDOMNode> node;
8619 0 : rv = domSelection->GetFocusNode(getter_AddRefs(node));
8620 0 : NS_ENSURE_SUCCESS(rv, false);
8621 0 : NS_ENSURE_TRUE(node, false);
8622 0 : nsCOMPtr<nsIContent> content(do_QueryInterface(node));
8623 0 : if (content) {
8624 0 : nsIContent* nonNative = content->FindFirstNonChromeOnlyAccessContent();
8625 0 : content = nonNative;
8626 : }
8627 :
8628 0 : if (content) {
8629 : // It seems like ScrollSelectionIntoView should be enough, but it's
8630 : // not. The problem is that scrolling the selection into view when it is
8631 : // below the current viewport will align the top line of the frame exactly
8632 : // with the bottom of the window. This is fine, BUT, the popup event causes
8633 : // the control to be re-focused which does this exact call to
8634 : // ScrollContentIntoView, which has a one-pixel disagreement of whether the
8635 : // frame is actually in view. The result is that the frame is aligned with
8636 : // the top of the window, but the menu is still at the bottom.
8637 : //
8638 : // Doing this call first forces the frame to be in view, eliminating the
8639 : // problem. The only difference in the result is that if your cursor is in
8640 : // an edit box below the current view, you'll get the edit box aligned with
8641 : // the top of the window. This is arguably better behavior anyway.
8642 0 : rv = ScrollContentIntoView(content,
8643 : nsIPresShell::ScrollAxis(
8644 : nsIPresShell::SCROLL_MINIMUM,
8645 : nsIPresShell::SCROLL_IF_NOT_VISIBLE),
8646 : nsIPresShell::ScrollAxis(
8647 : nsIPresShell::SCROLL_MINIMUM,
8648 : nsIPresShell::SCROLL_IF_NOT_VISIBLE),
8649 0 : nsIPresShell::SCROLL_OVERFLOW_HIDDEN);
8650 0 : NS_ENSURE_SUCCESS(rv, false);
8651 0 : frame = content->GetPrimaryFrame();
8652 0 : NS_WARNING_ASSERTION(frame, "No frame for focused content?");
8653 : }
8654 :
8655 : // Actually scroll the selection (ie caret) into view. Note that this must
8656 : // be synchronous since we will be checking the caret position on the screen.
8657 : //
8658 : // Be easy about errors, and just don't scroll in those cases. Better to have
8659 : // the correct menu at a weird place than the wrong menu.
8660 : // After ScrollSelectionIntoView(), the pending notifications might be
8661 : // flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
8662 0 : nsCOMPtr<nsISelectionController> selCon;
8663 0 : if (frame)
8664 0 : frame->GetSelectionController(GetPresContext(), getter_AddRefs(selCon));
8665 : else
8666 0 : selCon = static_cast<nsISelectionController *>(this);
8667 0 : if (selCon) {
8668 0 : rv = selCon->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL,
8669 : nsISelectionController::SELECTION_FOCUS_REGION,
8670 0 : nsISelectionController::SCROLL_SYNCHRONOUS);
8671 0 : NS_ENSURE_SUCCESS(rv, false);
8672 : }
8673 :
8674 0 : nsPresContext* presContext = GetPresContext();
8675 :
8676 : // get caret position relative to the closest view
8677 0 : nsRect caretCoords;
8678 0 : nsIFrame* caretFrame = caret->GetGeometry(&caretCoords);
8679 0 : if (!caretFrame)
8680 0 : return false;
8681 0 : nsPoint viewOffset;
8682 0 : nsView* view = caretFrame->GetClosestView(&viewOffset);
8683 0 : if (!view)
8684 0 : return false;
8685 : // and then get the caret coords relative to the event widget
8686 0 : if (aEventWidget) {
8687 0 : viewOffset += view->GetOffsetToWidget(aEventWidget);
8688 : }
8689 0 : caretCoords.MoveBy(viewOffset);
8690 :
8691 : // caret coordinates are in app units, convert to pixels
8692 0 : aTargetPt.x =
8693 0 : presContext->AppUnitsToDevPixels(caretCoords.x + caretCoords.width);
8694 0 : aTargetPt.y =
8695 0 : presContext->AppUnitsToDevPixels(caretCoords.y + caretCoords.height);
8696 :
8697 : // make sure rounding doesn't return a pixel which is outside the caret
8698 : // (e.g. one line lower)
8699 0 : aTargetPt.y -= 1;
8700 :
8701 0 : return true;
8702 : }
8703 :
8704 : void
8705 0 : PresShell::GetCurrentItemAndPositionForElement(nsIDOMElement *aCurrentEl,
8706 : nsIContent** aTargetToUse,
8707 : LayoutDeviceIntPoint& aTargetPt,
8708 : nsIWidget *aRootWidget)
8709 : {
8710 0 : nsCOMPtr<nsIContent> focusedContent(do_QueryInterface(aCurrentEl));
8711 0 : ScrollContentIntoView(focusedContent,
8712 : ScrollAxis(),
8713 : ScrollAxis(),
8714 0 : nsIPresShell::SCROLL_OVERFLOW_HIDDEN);
8715 :
8716 0 : nsPresContext* presContext = GetPresContext();
8717 :
8718 0 : bool istree = false, checkLineHeight = true;
8719 0 : nscoord extraTreeY = 0;
8720 :
8721 : #ifdef MOZ_XUL
8722 : // Set the position to just underneath the current item for multi-select
8723 : // lists or just underneath the selected item for single-select lists. If
8724 : // the element is not a list, or there is no selection, leave the position
8725 : // as is.
8726 0 : nsCOMPtr<nsIDOMXULSelectControlItemElement> item;
8727 : nsCOMPtr<nsIDOMXULMultiSelectControlElement> multiSelect =
8728 0 : do_QueryInterface(aCurrentEl);
8729 0 : if (multiSelect) {
8730 0 : checkLineHeight = false;
8731 :
8732 : int32_t currentIndex;
8733 0 : multiSelect->GetCurrentIndex(¤tIndex);
8734 0 : if (currentIndex >= 0) {
8735 : RefPtr<nsXULElement> xulElement =
8736 0 : nsXULElement::FromContent(focusedContent);
8737 0 : if (xulElement) {
8738 0 : IgnoredErrorResult ignored;
8739 0 : nsCOMPtr<nsIBoxObject> box = xulElement->GetBoxObject(ignored);
8740 0 : nsCOMPtr<nsITreeBoxObject> treeBox(do_QueryInterface(box));
8741 : // Tree view special case (tree items have no frames)
8742 : // Get the focused row and add its coordinates, which are already in pixels
8743 : // XXX Boris, should we create a new interface so that this doesn't
8744 : // need to know about trees? Something like nsINodelessChildCreator which
8745 : // could provide the current focus coordinates?
8746 0 : if (treeBox) {
8747 0 : treeBox->EnsureRowIsVisible(currentIndex);
8748 : int32_t firstVisibleRow, rowHeight;
8749 0 : treeBox->GetFirstVisibleRow(&firstVisibleRow);
8750 0 : treeBox->GetRowHeight(&rowHeight);
8751 :
8752 0 : extraTreeY += presContext->CSSPixelsToAppUnits(
8753 0 : (currentIndex - firstVisibleRow + 1) * rowHeight);
8754 0 : istree = true;
8755 :
8756 0 : nsCOMPtr<nsITreeColumns> cols;
8757 0 : treeBox->GetColumns(getter_AddRefs(cols));
8758 0 : if (cols) {
8759 0 : nsCOMPtr<nsITreeColumn> col;
8760 0 : cols->GetFirstColumn(getter_AddRefs(col));
8761 0 : if (col) {
8762 0 : nsCOMPtr<nsIDOMElement> colElement;
8763 0 : col->GetElement(getter_AddRefs(colElement));
8764 0 : nsCOMPtr<nsIContent> colContent(do_QueryInterface(colElement));
8765 0 : if (colContent) {
8766 0 : nsIFrame* frame = colContent->GetPrimaryFrame();
8767 0 : if (frame) {
8768 0 : extraTreeY += frame->GetSize().height;
8769 : }
8770 : }
8771 : }
8772 : }
8773 : }
8774 : else {
8775 0 : multiSelect->GetCurrentItem(getter_AddRefs(item));
8776 : }
8777 : }
8778 : }
8779 : }
8780 : else {
8781 : // don't check menulists as the selected item will be inside a popup.
8782 0 : nsCOMPtr<nsIDOMXULMenuListElement> menulist = do_QueryInterface(aCurrentEl);
8783 0 : if (!menulist) {
8784 : nsCOMPtr<nsIDOMXULSelectControlElement> select =
8785 0 : do_QueryInterface(aCurrentEl);
8786 0 : if (select) {
8787 0 : checkLineHeight = false;
8788 0 : select->GetSelectedItem(getter_AddRefs(item));
8789 : }
8790 : }
8791 : }
8792 :
8793 0 : if (item)
8794 0 : focusedContent = do_QueryInterface(item);
8795 : #endif
8796 :
8797 0 : nsIFrame *frame = focusedContent->GetPrimaryFrame();
8798 0 : if (frame) {
8799 0 : NS_ASSERTION(frame->PresContext() == GetPresContext(),
8800 : "handling event for focused content that is not in our document?");
8801 :
8802 0 : nsPoint frameOrigin(0, 0);
8803 :
8804 : // Get the frame's origin within its view
8805 0 : nsView *view = frame->GetClosestView(&frameOrigin);
8806 0 : NS_ASSERTION(view, "No view for frame");
8807 :
8808 : // View's origin relative the widget
8809 0 : if (aRootWidget) {
8810 0 : frameOrigin += view->GetOffsetToWidget(aRootWidget);
8811 : }
8812 :
8813 : // Start context menu down and to the right from top left of frame
8814 : // use the lineheight. This is a good distance to move the context
8815 : // menu away from the top left corner of the frame. If we always
8816 : // used the frame height, the context menu could end up far away,
8817 : // for example when we're focused on linked images.
8818 : // On the other hand, we want to use the frame height if it's less
8819 : // than the current line height, so that the context menu appears
8820 : // associated with the correct frame.
8821 0 : nscoord extra = 0;
8822 0 : if (!istree) {
8823 0 : extra = frame->GetSize().height;
8824 0 : if (checkLineHeight) {
8825 : nsIScrollableFrame *scrollFrame =
8826 0 : nsLayoutUtils::GetNearestScrollableFrame(frame);
8827 0 : if (scrollFrame) {
8828 0 : nsSize scrollAmount = scrollFrame->GetLineScrollAmount();
8829 0 : nsIFrame* f = do_QueryFrame(scrollFrame);
8830 0 : int32_t APD = presContext->AppUnitsPerDevPixel();
8831 0 : int32_t scrollAPD = f->PresContext()->AppUnitsPerDevPixel();
8832 0 : scrollAmount = scrollAmount.ScaleToOtherAppUnits(scrollAPD, APD);
8833 0 : if (extra > scrollAmount.height) {
8834 0 : extra = scrollAmount.height;
8835 : }
8836 : }
8837 : }
8838 : }
8839 :
8840 0 : aTargetPt.x = presContext->AppUnitsToDevPixels(frameOrigin.x);
8841 0 : aTargetPt.y = presContext->AppUnitsToDevPixels(
8842 0 : frameOrigin.y + extra + extraTreeY);
8843 : }
8844 :
8845 0 : NS_IF_ADDREF(*aTargetToUse = focusedContent);
8846 0 : }
8847 :
8848 : bool
8849 0 : PresShell::ShouldIgnoreInvalidation()
8850 : {
8851 0 : return mPaintingSuppressed || !mIsActive || mIsNeverPainting;
8852 : }
8853 :
8854 : void
8855 35 : PresShell::WillPaint()
8856 : {
8857 : // Check the simplest things first. In particular, it's important to
8858 : // check mIsActive before making any of the more expensive calls such
8859 : // as GetRootPresContext, for the case of a browser with a large
8860 : // number of tabs.
8861 : // Don't bother doing anything if some viewmanager in our tree is painting
8862 : // while we still have painting suppressed or we are not active.
8863 35 : if (!mIsActive || mPaintingSuppressed || !IsVisible()) {
8864 2 : return;
8865 : }
8866 :
8867 33 : nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext();
8868 33 : if (!rootPresContext) {
8869 : // In some edge cases, such as when we don't have a root frame yet,
8870 : // we can't find the root prescontext. There's nothing to do in that
8871 : // case.
8872 0 : return;
8873 : }
8874 :
8875 33 : rootPresContext->FlushWillPaintObservers();
8876 33 : if (mIsDestroying)
8877 0 : return;
8878 :
8879 : // Process reflows, if we have them, to reduce flicker due to invalidates and
8880 : // reflow being interspersed. Note that we _do_ allow this to be
8881 : // interruptible; if we can't do all the reflows it's better to flicker a bit
8882 : // than to freeze up.
8883 33 : FlushPendingNotifications(ChangesToFlush(FlushType::InterruptibleLayout, false));
8884 : }
8885 :
8886 : void
8887 3 : PresShell::WillPaintWindow()
8888 : {
8889 3 : nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext();
8890 3 : if (rootPresContext != mPresContext) {
8891 : // This could be a popup's presshell. We don't allow plugins in popups
8892 : // so there's nothing to do here.
8893 0 : return;
8894 : }
8895 :
8896 : #ifndef XP_MACOSX
8897 3 : rootPresContext->ApplyPluginGeometryUpdates();
8898 : #endif
8899 : }
8900 :
8901 : void
8902 3 : PresShell::DidPaintWindow()
8903 : {
8904 3 : nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext();
8905 3 : if (rootPresContext != mPresContext) {
8906 : // This could be a popup's presshell. No point in notifying XPConnect
8907 : // about compositing of popups.
8908 0 : return;
8909 : }
8910 :
8911 3 : if (!mHasReceivedPaintMessage) {
8912 2 : mHasReceivedPaintMessage = true;
8913 :
8914 4 : nsCOMPtr<nsIObserverService> obsvc = services::GetObserverService();
8915 2 : if (obsvc && mDocument) {
8916 2 : nsPIDOMWindowOuter* window = mDocument->GetWindow();
8917 4 : nsCOMPtr<nsIDOMChromeWindow> chromeWin(do_QueryInterface(window));
8918 2 : if (chromeWin) {
8919 1 : obsvc->NotifyObservers(chromeWin, "widget-first-paint", nullptr);
8920 : }
8921 : }
8922 : }
8923 : }
8924 :
8925 : bool
8926 124 : PresShell::IsVisible()
8927 : {
8928 124 : if (!mIsActive || !mViewManager)
8929 0 : return false;
8930 :
8931 124 : nsView* view = mViewManager->GetRootView();
8932 124 : if (!view)
8933 0 : return true;
8934 :
8935 : // inner view of subdoc frame
8936 124 : view = view->GetParent();
8937 124 : if (!view)
8938 123 : return true;
8939 :
8940 : // subdoc view
8941 1 : view = view->GetParent();
8942 1 : if (!view)
8943 0 : return true;
8944 :
8945 1 : nsIFrame* frame = view->GetFrame();
8946 1 : if (!frame)
8947 0 : return true;
8948 :
8949 1 : return frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY);
8950 : }
8951 :
8952 : nsresult
8953 0 : PresShell::GetAgentStyleSheets(nsTArray<RefPtr<StyleSheet>>& aSheets)
8954 : {
8955 0 : aSheets.Clear();
8956 0 : int32_t sheetCount = mStyleSet->SheetCount(SheetType::Agent);
8957 :
8958 0 : if (!aSheets.SetCapacity(sheetCount, fallible)) {
8959 0 : return NS_ERROR_OUT_OF_MEMORY;
8960 : }
8961 :
8962 0 : for (int32_t i = 0; i < sheetCount; ++i) {
8963 0 : StyleSheet* sheet = mStyleSet->StyleSheetAt(SheetType::Agent, i);
8964 0 : aSheets.AppendElement(sheet);
8965 : }
8966 :
8967 0 : return NS_OK;
8968 : }
8969 :
8970 : nsresult
8971 0 : PresShell::SetAgentStyleSheets(const nsTArray<RefPtr<StyleSheet>>& aSheets)
8972 : {
8973 0 : return mStyleSet->ReplaceSheets(SheetType::Agent, aSheets);
8974 : }
8975 :
8976 : nsresult
8977 0 : PresShell::AddOverrideStyleSheet(StyleSheet* aSheet)
8978 : {
8979 0 : return mStyleSet->PrependStyleSheet(SheetType::Override, aSheet);
8980 : }
8981 :
8982 : nsresult
8983 0 : PresShell::RemoveOverrideStyleSheet(StyleSheet* aSheet)
8984 : {
8985 0 : return mStyleSet->RemoveStyleSheet(SheetType::Override, aSheet);
8986 : }
8987 :
8988 : static void
8989 0 : FreezeElement(nsISupports *aSupports, void * /* unused */)
8990 : {
8991 0 : nsCOMPtr<nsIObjectLoadingContent> olc(do_QueryInterface(aSupports));
8992 0 : if (olc) {
8993 0 : olc->StopPluginInstance();
8994 : }
8995 0 : }
8996 :
8997 : static bool
8998 0 : FreezeSubDocument(nsIDocument *aDocument, void *aData)
8999 : {
9000 0 : nsIPresShell *shell = aDocument->GetShell();
9001 0 : if (shell)
9002 0 : shell->Freeze();
9003 :
9004 0 : return true;
9005 : }
9006 :
9007 : void
9008 0 : PresShell::Freeze()
9009 : {
9010 0 : mUpdateApproximateFrameVisibilityEvent.Revoke();
9011 :
9012 0 : MaybeReleaseCapturingContent();
9013 :
9014 0 : mDocument->EnumerateActivityObservers(FreezeElement, nullptr);
9015 :
9016 0 : if (mCaret) {
9017 0 : SetCaretEnabled(false);
9018 : }
9019 :
9020 0 : mPaintingSuppressed = true;
9021 :
9022 0 : if (mDocument) {
9023 0 : mDocument->EnumerateSubDocuments(FreezeSubDocument, nullptr);
9024 : }
9025 :
9026 0 : nsPresContext* presContext = GetPresContext();
9027 0 : if (presContext) {
9028 0 : presContext->DisableInteractionTimeRecording();
9029 0 : if (presContext->RefreshDriver()->GetPresContext() == presContext) {
9030 0 : presContext->RefreshDriver()->Freeze();
9031 : }
9032 : }
9033 :
9034 0 : mFrozen = true;
9035 0 : if (mDocument) {
9036 0 : UpdateImageLockingState();
9037 : }
9038 0 : }
9039 :
9040 : void
9041 0 : PresShell::FireOrClearDelayedEvents(bool aFireEvents)
9042 : {
9043 0 : mNoDelayedMouseEvents = false;
9044 0 : mNoDelayedKeyEvents = false;
9045 0 : if (!aFireEvents) {
9046 0 : mDelayedEvents.Clear();
9047 0 : return;
9048 : }
9049 :
9050 0 : if (mDocument) {
9051 0 : nsCOMPtr<nsIDocument> doc = mDocument;
9052 0 : while (!mIsDestroying && mDelayedEvents.Length() &&
9053 0 : !doc->EventHandlingSuppressed()) {
9054 0 : nsAutoPtr<DelayedEvent> ev(mDelayedEvents[0].forget());
9055 0 : mDelayedEvents.RemoveElementAt(0);
9056 0 : if (ev->IsKeyPressEvent() && mIsLastKeyDownCanceled) {
9057 0 : continue;
9058 : }
9059 0 : ev->Dispatch();
9060 : }
9061 0 : if (!doc->EventHandlingSuppressed()) {
9062 0 : mDelayedEvents.Clear();
9063 : }
9064 : }
9065 : }
9066 :
9067 : static void
9068 0 : ThawElement(nsISupports *aSupports, void *aShell)
9069 : {
9070 0 : nsCOMPtr<nsIObjectLoadingContent> olc(do_QueryInterface(aSupports));
9071 0 : if (olc) {
9072 0 : olc->AsyncStartPluginInstance();
9073 : }
9074 0 : }
9075 :
9076 : static bool
9077 0 : ThawSubDocument(nsIDocument *aDocument, void *aData)
9078 : {
9079 0 : nsIPresShell *shell = aDocument->GetShell();
9080 0 : if (shell)
9081 0 : shell->Thaw();
9082 :
9083 0 : return true;
9084 : }
9085 :
9086 : void
9087 0 : PresShell::Thaw()
9088 : {
9089 0 : nsPresContext* presContext = GetPresContext();
9090 0 : if (presContext &&
9091 0 : presContext->RefreshDriver()->GetPresContext() == presContext) {
9092 0 : presContext->RefreshDriver()->Thaw();
9093 : }
9094 :
9095 0 : mDocument->EnumerateActivityObservers(ThawElement, this);
9096 :
9097 0 : if (mDocument)
9098 0 : mDocument->EnumerateSubDocuments(ThawSubDocument, nullptr);
9099 :
9100 : // Get the activeness of our presshell, as this might have changed
9101 : // while we were in the bfcache
9102 0 : QueryIsActive();
9103 :
9104 : // We're now unfrozen
9105 0 : mFrozen = false;
9106 0 : UpdateImageLockingState();
9107 :
9108 0 : UnsuppressPainting();
9109 0 : }
9110 :
9111 : //--------------------------------------------------------
9112 : // Start of protected and private methods on the PresShell
9113 : //--------------------------------------------------------
9114 :
9115 : void
9116 158 : PresShell::MaybeScheduleReflow()
9117 : {
9118 158 : ASSERT_REFLOW_SCHEDULED_STATE();
9119 210 : if (mObservingLayoutFlushes || mIsDestroying || mIsReflowing ||
9120 52 : mDirtyRoots.IsEmpty())
9121 113 : return;
9122 :
9123 45 : if (!mPresContext->HasPendingInterrupt() || !ScheduleReflowOffTimer()) {
9124 45 : ScheduleReflow();
9125 : }
9126 :
9127 45 : ASSERT_REFLOW_SCHEDULED_STATE();
9128 : }
9129 :
9130 : void
9131 45 : PresShell::ScheduleReflow()
9132 : {
9133 45 : ASSERT_REFLOW_SCHEDULED_STATE();
9134 45 : DoObserveLayoutFlushes();
9135 45 : ASSERT_REFLOW_SCHEDULED_STATE();
9136 45 : }
9137 :
9138 : nsresult
9139 830 : PresShell::DidCauseReflow()
9140 : {
9141 830 : NS_ASSERTION(mChangeNestCount != 0, "Unexpected call to DidCauseReflow()");
9142 830 : --mChangeNestCount;
9143 830 : nsContentUtils::RemoveScriptBlocker();
9144 :
9145 830 : return NS_OK;
9146 : }
9147 :
9148 : void
9149 68 : PresShell::WillDoReflow()
9150 : {
9151 68 : mDocument->FlushUserFontSet();
9152 :
9153 68 : mPresContext->FlushCounterStyles();
9154 :
9155 68 : mFrameConstructor->BeginUpdate();
9156 :
9157 68 : mLastReflowStart = GetPerformanceNow();
9158 68 : }
9159 :
9160 : void
9161 68 : PresShell::DidDoReflow(bool aInterruptible)
9162 : {
9163 68 : mFrameConstructor->EndUpdate();
9164 :
9165 68 : HandlePostedReflowCallbacks(aInterruptible);
9166 :
9167 136 : nsCOMPtr<nsIDocShell> docShell = mPresContext->GetDocShell();
9168 68 : if (docShell) {
9169 29 : DOMHighResTimeStamp now = GetPerformanceNow();
9170 29 : docShell->NotifyReflowObservers(aInterruptible, mLastReflowStart, now);
9171 : }
9172 :
9173 68 : if (sSynthMouseMove) {
9174 68 : SynthesizeMouseMove(false);
9175 : }
9176 :
9177 68 : mPresContext->NotifyMissingFonts();
9178 68 : }
9179 :
9180 : DOMHighResTimeStamp
9181 97 : PresShell::GetPerformanceNow()
9182 : {
9183 97 : DOMHighResTimeStamp now = 0;
9184 :
9185 97 : if (nsPIDOMWindowInner* window = mDocument->GetInnerWindow()) {
9186 58 : Performance* perf = window->GetPerformance();
9187 :
9188 58 : if (perf) {
9189 58 : now = perf->Now();
9190 : }
9191 : }
9192 :
9193 97 : return now;
9194 : }
9195 :
9196 : void
9197 0 : PresShell::sReflowContinueCallback(nsITimer* aTimer, void* aPresShell)
9198 : {
9199 0 : RefPtr<PresShell> self = static_cast<PresShell*>(aPresShell);
9200 :
9201 0 : NS_PRECONDITION(aTimer == self->mReflowContinueTimer, "Unexpected timer");
9202 0 : self->mReflowContinueTimer = nullptr;
9203 0 : self->ScheduleReflow();
9204 0 : }
9205 :
9206 : bool
9207 0 : PresShell::ScheduleReflowOffTimer()
9208 : {
9209 0 : NS_PRECONDITION(!mObservingLayoutFlushes, "Shouldn't get here");
9210 0 : ASSERT_REFLOW_SCHEDULED_STATE();
9211 :
9212 0 : if (!mReflowContinueTimer) {
9213 0 : mReflowContinueTimer = do_CreateInstance("@mozilla.org/timer;1");
9214 0 : mReflowContinueTimer->SetTarget(
9215 0 : mDocument->EventTargetFor(TaskCategory::Other));
9216 0 : if (!mReflowContinueTimer ||
9217 0 : NS_FAILED(mReflowContinueTimer->
9218 : InitWithNamedFuncCallback(sReflowContinueCallback, this, 30,
9219 : nsITimer::TYPE_ONE_SHOT,
9220 : "sReflowContinueCallback"))) {
9221 0 : return false;
9222 : }
9223 : }
9224 0 : return true;
9225 : }
9226 :
9227 : bool
9228 70 : PresShell::DoReflow(nsIFrame* target, bool aInterruptible)
9229 : {
9230 70 : gfxTextPerfMetrics* tp = mPresContext->GetTextPerfMetrics();
9231 70 : TimeStamp timeStart;
9232 70 : if (tp) {
9233 0 : tp->Accumulate();
9234 0 : tp->reflowCount++;
9235 0 : timeStart = TimeStamp::Now();
9236 : }
9237 :
9238 70 : target->SchedulePaint();
9239 70 : nsIFrame *parent = nsLayoutUtils::GetCrossDocParentFrame(target);
9240 86 : while (parent) {
9241 8 : nsSVGEffects::InvalidateDirectRenderingObservers(parent);
9242 8 : parent = nsLayoutUtils::GetCrossDocParentFrame(parent);
9243 : }
9244 :
9245 70 : nsIURI* uri = mDocument->GetDocumentURI();
9246 140 : nsCString uriString = uri ? uri->GetSpecOrDefault() : NS_LITERAL_CSTRING("N/A");
9247 140 : AUTO_PROFILER_LABEL_DYNAMIC("PresShell::DoReflow", GRAPHICS, uriString.get());
9248 :
9249 70 : nsDocShell* docShell = static_cast<nsDocShell*>(GetPresContext()->GetDocShell());
9250 140 : RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
9251 70 : bool isTimelineRecording = timelines && timelines->HasConsumer(docShell);
9252 :
9253 70 : if (isTimelineRecording) {
9254 0 : timelines->AddMarkerForDocShell(docShell, "Reflow", MarkerTracingType::START);
9255 : }
9256 :
9257 70 : if (mReflowContinueTimer) {
9258 0 : mReflowContinueTimer->Cancel();
9259 0 : mReflowContinueTimer = nullptr;
9260 : }
9261 :
9262 70 : nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
9263 :
9264 : // CreateReferenceRenderingContext can return nullptr
9265 140 : RefPtr<gfxContext> rcx(CreateReferenceRenderingContext());
9266 :
9267 : #ifdef DEBUG
9268 70 : mCurrentReflowRoot = target;
9269 : #endif
9270 :
9271 : // If the target frame is the root of the frame hierarchy, then
9272 : // use all the available space. If it's simply a `reflow root',
9273 : // then use the target frame's size as the available space.
9274 70 : WritingMode wm = target->GetWritingMode();
9275 70 : LogicalSize size(wm);
9276 70 : if (target == rootFrame) {
9277 66 : size = LogicalSize(wm, mPresContext->GetVisibleArea().Size());
9278 : } else {
9279 4 : size = target->GetLogicalSize();
9280 : }
9281 :
9282 70 : NS_ASSERTION(!target->GetNextInFlow() && !target->GetPrevInFlow(),
9283 : "reflow roots should never split");
9284 :
9285 : // Don't pass size directly to the reflow state, since a
9286 : // constrained height implies page/column breaking.
9287 70 : LogicalSize reflowSize(wm, size.ISize(wm), NS_UNCONSTRAINEDSIZE);
9288 : ReflowInput reflowInput(mPresContext, target, rcx, reflowSize,
9289 70 : ReflowInput::CALLER_WILL_INIT);
9290 70 : reflowInput.mOrthogonalLimit = size.BSize(wm);
9291 :
9292 70 : if (rootFrame == target) {
9293 66 : reflowInput.Init(mPresContext);
9294 :
9295 : // When the root frame is being reflowed with unconstrained block-size
9296 : // (which happens when we're called from
9297 : // nsDocumentViewer::SizeToContent), we're effectively doing a
9298 : // resize in the block direction, since it changes the meaning of
9299 : // percentage block-sizes even if no block-sizes actually changed.
9300 : // The same applies when we reflow again after that computation. This is
9301 : // an unusual case, and isn't caught by ReflowInput::InitResizeFlags.
9302 66 : bool hasUnconstrainedBSize = size.BSize(wm) == NS_UNCONSTRAINEDSIZE;
9303 :
9304 66 : if (hasUnconstrainedBSize || mLastRootReflowHadUnconstrainedBSize) {
9305 0 : reflowInput.SetBResize(true);
9306 : }
9307 :
9308 66 : mLastRootReflowHadUnconstrainedBSize = hasUnconstrainedBSize;
9309 : } else {
9310 : // Initialize reflow state with current used border and padding,
9311 : // in case this was set specially by the parent frame when the reflow root
9312 : // was reflowed by its parent.
9313 4 : nsMargin currentBorder = target->GetUsedBorder();
9314 4 : nsMargin currentPadding = target->GetUsedPadding();
9315 4 : reflowInput.Init(mPresContext, nullptr, ¤tBorder, ¤tPadding);
9316 : }
9317 :
9318 : // fix the computed height
9319 70 : NS_ASSERTION(reflowInput.ComputedPhysicalMargin() == nsMargin(0, 0, 0, 0),
9320 : "reflow state should not set margin for reflow roots");
9321 70 : if (size.BSize(wm) != NS_UNCONSTRAINEDSIZE) {
9322 : nscoord computedBSize =
9323 70 : size.BSize(wm) - reflowInput.ComputedLogicalBorderPadding().BStartEnd(wm);
9324 70 : computedBSize = std::max(computedBSize, 0);
9325 70 : reflowInput.SetComputedBSize(computedBSize);
9326 : }
9327 70 : NS_ASSERTION(reflowInput.ComputedISize() ==
9328 : size.ISize(wm) -
9329 : reflowInput.ComputedLogicalBorderPadding().IStartEnd(wm),
9330 : "reflow state computed incorrect inline size");
9331 :
9332 70 : mPresContext->ReflowStarted(aInterruptible);
9333 70 : mIsReflowing = true;
9334 :
9335 70 : nsReflowStatus status;
9336 140 : ReflowOutput desiredSize(reflowInput);
9337 70 : target->Reflow(mPresContext, desiredSize, reflowInput, status);
9338 :
9339 : // If an incremental reflow is initiated at a frame other than the
9340 : // root frame, then its desired size had better not change! If it's
9341 : // initiated at the root, then the size better not change unless its
9342 : // height was unconstrained to start with.
9343 140 : nsRect boundsRelativeToTarget = nsRect(0, 0, desiredSize.Width(), desiredSize.Height());
9344 70 : NS_ASSERTION((target == rootFrame &&
9345 : size.BSize(wm) == NS_UNCONSTRAINEDSIZE) ||
9346 : (desiredSize.ISize(wm) == size.ISize(wm) &&
9347 : desiredSize.BSize(wm) == size.BSize(wm)),
9348 : "non-root frame's desired size changed during an "
9349 : "incremental reflow");
9350 70 : NS_ASSERTION(target == rootFrame ||
9351 : desiredSize.VisualOverflow().IsEqualInterior(boundsRelativeToTarget),
9352 : "non-root reflow roots must not have visible overflow");
9353 70 : NS_ASSERTION(target == rootFrame ||
9354 : desiredSize.ScrollableOverflow().IsEqualEdges(boundsRelativeToTarget),
9355 : "non-root reflow roots must not have scrollable overflow");
9356 70 : NS_ASSERTION(status.IsEmpty(),
9357 : "reflow roots should never split");
9358 :
9359 70 : target->SetSize(boundsRelativeToTarget.Size());
9360 :
9361 : // Always use boundsRelativeToTarget here, not desiredSize.GetVisualOverflowArea(),
9362 : // because for root frames (where they could be different, since root frames
9363 : // are allowed to have overflow) the root view bounds need to match the
9364 : // viewport bounds; the view manager "window dimensions" code depends on it.
9365 140 : nsContainerFrame::SyncFrameViewAfterReflow(mPresContext, target,
9366 : target->GetView(),
9367 140 : boundsRelativeToTarget);
9368 140 : nsContainerFrame::SyncWindowProperties(mPresContext, target,
9369 : target->GetView(), rcx,
9370 140 : nsContainerFrame::SET_ASYNC);
9371 :
9372 70 : target->DidReflow(mPresContext, nullptr, nsDidReflowStatus::FINISHED);
9373 70 : if (target == rootFrame && size.BSize(wm) == NS_UNCONSTRAINEDSIZE) {
9374 0 : mPresContext->SetVisibleArea(boundsRelativeToTarget);
9375 : }
9376 :
9377 : #ifdef DEBUG
9378 70 : mCurrentReflowRoot = nullptr;
9379 : #endif
9380 :
9381 70 : NS_ASSERTION(mPresContext->HasPendingInterrupt() ||
9382 : mFramesToDirty.Count() == 0,
9383 : "Why do we need to dirty anything if not interrupted?");
9384 :
9385 70 : mIsReflowing = false;
9386 70 : bool interrupted = mPresContext->HasPendingInterrupt();
9387 70 : if (interrupted) {
9388 : // Make sure target gets reflowed again.
9389 0 : for (auto iter = mFramesToDirty.Iter(); !iter.Done(); iter.Next()) {
9390 : // Mark frames dirty until target frame.
9391 0 : nsPtrHashKey<nsIFrame>* p = iter.Get();
9392 0 : for (nsIFrame* f = p->GetKey();
9393 0 : f && !NS_SUBTREE_DIRTY(f);
9394 : f = f->GetParent()) {
9395 0 : f->AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
9396 :
9397 0 : if (f == target) {
9398 0 : break;
9399 : }
9400 : }
9401 : }
9402 :
9403 0 : NS_ASSERTION(NS_SUBTREE_DIRTY(target), "Why is the target not dirty?");
9404 0 : mDirtyRoots.AppendElement(target);
9405 0 : SetNeedLayoutFlush();
9406 :
9407 : // Clear mFramesToDirty after we've done the NS_SUBTREE_DIRTY(target)
9408 : // assertion so that if it fails it's easier to see what's going on.
9409 : #ifdef NOISY_INTERRUPTIBLE_REFLOW
9410 : printf("mFramesToDirty.Count() == %u\n", mFramesToDirty.Count());
9411 : #endif /* NOISY_INTERRUPTIBLE_REFLOW */
9412 0 : mFramesToDirty.Clear();
9413 :
9414 : // Any FlushPendingNotifications with interruptible reflows
9415 : // should be suppressed now. We don't want to do extra reflow work
9416 : // before our reflow event happens.
9417 0 : mSuppressInterruptibleReflows = true;
9418 0 : MaybeScheduleReflow();
9419 : }
9420 :
9421 : // dump text perf metrics for reflows with significant text processing
9422 70 : if (tp) {
9423 0 : if (tp->current.numChars > 100) {
9424 0 : TimeDuration reflowTime = TimeStamp::Now() - timeStart;
9425 0 : LogTextPerfStats(tp, this, tp->current,
9426 0 : reflowTime.ToMilliseconds(), eLog_reflow, nullptr);
9427 : }
9428 0 : tp->Accumulate();
9429 : }
9430 :
9431 70 : if (isTimelineRecording) {
9432 0 : timelines->AddMarkerForDocShell(docShell, "Reflow", MarkerTracingType::END);
9433 : }
9434 :
9435 140 : return !interrupted;
9436 : }
9437 :
9438 : #ifdef DEBUG
9439 : void
9440 48 : PresShell::DoVerifyReflow()
9441 : {
9442 48 : if (GetVerifyReflowEnable()) {
9443 : // First synchronously render what we have so far so that we can
9444 : // see it.
9445 0 : nsView* rootView = mViewManager->GetRootView();
9446 0 : mViewManager->InvalidateView(rootView);
9447 :
9448 0 : FlushPendingNotifications(FlushType::Layout);
9449 0 : mInVerifyReflow = true;
9450 0 : bool ok = VerifyIncrementalReflow();
9451 0 : mInVerifyReflow = false;
9452 0 : if (VERIFY_REFLOW_ALL & gVerifyReflowFlags) {
9453 0 : printf("ProcessReflowCommands: finished (%s)\n",
9454 0 : ok ? "ok" : "failed");
9455 : }
9456 :
9457 0 : if (!mDirtyRoots.IsEmpty()) {
9458 0 : printf("XXX yikes! reflow commands queued during verify-reflow\n");
9459 : }
9460 : }
9461 48 : }
9462 : #endif
9463 :
9464 : // used with Telemetry metrics
9465 : #define NS_LONG_REFLOW_TIME_MS 5000
9466 :
9467 : bool
9468 105 : PresShell::ProcessReflowCommands(bool aInterruptible)
9469 : {
9470 105 : if (mDirtyRoots.IsEmpty() && !mShouldUnsuppressPainting) {
9471 : // Nothing to do; bail out
9472 57 : return true;
9473 : }
9474 :
9475 48 : mozilla::TimeStamp timerStart = mozilla::TimeStamp::Now();
9476 48 : bool interrupted = false;
9477 48 : if (!mDirtyRoots.IsEmpty()) {
9478 :
9479 : #ifdef DEBUG
9480 48 : if (VERIFY_REFLOW_DUMP_COMMANDS & gVerifyReflowFlags) {
9481 0 : printf("ProcessReflowCommands: begin incremental reflow\n");
9482 : }
9483 : #endif
9484 :
9485 : // If reflow is interruptible, then make a note of our deadline.
9486 : const PRIntervalTime deadline = aInterruptible
9487 48 : ? PR_IntervalNow() + PR_MicrosecondsToInterval(gMaxRCProcessingTime)
9488 48 : : (PRIntervalTime)0;
9489 :
9490 : // Scope for the reflow entry point
9491 : {
9492 96 : nsAutoScriptBlocker scriptBlocker;
9493 48 : WillDoReflow();
9494 96 : AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Reflow);
9495 96 : nsViewManager::AutoDisableRefresh refreshBlocker(mViewManager);
9496 :
9497 51 : do {
9498 : // Send an incremental reflow notification to the target frame.
9499 51 : int32_t idx = mDirtyRoots.Length() - 1;
9500 51 : nsIFrame *target = mDirtyRoots[idx];
9501 51 : mDirtyRoots.RemoveElementAt(idx);
9502 :
9503 51 : if (!NS_SUBTREE_DIRTY(target)) {
9504 : // It's not dirty anymore, which probably means the notification
9505 : // was posted in the middle of a reflow (perhaps with a reflow
9506 : // root in the middle). Don't do anything.
9507 1 : continue;
9508 : }
9509 :
9510 50 : interrupted = !DoReflow(target, aInterruptible);
9511 :
9512 : // Keep going until we're out of reflow commands, or we've run
9513 : // past our deadline, or we're interrupted.
9514 57 : } while (!interrupted && !mDirtyRoots.IsEmpty() &&
9515 4 : (!aInterruptible || PR_IntervalNow() < deadline));
9516 :
9517 48 : interrupted = !mDirtyRoots.IsEmpty();
9518 : }
9519 :
9520 : // Exiting the scriptblocker might have killed us
9521 48 : if (!mIsDestroying) {
9522 48 : DidDoReflow(aInterruptible);
9523 : }
9524 :
9525 : // DidDoReflow might have killed us
9526 48 : if (!mIsDestroying) {
9527 : #ifdef DEBUG
9528 48 : if (VERIFY_REFLOW_DUMP_COMMANDS & gVerifyReflowFlags) {
9529 : printf("\nPresShell::ProcessReflowCommands() finished: this=%p\n",
9530 0 : (void*)this);
9531 : }
9532 48 : DoVerifyReflow();
9533 : #endif
9534 :
9535 : // If any new reflow commands were enqueued during the reflow, schedule
9536 : // another reflow event to process them. Note that we want to do this
9537 : // after DidDoReflow(), since that method can change whether there are
9538 : // dirty roots around by flushing, and there's no point in posting a
9539 : // reflow event just to have the flush revoke it.
9540 48 : if (!mDirtyRoots.IsEmpty()) {
9541 0 : MaybeScheduleReflow();
9542 : // And record that we might need flushing
9543 0 : SetNeedLayoutFlush();
9544 : }
9545 : }
9546 : }
9547 :
9548 68 : if (!mIsDestroying && mShouldUnsuppressPainting &&
9549 20 : mDirtyRoots.IsEmpty()) {
9550 : // We only unlock if we're out of reflows. It's pointless
9551 : // to unlock if reflows are still pending, since reflows
9552 : // are just going to thrash the frames around some more. By
9553 : // waiting we avoid an overeager "jitter" effect.
9554 20 : mShouldUnsuppressPainting = false;
9555 20 : UnsuppressAndInvalidate();
9556 : }
9557 :
9558 48 : if (mDocument->GetRootElement()) {
9559 48 : TimeDuration elapsed = TimeStamp::Now() - timerStart;
9560 48 : int32_t intElapsed = int32_t(elapsed.ToMilliseconds());
9561 :
9562 48 : if (intElapsed > NS_LONG_REFLOW_TIME_MS) {
9563 0 : Telemetry::Accumulate(Telemetry::LONG_REFLOW_INTERRUPTIBLE,
9564 0 : aInterruptible ? 1 : 0);
9565 : }
9566 : }
9567 :
9568 48 : return !interrupted;
9569 : }
9570 :
9571 : void
9572 0 : PresShell::WindowSizeMoveDone()
9573 : {
9574 0 : if (mPresContext) {
9575 0 : EventStateManager::ClearGlobalActiveContent(nullptr);
9576 0 : ClearMouseCapture(nullptr);
9577 : }
9578 0 : }
9579 :
9580 : #ifdef MOZ_XUL
9581 : /*
9582 : * It's better to add stuff to the |DidSetStyleContext| method of the
9583 : * relevant frames than adding it here. These methods should (ideally,
9584 : * anyway) go away.
9585 : */
9586 :
9587 : // Return value says whether to walk children.
9588 : typedef bool (* frameWalkerFn)(nsIFrame *aFrame, void *aClosure);
9589 :
9590 : static bool
9591 0 : ReResolveMenusAndTrees(nsIFrame *aFrame, void *aClosure)
9592 : {
9593 : // Trees have a special style cache that needs to be flushed when
9594 : // the theme changes.
9595 0 : nsTreeBodyFrame *treeBody = do_QueryFrame(aFrame);
9596 0 : if (treeBody)
9597 0 : treeBody->ClearStyleAndImageCaches();
9598 :
9599 : // We deliberately don't re-resolve style on a menu's popup
9600 : // sub-content, since doing so slows menus to a crawl. That means we
9601 : // have to special-case them on a skin switch, and ensure that the
9602 : // popup frames just get destroyed completely.
9603 0 : nsMenuFrame* menu = do_QueryFrame(aFrame);
9604 0 : if (menu)
9605 0 : menu->CloseMenu(true);
9606 0 : return true;
9607 : }
9608 :
9609 : static bool
9610 0 : ReframeImageBoxes(nsIFrame *aFrame, void *aClosure)
9611 : {
9612 0 : nsStyleChangeList *list = static_cast<nsStyleChangeList*>(aClosure);
9613 0 : if (aFrame->IsImageBoxFrame()) {
9614 0 : list->AppendChange(aFrame, aFrame->GetContent(),
9615 0 : nsChangeHint_ReconstructFrame);
9616 0 : return false; // don't walk descendants
9617 : }
9618 0 : return true; // walk descendants
9619 : }
9620 :
9621 : static void
9622 0 : WalkFramesThroughPlaceholders(nsPresContext *aPresContext, nsIFrame *aFrame,
9623 : frameWalkerFn aFunc, void *aClosure)
9624 : {
9625 0 : bool walkChildren = (*aFunc)(aFrame, aClosure);
9626 0 : if (!walkChildren)
9627 0 : return;
9628 :
9629 0 : nsIFrame::ChildListIterator lists(aFrame);
9630 0 : for (; !lists.IsDone(); lists.Next()) {
9631 0 : nsFrameList::Enumerator childFrames(lists.CurrentList());
9632 0 : for (; !childFrames.AtEnd(); childFrames.Next()) {
9633 0 : nsIFrame* child = childFrames.get();
9634 0 : if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
9635 : // only do frames that are in flow, and recur through the
9636 : // out-of-flows of placeholders.
9637 0 : WalkFramesThroughPlaceholders(aPresContext,
9638 : nsPlaceholderFrame::GetRealFrameFor(child),
9639 0 : aFunc, aClosure);
9640 : }
9641 : }
9642 : }
9643 : }
9644 : #endif
9645 :
9646 : NS_IMETHODIMP
9647 0 : PresShell::Observe(nsISupports* aSubject,
9648 : const char* aTopic,
9649 : const char16_t* aData)
9650 : {
9651 0 : if (mIsDestroying) {
9652 0 : NS_WARNING("our observers should have been unregistered by now");
9653 0 : return NS_OK;
9654 : }
9655 :
9656 : #ifdef MOZ_XUL
9657 0 : if (!nsCRT::strcmp(aTopic, "chrome-flush-skin-caches")) {
9658 0 : nsIFrame *rootFrame = mFrameConstructor->GetRootFrame();
9659 : // Need to null-check because "chrome-flush-skin-caches" can happen
9660 : // at interesting times during startup.
9661 0 : if (rootFrame) {
9662 0 : NS_ASSERTION(mViewManager, "View manager must exist");
9663 :
9664 0 : AutoWeakFrame weakRoot(rootFrame);
9665 : // Have to make sure that the content notifications are flushed before we
9666 : // start messing with the frame model; otherwise we can get content doubling.
9667 0 : mDocument->FlushPendingNotifications(FlushType::ContentAndNotify);
9668 :
9669 0 : if (weakRoot.IsAlive()) {
9670 0 : WalkFramesThroughPlaceholders(mPresContext, rootFrame,
9671 0 : &ReResolveMenusAndTrees, nullptr);
9672 :
9673 : // Because "chrome:" URL equality is messy, reframe image box
9674 : // frames (hack!).
9675 0 : nsStyleChangeList changeList(mPresContext->StyleSet()->BackendType());
9676 0 : WalkFramesThroughPlaceholders(mPresContext, rootFrame,
9677 0 : ReframeImageBoxes, &changeList);
9678 : // Mark ourselves as not safe to flush while we're doing frame
9679 : // construction.
9680 : {
9681 0 : nsAutoScriptBlocker scriptBlocker;
9682 0 : ++mChangeNestCount;
9683 0 : RestyleManager* restyleManager = mPresContext->RestyleManager();
9684 0 : restyleManager->ProcessRestyledFrames(changeList);
9685 0 : restyleManager->FlushOverflowChangedTracker();
9686 0 : --mChangeNestCount;
9687 : }
9688 : }
9689 : }
9690 0 : return NS_OK;
9691 : }
9692 : #endif
9693 :
9694 0 : if (!nsCRT::strcmp(aTopic, "memory-pressure")) {
9695 0 : if (!AssumeAllFramesVisible() && mPresContext->IsRootContentDocument()) {
9696 0 : DoUpdateApproximateFrameVisibility(/* aRemoveOnly = */ true);
9697 : }
9698 0 : return NS_OK;
9699 : }
9700 :
9701 0 : if (!nsCRT::strcmp(aTopic, NS_WIDGET_WAKE_OBSERVER_TOPIC)) {
9702 0 : mLastOSWake = TimeStamp::Now();
9703 : }
9704 :
9705 0 : NS_WARNING("unrecognized topic in PresShell::Observe");
9706 0 : return NS_ERROR_FAILURE;
9707 : }
9708 :
9709 : bool
9710 0 : nsIPresShell::AddRefreshObserverInternal(nsARefreshObserver* aObserver,
9711 : FlushType aFlushType)
9712 : {
9713 0 : nsPresContext* presContext = GetPresContext();
9714 0 : return presContext &&
9715 0 : presContext->RefreshDriver()->AddRefreshObserver(aObserver, aFlushType);
9716 : }
9717 :
9718 : /* virtual */ bool
9719 0 : nsIPresShell::AddRefreshObserverExternal(nsARefreshObserver* aObserver,
9720 : FlushType aFlushType)
9721 : {
9722 0 : return AddRefreshObserverInternal(aObserver, aFlushType);
9723 : }
9724 :
9725 : bool
9726 0 : nsIPresShell::RemoveRefreshObserverInternal(nsARefreshObserver* aObserver,
9727 : FlushType aFlushType)
9728 : {
9729 0 : nsPresContext* presContext = GetPresContext();
9730 0 : return presContext &&
9731 0 : presContext->RefreshDriver()->RemoveRefreshObserver(aObserver, aFlushType);
9732 : }
9733 :
9734 : /* virtual */ bool
9735 0 : nsIPresShell::RemoveRefreshObserverExternal(nsARefreshObserver* aObserver,
9736 : FlushType aFlushType)
9737 : {
9738 0 : return RemoveRefreshObserverInternal(aObserver, aFlushType);
9739 : }
9740 :
9741 : /* virtual */ bool
9742 0 : nsIPresShell::AddPostRefreshObserver(nsAPostRefreshObserver* aObserver)
9743 : {
9744 0 : nsPresContext* presContext = GetPresContext();
9745 0 : if (!presContext) {
9746 0 : return false;
9747 : }
9748 0 : presContext->RefreshDriver()->AddPostRefreshObserver(aObserver);
9749 0 : return true;
9750 : }
9751 :
9752 : /* virtual */ bool
9753 0 : nsIPresShell::RemovePostRefreshObserver(nsAPostRefreshObserver* aObserver)
9754 : {
9755 0 : nsPresContext* presContext = GetPresContext();
9756 0 : if (!presContext) {
9757 0 : return false;
9758 : }
9759 0 : presContext->RefreshDriver()->RemovePostRefreshObserver(aObserver);
9760 0 : return true;
9761 : }
9762 :
9763 : void
9764 38 : nsIPresShell::DoObserveStyleFlushes()
9765 : {
9766 38 : MOZ_ASSERT(!ObservingStyleFlushes());
9767 38 : mObservingStyleFlushes =
9768 38 : mPresContext->RefreshDriver()->AddStyleFlushObserver(this);
9769 38 : }
9770 :
9771 : void
9772 45 : nsIPresShell::DoObserveLayoutFlushes()
9773 : {
9774 45 : MOZ_ASSERT(!ObservingLayoutFlushes());
9775 45 : mObservingLayoutFlushes =
9776 45 : mPresContext->RefreshDriver()->AddLayoutFlushObserver(this);
9777 45 : }
9778 :
9779 : //------------------------------------------------------
9780 : // End of protected and private methods on the PresShell
9781 : //------------------------------------------------------
9782 :
9783 : //------------------------------------------------------------------
9784 : //-- Delayed event Classes Impls
9785 : //------------------------------------------------------------------
9786 :
9787 0 : PresShell::DelayedInputEvent::DelayedInputEvent() :
9788 : DelayedEvent(),
9789 0 : mEvent(nullptr)
9790 : {
9791 0 : }
9792 :
9793 0 : PresShell::DelayedInputEvent::~DelayedInputEvent()
9794 : {
9795 0 : delete mEvent;
9796 0 : }
9797 :
9798 : void
9799 0 : PresShell::DelayedInputEvent::Dispatch()
9800 : {
9801 0 : if (!mEvent || !mEvent->mWidget) {
9802 0 : return;
9803 : }
9804 0 : nsCOMPtr<nsIWidget> widget = mEvent->mWidget;
9805 : nsEventStatus status;
9806 0 : widget->DispatchEvent(mEvent, status);
9807 : }
9808 :
9809 0 : PresShell::DelayedMouseEvent::DelayedMouseEvent(WidgetMouseEvent* aEvent) :
9810 0 : DelayedInputEvent()
9811 : {
9812 : WidgetMouseEvent* mouseEvent =
9813 0 : new WidgetMouseEvent(aEvent->IsTrusted(),
9814 0 : aEvent->mMessage,
9815 : aEvent->mWidget,
9816 0 : aEvent->mReason,
9817 0 : aEvent->mContextMenuTrigger);
9818 0 : mouseEvent->AssignMouseEventData(*aEvent, false);
9819 0 : mEvent = mouseEvent;
9820 0 : }
9821 :
9822 0 : PresShell::DelayedKeyEvent::DelayedKeyEvent(WidgetKeyboardEvent* aEvent) :
9823 0 : DelayedInputEvent()
9824 : {
9825 : WidgetKeyboardEvent* keyEvent =
9826 0 : new WidgetKeyboardEvent(aEvent->IsTrusted(),
9827 0 : aEvent->mMessage,
9828 0 : aEvent->mWidget);
9829 0 : keyEvent->AssignKeyEventData(*aEvent, false);
9830 0 : keyEvent->mFlags.mIsSynthesizedForTests = aEvent->mFlags.mIsSynthesizedForTests;
9831 0 : keyEvent->mFlags.mIsSuppressedOrDelayed = true;
9832 0 : mEvent = keyEvent;
9833 0 : }
9834 :
9835 : bool
9836 0 : PresShell::DelayedKeyEvent::IsKeyPressEvent()
9837 : {
9838 0 : return mEvent->mMessage == eKeyPress;
9839 : }
9840 :
9841 : // Start of DEBUG only code
9842 :
9843 : #ifdef DEBUG
9844 :
9845 : static void
9846 0 : LogVerifyMessage(nsIFrame* k1, nsIFrame* k2, const char* aMsg)
9847 : {
9848 0 : nsAutoString n1, n2;
9849 0 : if (k1) {
9850 0 : k1->GetFrameName(n1);
9851 : } else {
9852 0 : n1.AssignLiteral(u"(null)");
9853 : }
9854 :
9855 0 : if (k2) {
9856 0 : k2->GetFrameName(n2);
9857 : } else {
9858 0 : n2.AssignLiteral(u"(null)");
9859 : }
9860 :
9861 0 : printf("verifyreflow: %s %p != %s %p %s\n",
9862 0 : NS_LossyConvertUTF16toASCII(n1).get(), (void*)k1,
9863 0 : NS_LossyConvertUTF16toASCII(n2).get(), (void*)k2, aMsg);
9864 0 : }
9865 :
9866 : static void
9867 0 : LogVerifyMessage(nsIFrame* k1, nsIFrame* k2, const char* aMsg,
9868 : const nsRect& r1, const nsRect& r2)
9869 : {
9870 0 : printf("VerifyReflow Error:\n");
9871 0 : nsAutoString name;
9872 :
9873 0 : if (k1) {
9874 0 : k1->GetFrameName(name);
9875 0 : printf(" %s %p ", NS_LossyConvertUTF16toASCII(name).get(), (void*)k1);
9876 : }
9877 0 : printf("{%d, %d, %d, %d} != \n", r1.x, r1.y, r1.width, r1.height);
9878 :
9879 0 : if (k2) {
9880 0 : k2->GetFrameName(name);
9881 0 : printf(" %s %p ", NS_LossyConvertUTF16toASCII(name).get(), (void*)k2);
9882 : }
9883 : printf("{%d, %d, %d, %d}\n %s\n",
9884 0 : r2.x, r2.y, r2.width, r2.height, aMsg);
9885 0 : }
9886 :
9887 : static void
9888 0 : LogVerifyMessage(nsIFrame* k1, nsIFrame* k2, const char* aMsg,
9889 : const nsIntRect& r1, const nsIntRect& r2)
9890 : {
9891 0 : printf("VerifyReflow Error:\n");
9892 0 : nsAutoString name;
9893 :
9894 0 : if (k1) {
9895 0 : k1->GetFrameName(name);
9896 0 : printf(" %s %p ", NS_LossyConvertUTF16toASCII(name).get(), (void*)k1);
9897 : }
9898 0 : printf("{%d, %d, %d, %d} != \n", r1.x, r1.y, r1.width, r1.height);
9899 :
9900 0 : if (k2) {
9901 0 : k2->GetFrameName(name);
9902 0 : printf(" %s %p ", NS_LossyConvertUTF16toASCII(name).get(), (void*)k2);
9903 : }
9904 : printf("{%d, %d, %d, %d}\n %s\n",
9905 0 : r2.x, r2.y, r2.width, r2.height, aMsg);
9906 0 : }
9907 :
9908 : static bool
9909 0 : CompareTrees(nsPresContext* aFirstPresContext, nsIFrame* aFirstFrame,
9910 : nsPresContext* aSecondPresContext, nsIFrame* aSecondFrame)
9911 : {
9912 0 : if (!aFirstPresContext || !aFirstFrame || !aSecondPresContext || !aSecondFrame)
9913 0 : return true;
9914 : // XXX Evil hack to reduce false positives; I can't seem to figure
9915 : // out how to flush scrollbar changes correctly
9916 : //if (aFirstFrame->IsScrollbarFrame())
9917 : // return true;
9918 0 : bool ok = true;
9919 0 : nsIFrame::ChildListIterator lists1(aFirstFrame);
9920 0 : nsIFrame::ChildListIterator lists2(aSecondFrame);
9921 0 : do {
9922 0 : const nsFrameList& kids1 = !lists1.IsDone() ? lists1.CurrentList() : nsFrameList();
9923 0 : const nsFrameList& kids2 = !lists2.IsDone() ? lists2.CurrentList() : nsFrameList();
9924 0 : int32_t l1 = kids1.GetLength();
9925 0 : int32_t l2 = kids2.GetLength();
9926 0 : if (l1 != l2) {
9927 0 : ok = false;
9928 0 : LogVerifyMessage(kids1.FirstChild(), kids2.FirstChild(),
9929 0 : "child counts don't match: ");
9930 0 : printf("%d != %d\n", l1, l2);
9931 0 : if (0 == (VERIFY_REFLOW_ALL & gVerifyReflowFlags)) {
9932 0 : break;
9933 : }
9934 : }
9935 :
9936 0 : LayoutDeviceIntRect r1, r2;
9937 : nsView* v1;
9938 : nsView* v2;
9939 0 : for (nsFrameList::Enumerator e1(kids1), e2(kids2);
9940 : ;
9941 0 : e1.Next(), e2.Next()) {
9942 0 : nsIFrame* k1 = e1.get();
9943 0 : nsIFrame* k2 = e2.get();
9944 0 : if (((nullptr == k1) && (nullptr != k2)) ||
9945 0 : ((nullptr != k1) && (nullptr == k2))) {
9946 0 : ok = false;
9947 0 : LogVerifyMessage(k1, k2, "child lists are different\n");
9948 0 : break;
9949 : }
9950 0 : else if (nullptr != k1) {
9951 : // Verify that the frames are the same size
9952 0 : if (!k1->GetRect().IsEqualInterior(k2->GetRect())) {
9953 0 : ok = false;
9954 0 : LogVerifyMessage(k1, k2, "(frame rects)", k1->GetRect(), k2->GetRect());
9955 : }
9956 :
9957 : // Make sure either both have views or neither have views; if they
9958 : // do have views, make sure the views are the same size. If the
9959 : // views have widgets, make sure they both do or neither does. If
9960 : // they do, make sure the widgets are the same size.
9961 0 : v1 = k1->GetView();
9962 0 : v2 = k2->GetView();
9963 0 : if (((nullptr == v1) && (nullptr != v2)) ||
9964 0 : ((nullptr != v1) && (nullptr == v2))) {
9965 0 : ok = false;
9966 0 : LogVerifyMessage(k1, k2, "child views are not matched\n");
9967 : }
9968 0 : else if (nullptr != v1) {
9969 0 : if (!v1->GetBounds().IsEqualInterior(v2->GetBounds())) {
9970 0 : LogVerifyMessage(k1, k2, "(view rects)", v1->GetBounds(), v2->GetBounds());
9971 : }
9972 :
9973 0 : nsIWidget* w1 = v1->GetWidget();
9974 0 : nsIWidget* w2 = v2->GetWidget();
9975 0 : if (((nullptr == w1) && (nullptr != w2)) ||
9976 0 : ((nullptr != w1) && (nullptr == w2))) {
9977 0 : ok = false;
9978 0 : LogVerifyMessage(k1, k2, "child widgets are not matched\n");
9979 : }
9980 0 : else if (nullptr != w1) {
9981 0 : r1 = w1->GetBounds();
9982 0 : r2 = w2->GetBounds();
9983 0 : if (!r1.IsEqualEdges(r2)) {
9984 : LogVerifyMessage(k1, k2, "(widget rects)",
9985 0 : r1.ToUnknownRect(), r2.ToUnknownRect());
9986 : }
9987 : }
9988 : }
9989 0 : if (!ok && (0 == (VERIFY_REFLOW_ALL & gVerifyReflowFlags))) {
9990 0 : break;
9991 : }
9992 :
9993 : // XXX Should perhaps compare their float managers.
9994 :
9995 : // Compare the sub-trees too
9996 0 : if (!CompareTrees(aFirstPresContext, k1, aSecondPresContext, k2)) {
9997 0 : ok = false;
9998 0 : if (0 == (VERIFY_REFLOW_ALL & gVerifyReflowFlags)) {
9999 0 : break;
10000 : }
10001 : }
10002 : }
10003 : else {
10004 0 : break;
10005 : }
10006 0 : }
10007 0 : if (!ok && (0 == (VERIFY_REFLOW_ALL & gVerifyReflowFlags))) {
10008 0 : break;
10009 : }
10010 :
10011 0 : lists1.Next();
10012 0 : lists2.Next();
10013 0 : if (lists1.IsDone() != lists2.IsDone() ||
10014 0 : (!lists1.IsDone() && lists1.CurrentID() != lists2.CurrentID())) {
10015 0 : if (0 == (VERIFY_REFLOW_ALL & gVerifyReflowFlags)) {
10016 0 : ok = false;
10017 : }
10018 0 : LogVerifyMessage(kids1.FirstChild(), kids2.FirstChild(),
10019 0 : "child list names are not matched: ");
10020 0 : fprintf(stdout, "%s != %s\n",
10021 0 : !lists1.IsDone() ? mozilla::layout::ChildListName(lists1.CurrentID()) : "(null)",
10022 0 : !lists2.IsDone() ? mozilla::layout::ChildListName(lists2.CurrentID()) : "(null)");
10023 0 : break;
10024 : }
10025 0 : } while (ok && !lists1.IsDone());
10026 :
10027 0 : return ok;
10028 : }
10029 : #endif
10030 :
10031 : #if 0
10032 : static nsIFrame*
10033 : FindTopFrame(nsIFrame* aRoot)
10034 : {
10035 : if (aRoot) {
10036 : nsIContent* content = aRoot->GetContent();
10037 : if (content) {
10038 : nsIAtom* tag;
10039 : content->GetTag(tag);
10040 : if (nullptr != tag) {
10041 : NS_RELEASE(tag);
10042 : return aRoot;
10043 : }
10044 : }
10045 :
10046 : // Try one of the children
10047 : for (nsIFrame* kid : aRoot->PrincipalChildList()) {
10048 : nsIFrame* result = FindTopFrame(kid);
10049 : if (nullptr != result) {
10050 : return result;
10051 : }
10052 : }
10053 : }
10054 : return nullptr;
10055 : }
10056 : #endif
10057 :
10058 :
10059 : #ifdef DEBUG
10060 :
10061 : nsStyleSet*
10062 0 : PresShell::CloneStyleSet(nsStyleSet* aSet)
10063 : {
10064 0 : nsStyleSet* clone = new nsStyleSet();
10065 :
10066 0 : int32_t i, n = aSet->SheetCount(SheetType::Override);
10067 0 : for (i = 0; i < n; i++) {
10068 0 : CSSStyleSheet* ss = aSet->StyleSheetAt(SheetType::Override, i);
10069 0 : if (ss)
10070 0 : clone->AppendStyleSheet(SheetType::Override, ss);
10071 : }
10072 :
10073 : // The document expects to insert document stylesheets itself
10074 : #if 0
10075 : n = aSet->SheetCount(SheetType::Doc);
10076 : for (i = 0; i < n; i++) {
10077 : CSSStyleSheet* ss = aSet->StyleSheetAt(SheetType::Doc, i);
10078 : if (ss)
10079 : clone->AddDocStyleSheet(ss, mDocument);
10080 : }
10081 : #endif
10082 :
10083 0 : n = aSet->SheetCount(SheetType::User);
10084 0 : for (i = 0; i < n; i++) {
10085 0 : CSSStyleSheet* ss = aSet->StyleSheetAt(SheetType::User, i);
10086 0 : if (ss)
10087 0 : clone->AppendStyleSheet(SheetType::User, ss);
10088 : }
10089 :
10090 0 : n = aSet->SheetCount(SheetType::Agent);
10091 0 : for (i = 0; i < n; i++) {
10092 0 : CSSStyleSheet* ss = aSet->StyleSheetAt(SheetType::Agent, i);
10093 0 : if (ss)
10094 0 : clone->AppendStyleSheet(SheetType::Agent, ss);
10095 : }
10096 0 : return clone;
10097 : }
10098 :
10099 : // After an incremental reflow, we verify the correctness by doing a
10100 : // full reflow into a fresh frame tree.
10101 : bool
10102 0 : PresShell::VerifyIncrementalReflow()
10103 : {
10104 0 : if (VERIFY_REFLOW_NOISY & gVerifyReflowFlags) {
10105 0 : printf("Building Verification Tree...\n");
10106 : }
10107 :
10108 : // Create a presentation context to view the new frame tree
10109 : RefPtr<nsPresContext> cx =
10110 0 : new nsRootPresContext(mDocument, mPresContext->IsPaginated() ?
10111 : nsPresContext::eContext_PrintPreview :
10112 0 : nsPresContext::eContext_Galley);
10113 0 : NS_ENSURE_TRUE(cx, false);
10114 :
10115 0 : nsDeviceContext *dc = mPresContext->DeviceContext();
10116 0 : nsresult rv = cx->Init(dc);
10117 0 : NS_ENSURE_SUCCESS(rv, false);
10118 :
10119 : // Get our scrolling preference
10120 0 : nsView* rootView = mViewManager->GetRootView();
10121 0 : NS_ENSURE_TRUE(rootView->HasWidget(), false);
10122 0 : nsIWidget* parentWidget = rootView->GetWidget();
10123 :
10124 : // Create a new view manager.
10125 0 : RefPtr<nsViewManager> vm = new nsViewManager();
10126 0 : NS_ENSURE_TRUE(vm, false);
10127 0 : rv = vm->Init(dc);
10128 0 : NS_ENSURE_SUCCESS(rv, false);
10129 :
10130 : // Create a child window of the parent that is our "root view/window"
10131 : // Create a view
10132 0 : nsRect tbounds = mPresContext->GetVisibleArea();
10133 0 : nsView* view = vm->CreateView(tbounds, nullptr);
10134 0 : NS_ENSURE_TRUE(view, false);
10135 :
10136 : //now create the widget for the view
10137 0 : rv = view->CreateWidgetForParent(parentWidget, nullptr, true);
10138 0 : NS_ENSURE_SUCCESS(rv, false);
10139 :
10140 : // Setup hierarchical relationship in view manager
10141 0 : vm->SetRootView(view);
10142 :
10143 : // Make the new presentation context the same size as our
10144 : // presentation context.
10145 0 : nsRect r = mPresContext->GetVisibleArea();
10146 0 : cx->SetVisibleArea(r);
10147 :
10148 : // Create a new presentation shell to view the document. Use the
10149 : // exact same style information that this document has.
10150 0 : if (mStyleSet->IsServo()) {
10151 0 : NS_WARNING("VerifyIncrementalReflow cannot handle ServoStyleSets");
10152 0 : return true;
10153 : }
10154 0 : nsAutoPtr<nsStyleSet> newSet(CloneStyleSet(mStyleSet->AsGecko()));
10155 0 : nsCOMPtr<nsIPresShell> sh = mDocument->CreateShell(cx, vm, newSet.get());
10156 0 : NS_ENSURE_TRUE(sh, false);
10157 0 : newSet.forget();
10158 : // Note that after we create the shell, we must make sure to destroy it
10159 0 : sh->SetVerifyReflowEnable(false); // turn off verify reflow while we're reflowing the test frame tree
10160 0 : vm->SetPresShell(sh);
10161 : {
10162 0 : nsAutoCauseReflowNotifier crNotifier(this);
10163 0 : sh->Initialize(r.width, r.height);
10164 : }
10165 0 : mDocument->BindingManager()->ProcessAttachedQueue();
10166 0 : sh->FlushPendingNotifications(FlushType::Layout);
10167 0 : sh->SetVerifyReflowEnable(true); // turn on verify reflow again now that we're done reflowing the test frame tree
10168 : // Force the non-primary presshell to unsuppress; it doesn't want to normally
10169 : // because it thinks it's hidden
10170 0 : ((PresShell*)sh.get())->mPaintingSuppressed = false;
10171 0 : if (VERIFY_REFLOW_NOISY & gVerifyReflowFlags) {
10172 0 : printf("Verification Tree built, comparing...\n");
10173 : }
10174 :
10175 : // Now that the document has been reflowed, use its frame tree to
10176 : // compare against our frame tree.
10177 0 : nsIFrame* root1 = mFrameConstructor->GetRootFrame();
10178 0 : nsIFrame* root2 = sh->GetRootFrame();
10179 0 : bool ok = CompareTrees(mPresContext, root1, cx, root2);
10180 0 : if (!ok && (VERIFY_REFLOW_NOISY & gVerifyReflowFlags)) {
10181 0 : printf("Verify reflow failed, primary tree:\n");
10182 0 : root1->List(stdout, 0);
10183 0 : printf("Verification tree:\n");
10184 0 : root2->List(stdout, 0);
10185 : }
10186 :
10187 : #if 0
10188 : // Sample code for dumping page to png
10189 : // XXX Needs to be made more flexible
10190 : if (!ok) {
10191 : nsString stra;
10192 : static int num = 0;
10193 : stra.AppendLiteral("C:\\mozilla\\mozilla\\debug\\filea");
10194 : stra.AppendInt(num);
10195 : stra.AppendLiteral(".png");
10196 : gfxUtils::WriteAsPNG(sh, stra);
10197 : nsString strb;
10198 : strb.AppendLiteral("C:\\mozilla\\mozilla\\debug\\fileb");
10199 : strb.AppendInt(num);
10200 : strb.AppendLiteral(".png");
10201 : gfxUtils::WriteAsPNG(sh, strb);
10202 : ++num;
10203 : }
10204 : #endif
10205 :
10206 0 : sh->EndObservingDocument();
10207 0 : sh->Destroy();
10208 0 : if (VERIFY_REFLOW_NOISY & gVerifyReflowFlags) {
10209 0 : printf("Finished Verifying Reflow...\n");
10210 : }
10211 :
10212 0 : return ok;
10213 : }
10214 :
10215 : // Layout debugging hooks
10216 : void
10217 0 : PresShell::ListStyleContexts(FILE *out, int32_t aIndent)
10218 : {
10219 0 : nsIFrame* rootFrame = GetRootFrame();
10220 0 : if (rootFrame) {
10221 0 : rootFrame->StyleContext()->List(out, aIndent);
10222 : }
10223 :
10224 : // The root element's frame's style context is the root of a separate tree.
10225 0 : Element* rootElement = mDocument->GetRootElement();
10226 0 : if (rootElement) {
10227 0 : nsIFrame* rootElementFrame = rootElement->GetPrimaryFrame();
10228 0 : if (rootElementFrame) {
10229 0 : rootElementFrame->StyleContext()->List(out, aIndent);
10230 : }
10231 : }
10232 0 : }
10233 :
10234 : void
10235 0 : PresShell::ListStyleSheets(FILE *out, int32_t aIndent)
10236 : {
10237 0 : int32_t sheetCount = mStyleSet->SheetCount(SheetType::Doc);
10238 0 : for (int32_t i = 0; i < sheetCount; ++i) {
10239 0 : mStyleSet->StyleSheetAt(SheetType::Doc, i)->List(out, aIndent);
10240 0 : fputs("\n", out);
10241 : }
10242 0 : }
10243 :
10244 : void
10245 25 : PresShell::VerifyStyleTree()
10246 : {
10247 25 : VERIFY_STYLE_TREE;
10248 25 : }
10249 : #endif
10250 :
10251 : //=============================================================
10252 : //=============================================================
10253 : //-- Debug Reflow Counts
10254 : //=============================================================
10255 : //=============================================================
10256 : #ifdef MOZ_REFLOW_PERF
10257 : //-------------------------------------------------------------
10258 : void
10259 4 : PresShell::DumpReflows()
10260 : {
10261 4 : if (mReflowCountMgr) {
10262 8 : nsAutoCString uriStr;
10263 4 : if (mDocument) {
10264 4 : nsIURI *uri = mDocument->GetDocumentURI();
10265 4 : if (uri) {
10266 4 : uri->GetPath(uriStr);
10267 : }
10268 : }
10269 4 : mReflowCountMgr->DisplayTotals(uriStr.get());
10270 4 : mReflowCountMgr->DisplayHTMLTotals(uriStr.get());
10271 4 : mReflowCountMgr->DisplayDiffsInTotals();
10272 : }
10273 4 : }
10274 :
10275 : //-------------------------------------------------------------
10276 : void
10277 735 : PresShell::CountReflows(const char * aName, nsIFrame * aFrame)
10278 : {
10279 735 : if (mReflowCountMgr) {
10280 735 : mReflowCountMgr->Add(aName, aFrame);
10281 : }
10282 735 : }
10283 :
10284 : //-------------------------------------------------------------
10285 : void
10286 0 : PresShell::PaintCount(const char * aName,
10287 : gfxContext* aRenderingContext,
10288 : nsPresContext* aPresContext,
10289 : nsIFrame * aFrame,
10290 : const nsPoint& aOffset,
10291 : uint32_t aColor)
10292 : {
10293 0 : if (mReflowCountMgr) {
10294 0 : mReflowCountMgr->PaintCount(aName, aRenderingContext, aPresContext,
10295 0 : aFrame, aOffset, aColor);
10296 : }
10297 0 : }
10298 :
10299 : //-------------------------------------------------------------
10300 : void
10301 0 : PresShell::SetPaintFrameCount(bool aPaintFrameCounts)
10302 : {
10303 0 : if (mReflowCountMgr) {
10304 0 : mReflowCountMgr->SetPaintFrameCounts(aPaintFrameCounts);
10305 : }
10306 0 : }
10307 :
10308 : bool
10309 121 : PresShell::IsPaintingFrameCounts()
10310 : {
10311 121 : if (mReflowCountMgr)
10312 121 : return mReflowCountMgr->IsPaintingFrameCounts();
10313 0 : return false;
10314 : }
10315 :
10316 : //------------------------------------------------------------------
10317 : //-- Reflow Counter Classes Impls
10318 : //------------------------------------------------------------------
10319 :
10320 : //------------------------------------------------------------------
10321 0 : ReflowCounter::ReflowCounter(ReflowCountMgr * aMgr) :
10322 0 : mMgr(aMgr)
10323 : {
10324 0 : ClearTotals();
10325 0 : SetTotalsCache();
10326 0 : }
10327 :
10328 : //------------------------------------------------------------------
10329 0 : ReflowCounter::~ReflowCounter()
10330 : {
10331 :
10332 0 : }
10333 :
10334 : //------------------------------------------------------------------
10335 0 : void ReflowCounter::ClearTotals()
10336 : {
10337 0 : mTotal = 0;
10338 0 : }
10339 :
10340 : //------------------------------------------------------------------
10341 0 : void ReflowCounter::SetTotalsCache()
10342 : {
10343 0 : mCacheTotal = mTotal;
10344 0 : }
10345 :
10346 : //------------------------------------------------------------------
10347 0 : void ReflowCounter::CalcDiffInTotals()
10348 : {
10349 0 : mCacheTotal = mTotal - mCacheTotal;
10350 0 : }
10351 :
10352 : //------------------------------------------------------------------
10353 0 : void ReflowCounter::DisplayTotals(const char * aStr)
10354 : {
10355 0 : DisplayTotals(mTotal, aStr?aStr:"Totals");
10356 0 : }
10357 :
10358 : //------------------------------------------------------------------
10359 0 : void ReflowCounter::DisplayDiffTotals(const char * aStr)
10360 : {
10361 0 : DisplayTotals(mCacheTotal, aStr?aStr:"Diff Totals");
10362 0 : }
10363 :
10364 : //------------------------------------------------------------------
10365 0 : void ReflowCounter::DisplayHTMLTotals(const char * aStr)
10366 : {
10367 0 : DisplayHTMLTotals(mTotal, aStr?aStr:"Totals");
10368 0 : }
10369 :
10370 : //------------------------------------------------------------------
10371 0 : void ReflowCounter::DisplayTotals(uint32_t aTotal, const char * aTitle)
10372 : {
10373 : // figure total
10374 0 : if (aTotal == 0) {
10375 0 : return;
10376 : }
10377 0 : ReflowCounter * gTots = (ReflowCounter *)mMgr->LookUp(kGrandTotalsStr);
10378 :
10379 0 : printf("%25s\t", aTitle);
10380 0 : printf("%d\t", aTotal);
10381 0 : if (gTots != this && aTotal > 0) {
10382 0 : gTots->Add(aTotal);
10383 : }
10384 : }
10385 :
10386 : //------------------------------------------------------------------
10387 0 : void ReflowCounter::DisplayHTMLTotals(uint32_t aTotal, const char * aTitle)
10388 : {
10389 0 : if (aTotal == 0) {
10390 0 : return;
10391 : }
10392 :
10393 0 : ReflowCounter * gTots = (ReflowCounter *)mMgr->LookUp(kGrandTotalsStr);
10394 0 : FILE * fd = mMgr->GetOutFile();
10395 0 : if (!fd) {
10396 0 : return;
10397 : }
10398 :
10399 0 : fprintf(fd, "<tr><td><center>%s</center></td>", aTitle);
10400 0 : fprintf(fd, "<td><center>%d</center></td></tr>\n", aTotal);
10401 :
10402 0 : if (gTots != this && aTotal > 0) {
10403 0 : gTots->Add(aTotal);
10404 : }
10405 : }
10406 :
10407 : //------------------------------------------------------------------
10408 : //-- ReflowCountMgr
10409 : //------------------------------------------------------------------
10410 :
10411 : #define KEY_BUF_SIZE_FOR_PTR 24 // adequate char[] buffer to sprintf a pointer
10412 :
10413 28 : ReflowCountMgr::ReflowCountMgr()
10414 : {
10415 28 : mCounts = PL_NewHashTable(10, PL_HashString, PL_CompareStrings,
10416 : PL_CompareValues, nullptr, nullptr);
10417 28 : mIndiFrameCounts = PL_NewHashTable(10, PL_HashString, PL_CompareStrings,
10418 : PL_CompareValues, nullptr, nullptr);
10419 28 : mCycledOnce = false;
10420 28 : mDumpFrameCounts = false;
10421 28 : mDumpFrameByFrameCounts = false;
10422 28 : mPaintFrameByFrameCounts = false;
10423 28 : }
10424 :
10425 : //------------------------------------------------------------------
10426 12 : ReflowCountMgr::~ReflowCountMgr()
10427 : {
10428 4 : CleanUp();
10429 12 : }
10430 :
10431 : //------------------------------------------------------------------
10432 0 : ReflowCounter * ReflowCountMgr::LookUp(const char * aName)
10433 : {
10434 0 : if (nullptr != mCounts) {
10435 0 : ReflowCounter * counter = (ReflowCounter *)PL_HashTableLookup(mCounts, aName);
10436 0 : return counter;
10437 : }
10438 0 : return nullptr;
10439 :
10440 : }
10441 :
10442 : //------------------------------------------------------------------
10443 735 : void ReflowCountMgr::Add(const char * aName, nsIFrame * aFrame)
10444 : {
10445 735 : NS_ASSERTION(aName != nullptr, "Name shouldn't be null!");
10446 :
10447 735 : if (mDumpFrameCounts && nullptr != mCounts) {
10448 0 : ReflowCounter * counter = (ReflowCounter *)PL_HashTableLookup(mCounts, aName);
10449 0 : if (counter == nullptr) {
10450 0 : counter = new ReflowCounter(this);
10451 0 : char * name = NS_strdup(aName);
10452 0 : NS_ASSERTION(name != nullptr, "null ptr");
10453 0 : PL_HashTableAdd(mCounts, name, counter);
10454 : }
10455 0 : counter->Add();
10456 : }
10457 :
10458 735 : if ((mDumpFrameByFrameCounts || mPaintFrameByFrameCounts) &&
10459 0 : nullptr != mIndiFrameCounts &&
10460 : aFrame != nullptr) {
10461 : char key[KEY_BUF_SIZE_FOR_PTR];
10462 0 : SprintfLiteral(key, "%p", (void*)aFrame);
10463 0 : IndiReflowCounter * counter = (IndiReflowCounter *)PL_HashTableLookup(mIndiFrameCounts, key);
10464 0 : if (counter == nullptr) {
10465 0 : counter = new IndiReflowCounter(this);
10466 0 : counter->mFrame = aFrame;
10467 0 : counter->mName.AssignASCII(aName);
10468 0 : PL_HashTableAdd(mIndiFrameCounts, NS_strdup(key), counter);
10469 : }
10470 : // this eliminates extra counts from super classes
10471 0 : if (counter != nullptr && counter->mName.EqualsASCII(aName)) {
10472 0 : counter->mCount++;
10473 0 : counter->mCounter.Add(1);
10474 : }
10475 : }
10476 735 : }
10477 :
10478 : //------------------------------------------------------------------
10479 0 : void ReflowCountMgr::PaintCount(const char* aName,
10480 : gfxContext* aRenderingContext,
10481 : nsPresContext* aPresContext,
10482 : nsIFrame* aFrame,
10483 : const nsPoint& aOffset,
10484 : uint32_t aColor)
10485 : {
10486 0 : if (mPaintFrameByFrameCounts &&
10487 0 : nullptr != mIndiFrameCounts &&
10488 : aFrame != nullptr) {
10489 : char key[KEY_BUF_SIZE_FOR_PTR];
10490 0 : SprintfLiteral(key, "%p", (void*)aFrame);
10491 : IndiReflowCounter * counter =
10492 0 : (IndiReflowCounter *)PL_HashTableLookup(mIndiFrameCounts, key);
10493 0 : if (counter != nullptr && counter->mName.EqualsASCII(aName)) {
10494 0 : DrawTarget* drawTarget = aRenderingContext->GetDrawTarget();
10495 0 : int32_t appUnitsPerDevPixel = aPresContext->AppUnitsPerDevPixel();
10496 :
10497 0 : aRenderingContext->Save();
10498 : gfxPoint devPixelOffset =
10499 0 : nsLayoutUtils::PointToGfxPoint(aOffset, appUnitsPerDevPixel);
10500 : aRenderingContext->SetMatrix(
10501 0 : aRenderingContext->CurrentMatrix().PreTranslate(devPixelOffset));
10502 :
10503 : // We don't care about the document language or user fonts here;
10504 : // just get a default Latin font.
10505 0 : nsFont font(eFamily_serif, nsPresContext::CSSPixelsToAppUnits(11));
10506 0 : nsFontMetrics::Params params;
10507 0 : params.language = nsGkAtoms::x_western;
10508 0 : params.textPerf = aPresContext->GetTextPerfMetrics();
10509 : RefPtr<nsFontMetrics> fm =
10510 0 : aPresContext->DeviceContext()->GetMetricsFor(font, params);
10511 :
10512 : char buf[16];
10513 0 : int len = SprintfLiteral(buf, "%d", counter->mCount);
10514 0 : nscoord x = 0, y = fm->MaxAscent();
10515 0 : nscoord width, height = fm->MaxHeight();
10516 0 : fm->SetTextRunRTL(false);
10517 0 : width = fm->GetWidth(buf, len, drawTarget);
10518 :
10519 0 : Color color;
10520 0 : Color color2;
10521 0 : if (aColor != 0) {
10522 0 : color = Color::FromABGR(aColor);
10523 0 : color2 = Color(0.f, 0.f, 0.f);
10524 : } else {
10525 0 : gfx::Float rc = 0.f, gc = 0.f, bc = 0.f;
10526 0 : if (counter->mCount < 5) {
10527 0 : rc = 1.f;
10528 0 : gc = 1.f;
10529 0 : } else if (counter->mCount < 11) {
10530 0 : gc = 1.f;
10531 : } else {
10532 0 : rc = 1.f;
10533 : }
10534 0 : color = Color(rc, gc, bc);
10535 0 : color2 = Color(rc/2, gc/2, bc/2);
10536 : }
10537 :
10538 0 : nsRect rect(0,0, width+15, height+15);
10539 : Rect devPxRect =
10540 0 : NSRectToSnappedRect(rect, appUnitsPerDevPixel, *drawTarget);
10541 0 : ColorPattern black(ToDeviceColor(Color(0.f, 0.f, 0.f, 1.f)));
10542 0 : drawTarget->FillRect(devPxRect, black);
10543 :
10544 0 : aRenderingContext->SetColor(color2);
10545 0 : fm->DrawString(buf, len, x+15, y+15, aRenderingContext);
10546 0 : aRenderingContext->SetColor(color);
10547 0 : fm->DrawString(buf, len, x, y, aRenderingContext);
10548 :
10549 0 : aRenderingContext->Restore();
10550 : }
10551 : }
10552 0 : }
10553 :
10554 : //------------------------------------------------------------------
10555 0 : int ReflowCountMgr::RemoveItems(PLHashEntry *he, int i, void *arg)
10556 : {
10557 0 : char *str = (char *)he->key;
10558 0 : ReflowCounter * counter = (ReflowCounter *)he->value;
10559 0 : delete counter;
10560 0 : free(str);
10561 :
10562 0 : return HT_ENUMERATE_REMOVE;
10563 : }
10564 :
10565 : //------------------------------------------------------------------
10566 0 : int ReflowCountMgr::RemoveIndiItems(PLHashEntry *he, int i, void *arg)
10567 : {
10568 0 : char *str = (char *)he->key;
10569 0 : IndiReflowCounter * counter = (IndiReflowCounter *)he->value;
10570 0 : delete counter;
10571 0 : free(str);
10572 :
10573 0 : return HT_ENUMERATE_REMOVE;
10574 : }
10575 :
10576 : //------------------------------------------------------------------
10577 4 : void ReflowCountMgr::CleanUp()
10578 : {
10579 4 : if (nullptr != mCounts) {
10580 4 : PL_HashTableEnumerateEntries(mCounts, RemoveItems, nullptr);
10581 4 : PL_HashTableDestroy(mCounts);
10582 4 : mCounts = nullptr;
10583 : }
10584 :
10585 4 : if (nullptr != mIndiFrameCounts) {
10586 4 : PL_HashTableEnumerateEntries(mIndiFrameCounts, RemoveIndiItems, nullptr);
10587 4 : PL_HashTableDestroy(mIndiFrameCounts);
10588 4 : mIndiFrameCounts = nullptr;
10589 : }
10590 4 : }
10591 :
10592 : //------------------------------------------------------------------
10593 0 : int ReflowCountMgr::DoSingleTotal(PLHashEntry *he, int i, void *arg)
10594 : {
10595 0 : char *str = (char *)he->key;
10596 0 : ReflowCounter * counter = (ReflowCounter *)he->value;
10597 :
10598 0 : counter->DisplayTotals(str);
10599 :
10600 0 : return HT_ENUMERATE_NEXT;
10601 : }
10602 :
10603 : //------------------------------------------------------------------
10604 0 : void ReflowCountMgr::DoGrandTotals()
10605 : {
10606 0 : if (nullptr != mCounts) {
10607 0 : ReflowCounter * gTots = (ReflowCounter *)PL_HashTableLookup(mCounts, kGrandTotalsStr);
10608 0 : if (gTots == nullptr) {
10609 0 : gTots = new ReflowCounter(this);
10610 0 : PL_HashTableAdd(mCounts, NS_strdup(kGrandTotalsStr), gTots);
10611 : } else {
10612 0 : gTots->ClearTotals();
10613 : }
10614 :
10615 0 : printf("\t\t\t\tTotal\n");
10616 0 : for (uint32_t i=0;i<78;i++) {
10617 0 : printf("-");
10618 : }
10619 0 : printf("\n");
10620 0 : PL_HashTableEnumerateEntries(mCounts, DoSingleTotal, this);
10621 : }
10622 0 : }
10623 :
10624 0 : static void RecurseIndiTotals(nsPresContext* aPresContext,
10625 : PLHashTable * aHT,
10626 : nsIFrame * aParentFrame,
10627 : int32_t aLevel)
10628 : {
10629 0 : if (aParentFrame == nullptr) {
10630 0 : return;
10631 : }
10632 :
10633 : char key[KEY_BUF_SIZE_FOR_PTR];
10634 0 : SprintfLiteral(key, "%p", (void*)aParentFrame);
10635 0 : IndiReflowCounter * counter = (IndiReflowCounter *)PL_HashTableLookup(aHT, key);
10636 0 : if (counter) {
10637 0 : counter->mHasBeenOutput = true;
10638 0 : char * name = ToNewCString(counter->mName);
10639 0 : for (int32_t i=0;i<aLevel;i++) printf(" ");
10640 0 : printf("%s - %p [%d][", name, (void*)aParentFrame, counter->mCount);
10641 0 : printf("%d", counter->mCounter.GetTotal());
10642 0 : printf("]\n");
10643 0 : free(name);
10644 : }
10645 :
10646 0 : for (nsIFrame* child : aParentFrame->PrincipalChildList()) {
10647 0 : RecurseIndiTotals(aPresContext, aHT, child, aLevel+1);
10648 : }
10649 :
10650 : }
10651 :
10652 : //------------------------------------------------------------------
10653 0 : int ReflowCountMgr::DoSingleIndi(PLHashEntry *he, int i, void *arg)
10654 : {
10655 0 : IndiReflowCounter * counter = (IndiReflowCounter *)he->value;
10656 0 : if (counter && !counter->mHasBeenOutput) {
10657 0 : char * name = ToNewCString(counter->mName);
10658 0 : printf("%s - %p [%d][", name, (void*)counter->mFrame, counter->mCount);
10659 0 : printf("%d", counter->mCounter.GetTotal());
10660 0 : printf("]\n");
10661 0 : free(name);
10662 : }
10663 0 : return HT_ENUMERATE_NEXT;
10664 : }
10665 :
10666 : //------------------------------------------------------------------
10667 0 : void ReflowCountMgr::DoIndiTotalsTree()
10668 : {
10669 0 : if (nullptr != mCounts) {
10670 0 : printf("\n------------------------------------------------\n");
10671 0 : printf("-- Individual Frame Counts\n");
10672 0 : printf("------------------------------------------------\n");
10673 :
10674 0 : if (mPresShell) {
10675 0 : nsIFrame * rootFrame = mPresShell->FrameManager()->GetRootFrame();
10676 0 : RecurseIndiTotals(mPresContext, mIndiFrameCounts, rootFrame, 0);
10677 0 : printf("------------------------------------------------\n");
10678 0 : printf("-- Individual Counts of Frames not in Root Tree\n");
10679 0 : printf("------------------------------------------------\n");
10680 0 : PL_HashTableEnumerateEntries(mIndiFrameCounts, DoSingleIndi, this);
10681 : }
10682 : }
10683 0 : }
10684 :
10685 : //------------------------------------------------------------------
10686 0 : int ReflowCountMgr::DoSingleHTMLTotal(PLHashEntry *he, int i, void *arg)
10687 : {
10688 0 : char *str = (char *)he->key;
10689 0 : ReflowCounter * counter = (ReflowCounter *)he->value;
10690 :
10691 0 : counter->DisplayHTMLTotals(str);
10692 :
10693 0 : return HT_ENUMERATE_NEXT;
10694 : }
10695 :
10696 : //------------------------------------------------------------------
10697 0 : void ReflowCountMgr::DoGrandHTMLTotals()
10698 : {
10699 0 : if (nullptr != mCounts) {
10700 0 : ReflowCounter * gTots = (ReflowCounter *)PL_HashTableLookup(mCounts, kGrandTotalsStr);
10701 0 : if (gTots == nullptr) {
10702 0 : gTots = new ReflowCounter(this);
10703 0 : PL_HashTableAdd(mCounts, NS_strdup(kGrandTotalsStr), gTots);
10704 : } else {
10705 0 : gTots->ClearTotals();
10706 : }
10707 :
10708 : static const char * title[] = {"Class", "Reflows"};
10709 0 : fprintf(mFD, "<tr>");
10710 0 : for (uint32_t i=0; i < ArrayLength(title); i++) {
10711 0 : fprintf(mFD, "<td><center><b>%s<b></center></td>", title[i]);
10712 : }
10713 0 : fprintf(mFD, "</tr>\n");
10714 0 : PL_HashTableEnumerateEntries(mCounts, DoSingleHTMLTotal, this);
10715 : }
10716 0 : }
10717 :
10718 : //------------------------------------
10719 4 : void ReflowCountMgr::DisplayTotals(const char * aStr)
10720 : {
10721 : #ifdef DEBUG_rods
10722 : printf("%s\n", aStr?aStr:"No name");
10723 : #endif
10724 4 : if (mDumpFrameCounts) {
10725 0 : DoGrandTotals();
10726 : }
10727 4 : if (mDumpFrameByFrameCounts) {
10728 0 : DoIndiTotalsTree();
10729 : }
10730 :
10731 4 : }
10732 : //------------------------------------
10733 4 : void ReflowCountMgr::DisplayHTMLTotals(const char * aStr)
10734 : {
10735 : #ifdef WIN32x // XXX NOT XP!
10736 : char name[1024];
10737 :
10738 : char * sptr = strrchr(aStr, '/');
10739 : if (sptr) {
10740 : sptr++;
10741 : strcpy(name, sptr);
10742 : char * eptr = strrchr(name, '.');
10743 : if (eptr) {
10744 : *eptr = 0;
10745 : }
10746 : strcat(name, "_stats.html");
10747 : }
10748 : mFD = fopen(name, "w");
10749 : if (mFD) {
10750 : fprintf(mFD, "<html><head><title>Reflow Stats</title></head><body>\n");
10751 : const char * title = aStr?aStr:"No name";
10752 : fprintf(mFD, "<center><b>%s</b><br><table border=1 style=\"background-color:#e0e0e0\">", title);
10753 : DoGrandHTMLTotals();
10754 : fprintf(mFD, "</center></table>\n");
10755 : fprintf(mFD, "</body></html>\n");
10756 : fclose(mFD);
10757 : mFD = nullptr;
10758 : }
10759 : #endif // not XP!
10760 4 : }
10761 :
10762 : //------------------------------------------------------------------
10763 0 : int ReflowCountMgr::DoClearTotals(PLHashEntry *he, int i, void *arg)
10764 : {
10765 0 : ReflowCounter * counter = (ReflowCounter *)he->value;
10766 0 : counter->ClearTotals();
10767 :
10768 0 : return HT_ENUMERATE_NEXT;
10769 : }
10770 :
10771 : //------------------------------------------------------------------
10772 0 : void ReflowCountMgr::ClearTotals()
10773 : {
10774 0 : PL_HashTableEnumerateEntries(mCounts, DoClearTotals, this);
10775 0 : }
10776 :
10777 : //------------------------------------------------------------------
10778 0 : void ReflowCountMgr::ClearGrandTotals()
10779 : {
10780 0 : if (nullptr != mCounts) {
10781 0 : ReflowCounter * gTots = (ReflowCounter *)PL_HashTableLookup(mCounts, kGrandTotalsStr);
10782 0 : if (gTots == nullptr) {
10783 0 : gTots = new ReflowCounter(this);
10784 0 : PL_HashTableAdd(mCounts, NS_strdup(kGrandTotalsStr), gTots);
10785 : } else {
10786 0 : gTots->ClearTotals();
10787 0 : gTots->SetTotalsCache();
10788 : }
10789 : }
10790 0 : }
10791 :
10792 : //------------------------------------------------------------------
10793 0 : int ReflowCountMgr::DoDisplayDiffTotals(PLHashEntry *he, int i, void *arg)
10794 : {
10795 0 : bool cycledOnce = (arg != 0);
10796 :
10797 0 : char *str = (char *)he->key;
10798 0 : ReflowCounter * counter = (ReflowCounter *)he->value;
10799 :
10800 0 : if (cycledOnce) {
10801 0 : counter->CalcDiffInTotals();
10802 0 : counter->DisplayDiffTotals(str);
10803 : }
10804 0 : counter->SetTotalsCache();
10805 :
10806 0 : return HT_ENUMERATE_NEXT;
10807 : }
10808 :
10809 : //------------------------------------------------------------------
10810 4 : void ReflowCountMgr::DisplayDiffsInTotals()
10811 : {
10812 4 : if (mCycledOnce) {
10813 0 : printf("Differences\n");
10814 0 : for (int32_t i=0;i<78;i++) {
10815 0 : printf("-");
10816 : }
10817 0 : printf("\n");
10818 0 : ClearGrandTotals();
10819 : }
10820 4 : PL_HashTableEnumerateEntries(mCounts, DoDisplayDiffTotals, (void *)mCycledOnce);
10821 :
10822 4 : mCycledOnce = true;
10823 4 : }
10824 :
10825 : #endif // MOZ_REFLOW_PERF
10826 :
10827 0 : nsIFrame* nsIPresShell::GetAbsoluteContainingBlock(nsIFrame *aFrame)
10828 : {
10829 0 : return FrameConstructor()->GetAbsoluteContainingBlock(aFrame,
10830 0 : nsCSSFrameConstructor::ABS_POS);
10831 : }
10832 :
10833 : #ifdef ACCESSIBILITY
10834 : bool
10835 2396 : nsIPresShell::IsAccessibilityActive()
10836 : {
10837 2396 : return GetAccService() != nullptr;
10838 : }
10839 :
10840 : nsAccessibilityService*
10841 158 : nsIPresShell::AccService()
10842 : {
10843 158 : return GetAccService();
10844 : }
10845 : #endif
10846 :
10847 3 : void nsIPresShell::InitializeStatics()
10848 : {
10849 3 : MOZ_ASSERT(!sPointerCaptureList, "InitializeStatics called multiple times!");
10850 3 : sPointerCaptureList =
10851 3 : new nsClassHashtable<nsUint32HashKey, PointerCaptureInfo>;
10852 3 : sActivePointersIds = new nsClassHashtable<nsUint32HashKey, PointerInfo>;
10853 3 : }
10854 :
10855 0 : void nsIPresShell::ReleaseStatics()
10856 : {
10857 0 : MOZ_ASSERT(sPointerCaptureList, "ReleaseStatics called without Initialize!");
10858 0 : delete sPointerCaptureList;
10859 0 : sPointerCaptureList = nullptr;
10860 0 : delete sActivePointersIds;
10861 0 : sActivePointersIds = nullptr;
10862 0 : }
10863 :
10864 : // Asks our docshell whether we're active.
10865 28 : void PresShell::QueryIsActive()
10866 : {
10867 56 : nsCOMPtr<nsISupports> container = mPresContext->GetContainerWeak();
10868 28 : if (mDocument) {
10869 28 : nsIDocument* displayDoc = mDocument->GetDisplayDocument();
10870 28 : if (displayDoc) {
10871 : // Ok, we're an external resource document -- we need to use our display
10872 : // document's docshell to determine "IsActive" status, since we lack
10873 : // a container.
10874 0 : MOZ_ASSERT(!container,
10875 : "external resource doc shouldn't have its own container");
10876 :
10877 0 : nsIPresShell* displayPresShell = displayDoc->GetShell();
10878 0 : if (displayPresShell) {
10879 0 : container = displayPresShell->GetPresContext()->GetContainerWeak();
10880 : }
10881 : }
10882 : }
10883 :
10884 56 : nsCOMPtr<nsIDocShell> docshell(do_QueryInterface(container));
10885 28 : if (docshell) {
10886 : bool isActive;
10887 7 : nsresult rv = docshell->GetIsActive(&isActive);
10888 : // Even though in theory the docshell here could be "Inactive and
10889 : // Foreground", thus implying aIsHidden=false for SetIsActive(),
10890 : // this is a newly created PresShell so we'd like to invalidate anyway
10891 : // upon being made active to ensure that the contents get painted.
10892 7 : if (NS_SUCCEEDED(rv))
10893 7 : SetIsActive(isActive);
10894 : }
10895 28 : }
10896 :
10897 : // Helper for propagating mIsActive changes to external resources
10898 : static bool
10899 0 : SetExternalResourceIsActive(nsIDocument* aDocument, void* aClosure)
10900 : {
10901 0 : nsIPresShell* shell = aDocument->GetShell();
10902 0 : if (shell) {
10903 0 : shell->SetIsActive(*static_cast<bool*>(aClosure));
10904 : }
10905 0 : return true;
10906 : }
10907 :
10908 : static void
10909 0 : SetPluginIsActive(nsISupports* aSupports, void* aClosure)
10910 : {
10911 0 : nsCOMPtr<nsIContent> content(do_QueryInterface(aSupports));
10912 0 : if (!content) {
10913 0 : return;
10914 : }
10915 :
10916 0 : nsIFrame *frame = content->GetPrimaryFrame();
10917 0 : nsIObjectFrame *objectFrame = do_QueryFrame(frame);
10918 0 : if (objectFrame) {
10919 0 : objectFrame->SetIsDocumentActive(*static_cast<bool*>(aClosure));
10920 : }
10921 : }
10922 :
10923 : nsresult
10924 7 : PresShell::SetIsActive(bool aIsActive)
10925 : {
10926 7 : NS_PRECONDITION(mDocument, "should only be called with a document");
10927 :
10928 7 : mIsActive = aIsActive;
10929 :
10930 7 : nsPresContext* presContext = GetPresContext();
10931 14 : if (presContext &&
10932 7 : presContext->RefreshDriver()->GetPresContext() == presContext) {
10933 7 : presContext->RefreshDriver()->SetThrottled(!mIsActive);
10934 : }
10935 :
10936 : // Propagate state-change to my resource documents' PresShells
10937 7 : mDocument->EnumerateExternalResources(SetExternalResourceIsActive,
10938 7 : &aIsActive);
10939 7 : mDocument->EnumerateActivityObservers(SetPluginIsActive,
10940 7 : &aIsActive);
10941 7 : nsresult rv = UpdateImageLockingState();
10942 : #ifdef ACCESSIBILITY
10943 7 : if (aIsActive) {
10944 7 : nsAccessibilityService* accService = AccService();
10945 7 : if (accService) {
10946 0 : accService->PresShellActivated(this);
10947 : }
10948 : }
10949 : #endif
10950 7 : return rv;
10951 : }
10952 :
10953 : /*
10954 : * Determines the current image locking state. Called when one of the
10955 : * dependent factors changes.
10956 : */
10957 : nsresult
10958 7 : PresShell::UpdateImageLockingState()
10959 : {
10960 : // We're locked if we're both thawed and active.
10961 7 : bool locked = !mFrozen && mIsActive;
10962 :
10963 7 : nsresult rv = mDocument->ImageTracker()->SetLockingState(locked);
10964 :
10965 7 : if (locked) {
10966 : // Request decodes for visible image frames; we want to start decoding as
10967 : // quickly as possible when we get foregrounded to minimize flashing.
10968 7 : for (auto iter = mApproximatelyVisibleFrames.Iter(); !iter.Done(); iter.Next()) {
10969 0 : nsImageFrame* imageFrame = do_QueryFrame(iter.Get()->GetKey());
10970 0 : if (imageFrame) {
10971 0 : imageFrame->MaybeDecodeForPredictedSize();
10972 : }
10973 : }
10974 : }
10975 :
10976 7 : return rv;
10977 : }
10978 :
10979 : PresShell*
10980 10 : PresShell::GetRootPresShell()
10981 : {
10982 10 : if (mPresContext) {
10983 10 : nsPresContext* rootPresContext = mPresContext->GetRootPresContext();
10984 10 : if (rootPresContext) {
10985 10 : return static_cast<PresShell*>(rootPresContext->PresShell());
10986 : }
10987 : }
10988 0 : return nullptr;
10989 : }
10990 :
10991 : void
10992 21 : PresShell::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
10993 : nsArenaMemoryStats* aArenaObjectsSize,
10994 : size_t* aPresShellSize,
10995 : size_t* aStyleSetsSize,
10996 : size_t* aTextRunsSize,
10997 : size_t* aPresContextSize,
10998 : size_t* aFramePropertiesSize)
10999 : {
11000 21 : mFrameArena.AddSizeOfExcludingThis(aMallocSizeOf, aArenaObjectsSize);
11001 21 : *aPresShellSize += aMallocSizeOf(this);
11002 21 : if (mCaret) {
11003 21 : *aPresShellSize += mCaret->SizeOfIncludingThis(aMallocSizeOf);
11004 : }
11005 21 : *aPresShellSize += mApproximatelyVisibleFrames.ShallowSizeOfExcludingThis(aMallocSizeOf);
11006 21 : *aPresShellSize += mFramesToDirty.ShallowSizeOfExcludingThis(aMallocSizeOf);
11007 21 : *aPresShellSize += aArenaObjectsSize->mOther;
11008 :
11009 21 : if (nsStyleSet* styleSet = StyleSet()->GetAsGecko()) {
11010 21 : *aStyleSetsSize += styleSet->SizeOfIncludingThis(aMallocSizeOf);
11011 0 : } else if (ServoStyleSet* styleSet = StyleSet()->GetAsServo()) {
11012 0 : *aStyleSetsSize += styleSet->SizeOfIncludingThis(aMallocSizeOf);
11013 : } else {
11014 0 : MOZ_CRASH();
11015 : }
11016 :
11017 21 : *aTextRunsSize += SizeOfTextRuns(aMallocSizeOf);
11018 :
11019 21 : *aPresContextSize += mPresContext->SizeOfIncludingThis(aMallocSizeOf);
11020 :
11021 21 : nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
11022 21 : if (rootFrame) {
11023 21 : *aFramePropertiesSize +=
11024 21 : rootFrame->SizeOfFramePropertiesForTree(aMallocSizeOf);
11025 : }
11026 21 : }
11027 :
11028 : size_t
11029 21 : PresShell::SizeOfTextRuns(MallocSizeOf aMallocSizeOf) const
11030 : {
11031 21 : nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
11032 21 : if (!rootFrame) {
11033 0 : return 0;
11034 : }
11035 :
11036 : // clear the TEXT_RUN_MEMORY_ACCOUNTED flags
11037 : nsLayoutUtils::SizeOfTextRunsForFrames(rootFrame, nullptr,
11038 21 : /* clear = */true);
11039 :
11040 : // collect the total memory in use for textruns
11041 : return nsLayoutUtils::SizeOfTextRunsForFrames(rootFrame, aMallocSizeOf,
11042 21 : /* clear = */false);
11043 : }
11044 :
11045 : void
11046 0 : nsIPresShell::MarkFixedFramesForReflow(IntrinsicDirty aIntrinsicDirty)
11047 : {
11048 0 : nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
11049 0 : if (rootFrame) {
11050 0 : const nsFrameList& childList = rootFrame->GetChildList(nsIFrame::kFixedList);
11051 0 : for (nsIFrame* childFrame : childList) {
11052 0 : FrameNeedsReflow(childFrame, aIntrinsicDirty, NS_FRAME_IS_DIRTY);
11053 : }
11054 : }
11055 0 : }
11056 :
11057 : void
11058 0 : nsIPresShell::SetScrollPositionClampingScrollPortSize(nscoord aWidth, nscoord aHeight)
11059 : {
11060 0 : if (!mScrollPositionClampingScrollPortSizeSet ||
11061 0 : mScrollPositionClampingScrollPortSize.width != aWidth ||
11062 0 : mScrollPositionClampingScrollPortSize.height != aHeight) {
11063 0 : mScrollPositionClampingScrollPortSizeSet = true;
11064 0 : mScrollPositionClampingScrollPortSize.width = aWidth;
11065 0 : mScrollPositionClampingScrollPortSize.height = aHeight;
11066 :
11067 0 : if (nsIScrollableFrame* rootScrollFrame = GetRootScrollFrameAsScrollable()) {
11068 0 : rootScrollFrame->MarkScrollbarsDirtyForReflow();
11069 : }
11070 0 : MarkFixedFramesForReflow(nsIPresShell::eResize);
11071 : }
11072 0 : }
11073 :
11074 : void
11075 28 : PresShell::SetupFontInflation()
11076 : {
11077 28 : mFontSizeInflationEmPerLine = nsLayoutUtils::FontSizeInflationEmPerLine();
11078 28 : mFontSizeInflationMinTwips = nsLayoutUtils::FontSizeInflationMinTwips();
11079 28 : mFontSizeInflationLineThreshold = nsLayoutUtils::FontSizeInflationLineThreshold();
11080 28 : mFontSizeInflationForceEnabled = nsLayoutUtils::FontSizeInflationForceEnabled();
11081 28 : mFontSizeInflationDisabledInMasterProcess = nsLayoutUtils::FontSizeInflationDisabledInMasterProcess();
11082 :
11083 28 : NotifyFontSizeInflationEnabledIsDirty();
11084 28 : }
11085 :
11086 : void
11087 24 : nsIPresShell::RecomputeFontSizeInflationEnabled()
11088 : {
11089 24 : mFontSizeInflationEnabledIsDirty = false;
11090 24 : mFontSizeInflationEnabled = DetermineFontSizeInflationState();
11091 :
11092 24 : HandleSystemFontScale();
11093 24 : }
11094 :
11095 : bool
11096 24 : nsIPresShell::DetermineFontSizeInflationState()
11097 : {
11098 24 : MOZ_ASSERT(mPresContext, "our pres context should not be null");
11099 72 : if ((FontSizeInflationEmPerLine() == 0 &&
11100 24 : FontSizeInflationMinTwips() == 0) || mPresContext->IsChrome()) {
11101 24 : return false;
11102 : }
11103 :
11104 : // Force-enabling font inflation always trumps the heuristics here.
11105 0 : if (!FontSizeInflationForceEnabled()) {
11106 0 : if (TabChild* tab = TabChild::GetFrom(this)) {
11107 : // We're in a child process. Cancel inflation if we're not
11108 : // async-pan zoomed.
11109 0 : if (!tab->AsyncPanZoomEnabled()) {
11110 0 : return false;
11111 : }
11112 0 : } else if (XRE_IsParentProcess()) {
11113 : // We're in the master process. Cancel inflation if it's been
11114 : // explicitly disabled.
11115 0 : if (FontSizeInflationDisabledInMasterProcess()) {
11116 0 : return false;
11117 : }
11118 : }
11119 : }
11120 :
11121 : // XXXjwir3:
11122 : // See bug 706918, comment 23 for more information on this particular section
11123 : // of the code. We're using "screen size" in place of the size of the content
11124 : // area, because on mobile, these are close or equal. This will work for our
11125 : // purposes (bug 706198), but it will need to be changed in the future to be
11126 : // more correct when we bring the rest of the viewport code into platform.
11127 : // We actually want the size of the content area, in the event that we don't
11128 : // have any metadata about the width and/or height. On mobile, the screen size
11129 : // and the size of the content area are very close, or the same value.
11130 : // In XUL fennec, the content area is the size of the <browser> widget, but
11131 : // in native fennec, the content area is the size of the Gecko LayerView
11132 : // object.
11133 :
11134 : // TODO:
11135 : // Once bug 716575 has been resolved, this code should be changed so that it
11136 : // does the right thing on all platforms.
11137 : nsresult rv;
11138 : nsCOMPtr<nsIScreenManager> screenMgr =
11139 0 : do_GetService("@mozilla.org/gfx/screenmanager;1", &rv);
11140 0 : if (!NS_SUCCEEDED(rv)) {
11141 0 : return false;
11142 : }
11143 :
11144 0 : nsCOMPtr<nsIScreen> screen;
11145 0 : screenMgr->GetPrimaryScreen(getter_AddRefs(screen));
11146 0 : if (screen) {
11147 : int32_t screenLeft, screenTop, screenWidth, screenHeight;
11148 0 : screen->GetRect(&screenLeft, &screenTop, &screenWidth, &screenHeight);
11149 :
11150 : nsViewportInfo vInf =
11151 0 : GetDocument()->GetViewportInfo(ScreenIntSize(screenWidth, screenHeight));
11152 :
11153 0 : if (vInf.GetDefaultZoom() >= CSSToScreenScale(1.0f) || vInf.IsAutoSizeEnabled()) {
11154 0 : return false;
11155 : }
11156 : }
11157 :
11158 0 : return true;
11159 : }
11160 :
11161 : bool
11162 2400 : nsIPresShell::FontSizeInflationEnabled()
11163 : {
11164 2400 : if (mFontSizeInflationEnabledIsDirty) {
11165 24 : RecomputeFontSizeInflationEnabled();
11166 : }
11167 :
11168 2400 : return mFontSizeInflationEnabled;
11169 : }
11170 :
11171 : void
11172 24 : nsIPresShell::HandleSystemFontScale()
11173 : {
11174 24 : float fontScale = nsLayoutUtils::SystemFontScale();
11175 24 : if (fontScale == 0.0f) {
11176 0 : return;
11177 : }
11178 :
11179 24 : MOZ_ASSERT(mDocument && mPresContext, "our document and pres context should not be null");
11180 :
11181 24 : if (!mFontSizeInflationEnabled && !mDocument->IsSyntheticDocument()) {
11182 24 : mPresContext->SetSystemFontScale(fontScale);
11183 : } else {
11184 0 : mPresContext->SetSystemFontScale(1.0f);
11185 : }
11186 : }
11187 :
11188 : void
11189 0 : PresShell::PausePainting()
11190 : {
11191 0 : if (GetPresContext()->RefreshDriver()->GetPresContext() != GetPresContext())
11192 0 : return;
11193 :
11194 0 : mPaintingIsFrozen = true;
11195 0 : GetPresContext()->RefreshDriver()->Freeze();
11196 : }
11197 :
11198 : void
11199 0 : PresShell::ResumePainting()
11200 : {
11201 0 : if (GetPresContext()->RefreshDriver()->GetPresContext() != GetPresContext())
11202 0 : return;
11203 :
11204 0 : mPaintingIsFrozen = false;
11205 0 : GetPresContext()->RefreshDriver()->Thaw();
11206 : }
11207 :
11208 : void
11209 20 : nsIPresShell::SyncWindowProperties(nsView* aView)
11210 : {
11211 20 : nsIFrame* frame = aView->GetFrame();
11212 20 : if (frame && mPresContext) {
11213 : // CreateReferenceRenderingContext can return nullptr
11214 40 : RefPtr<gfxContext> rcx(CreateReferenceRenderingContext());
11215 20 : nsContainerFrame::SyncWindowProperties(mPresContext, frame, aView, rcx, 0);
11216 : }
11217 20 : }
11218 :
11219 : static SheetType
11220 0 : ToSheetType(uint32_t aServiceSheetType)
11221 : {
11222 0 : switch (aServiceSheetType) {
11223 : case nsIStyleSheetService::AGENT_SHEET:
11224 0 : return SheetType::Agent;
11225 : break;
11226 : case nsIStyleSheetService::USER_SHEET:
11227 0 : return SheetType::User;
11228 : break;
11229 : default:
11230 0 : MOZ_FALLTHROUGH_ASSERT("unexpected aSheetType value");
11231 : case nsIStyleSheetService::AUTHOR_SHEET:
11232 0 : return SheetType::Doc;
11233 : }
11234 : }
11235 :
11236 : nsresult
11237 0 : nsIPresShell::HasRuleProcessorUsedByMultipleStyleSets(uint32_t aSheetType,
11238 : bool* aRetVal)
11239 : {
11240 0 : *aRetVal = false;
11241 0 : if (nsStyleSet* styleSet = mStyleSet->GetAsGecko()) {
11242 : // ServoStyleSets do not have rule processors.
11243 0 : SheetType type = ToSheetType(aSheetType);
11244 0 : *aRetVal = styleSet->HasRuleProcessorUsedByMultipleStyleSets(type);
11245 : }
11246 0 : return NS_OK;
11247 : }
11248 :
11249 : void
11250 0 : PresShell::NotifyStyleSheetServiceSheetAdded(StyleSheet* aSheet,
11251 : uint32_t aSheetType)
11252 : {
11253 0 : if (!mStyleSet) {
11254 0 : return;
11255 : }
11256 :
11257 0 : switch (aSheetType) {
11258 : case nsIStyleSheetService::AGENT_SHEET:
11259 0 : AddAgentSheet(aSheet);
11260 0 : break;
11261 : case nsIStyleSheetService::USER_SHEET:
11262 0 : AddUserSheet(aSheet);
11263 0 : break;
11264 : case nsIStyleSheetService::AUTHOR_SHEET:
11265 0 : AddAuthorSheet(aSheet);
11266 0 : break;
11267 : default:
11268 0 : MOZ_ASSERT_UNREACHABLE("unexpected aSheetType value");
11269 : break;
11270 : }
11271 : }
11272 :
11273 : void
11274 0 : PresShell::NotifyStyleSheetServiceSheetRemoved(StyleSheet* aSheet,
11275 : uint32_t aSheetType)
11276 : {
11277 0 : if (!mStyleSet) {
11278 0 : return;
11279 : }
11280 :
11281 0 : RemoveSheet(ToSheetType(aSheetType), aSheet);
11282 : }
|