Source code

Revision control

Other Tools

1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
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
/* a presentation of a document, part 2 */
8
9
#include "mozilla/PresShell.h"
10
11
#include "mozilla/dom/FontFaceSet.h"
12
#include "mozilla/ArrayUtils.h"
13
#include "mozilla/Attributes.h"
14
#include "mozilla/AutoRestore.h"
15
#include "mozilla/ContentIterator.h"
16
#include "mozilla/EventDispatcher.h"
17
#include "mozilla/EventStateManager.h"
18
#include "mozilla/EventStates.h"
19
#include "mozilla/GeckoMVMContext.h"
20
#include "mozilla/IMEStateManager.h"
21
#include "mozilla/MemoryReporting.h"
22
#include "mozilla/dom/BrowserChild.h"
23
#include "mozilla/Likely.h"
24
#include "mozilla/Logging.h"
25
#include "mozilla/MouseEvents.h"
26
#include "mozilla/PerfStats.h"
27
#include "mozilla/PresShellInlines.h"
28
#include "mozilla/RangeUtils.h"
29
#include "mozilla/Sprintf.h"
30
#include "mozilla/StaticPrefs.h"
31
#include "mozilla/TextEvents.h"
32
#include "mozilla/TimeStamp.h"
33
#include "mozilla/TouchEvents.h"
34
#include "mozilla/UniquePtr.h"
35
#include "mozilla/Unused.h"
36
#include <algorithm>
37
38
#ifdef XP_WIN
39
# include "winuser.h"
40
#endif
41
42
#include "gfxContext.h"
43
#include "gfxUserFontSet.h"
44
#include "nsContentList.h"
45
#include "nsPresContext.h"
46
#include "nsIContent.h"
47
#include "mozilla/dom/BrowserBridgeChild.h"
48
#include "mozilla/dom/BrowsingContext.h"
49
#include "mozilla/dom/Element.h"
50
#include "mozilla/dom/PointerEventHandler.h"
51
#include "mozilla/dom/PopupBlocker.h"
52
#include "mozilla/dom/Document.h"
53
#include "mozilla/dom/DocumentInlines.h"
54
#include "nsAnimationManager.h"
55
#include "nsNameSpaceManager.h" // for Pref-related rule management (bugs 22963,20760,31816)
56
#include "nsFrame.h"
57
#include "FrameLayerBuilder.h"
58
#include "nsViewManager.h"
59
#include "nsView.h"
60
#include "nsCRTGlue.h"
61
#include "prinrval.h"
62
#include "nsTArray.h"
63
#include "nsCOMArray.h"
64
#include "nsContainerFrame.h"
65
#include "mozilla/dom/Selection.h"
66
#include "nsGkAtoms.h"
67
#include "nsRange.h"
68
#include "nsWindowSizes.h"
69
#include "nsCOMPtr.h"
70
#include "nsReadableUtils.h"
71
#include "nsPageSequenceFrame.h"
72
#include "nsIPermissionManager.h"
73
#include "nsIMozBrowserFrame.h"
74
#include "nsCaret.h"
75
#include "mozilla/AccessibleCaretEventHub.h"
76
#include "nsFrameManager.h"
77
#include "nsXPCOM.h"
78
#include "nsILayoutHistoryState.h"
79
#include "nsILineIterator.h" // for ScrollContentIntoView
80
#include "PLDHashTable.h"
81
#include "mozilla/dom/Touch.h"
82
#include "mozilla/dom/TouchEvent.h"
83
#include "mozilla/dom/PointerEventBinding.h"
84
#include "mozilla/dom/ShadowIncludingTreeIterator.h"
85
#include "nsIObserverService.h"
86
#include "nsDocShell.h" // for reflow observation
87
#include "nsIBaseWindow.h"
88
#include "nsError.h"
89
#include "nsLayoutUtils.h"
90
#include "nsViewportInfo.h"
91
#include "nsCSSRendering.h"
92
// for |#ifdef DEBUG| code
93
#include "prenv.h"
94
#include "nsDisplayList.h"
95
#include "nsRegion.h"
96
#include "nsAutoLayoutPhase.h"
97
#ifdef MOZ_GECKO_PROFILER
98
# include "AutoProfilerStyleMarker.h"
99
#endif
100
#ifdef MOZ_REFLOW_PERF
101
# include "nsFontMetrics.h"
102
#endif
103
#include "MobileViewportManager.h"
104
#include "OverflowChangedTracker.h"
105
#include "PositionedEventTargeting.h"
106
107
#include "nsIReflowCallback.h"
108
109
#include "nsPIDOMWindow.h"
110
#include "nsFocusManager.h"
111
#include "nsIObjectFrame.h"
112
#include "nsIObjectLoadingContent.h"
113
#include "nsNetUtil.h"
114
#include "nsThreadUtils.h"
115
#include "nsStyleSheetService.h"
116
#include "gfxUtils.h"
117
#include "mozilla/SMILAnimationController.h"
118
#include "SVGContentUtils.h"
119
#include "SVGObserverUtils.h"
120
#include "SVGFragmentIdentifier.h"
121
#include "nsFrameSelection.h"
122
123
#include "mozilla/dom/Performance.h"
124
#include "nsRefreshDriver.h"
125
#include "nsDOMNavigationTiming.h"
126
127
// Drag & Drop, Clipboard
128
#include "nsIDocShellTreeItem.h"
129
#include "nsIURI.h"
130
#include "nsIScrollableFrame.h"
131
#include "nsITimer.h"
132
#ifdef ACCESSIBILITY
133
# include "nsAccessibilityService.h"
134
# include "mozilla/a11y/DocAccessible.h"
135
# ifdef DEBUG
136
# include "mozilla/a11y/Logging.h"
137
# endif
138
#endif
139
140
// For style data reconstruction
141
#include "nsStyleChangeList.h"
142
#include "nsCSSFrameConstructor.h"
143
#ifdef MOZ_XUL
144
# include "nsMenuFrame.h"
145
# include "nsTreeBodyFrame.h"
146
# include "XULTreeElement.h"
147
# include "nsMenuPopupFrame.h"
148
# include "nsTreeColumns.h"
149
# include "nsIDOMXULMultSelectCntrlEl.h"
150
# include "nsIDOMXULSelectCntrlItemEl.h"
151
# include "nsIDOMXULMenuListElement.h"
152
# include "nsXULElement.h"
153
#endif // MOZ_XUL
154
155
#include "mozilla/layers/CompositorBridgeChild.h"
156
#include "ClientLayerManager.h"
157
#include "GeckoProfiler.h"
158
#include "gfxPlatform.h"
159
#include "Layers.h"
160
#include "LayerTreeInvalidation.h"
161
#include "mozilla/css/ImageLoader.h"
162
#include "mozilla/dom/DocumentTimeline.h"
163
#include "mozilla/dom/ScriptSettings.h"
164
#include "mozilla/ErrorResult.h"
165
#include "mozilla/Preferences.h"
166
#include "mozilla/Telemetry.h"
167
#include "nsCanvasFrame.h"
168
#include "nsIImageLoadingContent.h"
169
#include "nsImageFrame.h"
170
#include "nsIScreen.h"
171
#include "nsIScreenManager.h"
172
#include "nsPlaceholderFrame.h"
173
#include "nsTransitionManager.h"
174
#include "ChildIterator.h"
175
#include "mozilla/RestyleManager.h"
176
#include "nsIDragSession.h"
177
#include "nsIFrameInlines.h"
178
#include "mozilla/gfx/2D.h"
179
#include "nsSubDocumentFrame.h"
180
#include "nsQueryObject.h"
181
#include "nsLayoutStylesheetCache.h"
182
#include "mozilla/layers/InputAPZContext.h"
183
#include "mozilla/layers/FocusTarget.h"
184
#include "mozilla/layers/WebRenderLayerManager.h"
185
#include "mozilla/layers/WebRenderUserData.h"
186
#include "mozilla/layout/ScrollAnchorContainer.h"
187
#include "mozilla/ServoBindings.h"
188
#include "mozilla/ServoStyleSet.h"
189
#include "mozilla/StyleSheet.h"
190
#include "mozilla/StyleSheetInlines.h"
191
#include "mozilla/dom/ImageTracker.h"
192
#include "nsIDocShellTreeOwner.h"
193
#include "nsBindingManager.h"
194
#include "nsClassHashtable.h"
195
#include "nsHashKeys.h"
196
#include "VisualViewport.h"
197
198
#ifdef MOZ_TASK_TRACER
199
# include "GeckoTaskTracer.h"
200
using namespace mozilla::tasktracer;
201
#endif
202
203
// define the scalfactor of drag and drop images
204
// relative to the max screen height/width
205
#define RELATIVE_SCALEFACTOR 0.0925f
206
207
using namespace mozilla;
208
using namespace mozilla::css;
209
using namespace mozilla::dom;
210
using namespace mozilla::gfx;
211
using namespace mozilla::layers;
212
using namespace mozilla::gfx;
213
using namespace mozilla::layout;
214
using PaintFrameFlags = nsLayoutUtils::PaintFrameFlags;
215
typedef ScrollableLayerGuid::ViewID ViewID;
216
217
PresShell::CapturingContentInfo PresShell::sCapturingContentInfo;
218
219
// RangePaintInfo is used to paint ranges to offscreen buffers
220
struct RangePaintInfo {
221
RefPtr<nsRange> mRange;
222
nsDisplayListBuilder mBuilder;
223
nsDisplayList mList;
224
225
// offset of builder's reference frame to the root frame
226
nsPoint mRootOffset;
227
228
RangePaintInfo(nsRange* aRange, nsIFrame* aFrame)
229
: mRange(aRange),
230
mBuilder(aFrame, nsDisplayListBuilderMode::Painting, false) {
231
MOZ_COUNT_CTOR(RangePaintInfo);
232
mBuilder.BeginFrame();
233
}
234
235
~RangePaintInfo() {
236
mList.DeleteAll(&mBuilder);
237
mBuilder.EndFrame();
238
MOZ_COUNT_DTOR(RangePaintInfo);
239
}
240
};
241
242
#undef NOISY
243
244
// ----------------------------------------------------------------------
245
246
#ifdef DEBUG
247
// Set the environment variable GECKO_VERIFY_REFLOW_FLAGS to one or
248
// more of the following flags (comma separated) for handy debug
249
// output.
250
static VerifyReflowFlags gVerifyReflowFlags;
251
252
struct VerifyReflowFlagData {
253
const char* name;
254
VerifyReflowFlags bit;
255
};
256
257
static const VerifyReflowFlagData gFlags[] = {
258
// clang-format off
259
{ "verify", VerifyReflowFlags::On },
260
{ "reflow", VerifyReflowFlags::Noisy },
261
{ "all", VerifyReflowFlags::All },
262
{ "list-commands", VerifyReflowFlags::DumpCommands },
263
{ "noisy-commands", VerifyReflowFlags::NoisyCommands },
264
{ "really-noisy-commands", VerifyReflowFlags::ReallyNoisyCommands },
265
{ "resize", VerifyReflowFlags::DuringResizeReflow },
266
// clang-format on
267
};
268
269
# define NUM_VERIFY_REFLOW_FLAGS (sizeof(gFlags) / sizeof(gFlags[0]))
270
271
static void ShowVerifyReflowFlags() {
272
printf("Here are the available GECKO_VERIFY_REFLOW_FLAGS:\n");
273
const VerifyReflowFlagData* flag = gFlags;
274
const VerifyReflowFlagData* limit = gFlags + NUM_VERIFY_REFLOW_FLAGS;
275
while (flag < limit) {
276
printf(" %s\n", flag->name);
277
++flag;
278
}
279
printf("Note: GECKO_VERIFY_REFLOW_FLAGS is a comma separated list of flag\n");
280
printf("names (no whitespace)\n");
281
}
282
#endif
283
284
//========================================================================
285
//========================================================================
286
//========================================================================
287
#ifdef MOZ_REFLOW_PERF
288
class ReflowCountMgr;
289
290
static const char kGrandTotalsStr[] = "Grand Totals";
291
292
// Counting Class
293
class ReflowCounter {
294
public:
295
explicit ReflowCounter(ReflowCountMgr* aMgr = nullptr);
296
~ReflowCounter();
297
298
void ClearTotals();
299
void DisplayTotals(const char* aStr);
300
void DisplayDiffTotals(const char* aStr);
301
void DisplayHTMLTotals(const char* aStr);
302
303
void Add() { mTotal++; }
304
void Add(uint32_t aTotal) { mTotal += aTotal; }
305
306
void CalcDiffInTotals();
307
void SetTotalsCache();
308
309
void SetMgr(ReflowCountMgr* aMgr) { mMgr = aMgr; }
310
311
uint32_t GetTotal() { return mTotal; }
312
313
protected:
314
void DisplayTotals(uint32_t aTotal, const char* aTitle);
315
void DisplayHTMLTotals(uint32_t aTotal, const char* aTitle);
316
317
uint32_t mTotal;
318
uint32_t mCacheTotal;
319
320
ReflowCountMgr* mMgr; // weak reference (don't delete)
321
};
322
323
// Counting Class
324
class IndiReflowCounter {
325
public:
326
explicit IndiReflowCounter(ReflowCountMgr* aMgr = nullptr)
327
: mFrame(nullptr),
328
mCount(0),
329
mMgr(aMgr),
330
mCounter(aMgr),
331
mHasBeenOutput(false) {}
332
virtual ~IndiReflowCounter() {}
333
334
nsAutoString mName;
335
nsIFrame* mFrame; // weak reference (don't delete)
336
int32_t mCount;
337
338
ReflowCountMgr* mMgr; // weak reference (don't delete)
339
340
ReflowCounter mCounter;
341
bool mHasBeenOutput;
342
};
343
344
//--------------------
345
// Manager Class
346
//--------------------
347
class ReflowCountMgr {
348
public:
349
ReflowCountMgr();
350
virtual ~ReflowCountMgr();
351
352
void ClearTotals();
353
void ClearGrandTotals();
354
void DisplayTotals(const char* aStr);
355
void DisplayHTMLTotals(const char* aStr);
356
void DisplayDiffsInTotals();
357
358
void Add(const char* aName, nsIFrame* aFrame);
359
ReflowCounter* LookUp(const char* aName);
360
361
void PaintCount(const char* aName, gfxContext* aRenderingContext,
362
nsPresContext* aPresContext, nsIFrame* aFrame,
363
const nsPoint& aOffset, uint32_t aColor);
364
365
FILE* GetOutFile() { return mFD; }
366
367
void SetPresContext(nsPresContext* aPresContext) {
368
mPresContext = aPresContext; // weak reference
369
}
370
void SetPresShell(PresShell* aPresShell) {
371
mPresShell = aPresShell; // weak reference
372
}
373
374
void SetDumpFrameCounts(bool aVal) { mDumpFrameCounts = aVal; }
375
void SetDumpFrameByFrameCounts(bool aVal) { mDumpFrameByFrameCounts = aVal; }
376
void SetPaintFrameCounts(bool aVal) { mPaintFrameByFrameCounts = aVal; }
377
378
bool IsPaintingFrameCounts() { return mPaintFrameByFrameCounts; }
379
380
protected:
381
void DisplayTotals(uint32_t aTotal, uint32_t* aDupArray, char* aTitle);
382
void DisplayHTMLTotals(uint32_t aTotal, uint32_t* aDupArray, char* aTitle);
383
384
void DoGrandTotals();
385
void DoIndiTotalsTree();
386
387
// HTML Output Methods
388
void DoGrandHTMLTotals();
389
390
nsClassHashtable<nsCharPtrHashKey, ReflowCounter> mCounts;
391
nsClassHashtable<nsCharPtrHashKey, IndiReflowCounter> mIndiFrameCounts;
392
FILE* mFD;
393
394
bool mDumpFrameCounts;
395
bool mDumpFrameByFrameCounts;
396
bool mPaintFrameByFrameCounts;
397
398
bool mCycledOnce;
399
400
// Root Frame for Individual Tracking
401
nsPresContext* mPresContext;
402
PresShell* mPresShell;
403
404
// ReflowCountMgr gReflowCountMgr;
405
};
406
#endif
407
//========================================================================
408
409
// comment out to hide caret
410
#define SHOW_CARET
411
412
// The upper bound on the amount of time to spend reflowing, in
413
// microseconds. When this bound is exceeded and reflow commands are
414
// still queued up, a reflow event is posted. The idea is for reflow
415
// to not hog the processor beyond the time specifed in
416
// gMaxRCProcessingTime. This data member is initialized from the
417
// layout.reflow.timeslice pref.
418
#define NS_MAX_REFLOW_TIME 1000000
419
static int32_t gMaxRCProcessingTime = -1;
420
421
struct nsCallbackEventRequest {
422
nsIReflowCallback* callback;
423
nsCallbackEventRequest* next;
424
};
425
426
// ----------------------------------------------------------------------------
427
//
428
// NOTE(emilio): It'd be nice for this to assert that our document isn't in the
429
// bfcache, but font pref changes don't care about that, and maybe / probably
430
// shouldn't.
431
#ifdef DEBUG
432
# define ASSERT_REFLOW_SCHEDULED_STATE() \
433
{ \
434
if (ObservingLayoutFlushes()) { \
435
MOZ_ASSERT( \
436
mDocument->GetBFCacheEntry() || \
437
mPresContext->RefreshDriver()->IsLayoutFlushObserver(this), \
438
"Unexpected state"); \
439
} else { \
440
MOZ_ASSERT( \
441
!mPresContext->RefreshDriver()->IsLayoutFlushObserver(this), \
442
"Unexpected state"); \
443
} \
444
}
445
#else
446
# define ASSERT_REFLOW_SCHEDULED_STATE() /* nothing */
447
#endif
448
449
class nsAutoCauseReflowNotifier {
450
public:
451
explicit nsAutoCauseReflowNotifier(PresShell* aPresShell)
452
: mPresShell(aPresShell) {
453
mPresShell->WillCauseReflow();
454
}
455
~nsAutoCauseReflowNotifier() {
456
// This check should not be needed. Currently the only place that seem
457
// to need it is the code that deals with bug 337586.
458
if (!mPresShell->mHaveShutDown) {
459
mPresShell->DidCauseReflow();
460
} else {
461
nsContentUtils::RemoveScriptBlocker();
462
}
463
}
464
465
PresShell* mPresShell;
466
};
467
468
class MOZ_STACK_CLASS nsPresShellEventCB : public EventDispatchingCallback {
469
public:
470
explicit nsPresShellEventCB(PresShell* aPresShell) : mPresShell(aPresShell) {}
471
472
MOZ_CAN_RUN_SCRIPT
473
virtual void HandleEvent(EventChainPostVisitor& aVisitor) override {
474
if (aVisitor.mPresContext && aVisitor.mEvent->mClass != eBasicEventClass) {
475
if (aVisitor.mEvent->mMessage == eMouseDown ||
476
aVisitor.mEvent->mMessage == eMouseUp) {
477
// Mouse-up and mouse-down events call nsFrame::HandlePress/Release
478
// which call GetContentOffsetsFromPoint which requires up-to-date
479
// layout. Bring layout up-to-date now so that GetCurrentEventFrame()
480
// below will return a real frame and we don't have to worry about
481
// destroying it by flushing later.
482
MOZ_KnownLive(mPresShell)->FlushPendingNotifications(FlushType::Layout);
483
} else if (aVisitor.mEvent->mMessage == eWheel &&
484
aVisitor.mEventStatus != nsEventStatus_eConsumeNoDefault) {
485
nsIFrame* frame = mPresShell->GetCurrentEventFrame();
486
if (frame) {
487
// chrome (including addons) should be able to know if content
488
// handles both D3E "wheel" event and legacy mouse scroll events.
489
// We should dispatch legacy mouse events before dispatching the
490
// "wheel" event into system group.
491
RefPtr<EventStateManager> esm =
492
aVisitor.mPresContext->EventStateManager();
493
esm->DispatchLegacyMouseScrollEvents(
494
frame, aVisitor.mEvent->AsWheelEvent(), &aVisitor.mEventStatus);
495
}
496
}
497
nsIFrame* frame = mPresShell->GetCurrentEventFrame();
498
if (!frame && (aVisitor.mEvent->mMessage == eMouseUp ||
499
aVisitor.mEvent->mMessage == eTouchEnd)) {
500
// Redirect BUTTON_UP and TOUCH_END events to the root frame to ensure
501
// that capturing is released.
502
frame = mPresShell->GetRootFrame();
503
}
504
if (frame) {
505
frame->HandleEvent(MOZ_KnownLive(aVisitor.mPresContext),
506
aVisitor.mEvent->AsGUIEvent(),
507
&aVisitor.mEventStatus);
508
}
509
}
510
}
511
512
RefPtr<PresShell> mPresShell;
513
};
514
515
class nsBeforeFirstPaintDispatcher : public Runnable {
516
public:
517
explicit nsBeforeFirstPaintDispatcher(Document* aDocument)
518
: mozilla::Runnable("nsBeforeFirstPaintDispatcher"),
519
mDocument(aDocument) {}
520
521
// Fires the "before-first-paint" event so that interested parties (right now,
522
// the mobile browser) are aware of it.
523
NS_IMETHOD Run() override {
524
nsCOMPtr<nsIObserverService> observerService =
525
mozilla::services::GetObserverService();
526
if (observerService) {
527
observerService->NotifyObservers(ToSupports(mDocument),
528
"before-first-paint", nullptr);
529
}
530
return NS_OK;
531
}
532
533
private:
534
RefPtr<Document> mDocument;
535
};
536
537
// This is a helper class to track whether the targeted frame is destroyed after
538
// dispatching pointer events. In that case, we need the original targeted
539
// content so that we can dispatch the mouse events to it.
540
class MOZ_STACK_CLASS AutoPointerEventTargetUpdater final {
541
public:
542
AutoPointerEventTargetUpdater(PresShell* aShell, WidgetEvent* aEvent,
543
nsIFrame* aFrame, nsIContent** aTargetContent) {
544
MOZ_ASSERT(aEvent);
545
if (!aTargetContent || aEvent->mClass != ePointerEventClass) {
546
// Make the destructor happy.
547
mTargetContent = nullptr;
548
return;
549
}
550
MOZ_ASSERT(aShell);
551
MOZ_ASSERT(aFrame);
552
MOZ_ASSERT(!aFrame->GetContent() ||
553
aShell->GetDocument() == aFrame->GetContent()->OwnerDoc());
554
555
MOZ_ASSERT(StaticPrefs::dom_w3c_pointer_events_enabled());
556
mShell = aShell;
557
mWeakFrame = aFrame;
558
mTargetContent = aTargetContent;
559
aShell->mPointerEventTarget = aFrame->GetContent();
560
}
561
562
~AutoPointerEventTargetUpdater() {
563
if (!mTargetContent || !mShell || mWeakFrame.IsAlive()) {
564
return;
565
}
566
mShell->mPointerEventTarget.swap(*mTargetContent);
567
}
568
569
private:
570
RefPtr<PresShell> mShell;
571
AutoWeakFrame mWeakFrame;
572
nsIContent** mTargetContent;
573
};
574
575
void PresShell::DirtyRootsList::Add(nsIFrame* aFrame) {
576
// Is this root already scheduled for reflow?
577
// FIXME: This could possibly be changed to a uniqueness assertion, with some
578
// work in ResizeReflowIgnoreOverride (and maybe others?)
579
if (mList.Contains(aFrame)) {
580
// We don't expect frame to change depths.
581
MOZ_ASSERT(aFrame->GetDepthInFrameTree() ==
582
mList[mList.IndexOf(aFrame)].mDepth);
583
return;
584
}
585
586
mList.InsertElementSorted(
587
FrameAndDepth{aFrame, aFrame->GetDepthInFrameTree()},
588
FrameAndDepth::CompareByReverseDepth{});
589
}
590
591
void PresShell::DirtyRootsList::Remove(nsIFrame* aFrame) {
592
mList.RemoveElement(aFrame);
593
}
594
595
nsIFrame* PresShell::DirtyRootsList::PopShallowestRoot() {
596
// List is sorted in order of decreasing depth, so there are no deeper
597
// frames than the last one.
598
const FrameAndDepth& lastFAD = mList.LastElement();
599
nsIFrame* frame = lastFAD.mFrame;
600
// We don't expect frame to change depths.
601
MOZ_ASSERT(frame->GetDepthInFrameTree() == lastFAD.mDepth);
602
mList.RemoveLastElement();
603
return frame;
604
}
605
606
void PresShell::DirtyRootsList::Clear() { mList.Clear(); }
607
608
bool PresShell::DirtyRootsList::Contains(nsIFrame* aFrame) const {
609
return mList.Contains(aFrame);
610
}
611
612
bool PresShell::DirtyRootsList::IsEmpty() const { return mList.IsEmpty(); }
613
614
bool PresShell::DirtyRootsList::FrameIsAncestorOfDirtyRoot(
615
nsIFrame* aFrame) const {
616
MOZ_ASSERT(aFrame);
617
618
// Look for a path from any dirty roots to aFrame, following GetParent().
619
// This check mirrors what FrameNeedsReflow() would have done if the reflow
620
// root didn't get in the way.
621
for (nsIFrame* dirtyFrame : mList) {
622
do {
623
if (dirtyFrame == aFrame) {
624
return true;
625
}
626
dirtyFrame = dirtyFrame->GetParent();
627
} while (dirtyFrame);
628
}
629
630
return false;
631
}
632
633
bool PresShell::sDisableNonTestMouseEvents = false;
634
635
LazyLogModule PresShell::gLog("PresShell");
636
637
TimeStamp PresShell::EventHandler::sLastInputCreated;
638
TimeStamp PresShell::EventHandler::sLastInputProcessed;
639
StaticRefPtr<Element> PresShell::EventHandler::sLastKeyDownEventTargetElement;
640
641
bool PresShell::sProcessInteractable = false;
642
643
static bool gVerifyReflowEnabled;
644
645
bool PresShell::GetVerifyReflowEnable() {
646
#ifdef DEBUG
647
static bool firstTime = true;
648
if (firstTime) {
649
firstTime = false;
650
char* flags = PR_GetEnv("GECKO_VERIFY_REFLOW_FLAGS");
651
if (flags) {
652
bool error = false;
653
654
for (;;) {
655
char* comma = PL_strchr(flags, ',');
656
if (comma) *comma = '\0';
657
658
bool found = false;
659
const VerifyReflowFlagData* flag = gFlags;
660
const VerifyReflowFlagData* limit = gFlags + NUM_VERIFY_REFLOW_FLAGS;
661
while (flag < limit) {
662
if (PL_strcasecmp(flag->name, flags) == 0) {
663
gVerifyReflowFlags |= flag->bit;
664
found = true;
665
break;
666
}
667
++flag;
668
}
669
670
if (!found) error = true;
671
672
if (!comma) break;
673
674
*comma = ',';
675
flags = comma + 1;
676
}
677
678
if (error) ShowVerifyReflowFlags();
679
}
680
681
if (VerifyReflowFlags::On & gVerifyReflowFlags) {
682
gVerifyReflowEnabled = true;
683
684
printf("Note: verifyreflow is enabled");
685
if (VerifyReflowFlags::Noisy & gVerifyReflowFlags) {
686
printf(" (noisy)");
687
}
688
if (VerifyReflowFlags::All & gVerifyReflowFlags) {
689
printf(" (all)");
690
}
691
if (VerifyReflowFlags::DumpCommands & gVerifyReflowFlags) {
692
printf(" (show reflow commands)");
693
}
694
if (VerifyReflowFlags::NoisyCommands & gVerifyReflowFlags) {
695
printf(" (noisy reflow commands)");
696
if (VerifyReflowFlags::ReallyNoisyCommands & gVerifyReflowFlags) {
697
printf(" (REALLY noisy reflow commands)");
698
}
699
}
700
printf("\n");
701
}
702
}
703
#endif
704
return gVerifyReflowEnabled;
705
}
706
707
void PresShell::SetVerifyReflowEnable(bool aEnabled) {
708
gVerifyReflowEnabled = aEnabled;
709
}
710
711
void PresShell::AddAutoWeakFrame(AutoWeakFrame* aWeakFrame) {
712
if (aWeakFrame->GetFrame()) {
713
aWeakFrame->GetFrame()->AddStateBits(NS_FRAME_EXTERNAL_REFERENCE);
714
}
715
aWeakFrame->SetPreviousWeakFrame(mAutoWeakFrames);
716
mAutoWeakFrames = aWeakFrame;
717
}
718
719
void PresShell::AddWeakFrame(WeakFrame* aWeakFrame) {
720
if (aWeakFrame->GetFrame()) {
721
aWeakFrame->GetFrame()->AddStateBits(NS_FRAME_EXTERNAL_REFERENCE);
722
}
723
MOZ_ASSERT(!mWeakFrames.GetEntry(aWeakFrame));
724
mWeakFrames.PutEntry(aWeakFrame);
725
}
726
727
void PresShell::RemoveAutoWeakFrame(AutoWeakFrame* aWeakFrame) {
728
if (mAutoWeakFrames == aWeakFrame) {
729
mAutoWeakFrames = aWeakFrame->GetPreviousWeakFrame();
730
return;
731
}
732
AutoWeakFrame* nextWeak = mAutoWeakFrames;
733
while (nextWeak && nextWeak->GetPreviousWeakFrame() != aWeakFrame) {
734
nextWeak = nextWeak->GetPreviousWeakFrame();
735
}
736
if (nextWeak) {
737
nextWeak->SetPreviousWeakFrame(aWeakFrame->GetPreviousWeakFrame());
738
}
739
}
740
741
void PresShell::RemoveWeakFrame(WeakFrame* aWeakFrame) {
742
MOZ_ASSERT(mWeakFrames.GetEntry(aWeakFrame));
743
mWeakFrames.RemoveEntry(aWeakFrame);
744
}
745
746
already_AddRefed<nsFrameSelection> PresShell::FrameSelection() {
747
RefPtr<nsFrameSelection> ret = mSelection;
748
return ret.forget();
749
}
750
751
//----------------------------------------------------------------------
752
753
static bool sSynthMouseMove = true;
754
static uint32_t sNextPresShellId;
755
756
/* static */
757
bool PresShell::AccessibleCaretEnabled(nsIDocShell* aDocShell) {
758
// If the pref forces it on, then enable it.
759
if (StaticPrefs::layout_accessiblecaret_enabled()) {
760
return true;
761
}
762
// If the touch pref is on, and touch events are enabled (this depends
763
// on the specific device running), then enable it.
764
if (StaticPrefs::layout_accessiblecaret_enabled_on_touch() &&
765
dom::TouchEvent::PrefEnabled(aDocShell)) {
766
return true;
767
}
768
// Otherwise, disabled.
769
return false;
770
}
771
772
PresShell::PresShell()
773
: mViewManager(nullptr),
774
mFrameManager(nullptr),
775
mAutoWeakFrames(nullptr),
776
#ifdef ACCESSIBILITY
777
mDocAccessible(nullptr),
778
#endif // #ifdef ACCESSIBILITY
779
mCurrentEventFrame(nullptr),
780
mMouseLocation(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE),
781
mPaintCount(0),
782
mAPZFocusSequenceNumber(0),
783
mCanvasBackgroundColor(NS_RGBA(0, 0, 0, 0)),
784
mActiveSuppressDisplayport(0),
785
mPresShellId(sNextPresShellId++),
786
mFontSizeInflationEmPerLine(0),
787
mFontSizeInflationMinTwips(0),
788
mFontSizeInflationLineThreshold(0),
789
mSelectionFlags(nsISelectionDisplay::DISPLAY_TEXT |
790
nsISelectionDisplay::DISPLAY_IMAGES),
791
mChangeNestCount(0),
792
mRenderingStateFlags(RenderingStateFlags::None),
793
mInFlush(false),
794
mCaretEnabled(false),
795
mNeedLayoutFlush(true),
796
mNeedStyleFlush(true),
797
mNeedThrottledAnimationFlush(true),
798
mVisualViewportSizeSet(false),
799
mDidInitialize(false),
800
mIsDestroying(false),
801
mIsReflowing(false),
802
mIsObservingDocument(false),
803
mForbiddenToFlush(false),
804
mIsDocumentGone(false),
805
mHaveShutDown(false),
806
mPaintingSuppressed(false),
807
mLastRootReflowHadUnconstrainedBSize(false),
808
mShouldUnsuppressPainting(false),
809
mIgnoreFrameDestruction(false),
810
mIsActive(true),
811
mFrozen(false),
812
mIsFirstPaint(true), // FIXME/bug 735029: find a better solution
813
mObservesMutationsForPrint(false),
814
mWasLastReflowInterrupted(false),
815
mObservingStyleFlushes(false),
816
mObservingLayoutFlushes(false),
817
mResizeEventPending(false),
818
mFontSizeInflationForceEnabled(false),
819
mFontSizeInflationDisabledInMasterProcess(false),
820
mFontSizeInflationEnabled(false),
821
mPaintingIsFrozen(false),
822
mIsNeverPainting(false),
823
mResolutionUpdated(false),
824
mResolutionUpdatedByApz(false),
825
mUnderHiddenEmbedderElement(false),
826
mDocumentLoading(false),
827
mNoDelayedMouseEvents(false),
828
mNoDelayedKeyEvents(false),
829
mApproximateFrameVisibilityVisited(false),
830
mNextPaintCompressed(false),
831
mHasCSSBackgroundColor(true),
832
mIsLastChromeOnlyEscapeKeyConsumed(false),
833
mHasReceivedPaintMessage(false),
834
mIsLastKeyDownCanceled(false),
835
mHasHandledUserInput(false),
836
mForceDispatchKeyPressEventsForNonPrintableKeys(false),
837
mForceUseLegacyKeyCodeAndCharCodeValues(false),
838
mInitializedWithKeyPressEventDispatchingBlacklist(false),
839
mForceUseLegacyNonPrimaryDispatch(false),
840
mInitializedWithClickEventDispatchingBlacklist(false) {
841
MOZ_LOG(gLog, LogLevel::Debug, ("PresShell::PresShell this=%p", this));
842
843
#ifdef MOZ_REFLOW_PERF
844
mReflowCountMgr = MakeUnique<ReflowCountMgr>();
845
mReflowCountMgr->SetPresContext(mPresContext);
846
mReflowCountMgr->SetPresShell(this);
847
#endif
848
mLastOSWake = mLoadBegin = TimeStamp::Now();
849
850
static bool addedSynthMouseMove = false;
851
if (!addedSynthMouseMove) {
852
Preferences::AddBoolVarCache(&sSynthMouseMove,
853
"layout.reflow.synthMouseMove", true);
854
addedSynthMouseMove = true;
855
}
856
PointerEventHandler::Initialize();
857
}
858
859
NS_INTERFACE_TABLE_HEAD(PresShell)
860
NS_INTERFACE_TABLE_BEGIN
861
// In most cases, PresShell should be treated as concrete class, but need to
862
// QI for weak reference. Therefore, the case needed by do_QueryReferent()
863
// should be tested first.
864
NS_INTERFACE_TABLE_ENTRY(PresShell, PresShell)
865
NS_INTERFACE_TABLE_ENTRY(PresShell, nsIDocumentObserver)
866
NS_INTERFACE_TABLE_ENTRY(PresShell, nsISelectionController)
867
NS_INTERFACE_TABLE_ENTRY(PresShell, nsISelectionDisplay)
868
NS_INTERFACE_TABLE_ENTRY(PresShell, nsIObserver)
869
NS_INTERFACE_TABLE_ENTRY(PresShell, nsISupportsWeakReference)
870
NS_INTERFACE_TABLE_ENTRY(PresShell, nsIMutationObserver)
871
NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(PresShell, nsISupports, nsIObserver)
872
NS_INTERFACE_TABLE_END
873
NS_INTERFACE_TABLE_TO_MAP_SEGUE
874
NS_INTERFACE_MAP_END
875
876
NS_IMPL_ADDREF(PresShell)
877
NS_IMPL_RELEASE(PresShell)
878
879
PresShell::~PresShell() {
880
MOZ_RELEASE_ASSERT(!mForbiddenToFlush,
881
"Flag should only be set temporarily, while doing things "
882
"that shouldn't cause destruction");
883
MOZ_LOG(gLog, LogLevel::Debug, ("PresShell::~PresShell this=%p", this));
884
885
if (!mHaveShutDown) {
886
MOZ_ASSERT_UNREACHABLE("Someone did not call PresShell::Destroy()");
887
Destroy();
888
}
889
890
NS_ASSERTION(mCurrentEventContentStack.Count() == 0,
891
"Huh, event content left on the stack in pres shell dtor!");
892
NS_ASSERTION(mFirstCallbackEventRequest == nullptr &&
893
mLastCallbackEventRequest == nullptr,
894
"post-reflow queues not empty. This means we're leaking");
895
896
// Verify that if painting was frozen, but we're being removed from the tree,
897
// that we now re-enable painting on our refresh driver, since it may need to
898
// be re-used by another presentation.
899
if (mPaintingIsFrozen) {
900
mPresContext->RefreshDriver()->Thaw();
901
}
902
903
MOZ_ASSERT(mAllocatedPointers.IsEmpty(),
904
"Some pres arena objects were not freed");
905
906
mFrameManager = nullptr;
907
mFrameConstructor = nullptr;
908
909
mCurrentEventContent = nullptr;
910
}
911
912
/**
913
* Initialize the presentation shell. Create view manager and style
914
* manager.
915
* Note this can't be merged into our constructor because caret initialization
916
* calls AddRef() on us.
917
*/
918
void PresShell::Init(Document* aDocument, nsPresContext* aPresContext,
919
nsViewManager* aViewManager) {
920
MOZ_ASSERT(aDocument, "null ptr");
921
MOZ_ASSERT(aPresContext, "null ptr");
922
MOZ_ASSERT(aViewManager, "null ptr");
923
MOZ_ASSERT(!mDocument, "already initialized");
924
925
if (!aDocument || !aPresContext || !aViewManager || mDocument) {
926
return;
927
}
928
929
mDocument = aDocument;
930
mViewManager = aViewManager;
931
932
// mDocument is now set. It might have a display document whose "need layout/
933
// style" flush flags are not set, but ours will be set. To keep these
934
// consistent, call the flag setting functions to propagate those flags up
935
// to the display document.
936
SetNeedLayoutFlush();
937
SetNeedStyleFlush();
938
939
// Create our frame constructor.
940
mFrameConstructor = MakeUnique<nsCSSFrameConstructor>(mDocument, this);
941
942
mFrameManager = mFrameConstructor.get();
943
944
// The document viewer owns both view manager and pres shell.
945
mViewManager->SetPresShell(this);
946
947
// Bind the context to the presentation shell.
948
mPresContext = aPresContext;
949
mPresContext->AttachPresShell(this);
950
951
mPresContext->DeviceContext()->InitFontCache();
952
953
// FIXME(emilio, bug 1544185): Some Android code somehow depends on the shell
954
// being eagerly registered as a style flush observer. This shouldn't be
955
// needed otherwise.
956
EnsureStyleFlush();
957
958
// Add the preference style sheet.
959
UpdatePreferenceStyles();
960
961
bool accessibleCaretEnabled =
962
AccessibleCaretEnabled(mDocument->GetDocShell());
963
if (accessibleCaretEnabled) {
964
// Need to happen before nsFrameSelection has been set up.
965
mAccessibleCaretEventHub = new AccessibleCaretEventHub(this);
966
}
967
968
mSelection = new nsFrameSelection();
969
970
RefPtr<nsFrameSelection> frameSelection = mSelection;
971
frameSelection->Init(this, nullptr, accessibleCaretEnabled);
972
973
// Important: this has to happen after the selection has been set up
974
#ifdef SHOW_CARET
975
// make the caret
976
mCaret = new nsCaret();
977
mCaret->Init(this);
978
mOriginalCaret = mCaret;
979
980
// SetCaretEnabled(true); // make it show in browser windows
981
#endif
982
// set up selection to be displayed in document
983
// Don't enable selection for print media
984
nsPresContext::nsPresContextType type = aPresContext->Type();
985
if (type != nsPresContext::eContext_PrintPreview &&
986
type != nsPresContext::eContext_Print)
987
SetDisplaySelection(nsISelectionController::SELECTION_DISABLED);
988
989
if (gMaxRCProcessingTime == -1) {
990
gMaxRCProcessingTime =
991
Preferences::GetInt("layout.reflow.timeslice", NS_MAX_REFLOW_TIME);
992
}
993
994
if (nsStyleSheetService* ss = nsStyleSheetService::GetInstance()) {
995
ss->RegisterPresShell(this);
996
}
997
998
{
999
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
1000
if (os) {
1001
os->AddObserver(this, "memory-pressure", false);
1002
os->AddObserver(this, NS_WIDGET_WAKE_OBSERVER_TOPIC, false);
1003
if (XRE_IsParentProcess() && !sProcessInteractable) {
1004
os->AddObserver(this, "sessionstore-one-or-no-tab-restored", false);
1005
}
1006
os->AddObserver(this, "font-info-updated", false);
1007
}
1008
}
1009
1010
#ifdef MOZ_REFLOW_PERF
1011
if (mReflowCountMgr) {
1012
bool paintFrameCounts =
1013
Preferences::GetBool("layout.reflow.showframecounts");
1014
1015
bool dumpFrameCounts =
1016
Preferences::GetBool("layout.reflow.dumpframecounts");
1017
1018
bool dumpFrameByFrameCounts =
1019
Preferences::GetBool("layout.reflow.dumpframebyframecounts");
1020
1021
mReflowCountMgr->SetDumpFrameCounts(dumpFrameCounts);
1022
mReflowCountMgr->SetDumpFrameByFrameCounts(dumpFrameByFrameCounts);
1023
mReflowCountMgr->SetPaintFrameCounts(paintFrameCounts);
1024
}
1025
#endif
1026
1027
if (mDocument->HasAnimationController()) {
1028
SMILAnimationController* animCtrl = mDocument->GetAnimationController();
1029
animCtrl->NotifyRefreshDriverCreated(GetPresContext()->RefreshDriver());
1030
}
1031
1032
for (DocumentTimeline* timeline : mDocument->Timelines()) {
1033
timeline->NotifyRefreshDriverCreated(GetPresContext()->RefreshDriver());
1034
}
1035
1036
// Get our activeness from the docShell.
1037
QueryIsActive();
1038
1039
// Setup our font inflation preferences.
1040
mFontSizeInflationEmPerLine = nsLayoutUtils::FontSizeInflationEmPerLine();
1041
mFontSizeInflationMinTwips = nsLayoutUtils::FontSizeInflationMinTwips();
1042
mFontSizeInflationLineThreshold =
1043
nsLayoutUtils::FontSizeInflationLineThreshold();
1044
mFontSizeInflationForceEnabled =
1045
nsLayoutUtils::FontSizeInflationForceEnabled();
1046
mFontSizeInflationDisabledInMasterProcess =
1047
nsLayoutUtils::FontSizeInflationDisabledInMasterProcess();
1048
// We'll compute the font size inflation state in Initialize(), when we know
1049
// the document type.
1050
1051
mTouchManager.Init(this, mDocument);
1052
1053
if (mPresContext->IsRootContentDocumentCrossProcess()) {
1054
mZoomConstraintsClient = new ZoomConstraintsClient();
1055
mZoomConstraintsClient->Init(this, mDocument);
1056
1057
// We call this to create mMobileViewportManager, if it is needed.
1058
UpdateViewportOverridden(false);
1059
}
1060
1061
if (nsCOMPtr<nsIDocShell> docShell = mPresContext->GetDocShell()) {
1062
BrowsingContext* bc = nsDocShell::Cast(docShell)->GetBrowsingContext();
1063
bool embedderFrameIsHidden = true;
1064
if (Element* embedderElement = bc->GetEmbedderElement()) {
1065
if (auto embedderFrame = embedderElement->GetPrimaryFrame()) {
1066
embedderFrameIsHidden = !embedderFrame->StyleVisibility()->IsVisible();
1067
}
1068
}
1069
1070
if (BrowsingContext* parent = bc->GetParent()) {
1071
if (nsCOMPtr<nsIDocShell> parentDocShell = parent->GetDocShell()) {
1072
if (PresShell* parentPresShell = parentDocShell->GetPresShell()) {
1073
mUnderHiddenEmbedderElement =
1074
parentPresShell->IsUnderHiddenEmbedderElement() ||
1075
embedderFrameIsHidden;
1076
}
1077
}
1078
}
1079
}
1080
}
1081
1082
enum TextPerfLogType { eLog_reflow, eLog_loaddone, eLog_totals };
1083
1084
static void LogTextPerfStats(gfxTextPerfMetrics* aTextPerf,
1085
PresShell* aPresShell,
1086
const gfxTextPerfMetrics::TextCounts& aCounts,
1087
float aTime, TextPerfLogType aLogType,
1088
const char* aURL) {
1089
LogModule* tpLog = gfxPlatform::GetLog(eGfxLog_textperf);
1090
1091
// ignore XUL contexts unless at debug level
1092
mozilla::LogLevel logLevel = LogLevel::Warning;
1093
if (aCounts.numContentTextRuns == 0) {
1094
logLevel = LogLevel::Debug;
1095
}
1096
1097
if (!MOZ_LOG_TEST(tpLog, logLevel)) {
1098
return;
1099
}
1100
1101
char prefix[256];
1102
1103
switch (aLogType) {
1104
case eLog_reflow:
1105
SprintfLiteral(prefix, "(textperf-reflow) %p time-ms: %7.0f", aPresShell,
1106
aTime);
1107
break;
1108
case eLog_loaddone:
1109
SprintfLiteral(prefix, "(textperf-loaddone) %p time-ms: %7.0f",
1110
aPresShell, aTime);
1111
break;
1112
default:
1113
MOZ_ASSERT(aLogType == eLog_totals, "unknown textperf log type");
1114
SprintfLiteral(prefix, "(textperf-totals) %p", aPresShell);
1115
}
1116
1117
double hitRatio = 0.0;
1118
uint32_t lookups = aCounts.wordCacheHit + aCounts.wordCacheMiss;
1119
if (lookups) {
1120
hitRatio = double(aCounts.wordCacheHit) / double(lookups);
1121
}
1122
1123
if (aLogType == eLog_loaddone) {
1124
MOZ_LOG(
1125
tpLog, logLevel,
1126
("%s reflow: %d chars: %d "
1127
"[%s] "
1128
"content-textruns: %d chrome-textruns: %d "
1129
"max-textrun-len: %d "
1130
"word-cache-lookups: %d word-cache-hit-ratio: %4.3f "
1131
"word-cache-space: %d word-cache-long: %d "
1132
"pref-fallbacks: %d system-fallbacks: %d "
1133
"textruns-const: %d textruns-destr: %d "
1134
"generic-lookups: %d "
1135
"cumulative-textruns-destr: %d\n",
1136
prefix, aTextPerf->reflowCount, aCounts.numChars, (aURL ? aURL : ""),
1137
aCounts.numContentTextRuns, aCounts.numChromeTextRuns,
1138
aCounts.maxTextRunLen, lookups, hitRatio, aCounts.wordCacheSpaceRules,
1139
aCounts.wordCacheLong, aCounts.fallbackPrefs, aCounts.fallbackSystem,
1140
aCounts.textrunConst, aCounts.textrunDestr, aCounts.genericLookups,
1141
aTextPerf->cumulative.textrunDestr));
1142
} else {
1143
MOZ_LOG(
1144
tpLog, logLevel,
1145
("%s reflow: %d chars: %d "
1146
"content-textruns: %d chrome-textruns: %d "
1147
"max-textrun-len: %d "
1148
"word-cache-lookups: %d word-cache-hit-ratio: %4.3f "
1149
"word-cache-space: %d word-cache-long: %d "
1150
"pref-fallbacks: %d system-fallbacks: %d "
1151
"textruns-const: %d textruns-destr: %d "
1152
"generic-lookups: %d "
1153
"cumulative-textruns-destr: %d\n",
1154
prefix, aTextPerf->reflowCount, aCounts.numChars,
1155
aCounts.numContentTextRuns, aCounts.numChromeTextRuns,
1156
aCounts.maxTextRunLen, lookups, hitRatio, aCounts.wordCacheSpaceRules,
1157
aCounts.wordCacheLong, aCounts.fallbackPrefs, aCounts.fallbackSystem,
1158
aCounts.textrunConst, aCounts.textrunDestr, aCounts.genericLookups,
1159
aTextPerf->cumulative.textrunDestr));
1160
}
1161
}
1162
1163
void PresShell::Destroy() {
1164
// Do not add code before this line please!
1165
if (mHaveShutDown) {
1166
return;
1167
}
1168
1169
NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
1170
"destroy called on presshell while scripts not blocked");
1171
1172
AUTO_PROFILER_LABEL("PresShell::Destroy", LAYOUT);
1173
1174
// dump out cumulative text perf metrics
1175
gfxTextPerfMetrics* tp;
1176
if (mPresContext && (tp = mPresContext->GetTextPerfMetrics())) {
1177
tp->Accumulate();
1178
if (tp->cumulative.numChars > 0) {
1179
LogTextPerfStats(tp, this, tp->cumulative, 0.0, eLog_totals, nullptr);
1180
}
1181
}
1182
if (mPresContext) {
1183
if (gfxUserFontSet* fs = mPresContext->GetUserFontSet()) {
1184
uint32_t fontCount;
1185
uint64_t fontSize;
1186
fs->GetLoadStatistics(fontCount, fontSize);
1187
Telemetry::Accumulate(Telemetry::WEBFONT_PER_PAGE, fontCount);
1188
Telemetry::Accumulate(Telemetry::WEBFONT_SIZE_PER_PAGE,
1189
uint32_t(fontSize / 1024));
1190
} else {
1191
Telemetry::Accumulate(Telemetry::WEBFONT_PER_PAGE, 0);
1192
Telemetry::Accumulate(Telemetry::WEBFONT_SIZE_PER_PAGE, 0);
1193
}
1194
}
1195
1196
#ifdef MOZ_REFLOW_PERF
1197
DumpReflows();
1198
mReflowCountMgr = nullptr;
1199
#endif
1200
1201
if (mZoomConstraintsClient) {
1202
mZoomConstraintsClient->Destroy();
1203
mZoomConstraintsClient = nullptr;
1204
}
1205
if (mMobileViewportManager) {
1206
mMobileViewportManager->Destroy();
1207
mMobileViewportManager = nullptr;
1208
mMVMContext = nullptr;
1209
}
1210
1211
#ifdef ACCESSIBILITY
1212
if (mDocAccessible) {
1213
# ifdef DEBUG
1214
if (a11y::logging::IsEnabled(a11y::logging::eDocDestroy))
1215
a11y::logging::DocDestroy("presshell destroyed", mDocument);
1216
# endif
1217
1218
mDocAccessible->Shutdown();
1219
mDocAccessible = nullptr;
1220
}
1221
#endif // ACCESSIBILITY
1222
1223
MaybeReleaseCapturingContent();
1224
1225
EventHandler::OnPresShellDestroy(mDocument);
1226
1227
if (mContentToScrollTo) {
1228
mContentToScrollTo->DeleteProperty(nsGkAtoms::scrolling);
1229
mContentToScrollTo = nullptr;
1230
}
1231
1232
if (mPresContext) {
1233
// We need to notify the destroying the nsPresContext to ESM for
1234
// suppressing to use from ESM.
1235
mPresContext->EventStateManager()->NotifyDestroyPresContext(mPresContext);
1236
}
1237
1238
if (nsStyleSheetService* ss = nsStyleSheetService::GetInstance()) {
1239
ss->UnregisterPresShell(this);
1240
}
1241
1242
{
1243
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
1244
if (os) {
1245
os->RemoveObserver(this, "memory-pressure");
1246
os->RemoveObserver(this, NS_WIDGET_WAKE_OBSERVER_TOPIC);
1247
if (XRE_IsParentProcess()) {
1248
os->RemoveObserver(this, "sessionstore-one-or-no-tab-restored");
1249
}
1250
os->RemoveObserver(this, "font-info-updated");
1251
}
1252
}
1253
1254
// If our paint suppression timer is still active, kill it.
1255
if (mPaintSuppressionTimer) {
1256
mPaintSuppressionTimer->Cancel();
1257
mPaintSuppressionTimer = nullptr;
1258
}
1259
1260
// Same for our reflow continuation timer
1261
if (mReflowContinueTimer) {
1262
mReflowContinueTimer->Cancel();
1263
mReflowContinueTimer = nullptr;
1264
}
1265
1266
if (mDelayedPaintTimer) {
1267
mDelayedPaintTimer->Cancel();
1268
mDelayedPaintTimer = nullptr;
1269
}
1270
1271
mSynthMouseMoveEvent.Revoke();
1272
1273
mUpdateApproximateFrameVisibilityEvent.Revoke();
1274
1275
ClearApproximatelyVisibleFramesList(Some(OnNonvisible::DiscardImages));
1276
1277
if (mCaret) {
1278
mCaret->Terminate();
1279
mCaret = nullptr;
1280
}
1281
1282
if (mSelection) {
1283
RefPtr<nsFrameSelection> frameSelection = mSelection;
1284
frameSelection->DisconnectFromPresShell();
1285
}
1286
1287
if (mAccessibleCaretEventHub) {
1288
mAccessibleCaretEventHub->Terminate();
1289
mAccessibleCaretEventHub = nullptr;
1290
}
1291
1292
// release our pref style sheet, if we have one still
1293
//
1294
// TODO(emilio): Should we move the preference sheet tracking to the Document?
1295
RemovePreferenceStyles();
1296
1297
mIsDestroying = true;
1298
1299
// We can't release all the event content in
1300
// mCurrentEventContentStack here since there might be code on the
1301
// stack that will release the event content too. Double release
1302
// bad!
1303
1304
// The frames will be torn down, so remove them from the current
1305
// event frame stack (since they'd be dangling references if we'd
1306
// leave them in) and null out the mCurrentEventFrame pointer as
1307
// well.
1308
1309
mCurrentEventFrame = nullptr;
1310
1311
int32_t i, count = mCurrentEventFrameStack.Length();
1312
for (i = 0; i < count; i++) {
1313
mCurrentEventFrameStack[i] = nullptr;
1314
}
1315
1316
mFramesToDirty.Clear();
1317
mPendingScrollAnchorSelection.Clear();
1318
mPendingScrollAnchorAdjustment.Clear();
1319
1320
if (mViewManager) {
1321
// Clear the view manager's weak pointer back to |this| in case it
1322
// was leaked.
1323
mViewManager->SetPresShell(nullptr);
1324
mViewManager = nullptr;
1325
}
1326
1327
nsRefreshDriver* rd = GetPresContext()->RefreshDriver();
1328
1329
// This shell must be removed from the document before the frame
1330
// hierarchy is torn down to avoid finding deleted frames through
1331
// this presshell while the frames are being torn down
1332
if (mDocument) {
1333
NS_ASSERTION(mDocument->GetPresShell() == this, "Wrong shell?");
1334
mDocument->ClearServoRestyleRoot();
1335
mDocument->DeletePresShell();
1336
1337
if (mDocument->HasAnimationController()) {
1338
mDocument->GetAnimationController()->NotifyRefreshDriverDestroying(rd);
1339
}
1340
for (DocumentTimeline* timeline : mDocument->Timelines()) {
1341
timeline->NotifyRefreshDriverDestroying(rd);
1342
}
1343
}
1344
1345
if (mPresContext) {
1346
rd->CancelPendingAnimationEvents(mPresContext->AnimationEventDispatcher());
1347
}
1348
1349
// Revoke any pending events. We need to do this and cancel pending reflows
1350
// before we destroy the frame manager, since apparently frame destruction
1351
// sometimes spins the event queue when plug-ins are involved(!).
1352
StopObservingRefreshDriver();
1353
1354
if (rd->GetPresContext() == GetPresContext()) {
1355
rd->RevokeViewManagerFlush();
1356
}
1357
1358
CancelAllPendingReflows();
1359
CancelPostedReflowCallbacks();
1360
1361
// Destroy the frame manager. This will destroy the frame hierarchy
1362
mFrameConstructor->WillDestroyFrameTree();
1363
1364
NS_WARNING_ASSERTION(!mAutoWeakFrames && mWeakFrames.IsEmpty(),
1365
"Weak frames alive after destroying FrameManager");
1366
while (mAutoWeakFrames) {
1367
mAutoWeakFrames->Clear(this);
1368
}
1369
nsTArray<WeakFrame*> toRemove(mWeakFrames.Count());
1370
for (auto iter = mWeakFrames.Iter(); !iter.Done(); iter.Next()) {
1371
toRemove.AppendElement(iter.Get()->GetKey());
1372
}
1373
for (WeakFrame* weakFrame : toRemove) {
1374
weakFrame->Clear(this);
1375
}
1376
1377
if (mPresContext) {
1378
// We hold a reference to the pres context, and it holds a weak link back
1379
// to us. To avoid the pres context having a dangling reference, set its
1380
// pres shell to nullptr
1381
mPresContext->DetachPresShell();
1382
}
1383
1384
mHaveShutDown = true;
1385
1386
mTouchManager.Destroy();
1387
}
1388
1389
void PresShell::StopObservingRefreshDriver() {
1390
nsRefreshDriver* rd = mPresContext->RefreshDriver();
1391
if (mResizeEventPending) {
1392
rd->RemoveResizeEventFlushObserver(this);
1393
}
1394
if (mObservingLayoutFlushes) {
1395
rd->RemoveLayoutFlushObserver(this);
1396
}
1397
if (mObservingStyleFlushes) {
1398
rd->RemoveStyleFlushObserver(this);
1399
}
1400
}
1401
1402
void PresShell::StartObservingRefreshDriver() {
1403
nsRefreshDriver* rd = mPresContext->RefreshDriver();
1404
if (mResizeEventPending) {
1405
rd->AddResizeEventFlushObserver(this);
1406
}
1407
if (mObservingLayoutFlushes) {
1408
rd->AddLayoutFlushObserver(this);
1409
}
1410
if (mObservingStyleFlushes) {
1411
rd->AddStyleFlushObserver(this);
1412
}
1413
}
1414
1415
nsRefreshDriver* PresShell::GetRefreshDriver() const {
1416
return mPresContext ? mPresContext->RefreshDriver() : nullptr;
1417
}
1418
1419
void PresShell::SetAuthorStyleDisabled(bool aStyleDisabled) {
1420
if (aStyleDisabled != StyleSet()->GetAuthorStyleDisabled()) {
1421
StyleSet()->SetAuthorStyleDisabled(aStyleDisabled);
1422
mDocument->ApplicableStylesChanged();
1423
1424
nsCOMPtr<nsIObserverService> observerService =
1425
mozilla::services::GetObserverService();
1426
if (observerService) {
1427
observerService->NotifyObservers(
1428
ToSupports(mDocument), "author-style-disabled-changed", nullptr);
1429
}
1430
}
1431
}
1432
1433
bool PresShell::GetAuthorStyleDisabled() const {
1434
return StyleSet()->GetAuthorStyleDisabled();
1435
}
1436
1437
void PresShell::UpdatePreferenceStyles() {
1438
if (!mDocument) {
1439
return;
1440
}
1441
1442
// If the document doesn't have a window there's no need to notify
1443
// its presshell about changes to preferences since the document is
1444
// in a state where it doesn't matter any more (see
1445
// nsDocumentViewer::Close()).
1446
if (!mDocument->GetWindow()) {
1447
return;
1448
}
1449
1450
// Documents in chrome shells do not have any preference style rules applied.
1451
if (nsContentUtils::IsInChromeDocshell(mDocument)) {
1452
return;
1453
}
1454
1455
PreferenceSheet::EnsureInitialized();
1456
auto cache = nsLayoutStylesheetCache::Singleton();
1457
1458
RefPtr<StyleSheet> newPrefSheet =
1459
PreferenceSheet::ShouldUseChromePrefs(*mDocument)
1460
? cache->ChromePreferenceSheet()
1461
: cache->ContentPreferenceSheet();
1462
1463
if (mPrefStyleSheet == newPrefSheet) {
1464
return;
1465
}
1466
1467
RemovePreferenceStyles();
1468
1469
// NOTE(emilio): This sheet is added as an agent sheet, because we don't want
1470
// it to be modifiable from devtools and similar, see bugs 1239336 and
1471
// 1436782. I think it conceptually should be a user sheet, and could be
1472
// without too much trouble I'd think.
1473
StyleSet()->AppendStyleSheet(StyleOrigin::UserAgent, newPrefSheet);
1474
mPrefStyleSheet = newPrefSheet;
1475
}
1476
1477
void PresShell::RemovePreferenceStyles() {
1478
if (mPrefStyleSheet) {
1479
StyleSet()->RemoveStyleSheet(StyleOrigin::UserAgent, mPrefStyleSheet);
1480
mPrefStyleSheet = nullptr;
1481
}
1482
}
1483
1484
void PresShell::AddUserSheet(StyleSheet* aSheet) {
1485
// Make sure this does what nsDocumentViewer::CreateStyleSet does wrt
1486
// ordering. We want this new sheet to come after all the existing stylesheet
1487
// service sheets (which are at the start), but before other user sheets; see
1488
// nsIStyleSheetService.idl for the ordering.
1489
1490
nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance();
1491
nsTArray<RefPtr<StyleSheet>>& userSheets = *sheetService->UserStyleSheets();
1492
1493
// Search for the place to insert the new user sheet. Since all of the
1494
// stylesheet service provided user sheets should be at the start of the style
1495
// set's list, and aSheet should be at the end of userSheets. Given that, we
1496
// can find the right place to insert the new sheet based on the length of
1497
// userSheets.
1498
MOZ_ASSERT(aSheet);
1499
MOZ_ASSERT(userSheets.LastElement() == aSheet);
1500
1501
size_t index = userSheets.Length() - 1;
1502
1503
// Assert that all of userSheets (except for the last, new element) matches up
1504
// with what's in the style set.
1505
for (size_t i = 0; i < index; ++i) {
1506
MOZ_ASSERT(StyleSet()->SheetAt(StyleOrigin::User, i) == userSheets[i]);
1507
}
1508
1509
if (index == static_cast<size_t>(StyleSet()->SheetCount(StyleOrigin::User))) {
1510
StyleSet()->AppendStyleSheet(StyleOrigin::User, aSheet);
1511
} else {
1512
StyleSheet* ref = StyleSet()->SheetAt(StyleOrigin::User, index);
1513
StyleSet()->InsertStyleSheetBefore(StyleOrigin::User, aSheet, ref);
1514
}
1515
1516
mDocument->ApplicableStylesChanged();
1517
}
1518
1519
void PresShell::AddAgentSheet(StyleSheet* aSheet) {
1520
// Make sure this does what nsDocumentViewer::CreateStyleSet does
1521
// wrt ordering.
1522
StyleSet()->AppendStyleSheet(StyleOrigin::UserAgent, aSheet);
1523
mDocument->ApplicableStylesChanged();
1524
}
1525
1526
void PresShell::AddAuthorSheet(StyleSheet* aSheet) {
1527
// Document specific "additional" Author sheets should be stronger than the
1528
// ones added with the StyleSheetService.
1529
StyleSheet* firstAuthorSheet = mDocument->GetFirstAdditionalAuthorSheet();
1530
if (firstAuthorSheet) {
1531
StyleSet()->InsertStyleSheetBefore(StyleOrigin::Author, aSheet,
1532
firstAuthorSheet);
1533
} else {
1534
StyleSet()->AppendStyleSheet(StyleOrigin::Author, aSheet);
1535
}
1536
1537
mDocument->ApplicableStylesChanged();
1538
}
1539
1540
void PresShell::RemoveSheet(StyleOrigin aOrigin, StyleSheet* aSheet) {
1541
StyleSet()->RemoveStyleSheet(aOrigin, aSheet);
1542
mDocument->ApplicableStylesChanged();
1543
}
1544
1545
NS_IMETHODIMP
1546
PresShell::SetDisplaySelection(int16_t aToggle) {
1547
RefPtr<nsFrameSelection> frameSelection = mSelection;
1548
frameSelection->SetDisplaySelection(aToggle);
1549
return NS_OK;
1550
}
1551
1552
NS_IMETHODIMP
1553
PresShell::GetDisplaySelection(int16_t* aToggle) {
1554
RefPtr<nsFrameSelection> frameSelection = mSelection;
1555
*aToggle = frameSelection->GetDisplaySelection();
1556
return NS_OK;
1557
}
1558
1559
NS_IMETHODIMP
1560
PresShell::GetSelectionFromScript(RawSelectionType aRawSelectionType,
1561
Selection** aSelection) {
1562
if (!aSelection || !mSelection) return NS_ERROR_NULL_POINTER;
1563
1564
RefPtr<nsFrameSelection> frameSelection = mSelection;
1565
RefPtr<Selection> selection =
1566
frameSelection->GetSelection(ToSelectionType(aRawSelectionType));
1567
1568
if (!selection) {
1569
return NS_ERROR_INVALID_ARG;
1570
}
1571
1572
selection.forget(aSelection);
1573
return NS_OK;
1574
}
1575
1576
Selection* PresShell::GetSelection(RawSelectionType aRawSelectionType) {
1577
if (!mSelection) {
1578
return nullptr;
1579
}
1580
1581
RefPtr<nsFrameSelection> frameSelection = mSelection;
1582
return frameSelection->GetSelection(ToSelectionType(aRawSelectionType));
1583
}
1584
1585
Selection* PresShell::GetCurrentSelection(SelectionType aSelectionType) {
1586
if (!mSelection) return nullptr;
1587
1588
RefPtr<nsFrameSelection> frameSelection = mSelection;
1589
return frameSelection->GetSelection(aSelectionType);
1590
}
1591
1592
already_AddRefed<nsISelectionController>
1593
PresShell::GetSelectionControllerForFocusedContent(
1594
nsIContent** aFocusedContent) {
1595
if (aFocusedContent) {
1596
*aFocusedContent = nullptr;
1597
}
1598
1599
if (mDocument) {
1600
nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
1601
nsCOMPtr<nsIContent> focusedContent = nsFocusManager::GetFocusedDescendant(
1602
mDocument->GetWindow(), nsFocusManager::eOnlyCurrentWindow,
1603
getter_AddRefs(focusedWindow));
1604
if (focusedContent) {
1605
nsIFrame* frame = focusedContent->GetPrimaryFrame();
1606
if (frame) {
1607
nsCOMPtr<nsISelectionController> selectionController;
1608
frame->GetSelectionController(mPresContext,
1609
getter_AddRefs(selectionController));
1610
if (selectionController) {
1611
if (aFocusedContent) {
1612
focusedContent.forget(aFocusedContent);
1613
}
1614
return selectionController.forget();
1615
}
1616
}
1617
}
1618
}
1619
nsCOMPtr<nsISelectionController> self(this);
1620
return self.forget();
1621
}
1622
1623
NS_IMETHODIMP
1624
PresShell::ScrollSelectionIntoView(RawSelectionType aRawSelectionType,
1625
SelectionRegion aRegion, int16_t aFlags) {
1626
if (!mSelection) return NS_ERROR_NULL_POINTER;
1627
1628
RefPtr<nsFrameSelection> frameSelection = mSelection;
1629
return frameSelection->ScrollSelectionIntoView(
1630
ToSelectionType(aRawSelectionType), aRegion, aFlags);
1631
}
1632
1633
NS_IMETHODIMP
1634
PresShell::RepaintSelection(RawSelectionType aRawSelectionType) {
1635
if (!mSelection) {
1636
return NS_ERROR_NULL_POINTER;
1637
}
1638
1639
if (MOZ_UNLIKELY(mIsDestroying)) {
1640
return NS_OK;
1641
}
1642
1643
RefPtr<nsFrameSelection> frameSelection = mSelection;
1644
return frameSelection->RepaintSelection(ToSelectionType(aRawSelectionType));
1645
}
1646
1647
// Make shell be a document observer
1648
void PresShell::BeginObservingDocument() {
1649
if (mDocument && !mIsDestroying) {
1650
mIsObservingDocument = true;
1651
if (mIsDocumentGone) {
1652
NS_WARNING(
1653
"Adding a presshell that was disconnected from the document "
1654
"as a document observer? Sounds wrong...");
1655
mIsDocumentGone = false;
1656
}
1657
}
1658
}
1659
1660
// Make shell stop being a document observer
1661
void PresShell::EndObservingDocument() {
1662
// XXXbz do we need to tell the frame constructor that the document
1663
// is gone, perhaps? Except for printing it's NOT gone, sometimes.
1664
mIsDocumentGone = true;
1665
mIsObservingDocument = false;
1666
}
1667
1668
#ifdef DEBUG_kipp
1669
char* nsPresShell_ReflowStackPointerTop;
1670
#endif
1671
1672
class XBLConstructorRunner : public Runnable {
1673
public:
1674
explicit XBLConstructorRunner(Document* aDocument)
1675
: Runnable("XBLConstructorRunner"), mDocument(aDocument) {}
1676
1677
NS_IMETHOD Run() override {
1678
mDocument->BindingManager()->ProcessAttachedQueue();
1679
return NS_OK;
1680
}
1681
1682
private:
1683
RefPtr<Document> mDocument;
1684
};
1685
1686
nsresult PresShell::Initialize() {
1687
if (mIsDestroying) {
1688
return NS_OK;
1689
}
1690
1691
if (!mDocument) {
1692
// Nothing to do
1693
return NS_OK;
1694
}
1695
1696
MOZ_LOG(gLog, LogLevel::Debug, ("PresShell::Initialize this=%p", this));
1697
1698
NS_ASSERTION(!mDidInitialize, "Why are we being called?");
1699
1700
RefPtr<PresShell> kungFuDeathGrip(this);
1701
1702
RecomputeFontSizeInflationEnabled();
1703
MOZ_DIAGNOSTIC_ASSERT(!mIsDestroying);
1704
1705
// Ensure the pres context doesn't think it has changed, since we haven't even
1706
// started layout. This avoids spurious restyles / reflows afterwards.
1707
//
1708
// Note that this is very intentionally before setting mDidInitialize so it
1709
// doesn't notify the document, or run media query change events.
1710
mPresContext->FlushPendingMediaFeatureValuesChanged();
1711
MOZ_DIAGNOSTIC_ASSERT(!mIsDestroying);
1712
1713
mDidInitialize = true;
1714
1715
#ifdef DEBUG
1716
if (VerifyReflowFlags::NoisyCommands & gVerifyReflowFlags) {
1717
if (mDocument) {
1718
nsIURI* uri = mDocument->GetDocumentURI();
1719
if (uri) {
1720
printf("*** PresShell::Initialize (this=%p, url='%s')\n", (void*)this,
1721
uri->GetSpecOrDefault().get());
1722
}
1723
}
1724
}
1725
#endif
1726
1727
// Get the root frame from the frame manager
1728
// XXXbz it would be nice to move this somewhere else... like frame manager
1729
// Init(), say. But we need to make sure our views are all set up by the
1730
// time we do this!
1731
nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
1732
NS_ASSERTION(!rootFrame, "How did that happen, exactly?");
1733
1734
if (!rootFrame) {
1735
nsAutoScriptBlocker scriptBlocker;
1736
rootFrame = mFrameConstructor->ConstructRootFrame();
1737
mFrameConstructor->SetRootFrame(rootFrame);
1738
}
1739
1740
NS_ENSURE_STATE(!mHaveShutDown);
1741
1742
if (!rootFrame) {
1743
return NS_ERROR_OUT_OF_MEMORY;
1744
}
1745
1746
if (Element* root = mDocument->GetRootElement()) {
1747
{
1748
nsAutoCauseReflowNotifier reflowNotifier(this);
1749
// Have the style sheet processor construct frame for the root
1750
// content object down
1751
mFrameConstructor->ContentInserted(
1752
root, nullptr, nsCSSFrameConstructor::InsertionKind::Sync);
1753
1754
// Something in mFrameConstructor->ContentInserted may have caused
1755
// Destroy() to get called, bug 337586.
1756
NS_ENSURE_STATE(!mHaveShutDown);
1757
}
1758
1759
// nsAutoCauseReflowNotifier (which sets up a script blocker) going out of
1760
// scope may have killed us too
1761
NS_ENSURE_STATE(!mHaveShutDown);
1762
1763
// Run the XBL binding constructors for any new frames we've constructed.
1764
// (Do this in a script runner, since our caller might have a script
1765
// blocker on the stack.)
1766
nsContentUtils::AddScriptRunner(new XBLConstructorRunner(mDocument));
1767
1768
// XBLConstructorRunner might destroy us.
1769
NS_ENSURE_STATE(!mHaveShutDown);
1770
}
1771
1772
mDocument->TriggerAutoFocus();
1773
1774
NS_ASSERTION(rootFrame, "How did that happen?");
1775
1776
// Note: when the frame was created above it had the NS_FRAME_IS_DIRTY bit
1777
// set, but XBL processing could have caused a reflow which clears it.
1778
if (MOZ_LIKELY(rootFrame->GetStateBits() & NS_FRAME_IS_DIRTY)) {
1779
// Unset the DIRTY bits so that FrameNeedsReflow() will work right.
1780
rootFrame->RemoveStateBits(NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN);
1781
NS_ASSERTION(!mDirtyRoots.Contains(rootFrame),
1782
"Why is the root in mDirtyRoots already?");
1783
FrameNeedsReflow(rootFrame, IntrinsicDirty::Resize, NS_FRAME_IS_DIRTY);
1784
NS_ASSERTION(mDirtyRoots.Contains(rootFrame),
1785
"Should be in mDirtyRoots now");
1786
NS_ASSERTION(mObservingLayoutFlushes, "Why no reflow scheduled?");
1787
}
1788
1789
// Restore our root scroll position now if we're getting here after EndLoad
1790
// got called, since this is our one chance to do it. Note that we need not
1791
// have reflowed for this to work; when the scrollframe is finally reflowed
1792
// it'll pick up the position we store in it here.
1793
if (!mDocumentLoading) {
1794
RestoreRootScrollPosition();
1795
}
1796
1797
// For printing, we just immediately unsuppress.
1798
if (!mPresContext->IsPaginated()) {
1799
// Kick off a one-shot timer based off our pref value. When this timer
1800
// fires, if painting is still locked down, then we will go ahead and
1801
// trigger a full invalidate and allow painting to proceed normally.
1802
mPaintingSuppressed = true;
1803
// Don't suppress painting if the document isn't loading.
1804
Document::ReadyState readyState = mDocument->GetReadyStateEnum();
1805
if (readyState != Document::READYSTATE_COMPLETE) {
1806
mPaintSuppressionTimer = NS_NewTimer();
1807
}
1808
if (!mPaintSuppressionTimer) {
1809
mPaintingSuppressed = false;
1810
} else {
1811
// Initialize the timer.
1812
1813
// Default to PAINTLOCK_EVENT_DELAY if we can't get the pref value.
1814
int32_t delay = Preferences::GetInt("nglayout.initialpaint.delay",
1815
PAINTLOCK_EVENT_DELAY);
1816
1817
mPaintSuppressionTimer->SetTarget(
1818
mDocument->EventTargetFor(TaskCategory::Other));
1819
mPaintSuppressionTimer->InitWithNamedFuncCallback(
1820
sPaintSuppressionCallback, this, delay, nsITimer::TYPE_ONE_SHOT,
1821
"PresShell::sPaintSuppressionCallback");
1822
}
1823
}
1824
1825
// If we get here and painting is not suppressed, we still want to run the
1826
// unsuppression logic, so set mShouldUnsuppressPainting to true.
1827
if (!mPaintingSuppressed) {
1828
mShouldUnsuppressPainting = true;
1829
}
1830
1831
return NS_OK; // XXX this needs to be real. MMP
1832
}
1833
1834
void PresShell::sPaintSuppressionCallback(nsITimer* aTimer, void* aPresShell) {
1835
RefPtr<PresShell> self = static_cast<PresShell*>(aPresShell);
1836
if (self) self->UnsuppressPainting();
1837
}
1838
1839
nsresult PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight,
1840
nscoord aOldWidth, nscoord aOldHeight,
1841
ResizeReflowOptions aOptions) {
1842
if (mZoomConstraintsClient) {
1843
// If we have a ZoomConstraintsClient and the available screen area
1844
// changed, then we might need to disable double-tap-to-zoom, so notify
1845
// the ZCC to update itself.
1846
mZoomConstraintsClient->ScreenSizeChanged();
1847
}
1848
if (mMobileViewportManager) {
1849
// If we have a mobile viewport manager, request a reflow from it. It can
1850
// recompute the final CSS viewport and trigger a call to
1851
// ResizeReflowIgnoreOverride if it changed. We don't force adjusting
1852
// of resolution, because that is only necessary when we are destroying
1853
// the MVM.
1854
mMobileViewportManager->RequestReflow(false);
1855
return NS_OK;
1856
}
1857
1858
return ResizeReflowIgnoreOverride(aWidth, aHeight, aOldWidth, aOldHeight,
1859
aOptions);
1860
}
1861
1862
nsresult PresShell::ResizeReflowIgnoreOverride(nscoord aWidth, nscoord aHeight,
1863
nscoord aOldWidth,
1864
nscoord aOldHeight,
1865
ResizeReflowOptions aOptions) {
1866
MOZ_ASSERT(!mIsReflowing, "Shouldn't be in reflow here!");
1867
1868
nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
1869
if (!rootFrame) {
1870
// If we don't have a root frame yet, that means we haven't had our initial
1871
// reflow... If that's the case, and aWidth or aHeight is unconstrained,
1872
// ignore them altogether.
1873
if (aHeight == NS_UNCONSTRAINEDSIZE || aWidth == NS_UNCONSTRAINEDSIZE) {
1874
// We can't do the work needed for SizeToContent without a root
1875
// frame, and we want to return before setting the visible area.
1876
return