Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/layout/base/nsPresContext.cpp
Line
Count
Source (jump to first uncovered line)
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 1 */
8
9
#include "nsPresContext.h"
10
11
#include "mozilla/ArrayUtils.h"
12
#include "mozilla/DebugOnly.h"
13
#include "mozilla/Encoding.h"
14
#include "mozilla/EventDispatcher.h"
15
#include "mozilla/EventStateManager.h"
16
17
#include "base/basictypes.h"
18
19
#include "nsCOMPtr.h"
20
#include "nsCSSFrameConstructor.h"
21
#include "nsIPresShell.h"
22
#include "nsIPresShellInlines.h"
23
#include "nsDocShell.h"
24
#include "nsIContentViewer.h"
25
#include "nsPIDOMWindow.h"
26
#include "mozilla/ServoStyleSet.h"
27
#include "nsIContent.h"
28
#include "nsIFrame.h"
29
#include "nsIDocument.h"
30
#include "nsIDocumentInlines.h"
31
#include "nsIPrintSettings.h"
32
#include "nsLanguageAtomService.h"
33
#include "mozilla/LookAndFeel.h"
34
#include "nsIInterfaceRequestorUtils.h"
35
#include "nsHTMLDocument.h"
36
#include "nsIWeakReferenceUtils.h"
37
#include "nsThreadUtils.h"
38
#include "nsLayoutUtils.h"
39
#include "nsViewManager.h"
40
#include "mozilla/RestyleManager.h"
41
#include "SurfaceCacheUtils.h"
42
#include "nsMediaFeatures.h"
43
#include "gfxPlatform.h"
44
#include "nsFontFaceLoader.h"
45
#include "mozilla/AnimationEventDispatcher.h"
46
#include "mozilla/EffectCompositor.h"
47
#include "mozilla/EventListenerManager.h"
48
#include "prenv.h"
49
#include "nsPluginFrame.h"
50
#include "nsTransitionManager.h"
51
#include "nsAnimationManager.h"
52
#include "CounterStyleManager.h"
53
#include "mozilla/MemoryReporting.h"
54
#include "mozilla/dom/Element.h"
55
#include "nsIMessageManager.h"
56
#include "mozilla/dom/HTMLBodyElement.h"
57
#include "mozilla/dom/MediaQueryList.h"
58
#include "nsSMILAnimationController.h"
59
#include "mozilla/css/ImageLoader.h"
60
#include "mozilla/dom/PBrowserParent.h"
61
#include "mozilla/dom/TabChild.h"
62
#include "mozilla/dom/TabParent.h"
63
#include "nsRefreshDriver.h"
64
#include "Layers.h"
65
#include "LayerUserData.h"
66
#include "ClientLayerManager.h"
67
#include "mozilla/dom/NotifyPaintEvent.h"
68
#include "gfxPrefs.h"
69
#include "nsIDOMChromeWindow.h"
70
#include "nsFrameLoader.h"
71
#include "nsContentUtils.h"
72
#include "nsPIWindowRoot.h"
73
#include "mozilla/Preferences.h"
74
#include "gfxTextRun.h"
75
#include "nsFontFaceUtils.h"
76
#include "nsLayoutStylesheetCache.h"
77
#include "mozilla/ServoBindings.h"
78
#include "mozilla/StyleSheet.h"
79
#include "mozilla/StyleSheetInlines.h"
80
#include "mozilla/Telemetry.h"
81
#include "mozilla/dom/Performance.h"
82
#include "mozilla/dom/PerformanceTiming.h"
83
#include "mozilla/layers/APZThreadUtils.h"
84
85
// Needed for Start/Stop of Image Animation
86
#include "imgIContainer.h"
87
#include "nsIImageLoadingContent.h"
88
89
#include "nsBidiUtils.h"
90
#include "nsServiceManagerUtils.h"
91
#include "nsBidi.h"
92
93
#include "mozilla/dom/URL.h"
94
#include "mozilla/ServoCSSParser.h"
95
96
using namespace mozilla;
97
using namespace mozilla::dom;
98
using namespace mozilla::gfx;
99
using namespace mozilla::layers;
100
101
uint8_t gNotifySubDocInvalidationData;
102
103
// This preference was first introduced in Bug 232227, in order to prevent
104
// system colors from being exposed to CSS or canvas.
105
constexpr char kUseStandinsForNativeColors[] = "ui.use_standins_for_native_colors";
106
107
/**
108
 * Layer UserData for ContainerLayers that want to be notified
109
 * of local invalidations of them and their descendant layers.
110
 * Pass a callback to ComputeDifferences to have these called.
111
 */
112
class ContainerLayerPresContext : public LayerUserData {
113
public:
114
  nsPresContext* mPresContext;
115
};
116
117
118
nscolor
119
nsPresContext::MakeColorPref(const nsString& aColor)
120
0
{
121
0
  ServoStyleSet* styleSet = mShell ? mShell->StyleSet() : nullptr;
122
0
123
0
  nscolor result;
124
0
  bool ok = ServoCSSParser::
125
0
    ComputeColor(styleSet, NS_RGB(0, 0, 0), aColor, &result);
126
0
127
0
  if (!ok) {
128
0
    // Any better choices?
129
0
    result = NS_RGB(0, 0, 0);
130
0
  }
131
0
132
0
  return result;
133
0
}
134
135
bool
136
nsPresContext::IsDOMPaintEventPending()
137
0
{
138
0
  if (!mTransactions.IsEmpty()) {
139
0
    return true;
140
0
  }
141
0
142
0
  nsRootPresContext* drpc = GetRootPresContext();
143
0
  if (drpc && drpc->mRefreshDriver->ViewManagerFlushIsPending()) {
144
0
    // Since we're promising that there will be a MozAfterPaint event
145
0
    // fired, we record an empty invalidation in case display list
146
0
    // invalidation doesn't invalidate anything further.
147
0
    NotifyInvalidation(drpc->mRefreshDriver->LastTransactionId().Next(), nsRect(0, 0, 0, 0));
148
0
    return true;
149
0
  }
150
0
  return false;
151
0
}
152
153
void
154
nsPresContext::ForceReflowForFontInfoUpdate()
155
0
{
156
0
  // We can trigger reflow by pretending a font.* preference has changed;
157
0
  // this is the same mechanism as gfxPlatform::ForceGlobalReflow() uses
158
0
  // if new fonts are installed during the session, for example.
159
0
  PreferenceChanged("font.internaluseonly.changed");
160
0
}
161
162
static bool
163
IsVisualCharset(NotNull<const Encoding*> aCharset)
164
0
{
165
0
  return aCharset == ISO_8859_8_ENCODING;
166
0
}
167
168
nsPresContext::nsPresContext(nsIDocument* aDocument, nsPresContextType aType)
169
  : mType(aType),
170
    mShell(nullptr),
171
    mDocument(aDocument),
172
    mMedium(aType == eContext_Galley ? nsGkAtoms::screen : nsGkAtoms::print),
173
    mMediaEmulated(mMedium),
174
    mLinkHandler(nullptr),
175
    mInflationDisabledForShrinkWrap(false),
176
    mBaseMinFontSize(0),
177
    mSystemFontScale(1.0),
178
    mTextZoom(1.0),
179
    mEffectiveTextZoom(1.0),
180
    mFullZoom(1.0),
181
    mOverrideDPPX(0.0),
182
    mLastFontInflationScreenSize(gfxSize(-1.0, -1.0)),
183
    mCurAppUnitsPerDevPixel(0),
184
    mAutoQualityMinFontSizePixelsPref(0),
185
    mLangService(nsLanguageAtomService::GetService()),
186
    // origin nscoord_MIN is impossible, so the first ResizeReflow always fires
187
    mLastResizeEventVisibleArea(nsRect(nscoord_MIN, nscoord_MIN,
188
                                       NS_UNCONSTRAINEDSIZE,
189
                                       NS_UNCONSTRAINEDSIZE)),
190
    mPageSize(-1, -1),
191
    mPageScale(0.0),
192
    mPPScale(1.0f),
193
    mDefaultColor(NS_RGBA(0,0,0,0)),
194
    mBackgroundColor(NS_RGB(0xFF, 0xFF, 0xFF)),
195
    mLinkColor(NS_RGB(0x00, 0x00, 0xEE)),
196
    mActiveLinkColor(NS_RGB(0xEE, 0x00, 0x00)),
197
    mVisitedLinkColor(NS_RGB(0x55, 0x1A, 0x8B)),
198
    mFocusBackgroundColor(mBackgroundColor),
199
    mFocusTextColor(mDefaultColor),
200
    mBodyTextColor(mDefaultColor),
201
    mViewportScrollOverrideElement(nullptr),
202
    mViewportScrollStyles(NS_STYLE_OVERFLOW_AUTO, NS_STYLE_OVERFLOW_AUTO),
203
    mFocusRingWidth(1),
204
    mExistThrottledUpdates(false),
205
    // mImageAnimationMode is initialised below, in constructor body
206
    mImageAnimationModePref(imgIContainer::kNormalAnimMode),
207
    mFontGroupCacheDirty(true),
208
    mInterruptChecksToSkip(0),
209
    mElementsRestyled(0),
210
    mFramesConstructed(0),
211
    mFramesReflowed(0),
212
    mInteractionTimeEnabled(true),
213
    mHasPendingInterrupt(false),
214
    mPendingInterruptFromTest(false),
215
    mInterruptsEnabled(false),
216
    mUseDocumentFonts(true),
217
    mUseDocumentColors(true),
218
    mUnderlineLinks(true),
219
    mSendAfterPaintToContent(false),
220
    mUseFocusColors(false),
221
    mFocusRingOnAnything(false),
222
    mFocusRingStyle(false),
223
    mDrawImageBackground(true), // always draw the background
224
    mDrawColorBackground(true),
225
    // mNeverAnimate is initialised below, in constructor body
226
    mIsRenderingOnlySelection(false),
227
    mPaginated(aType != eContext_Galley),
228
    mCanPaginatedScroll(false),
229
    mDoScaledTwips(true),
230
    mIsRootPaginatedDocument(false),
231
    mPrefBidiDirection(false),
232
    mPrefScrollbarSide(0),
233
    mPendingSysColorChanged(false),
234
    mPendingThemeChanged(false),
235
    mPendingUIResolutionChanged(false),
236
    mPrefChangePendingNeedsReflow(false),
237
    mPostedPrefChangedRunnable(false),
238
    mIsEmulatingMedia(false),
239
    mIsGlyph(false),
240
    mUsesRootEMUnits(false),
241
    mUsesExChUnits(false),
242
    mCounterStylesDirty(true),
243
    mFontFeatureValuesDirty(true),
244
    mSuppressResizeReflow(false),
245
    mIsVisual(false),
246
    mIsChrome(false),
247
    mIsChromeOriginImage(false),
248
    mPaintFlashing(false),
249
    mPaintFlashingInitialized(false),
250
    mHasWarnedAboutPositionedTableParts(false),
251
    mHasWarnedAboutTooLargeDashedOrDottedRadius(false),
252
    mQuirkSheetAdded(false),
253
    mNeedsPrefUpdate(false),
254
    mHadNonBlankPaint(false)
255
#ifdef DEBUG
256
    , mInitialized(false)
257
#endif
258
0
{
259
0
  PodZero(&mBorderWidthTable);
260
#ifdef DEBUG
261
  PodZero(&mLayoutPhaseCount);
262
#endif
263
264
0
  if (!IsDynamic()) {
265
0
    mImageAnimationMode = imgIContainer::kDontAnimMode;
266
0
    mNeverAnimate = true;
267
0
  } else {
268
0
    mImageAnimationMode = imgIContainer::kNormalAnimMode;
269
0
    mNeverAnimate = false;
270
0
  }
271
0
  NS_ASSERTION(mDocument, "Null document");
272
0
273
0
  // if text perf logging enabled, init stats struct
274
0
  if (MOZ_LOG_TEST(gfxPlatform::GetLog(eGfxLog_textperf), LogLevel::Warning)) {
275
0
    mTextPerf = new gfxTextPerfMetrics();
276
0
  }
277
0
278
0
  if (Preferences::GetBool(GFX_MISSING_FONTS_NOTIFY_PREF)) {
279
0
    mMissingFonts = new gfxMissingFontRecorder();
280
0
  }
281
0
}
282
283
static const char* gExactCallbackPrefs[] = {
284
  "browser.underline_anchors",
285
  "browser.anchor_color",
286
  "browser.active_color",
287
  "browser.visited_color",
288
  "image.animation_mode",
289
  "dom.send_after_paint_to_content",
290
  "layout.css.dpi",
291
  "layout.css.devPixelsPerPx",
292
  "nglayout.debug.paint_flashing",
293
  "nglayout.debug.paint_flashing_chrome",
294
  kUseStandinsForNativeColors,
295
  "intl.accept_languages",
296
  nullptr,
297
};
298
299
static const char* gPrefixCallbackPrefs[] = {
300
  "font.",
301
  "browser.display.",
302
  "bidi.",
303
  "gfx.font_rendering.",
304
  nullptr,
305
};
306
307
void
308
nsPresContext::Destroy()
309
0
{
310
0
  if (mEventManager) {
311
0
    // unclear if these are needed, but can't hurt
312
0
    mEventManager->NotifyDestroyPresContext(this);
313
0
    mEventManager->SetPresContext(nullptr);
314
0
    mEventManager = nullptr;
315
0
  }
316
0
317
0
  // Unregister preference callbacks
318
0
  Preferences::UnregisterPrefixCallbacks(
319
0
    PREF_CHANGE_METHOD(nsPresContext::PreferenceChanged),
320
0
    gPrefixCallbackPrefs, this);
321
0
  Preferences::UnregisterCallbacks(
322
0
    PREF_CHANGE_METHOD(nsPresContext::PreferenceChanged),
323
0
    gExactCallbackPrefs, this);
324
0
325
0
  mRefreshDriver = nullptr;
326
0
}
327
328
nsPresContext::~nsPresContext()
329
0
{
330
0
  MOZ_ASSERT(!mShell, "Presshell forgot to clear our mShell pointer");
331
0
  DetachShell();
332
0
333
0
  Destroy();
334
0
}
335
336
0
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsPresContext)
337
0
   NS_INTERFACE_MAP_ENTRY(nsISupports)
338
0
NS_INTERFACE_MAP_END
339
340
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsPresContext)
341
NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(nsPresContext, LastRelease())
342
343
void
344
nsPresContext::LastRelease()
345
0
{
346
0
  if (mMissingFonts) {
347
0
    mMissingFonts->Clear();
348
0
  }
349
0
}
350
351
NS_IMPL_CYCLE_COLLECTION_CLASS(nsPresContext)
352
353
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsPresContext)
354
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnimationEventDispatcher);
355
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument);
356
0
  // NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mDeviceContext); // not xpcom
357
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEffectCompositor);
358
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEventManager);
359
0
  // NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mLanguage); // an atom
360
0
361
0
  // NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTheme); // a service
362
0
  // NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLangService); // a service
363
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrintSettings);
364
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
365
366
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsPresContext)
367
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mAnimationEventDispatcher);
368
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument);
369
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDeviceContext); // worth bothering?
370
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mEffectCompositor);
371
0
  // NS_RELEASE(tmp->mLanguage); // an atom
372
0
  // NS_IMPL_CYCLE_COLLECTION_UNLINK(mTheme); // a service
373
0
  // NS_IMPL_CYCLE_COLLECTION_UNLINK(mLangService); // a service
374
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mPrintSettings);
375
0
376
0
  tmp->Destroy();
377
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
378
379
// whether no native theme service exists;
380
// if this gets set to true, we'll stop asking for it.
381
static bool sNoTheme = false;
382
383
// Set to true when LookAndFeelChanged needs to be called.  This is used
384
// because the look and feel is a service, so there's no need to notify it from
385
// more than one prescontext.
386
static bool sLookAndFeelChanged;
387
388
// Set to true when ThemeChanged needs to be called on mTheme.  This is used
389
// because mTheme is a service, so there's no need to notify it from more than
390
// one prescontext.
391
static bool sThemeChanged;
392
393
void
394
nsPresContext::GetDocumentColorPreferences()
395
0
{
396
0
  // Make sure the preferences are initialized.  In the normal run,
397
0
  // they would already be, because gfxPlatform would have been created,
398
0
  // but in some reference tests, that is not the case.
399
0
  gfxPrefs::GetSingleton();
400
0
401
0
  int32_t useAccessibilityTheme = 0;
402
0
  bool usePrefColors = true;
403
0
  bool isChromeDocShell = false;
404
0
  static int32_t sDocumentColorsSetting;
405
0
  static bool sDocumentColorsSettingPrefCached = false;
406
0
  static bool sUseStandinsForNativeColors = false;
407
0
  if (!sDocumentColorsSettingPrefCached) {
408
0
    sDocumentColorsSettingPrefCached = true;
409
0
    Preferences::AddIntVarCache(&sDocumentColorsSetting,
410
0
                                "browser.display.document_color_use",
411
0
                                0);
412
0
413
0
    // The preference "ui.use_standins_for_native_colors" also affects
414
0
    // default foreground and background colors.
415
0
    Preferences::AddBoolVarCache(&sUseStandinsForNativeColors,
416
0
                                 kUseStandinsForNativeColors);
417
0
  }
418
0
419
0
  nsIDocument* doc = mDocument->GetDisplayDocument();
420
0
  if (doc && doc->GetDocShell()) {
421
0
    isChromeDocShell = nsIDocShellTreeItem::typeChrome ==
422
0
                       doc->GetDocShell()->ItemType();
423
0
  } else {
424
0
    nsCOMPtr<nsIDocShellTreeItem> docShell(mContainer);
425
0
    if (docShell) {
426
0
      isChromeDocShell = nsIDocShellTreeItem::typeChrome == docShell->ItemType();
427
0
    }
428
0
  }
429
0
430
0
  mIsChromeOriginImage = mDocument->IsBeingUsedAsImage() &&
431
0
                         IsChromeURI(mDocument->GetDocumentURI());
432
0
433
0
  if (isChromeDocShell || mIsChromeOriginImage) {
434
0
    usePrefColors = false;
435
0
  } else {
436
0
    useAccessibilityTheme =
437
0
      LookAndFeel::GetInt(LookAndFeel::eIntID_UseAccessibilityTheme, 0);
438
0
    usePrefColors = !useAccessibilityTheme;
439
0
  }
440
0
  if (usePrefColors) {
441
0
    usePrefColors =
442
0
      !Preferences::GetBool("browser.display.use_system_colors", false);
443
0
  }
444
0
445
0
  if (sUseStandinsForNativeColors) {
446
0
    // Once the preference "ui.use_standins_for_native_colors" is enabled,
447
0
    // use fixed color values instead of prefered colors and system colors.
448
0
    mDefaultColor = LookAndFeel::GetColorUsingStandins(
449
0
        LookAndFeel::eColorID_windowtext, NS_RGB(0x00, 0x00, 0x00));
450
0
    mBackgroundColor = LookAndFeel::GetColorUsingStandins(
451
0
        LookAndFeel::eColorID_window, NS_RGB(0xff, 0xff, 0xff));
452
0
  } else if (usePrefColors) {
453
0
    nsAutoString colorStr;
454
0
    Preferences::GetString("browser.display.foreground_color", colorStr);
455
0
    if (!colorStr.IsEmpty()) {
456
0
      mDefaultColor = MakeColorPref(colorStr);
457
0
    }
458
0
459
0
    colorStr.Truncate();
460
0
    Preferences::GetString("browser.display.background_color", colorStr);
461
0
    if (!colorStr.IsEmpty()) {
462
0
      mBackgroundColor = MakeColorPref(colorStr);
463
0
    }
464
0
  }
465
0
  else {
466
0
    mDefaultColor =
467
0
      LookAndFeel::GetColor(LookAndFeel::eColorID_WindowForeground,
468
0
                            NS_RGB(0x00, 0x00, 0x00));
469
0
    mBackgroundColor =
470
0
      LookAndFeel::GetColor(LookAndFeel::eColorID_WindowBackground,
471
0
                            NS_RGB(0xFF, 0xFF, 0xFF));
472
0
  }
473
0
474
0
  // Wherever we got the default background color from, ensure it is
475
0
  // opaque.
476
0
  mBackgroundColor = NS_ComposeColors(NS_RGB(0xFF, 0xFF, 0xFF),
477
0
                                      mBackgroundColor);
478
0
479
0
480
0
  // Now deal with the pref:
481
0
  // 0 = default: always, except in high contrast mode
482
0
  // 1 = always
483
0
  // 2 = never
484
0
  if (sDocumentColorsSetting == 1 || mDocument->IsBeingUsedAsImage()) {
485
0
    mUseDocumentColors = true;
486
0
  } else if (sDocumentColorsSetting == 2) {
487
0
    mUseDocumentColors = isChromeDocShell || mIsChromeOriginImage;
488
0
  } else {
489
0
    MOZ_ASSERT(!useAccessibilityTheme ||
490
0
               !(isChromeDocShell || mIsChromeOriginImage),
491
0
               "The accessibility theme should only be on for non-chrome");
492
0
    mUseDocumentColors = !useAccessibilityTheme;
493
0
  }
494
0
}
495
496
void
497
nsPresContext::GetUserPreferences()
498
0
{
499
0
  if (!GetPresShell()) {
500
0
    // No presshell means nothing to do here.  We'll do this when we
501
0
    // get a presshell.
502
0
    return;
503
0
  }
504
0
505
0
  mAutoQualityMinFontSizePixelsPref =
506
0
    Preferences::GetInt("browser.display.auto_quality_min_font_size");
507
0
508
0
  // * document colors
509
0
  GetDocumentColorPreferences();
510
0
511
0
  mSendAfterPaintToContent =
512
0
    Preferences::GetBool("dom.send_after_paint_to_content",
513
0
                         mSendAfterPaintToContent);
514
0
515
0
  // * link colors
516
0
  mUnderlineLinks =
517
0
    Preferences::GetBool("browser.underline_anchors", mUnderlineLinks);
518
0
519
0
  nsAutoString colorStr;
520
0
  Preferences::GetString("browser.anchor_color", colorStr);
521
0
  if (!colorStr.IsEmpty()) {
522
0
    mLinkColor = MakeColorPref(colorStr);
523
0
  }
524
0
525
0
  colorStr.Truncate();
526
0
  Preferences::GetString("browser.active_color", colorStr);
527
0
  if (!colorStr.IsEmpty()) {
528
0
    mActiveLinkColor = MakeColorPref(colorStr);
529
0
  }
530
0
531
0
  colorStr.Truncate();
532
0
  Preferences::GetString("browser.visited_color", colorStr);
533
0
  if (!colorStr.IsEmpty()) {
534
0
    mVisitedLinkColor = MakeColorPref(colorStr);
535
0
  }
536
0
537
0
  mUseFocusColors =
538
0
    Preferences::GetBool("browser.display.use_focus_colors", mUseFocusColors);
539
0
540
0
  mFocusTextColor = mDefaultColor;
541
0
  mFocusBackgroundColor = mBackgroundColor;
542
0
543
0
  colorStr.Truncate();
544
0
  Preferences::GetString("browser.display.focus_text_color", colorStr);
545
0
  if (!colorStr.IsEmpty()) {
546
0
    mFocusTextColor = MakeColorPref(colorStr);
547
0
  }
548
0
549
0
  colorStr.Truncate();
550
0
  Preferences::GetString("browser.display.focus_background_color", colorStr);
551
0
  if (!colorStr.IsEmpty()) {
552
0
    mFocusBackgroundColor = MakeColorPref(colorStr);
553
0
  }
554
0
555
0
  mFocusRingWidth =
556
0
    Preferences::GetInt("browser.display.focus_ring_width", mFocusRingWidth);
557
0
558
0
  mFocusRingOnAnything =
559
0
    Preferences::GetBool("browser.display.focus_ring_on_anything",
560
0
                         mFocusRingOnAnything);
561
0
562
0
  mFocusRingStyle =
563
0
    Preferences::GetInt("browser.display.focus_ring_style", mFocusRingStyle);
564
0
565
0
  mBodyTextColor = mDefaultColor;
566
0
567
0
  // * use fonts?
568
0
  mUseDocumentFonts =
569
0
    Preferences::GetInt("browser.display.use_document_fonts") != 0;
570
0
571
0
  mPrefScrollbarSide = Preferences::GetInt("layout.scrollbar.side");
572
0
573
0
  mLangGroupFontPrefs.Reset();
574
0
  mFontGroupCacheDirty = true;
575
0
  StaticPresData::Get()->ResetCachedFontPrefs();
576
0
577
0
  // * image animation
578
0
  nsAutoCString animatePref;
579
0
  Preferences::GetCString("image.animation_mode", animatePref);
580
0
  if (animatePref.EqualsLiteral("normal"))
581
0
    mImageAnimationModePref = imgIContainer::kNormalAnimMode;
582
0
  else if (animatePref.EqualsLiteral("none"))
583
0
    mImageAnimationModePref = imgIContainer::kDontAnimMode;
584
0
  else if (animatePref.EqualsLiteral("once"))
585
0
    mImageAnimationModePref = imgIContainer::kLoopOnceAnimMode;
586
0
  else // dynamic change to invalid value should act like it does initially
587
0
    mImageAnimationModePref = imgIContainer::kNormalAnimMode;
588
0
589
0
  uint32_t bidiOptions = GetBidi();
590
0
591
0
  int32_t prefInt =
592
0
    Preferences::GetInt(IBMBIDI_TEXTDIRECTION_STR,
593
0
                        GET_BIDI_OPTION_DIRECTION(bidiOptions));
594
0
  SET_BIDI_OPTION_DIRECTION(bidiOptions, prefInt);
595
0
  mPrefBidiDirection = prefInt;
596
0
597
0
  prefInt =
598
0
    Preferences::GetInt(IBMBIDI_TEXTTYPE_STR,
599
0
                        GET_BIDI_OPTION_TEXTTYPE(bidiOptions));
600
0
  SET_BIDI_OPTION_TEXTTYPE(bidiOptions, prefInt);
601
0
602
0
  prefInt =
603
0
    Preferences::GetInt(IBMBIDI_NUMERAL_STR,
604
0
                        GET_BIDI_OPTION_NUMERAL(bidiOptions));
605
0
  SET_BIDI_OPTION_NUMERAL(bidiOptions, prefInt);
606
0
607
0
  // We don't need to force reflow: either we are initializing a new
608
0
  // prescontext or we are being called from UpdateAfterPreferencesChanged()
609
0
  // which triggers a reflow anyway.
610
0
  SetBidi(bidiOptions);
611
0
}
612
613
void
614
nsPresContext::InvalidatePaintedLayers()
615
0
{
616
0
  if (!mShell)
617
0
    return;
618
0
  if (nsIFrame* rootFrame = mShell->GetRootFrame()) {
619
0
    // FrameLayerBuilder caches invalidation-related values that depend on the
620
0
    // appunits-per-dev-pixel ratio, so ensure that all PaintedLayer drawing
621
0
    // is completely flushed.
622
0
    rootFrame->InvalidateFrameSubtree();
623
0
  }
624
0
}
625
626
void
627
nsPresContext::AppUnitsPerDevPixelChanged()
628
0
{
629
0
  InvalidatePaintedLayers();
630
0
631
0
  if (mDeviceContext) {
632
0
    mDeviceContext->FlushFontCache();
633
0
  }
634
0
635
0
  MediaFeatureValuesChanged({
636
0
    eRestyle_ForceDescendants,
637
0
    NS_STYLE_HINT_REFLOW,
638
0
    MediaFeatureChangeReason::ResolutionChange
639
0
  });
640
0
641
0
  mCurAppUnitsPerDevPixel = AppUnitsPerDevPixel();
642
0
}
643
644
void
645
nsPresContext::PreferenceChanged(const char* aPrefName)
646
0
{
647
0
  nsDependentCString prefName(aPrefName);
648
0
  if (prefName.EqualsLiteral("layout.css.dpi") ||
649
0
      prefName.EqualsLiteral("layout.css.devPixelsPerPx")) {
650
0
651
0
    int32_t oldAppUnitsPerDevPixel = AppUnitsPerDevPixel();
652
0
    if (mDeviceContext->CheckDPIChange() && mShell) {
653
0
      nsCOMPtr<nsIPresShell> shell = mShell;
654
0
      // Re-fetch the view manager's window dimensions in case there's a deferred
655
0
      // resize which hasn't affected our mVisibleArea yet
656
0
      nscoord oldWidthAppUnits, oldHeightAppUnits;
657
0
      RefPtr<nsViewManager> vm = shell->GetViewManager();
658
0
      if (!vm) {
659
0
        return;
660
0
      }
661
0
      vm->GetWindowDimensions(&oldWidthAppUnits, &oldHeightAppUnits);
662
0
      float oldWidthDevPixels = oldWidthAppUnits/oldAppUnitsPerDevPixel;
663
0
      float oldHeightDevPixels = oldHeightAppUnits/oldAppUnitsPerDevPixel;
664
0
665
0
      nscoord width = NSToCoordRound(oldWidthDevPixels*AppUnitsPerDevPixel());
666
0
      nscoord height = NSToCoordRound(oldHeightDevPixels*AppUnitsPerDevPixel());
667
0
      vm->SetWindowDimensions(width, height);
668
0
669
0
      AppUnitsPerDevPixelChanged();
670
0
    }
671
0
    return;
672
0
  }
673
0
  if (prefName.EqualsLiteral(GFX_MISSING_FONTS_NOTIFY_PREF)) {
674
0
    if (Preferences::GetBool(GFX_MISSING_FONTS_NOTIFY_PREF)) {
675
0
      if (!mMissingFonts) {
676
0
        mMissingFonts = new gfxMissingFontRecorder();
677
0
        // trigger reflow to detect missing fonts on the current page
678
0
        mPrefChangePendingNeedsReflow = true;
679
0
      }
680
0
    } else {
681
0
      if (mMissingFonts) {
682
0
        mMissingFonts->Clear();
683
0
      }
684
0
      mMissingFonts = nullptr;
685
0
    }
686
0
  }
687
0
  if (StringBeginsWith(prefName, NS_LITERAL_CSTRING("font.")) ||
688
0
      prefName.EqualsLiteral("intl.accept_languages")) {
689
0
    // Changes to font family preferences don't change anything in the
690
0
    // computed style data, so the style system won't generate a reflow
691
0
    // hint for us.  We need to do that manually.
692
0
693
0
    // FIXME We could probably also handle changes to
694
0
    // browser.display.auto_quality_min_font_size here, but that
695
0
    // probably also requires clearing the text run cache, so don't
696
0
    // bother (yet, anyway).
697
0
    mPrefChangePendingNeedsReflow = true;
698
0
  }
699
0
  if (StringBeginsWith(prefName, NS_LITERAL_CSTRING("bidi."))) {
700
0
    // Changes to bidi prefs need to trigger a reflow (see bug 443629)
701
0
    mPrefChangePendingNeedsReflow = true;
702
0
703
0
    // Changes to bidi.numeral also needs to empty the text run cache.
704
0
    // This is handled in gfxTextRunWordCache.cpp.
705
0
  }
706
0
  if (StringBeginsWith(prefName, NS_LITERAL_CSTRING("gfx.font_rendering."))) {
707
0
    // Changes to font_rendering prefs need to trigger a reflow
708
0
    mPrefChangePendingNeedsReflow = true;
709
0
  }
710
0
711
0
  // We will end up calling InvalidatePreferenceSheets one from each pres
712
0
  // context, but all it's doing is clearing its cached sheet pointers, so it
713
0
  // won't be wastefully recreating the sheet multiple times.
714
0
  //
715
0
  // The first pres context that has its pref changed runnable called will
716
0
  // be the one to cause the reconstruction of the pref style sheet.
717
0
  nsLayoutStylesheetCache::InvalidatePreferenceSheets();
718
0
  DispatchPrefChangedRunnableIfNeeded();
719
0
720
0
  if (prefName.EqualsLiteral("nglayout.debug.paint_flashing") ||
721
0
      prefName.EqualsLiteral("nglayout.debug.paint_flashing_chrome")) {
722
0
    mPaintFlashingInitialized = false;
723
0
    return;
724
0
  }
725
0
}
726
727
void
728
nsPresContext::DispatchPrefChangedRunnableIfNeeded()
729
0
{
730
0
  if (mPostedPrefChangedRunnable) {
731
0
    return;
732
0
  }
733
0
734
0
  nsCOMPtr<nsIRunnable> runnable =
735
0
    NewRunnableMethod("nsPresContext::UpdateAfterPreferencesChanged",
736
0
                      this,
737
0
                      &nsPresContext::UpdateAfterPreferencesChanged);
738
0
  nsresult rv = Document()->Dispatch(TaskCategory::Other, runnable.forget());
739
0
  if (NS_SUCCEEDED(rv)) {
740
0
    mPostedPrefChangedRunnable = true;
741
0
  }
742
0
}
743
744
void
745
nsPresContext::UpdateAfterPreferencesChanged()
746
0
{
747
0
  mPostedPrefChangedRunnable = false;
748
0
  if (!mShell) {
749
0
    return;
750
0
  }
751
0
752
0
  if (!mContainer) {
753
0
    // Delay updating until there is a container
754
0
    mNeedsPrefUpdate = true;
755
0
    return;
756
0
  }
757
0
758
0
  nsCOMPtr<nsIDocShellTreeItem> docShell(mContainer);
759
0
  if (docShell && nsIDocShellTreeItem::typeChrome == docShell->ItemType()) {
760
0
    return;
761
0
  }
762
0
763
0
  // Initialize our state from the user preferences
764
0
  GetUserPreferences();
765
0
766
0
  // update the presShell: tell it to set the preference style rules up
767
0
  mShell->UpdatePreferenceStyles();
768
0
769
0
  InvalidatePaintedLayers();
770
0
  mDeviceContext->FlushFontCache();
771
0
772
0
  nsChangeHint hint = nsChangeHint(0);
773
0
774
0
  if (mPrefChangePendingNeedsReflow) {
775
0
    hint |= NS_STYLE_HINT_REFLOW;
776
0
  }
777
0
778
0
  // Preferences require rerunning selector matching because we rebuild
779
0
  // the pref style sheet for some preference changes.
780
0
  RebuildAllStyleData(hint, eRestyle_Subtree);
781
0
}
782
783
nsresult
784
nsPresContext::Init(nsDeviceContext* aDeviceContext)
785
0
{
786
0
  NS_ASSERTION(!mInitialized, "attempt to reinit pres context");
787
0
  NS_ENSURE_ARG(aDeviceContext);
788
0
789
0
  mDeviceContext = aDeviceContext;
790
0
791
0
  // In certain rare cases (such as changing page mode), we tear down layout
792
0
  // state and re-initialize a new prescontext for a document. Given that we
793
0
  // hang style state off the DOM, we detect that re-initialization case and
794
0
  // lazily drop the servo data. We don't do this eagerly during layout teardown
795
0
  // because that would incur an extra whole-tree traversal that's unnecessary
796
0
  // most of the time.
797
0
  //
798
0
  // FIXME(emilio): I'm pretty sure this doesn't happen after bug 1414999.
799
0
  Element* root = mDocument->GetRootElement();
800
0
  if (root && root->HasServoData()) {
801
0
    RestyleManager::ClearServoDataFromSubtree(root);
802
0
  }
803
0
804
0
  if (mDeviceContext->SetFullZoom(mFullZoom))
805
0
    mDeviceContext->FlushFontCache();
806
0
  mCurAppUnitsPerDevPixel = AppUnitsPerDevPixel();
807
0
808
0
  mEventManager = new mozilla::EventStateManager();
809
0
810
0
  mAnimationEventDispatcher = new mozilla::AnimationEventDispatcher(this);
811
0
  mEffectCompositor = new mozilla::EffectCompositor(this);
812
0
  mTransitionManager = MakeUnique<nsTransitionManager>(this);
813
0
  mAnimationManager = MakeUnique<nsAnimationManager>(this);
814
0
815
0
  if (mDocument->GetDisplayDocument()) {
816
0
    NS_ASSERTION(mDocument->GetDisplayDocument()->GetPresContext(),
817
0
                 "Why are we being initialized?");
818
0
    mRefreshDriver = mDocument->GetDisplayDocument()->
819
0
      GetPresContext()->RefreshDriver();
820
0
  } else {
821
0
    nsIDocument* parent = mDocument->GetParentDocument();
822
0
    // Unfortunately, sometimes |parent| here has no presshell because
823
0
    // printing screws up things.  Assert that in other cases it does,
824
0
    // but whenever the shell is null just fall back on using our own
825
0
    // refresh driver.
826
0
    NS_ASSERTION(!parent || mDocument->IsStaticDocument() || parent->GetShell(),
827
0
                 "How did we end up with a presshell if our parent doesn't "
828
0
                 "have one?");
829
0
    if (parent && parent->GetPresContext()) {
830
0
      // We don't have our container set yet at this point
831
0
      nsCOMPtr<nsIDocShellTreeItem> ourItem = mDocument->GetDocShell();
832
0
      if (ourItem) {
833
0
        nsCOMPtr<nsIDocShellTreeItem> parentItem;
834
0
        ourItem->GetSameTypeParent(getter_AddRefs(parentItem));
835
0
        if (parentItem) {
836
0
          Element* containingElement =
837
0
            parent->FindContentForSubDocument(mDocument);
838
0
          if (!containingElement->IsXULElement() ||
839
0
              !containingElement->
840
0
                HasAttr(kNameSpaceID_None,
841
0
                        nsGkAtoms::forceOwnRefreshDriver)) {
842
0
            mRefreshDriver = parent->GetPresContext()->RefreshDriver();
843
0
          }
844
0
        }
845
0
      }
846
0
    }
847
0
848
0
    if (!mRefreshDriver) {
849
0
      mRefreshDriver = new nsRefreshDriver(this);
850
0
    }
851
0
  }
852
0
853
0
  // Register callbacks so we're notified when the preferences change
854
0
  Preferences::RegisterPrefixCallbacks(
855
0
    PREF_CHANGE_METHOD(nsPresContext::PreferenceChanged),
856
0
    gPrefixCallbackPrefs, this);
857
0
  Preferences::RegisterCallbacks(
858
0
    PREF_CHANGE_METHOD(nsPresContext::PreferenceChanged),
859
0
    gExactCallbackPrefs, this);
860
0
861
0
  nsresult rv = mEventManager->Init();
862
0
  NS_ENSURE_SUCCESS(rv, rv);
863
0
864
0
  mEventManager->SetPresContext(this);
865
0
866
#ifdef DEBUG
867
  mInitialized = true;
868
#endif
869
870
0
  return NS_OK;
871
0
}
872
873
// Note: We don't hold a reference on the shell; it has a reference to
874
// us
875
void
876
nsPresContext::AttachShell(nsIPresShell* aShell)
877
0
{
878
0
  MOZ_ASSERT(!mShell);
879
0
  mShell = aShell;
880
0
881
0
  mRestyleManager = MakeUnique<mozilla::RestyleManager>(this);
882
0
883
0
  // Since CounterStyleManager is also the name of a method of
884
0
  // nsPresContext, it is necessary to prefix the class with the mozilla
885
0
  // namespace here.
886
0
  mCounterStyleManager = new mozilla::CounterStyleManager(this);
887
0
888
0
  nsIDocument *doc = mShell->GetDocument();
889
0
  NS_ASSERTION(doc, "expect document here");
890
0
  if (doc) {
891
0
    // Have to update PresContext's mDocument before calling any other methods.
892
0
    mDocument = doc;
893
0
  }
894
0
  // Initialize our state from the user preferences, now that we
895
0
  // have a presshell, and hence a document.
896
0
  GetUserPreferences();
897
0
898
0
  if (doc) {
899
0
    nsIURI *docURI = doc->GetDocumentURI();
900
0
901
0
    if (IsDynamic() && docURI) {
902
0
      bool isChrome = false;
903
0
      bool isRes = false;
904
0
      docURI->SchemeIs("chrome", &isChrome);
905
0
      docURI->SchemeIs("resource", &isRes);
906
0
907
0
      if (!isChrome && !isRes)
908
0
        mImageAnimationMode = mImageAnimationModePref;
909
0
      else
910
0
        mImageAnimationMode = imgIContainer::kNormalAnimMode;
911
0
    }
912
0
913
0
    UpdateCharSet(doc->GetDocumentCharacterSet());
914
0
  }
915
0
}
916
917
void
918
nsPresContext::DetachShell()
919
0
{
920
0
  // The counter style manager's destructor needs to deallocate with the
921
0
  // presshell arena. Disconnect it before nulling out the shell.
922
0
  //
923
0
  // XXXbholley: Given recent refactorings, it probably makes more sense to
924
0
  // just null our mShell at the bottom of this function. I'm leaving it
925
0
  // this way to preserve the old ordering, but I doubt anything would break.
926
0
  if (mCounterStyleManager) {
927
0
    mCounterStyleManager->Disconnect();
928
0
    mCounterStyleManager = nullptr;
929
0
  }
930
0
931
0
  mShell = nullptr;
932
0
933
0
  if (mAnimationEventDispatcher) {
934
0
    mAnimationEventDispatcher->Disconnect();
935
0
    mAnimationEventDispatcher = nullptr;
936
0
  }
937
0
  if (mEffectCompositor) {
938
0
    mEffectCompositor->Disconnect();
939
0
    mEffectCompositor = nullptr;
940
0
  }
941
0
  if (mTransitionManager) {
942
0
    mTransitionManager->Disconnect();
943
0
    mTransitionManager = nullptr;
944
0
  }
945
0
  if (mAnimationManager) {
946
0
    mAnimationManager->Disconnect();
947
0
    mAnimationManager = nullptr;
948
0
  }
949
0
  if (mRestyleManager) {
950
0
    mRestyleManager->Disconnect();
951
0
    mRestyleManager = nullptr;
952
0
  }
953
0
  if (mRefreshDriver && mRefreshDriver->GetPresContext() == this) {
954
0
    mRefreshDriver->Disconnect();
955
0
    // Can't null out the refresh driver here.
956
0
  }
957
0
958
0
  if (IsRoot()) {
959
0
    nsRootPresContext* thisRoot = static_cast<nsRootPresContext*>(this);
960
0
961
0
    // Have to cancel our plugin geometry timer, because the
962
0
    // callback for that depends on a non-null presshell.
963
0
    thisRoot->CancelApplyPluginGeometryTimer();
964
0
  }
965
0
}
966
967
void
968
nsPresContext::DoChangeCharSet(NotNull<const Encoding*> aCharSet)
969
0
{
970
0
  UpdateCharSet(aCharSet);
971
0
  mDeviceContext->FlushFontCache();
972
0
973
0
  // If a document contains one or more <script> elements, frame construction
974
0
  // might happen earlier than the UpdateCharSet(), so we need to restyle
975
0
  // descendants to make their style data up-to-date.
976
0
  //
977
0
  // FIXME(emilio): Revisit whether this is true after bug 1438911.
978
0
  RebuildAllStyleData(NS_STYLE_HINT_REFLOW, eRestyle_ForceDescendants);
979
0
}
980
981
void
982
nsPresContext::UpdateCharSet(NotNull<const Encoding*> aCharSet)
983
0
{
984
0
  mLanguage = mLangService->LookupCharSet(aCharSet);
985
0
  // this will be a language group (or script) code rather than a true language code
986
0
987
0
  // bug 39570: moved from nsLanguageAtomService::LookupCharSet()
988
0
  if (mLanguage == nsGkAtoms::Unicode) {
989
0
    mLanguage = mLangService->GetLocaleLanguage();
990
0
  }
991
0
  mLangGroupFontPrefs.Reset();
992
0
  mFontGroupCacheDirty = true;
993
0
994
0
  switch (GET_BIDI_OPTION_TEXTTYPE(GetBidi())) {
995
0
996
0
    case IBMBIDI_TEXTTYPE_LOGICAL:
997
0
      SetVisualMode(false);
998
0
      break;
999
0
1000
0
    case IBMBIDI_TEXTTYPE_VISUAL:
1001
0
      SetVisualMode(true);
1002
0
      break;
1003
0
1004
0
    case IBMBIDI_TEXTTYPE_CHARSET:
1005
0
    default:
1006
0
      SetVisualMode(IsVisualCharset(aCharSet));
1007
0
  }
1008
0
}
1009
1010
void
1011
nsPresContext::DispatchCharSetChange(NotNull<const Encoding*> aEncoding)
1012
0
{
1013
0
  // In Servo RebuildAllStyleData is async, so no need to do the runnable dance.
1014
0
  DoChangeCharSet(aEncoding);
1015
0
}
1016
1017
nsPresContext*
1018
nsPresContext::GetParentPresContext()
1019
0
{
1020
0
  nsIPresShell* shell = GetPresShell();
1021
0
  if (shell) {
1022
0
    nsViewManager* viewManager = shell->GetViewManager();
1023
0
    if (viewManager) {
1024
0
      nsView* view = viewManager->GetRootView();
1025
0
      if (view) {
1026
0
        view = view->GetParent(); // anonymous inner view
1027
0
        if (view) {
1028
0
          view = view->GetParent(); // subdocumentframe's view
1029
0
          if (view) {
1030
0
            nsIFrame* f = view->GetFrame();
1031
0
            if (f) {
1032
0
              return f->PresContext();
1033
0
            }
1034
0
          }
1035
0
        }
1036
0
      }
1037
0
    }
1038
0
  }
1039
0
  return nullptr;
1040
0
}
1041
1042
nsPresContext*
1043
nsPresContext::GetToplevelContentDocumentPresContext()
1044
0
{
1045
0
  if (IsChrome())
1046
0
    return nullptr;
1047
0
  nsPresContext* pc = this;
1048
0
  for (;;) {
1049
0
    nsPresContext* parent = pc->GetParentPresContext();
1050
0
    if (!parent || parent->IsChrome())
1051
0
      return pc;
1052
0
    pc = parent;
1053
0
  }
1054
0
}
1055
1056
nsIWidget*
1057
nsPresContext::GetNearestWidget(nsPoint* aOffset)
1058
0
{
1059
0
  NS_ENSURE_TRUE(mShell, nullptr);
1060
0
  nsIFrame* frame = mShell->GetRootFrame();
1061
0
  NS_ENSURE_TRUE(frame, nullptr);
1062
0
  return frame->GetView()->GetNearestWidget(aOffset);
1063
0
}
1064
1065
nsIWidget*
1066
nsPresContext::GetRootWidget()
1067
0
{
1068
0
  NS_ENSURE_TRUE(mShell, nullptr);
1069
0
  nsViewManager* vm = mShell->GetViewManager();
1070
0
  if (!vm) {
1071
0
    return nullptr;
1072
0
  }
1073
0
  nsCOMPtr<nsIWidget> widget;
1074
0
  vm->GetRootWidget(getter_AddRefs(widget));
1075
0
  return widget.get();
1076
0
}
1077
1078
// We may want to replace this with something faster, maybe caching the root prescontext
1079
nsRootPresContext*
1080
nsPresContext::GetRootPresContext()
1081
0
{
1082
0
  nsPresContext* pc = this;
1083
0
  for (;;) {
1084
0
    nsPresContext* parent = pc->GetParentPresContext();
1085
0
    if (!parent)
1086
0
      break;
1087
0
    pc = parent;
1088
0
  }
1089
0
  return pc->IsRoot() ? static_cast<nsRootPresContext*>(pc) : nullptr;
1090
0
}
1091
1092
void
1093
nsPresContext::CompatibilityModeChanged()
1094
0
{
1095
0
  if (!mShell) {
1096
0
    return;
1097
0
  }
1098
0
1099
0
  ServoStyleSet* styleSet = mShell->StyleSet();
1100
0
  styleSet->CompatibilityModeChanged();
1101
0
1102
0
  mShell->EnsureStyleFlush();
1103
0
1104
0
  if (mDocument->IsSVGDocument()) {
1105
0
    // SVG documents never load quirk.css.
1106
0
    return;
1107
0
  }
1108
0
1109
0
  bool needsQuirkSheet = CompatibilityMode() == eCompatibility_NavQuirks;
1110
0
  if (mQuirkSheetAdded == needsQuirkSheet) {
1111
0
    return;
1112
0
  }
1113
0
1114
0
  auto cache = nsLayoutStylesheetCache::Singleton();
1115
0
  StyleSheet* sheet = cache->QuirkSheet();
1116
0
1117
0
  if (needsQuirkSheet) {
1118
0
    // quirk.css needs to come after html.css; we just keep it at the end.
1119
0
    DebugOnly<nsresult> rv =
1120
0
      styleSet->AppendStyleSheet(SheetType::Agent, sheet);
1121
0
    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "failed to insert quirk.css");
1122
0
  } else {
1123
0
    DebugOnly<nsresult> rv =
1124
0
      styleSet->RemoveStyleSheet(SheetType::Agent, sheet);
1125
0
    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "failed to remove quirk.css");
1126
0
  }
1127
0
1128
0
  mQuirkSheetAdded = needsQuirkSheet;
1129
0
  mShell->ApplicableStylesChanged();
1130
0
}
1131
1132
// Helper function for setting Anim Mode on image
1133
static void SetImgAnimModeOnImgReq(imgIRequest* aImgReq, uint16_t aMode)
1134
0
{
1135
0
  if (aImgReq) {
1136
0
    nsCOMPtr<imgIContainer> imgCon;
1137
0
    aImgReq->GetImage(getter_AddRefs(imgCon));
1138
0
    if (imgCon) {
1139
0
      imgCon->SetAnimationMode(aMode);
1140
0
    }
1141
0
  }
1142
0
}
1143
1144
// IMPORTANT: Assumption is that all images for a Presentation
1145
// have the same Animation Mode (pavlov said this was OK)
1146
//
1147
// Walks content and set the animation mode
1148
// this is a way to turn on/off image animations
1149
void nsPresContext::SetImgAnimations(nsIContent *aParent, uint16_t aMode)
1150
0
{
1151
0
  nsCOMPtr<nsIImageLoadingContent> imgContent(do_QueryInterface(aParent));
1152
0
  if (imgContent) {
1153
0
    nsCOMPtr<imgIRequest> imgReq;
1154
0
    imgContent->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
1155
0
                           getter_AddRefs(imgReq));
1156
0
    SetImgAnimModeOnImgReq(imgReq, aMode);
1157
0
  }
1158
0
1159
0
  for (nsIContent* childContent = aParent->GetFirstChild();
1160
0
       childContent; childContent = childContent->GetNextSibling()) {
1161
0
    SetImgAnimations(childContent, aMode);
1162
0
  }
1163
0
}
1164
1165
void
1166
nsPresContext::SetSMILAnimations(nsIDocument *aDoc, uint16_t aNewMode,
1167
                                 uint16_t aOldMode)
1168
0
{
1169
0
  if (aDoc->HasAnimationController()) {
1170
0
    nsSMILAnimationController* controller = aDoc->GetAnimationController();
1171
0
    switch (aNewMode)
1172
0
    {
1173
0
      case imgIContainer::kNormalAnimMode:
1174
0
      case imgIContainer::kLoopOnceAnimMode:
1175
0
        if (aOldMode == imgIContainer::kDontAnimMode)
1176
0
          controller->Resume(nsSMILTimeContainer::PAUSE_USERPREF);
1177
0
        break;
1178
0
1179
0
      case imgIContainer::kDontAnimMode:
1180
0
        if (aOldMode != imgIContainer::kDontAnimMode)
1181
0
          controller->Pause(nsSMILTimeContainer::PAUSE_USERPREF);
1182
0
        break;
1183
0
    }
1184
0
  }
1185
0
}
1186
1187
void
1188
nsPresContext::SetImageAnimationMode(uint16_t aMode)
1189
0
{
1190
0
  NS_ASSERTION(aMode == imgIContainer::kNormalAnimMode ||
1191
0
               aMode == imgIContainer::kDontAnimMode ||
1192
0
               aMode == imgIContainer::kLoopOnceAnimMode, "Wrong Animation Mode is being set!");
1193
0
1194
0
  // Image animation mode cannot be changed when rendering to a printer.
1195
0
  if (!IsDynamic())
1196
0
    return;
1197
0
1198
0
  // Now walk the content tree and set the animation mode
1199
0
  // on all the images.
1200
0
  if (mShell != nullptr) {
1201
0
    nsIDocument *doc = mShell->GetDocument();
1202
0
    if (doc) {
1203
0
      doc->StyleImageLoader()->SetAnimationMode(aMode);
1204
0
1205
0
      Element *rootElement = doc->GetRootElement();
1206
0
      if (rootElement) {
1207
0
        SetImgAnimations(rootElement, aMode);
1208
0
      }
1209
0
      SetSMILAnimations(doc, aMode, mImageAnimationMode);
1210
0
    }
1211
0
  }
1212
0
1213
0
  mImageAnimationMode = aMode;
1214
0
}
1215
1216
already_AddRefed<nsAtom>
1217
nsPresContext::GetContentLanguage() const
1218
0
{
1219
0
  nsAutoString language;
1220
0
  Document()->GetContentLanguage(language);
1221
0
  language.StripWhitespace();
1222
0
1223
0
  // Content-Language may be a comma-separated list of language codes,
1224
0
  // in which case the HTML5 spec says to treat it as unknown
1225
0
  if (!language.IsEmpty() &&
1226
0
      !language.Contains(char16_t(','))) {
1227
0
    return NS_Atomize(language);
1228
0
    // NOTE:  This does *not* count as an explicit language; in other
1229
0
    // words, it doesn't trigger language-specific hyphenation.
1230
0
  }
1231
0
  return nullptr;
1232
0
}
1233
1234
void
1235
nsPresContext::UpdateEffectiveTextZoom()
1236
0
{
1237
0
  float newZoom = mSystemFontScale * mTextZoom;
1238
0
  float minZoom = nsLayoutUtils::MinZoom();
1239
0
  float maxZoom = nsLayoutUtils::MaxZoom();
1240
0
1241
0
  if (newZoom < minZoom) {
1242
0
    newZoom = minZoom;
1243
0
  } else if (newZoom > maxZoom) {
1244
0
    newZoom = maxZoom;
1245
0
  }
1246
0
1247
0
  mEffectiveTextZoom = newZoom;
1248
0
1249
0
  // Media queries could have changed, since we changed the meaning
1250
0
  // of 'em' units in them.
1251
0
  MediaFeatureValuesChanged({
1252
0
    eRestyle_ForceDescendants,
1253
0
    NS_STYLE_HINT_REFLOW,
1254
0
    MediaFeatureChangeReason::ZoomChange
1255
0
  });
1256
0
}
1257
1258
float
1259
nsPresContext::GetDeviceFullZoom()
1260
0
{
1261
0
  return mDeviceContext->GetFullZoom();
1262
0
}
1263
1264
void
1265
nsPresContext::SetFullZoom(float aZoom)
1266
0
{
1267
0
  if (!mShell || mFullZoom == aZoom) {
1268
0
    return;
1269
0
  }
1270
0
1271
0
  // Re-fetch the view manager's window dimensions in case there's a deferred
1272
0
  // resize which hasn't affected our mVisibleArea yet
1273
0
  nscoord oldWidthAppUnits, oldHeightAppUnits;
1274
0
  mShell->GetViewManager()->GetWindowDimensions(&oldWidthAppUnits, &oldHeightAppUnits);
1275
0
  float oldWidthDevPixels = oldWidthAppUnits / float(mCurAppUnitsPerDevPixel);
1276
0
  float oldHeightDevPixels = oldHeightAppUnits / float(mCurAppUnitsPerDevPixel);
1277
0
  mDeviceContext->SetFullZoom(aZoom);
1278
0
1279
0
  NS_ASSERTION(!mSuppressResizeReflow, "two zooms happening at the same time? impossible!");
1280
0
  mSuppressResizeReflow = true;
1281
0
1282
0
  mFullZoom = aZoom;
1283
0
  mShell->GetViewManager()->
1284
0
    SetWindowDimensions(NSToCoordRound(oldWidthDevPixels * AppUnitsPerDevPixel()),
1285
0
                        NSToCoordRound(oldHeightDevPixels * AppUnitsPerDevPixel()));
1286
0
1287
0
  AppUnitsPerDevPixelChanged();
1288
0
1289
0
  mSuppressResizeReflow = false;
1290
0
}
1291
1292
void
1293
nsPresContext::SetOverrideDPPX(float aDPPX)
1294
0
{
1295
0
  // SetOverrideDPPX is called during navigations, including history
1296
0
  // traversals.  In that case, it's typically called with our current value,
1297
0
  // and we don't need to actually do anything.
1298
0
  if (aDPPX == mOverrideDPPX) {
1299
0
    return;
1300
0
  }
1301
0
1302
0
  mOverrideDPPX = aDPPX;
1303
0
  MediaFeatureValuesChanged({ MediaFeatureChangeReason::ResolutionChange });
1304
0
}
1305
1306
gfxSize
1307
nsPresContext::ScreenSizeInchesForFontInflation(bool* aChanged)
1308
0
{
1309
0
  if (aChanged) {
1310
0
    *aChanged = false;
1311
0
  }
1312
0
1313
0
  nsDeviceContext *dx = DeviceContext();
1314
0
  nsRect clientRect;
1315
0
  dx->GetClientRect(clientRect); // FIXME: GetClientRect looks expensive
1316
0
  float unitsPerInch = dx->AppUnitsPerPhysicalInch();
1317
0
  gfxSize deviceSizeInches(float(clientRect.width) / unitsPerInch,
1318
0
                           float(clientRect.height) / unitsPerInch);
1319
0
1320
0
  if (mLastFontInflationScreenSize == gfxSize(-1.0, -1.0)) {
1321
0
    mLastFontInflationScreenSize = deviceSizeInches;
1322
0
  }
1323
0
1324
0
  if (deviceSizeInches != mLastFontInflationScreenSize && aChanged) {
1325
0
    *aChanged = true;
1326
0
    mLastFontInflationScreenSize = deviceSizeInches;
1327
0
  }
1328
0
1329
0
  return deviceSizeInches;
1330
0
}
1331
1332
static bool
1333
CheckOverflow(const nsStyleDisplay* aDisplay, ScrollStyles* aStyles)
1334
0
{
1335
0
  if (aDisplay->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE &&
1336
0
      aDisplay->mScrollBehavior == NS_STYLE_SCROLL_BEHAVIOR_AUTO &&
1337
0
      aDisplay->mScrollSnapTypeX == NS_STYLE_SCROLL_SNAP_TYPE_NONE &&
1338
0
      aDisplay->mScrollSnapTypeY == NS_STYLE_SCROLL_SNAP_TYPE_NONE &&
1339
0
      aDisplay->mScrollSnapPointsX == nsStyleCoord(eStyleUnit_None) &&
1340
0
      aDisplay->mScrollSnapPointsY == nsStyleCoord(eStyleUnit_None) &&
1341
0
      !aDisplay->mScrollSnapDestination.mXPosition.mHasPercent &&
1342
0
      !aDisplay->mScrollSnapDestination.mYPosition.mHasPercent &&
1343
0
      aDisplay->mScrollSnapDestination.mXPosition.mLength == 0 &&
1344
0
      aDisplay->mScrollSnapDestination.mYPosition.mLength == 0) {
1345
0
    return false;
1346
0
  }
1347
0
1348
0
  if (aDisplay->mOverflowX == NS_STYLE_OVERFLOW_CLIP) {
1349
0
    *aStyles = ScrollStyles(NS_STYLE_OVERFLOW_HIDDEN,
1350
0
                            NS_STYLE_OVERFLOW_HIDDEN, aDisplay);
1351
0
  } else {
1352
0
    *aStyles = ScrollStyles(aDisplay);
1353
0
  }
1354
0
  return true;
1355
0
}
1356
1357
static Element*
1358
GetPropagatedScrollStylesForViewport(nsPresContext* aPresContext,
1359
                                     ScrollStyles *aStyles)
1360
0
{
1361
0
  nsIDocument* document = aPresContext->Document();
1362
0
  Element* docElement = document->GetRootElement();
1363
0
1364
0
  // docElement might be null if we're doing this after removing it.
1365
0
  if (!docElement) {
1366
0
    return nullptr;
1367
0
  }
1368
0
1369
0
  // Check the style on the document root element
1370
0
  ServoStyleSet* styleSet = aPresContext->StyleSet();
1371
0
  RefPtr<ComputedStyle> rootStyle =
1372
0
    styleSet->ResolveStyleFor(docElement, LazyComputeBehavior::Allow);
1373
0
  if (CheckOverflow(rootStyle->StyleDisplay(), aStyles)) {
1374
0
    // tell caller we stole the overflow style from the root element
1375
0
    return docElement;
1376
0
  }
1377
0
1378
0
  // Don't look in the BODY for non-HTML documents or HTML documents
1379
0
  // with non-HTML roots.
1380
0
  // XXX this should be earlier; we shouldn't even look at the document root
1381
0
  // for non-HTML documents. Fix this once we support explicit CSS styling
1382
0
  // of the viewport
1383
0
  if (!document->IsHTMLOrXHTML() || !docElement->IsHTMLElement()) {
1384
0
    return nullptr;
1385
0
  }
1386
0
1387
0
  Element* bodyElement = document->AsHTMLDocument()->GetBodyElement();
1388
0
  if (!bodyElement) {
1389
0
    // No body, nothing to do here.
1390
0
    return nullptr;
1391
0
  }
1392
0
1393
0
  MOZ_ASSERT(bodyElement->IsHTMLElement(nsGkAtoms::body),
1394
0
             "GetBodyElement returned something bogus");
1395
0
1396
0
  RefPtr<ComputedStyle> bodyStyle =
1397
0
    styleSet->ResolveStyleFor(bodyElement,
1398
0
                              LazyComputeBehavior::Allow);
1399
0
1400
0
  if (CheckOverflow(bodyStyle->StyleDisplay(), aStyles)) {
1401
0
    // tell caller we stole the overflow style from the body element
1402
0
    return bodyElement;
1403
0
  }
1404
0
1405
0
  return nullptr;
1406
0
}
1407
1408
Element*
1409
nsPresContext::UpdateViewportScrollStylesOverride()
1410
0
{
1411
0
  // Start off with our default styles, and then update them as needed.
1412
0
  mViewportScrollStyles = ScrollStyles(NS_STYLE_OVERFLOW_AUTO,
1413
0
                                       NS_STYLE_OVERFLOW_AUTO);
1414
0
  mViewportScrollOverrideElement = nullptr;
1415
0
  // Don't propagate the scrollbar state in printing or print preview.
1416
0
  if (!IsPaginated()) {
1417
0
    mViewportScrollOverrideElement =
1418
0
      GetPropagatedScrollStylesForViewport(this, &mViewportScrollStyles);
1419
0
  }
1420
0
1421
0
  nsIDocument* document = Document();
1422
0
  if (Element* fullscreenElement = document->GetFullscreenElement()) {
1423
0
    // If the document is in fullscreen, but the fullscreen element is
1424
0
    // not the root element, we should explicitly suppress the scrollbar
1425
0
    // here. Note that, we still need to return the original element
1426
0
    // the styles are from, so that the state of those elements is not
1427
0
    // affected across fullscreen change.
1428
0
    if (fullscreenElement != document->GetRootElement() &&
1429
0
        fullscreenElement != mViewportScrollOverrideElement) {
1430
0
      mViewportScrollStyles = ScrollStyles(NS_STYLE_OVERFLOW_HIDDEN,
1431
0
                                           NS_STYLE_OVERFLOW_HIDDEN);
1432
0
    }
1433
0
  }
1434
0
  return mViewportScrollOverrideElement;
1435
0
}
1436
1437
bool
1438
nsPresContext::ElementWouldPropagateScrollStyles(const Element& aElement)
1439
0
{
1440
0
  MOZ_ASSERT(IsPaginated(), "Should only be called on paginated contexts");
1441
0
  if (aElement.GetParent() && !aElement.IsHTMLElement(nsGkAtoms::body)) {
1442
0
    // We certainly won't be propagating from this element.
1443
0
    return false;
1444
0
  }
1445
0
1446
0
  // Go ahead and just call GetPropagatedScrollStylesForViewport, but update
1447
0
  // a dummy ScrollStyles we don't care about.  It'll do a bit of extra work,
1448
0
  // but saves us having to have more complicated code or more code duplication;
1449
0
  // in practice we will make this call quite rarely, because we checked for all
1450
0
  // the common cases above.
1451
0
  ScrollStyles dummy(NS_STYLE_OVERFLOW_AUTO, NS_STYLE_OVERFLOW_AUTO);
1452
0
  return GetPropagatedScrollStylesForViewport(this, &dummy) == &aElement;
1453
0
}
1454
1455
void
1456
nsPresContext::SetContainer(nsIDocShell* aDocShell)
1457
0
{
1458
0
  if (aDocShell) {
1459
0
    NS_ASSERTION(!(mContainer && mNeedsPrefUpdate),
1460
0
                 "Should only need pref update if mContainer is null.");
1461
0
    mContainer = static_cast<nsDocShell*>(aDocShell);
1462
0
    if (mNeedsPrefUpdate) {
1463
0
      DispatchPrefChangedRunnableIfNeeded();
1464
0
      mNeedsPrefUpdate = false;
1465
0
    }
1466
0
  } else {
1467
0
    mContainer = WeakPtr<nsDocShell>();
1468
0
  }
1469
0
  UpdateIsChrome();
1470
0
  if (mContainer) {
1471
0
    GetDocumentColorPreferences();
1472
0
  }
1473
0
}
1474
1475
nsISupports*
1476
nsPresContext::GetContainerWeak() const
1477
0
{
1478
0
  return static_cast<nsIDocShell*>(mContainer);
1479
0
}
1480
1481
nsIDocShell*
1482
nsPresContext::GetDocShell() const
1483
0
{
1484
0
  return mContainer;
1485
0
}
1486
1487
/* virtual */ void
1488
nsPresContext::Detach()
1489
0
{
1490
0
  SetContainer(nullptr);
1491
0
  SetLinkHandler(nullptr);
1492
0
}
1493
1494
bool
1495
nsPresContext::BidiEnabled() const
1496
0
{
1497
0
  return Document()->GetBidiEnabled();
1498
0
}
1499
1500
void
1501
nsPresContext::SetBidiEnabled() const
1502
0
{
1503
0
  if (mShell) {
1504
0
    nsIDocument *doc = mShell->GetDocument();
1505
0
    if (doc) {
1506
0
      doc->SetBidiEnabled();
1507
0
    }
1508
0
  }
1509
0
}
1510
1511
void
1512
nsPresContext::SetBidi(uint32_t aSource)
1513
0
{
1514
0
  // Don't do all this stuff unless the options have changed.
1515
0
  if (aSource == GetBidi()) {
1516
0
    return;
1517
0
  }
1518
0
1519
0
  Document()->SetBidiOptions(aSource);
1520
0
  if (IBMBIDI_TEXTDIRECTION_RTL == GET_BIDI_OPTION_DIRECTION(aSource)
1521
0
      || IBMBIDI_NUMERAL_HINDI == GET_BIDI_OPTION_NUMERAL(aSource)) {
1522
0
    SetBidiEnabled();
1523
0
  }
1524
0
  if (IBMBIDI_TEXTTYPE_VISUAL == GET_BIDI_OPTION_TEXTTYPE(aSource)) {
1525
0
    SetVisualMode(true);
1526
0
  }
1527
0
  else if (IBMBIDI_TEXTTYPE_LOGICAL == GET_BIDI_OPTION_TEXTTYPE(aSource)) {
1528
0
    SetVisualMode(false);
1529
0
  }
1530
0
  else {
1531
0
    nsIDocument* doc = mShell->GetDocument();
1532
0
    if (doc) {
1533
0
      SetVisualMode(IsVisualCharset(doc->GetDocumentCharacterSet()));
1534
0
    }
1535
0
  }
1536
0
}
1537
1538
uint32_t
1539
nsPresContext::GetBidi() const
1540
0
{
1541
0
  return Document()->GetBidiOptions();
1542
0
}
1543
1544
bool
1545
nsPresContext::IsTopLevelWindowInactive()
1546
0
{
1547
0
  return Document()->IsTopLevelWindowInactive();
1548
0
}
1549
1550
void
1551
nsPresContext::RecordInteractionTime(InteractionType aType,
1552
                                     const TimeStamp& aTimeStamp)
1553
0
{
1554
0
  if (!mInteractionTimeEnabled || aTimeStamp.IsNull()) {
1555
0
    return;
1556
0
  }
1557
0
1558
0
  // Array of references to the member variable of each time stamp
1559
0
  // for the different interaction types, keyed by InteractionType.
1560
0
  TimeStamp nsPresContext::*interactionTimes[] = {
1561
0
    &nsPresContext::mFirstClickTime,
1562
0
    &nsPresContext::mFirstKeyTime,
1563
0
    &nsPresContext::mFirstMouseMoveTime,
1564
0
    &nsPresContext::mFirstScrollTime
1565
0
  };
1566
0
1567
0
  // Array of histogram IDs for the different interaction types,
1568
0
  // keyed by InteractionType.
1569
0
  Telemetry::HistogramID histogramIds[] = {
1570
0
    Telemetry::TIME_TO_FIRST_CLICK_MS,
1571
0
    Telemetry::TIME_TO_FIRST_KEY_INPUT_MS,
1572
0
    Telemetry::TIME_TO_FIRST_MOUSE_MOVE_MS,
1573
0
    Telemetry::TIME_TO_FIRST_SCROLL_MS
1574
0
  };
1575
0
1576
0
  TimeStamp& interactionTime = this->*(
1577
0
    interactionTimes[static_cast<uint32_t>(aType)]);
1578
0
  if (!interactionTime.IsNull()) {
1579
0
    // We have already recorded an interaction time.
1580
0
    return;
1581
0
  }
1582
0
1583
0
  // Record the interaction time if it occurs after the first paint
1584
0
  // of the top level content document.
1585
0
  nsPresContext* topContentPresContext =
1586
0
    GetToplevelContentDocumentPresContext();
1587
0
1588
0
  if (!topContentPresContext) {
1589
0
    // There is no top content pres context so we don't care
1590
0
    // about the interaction time. Record a value anyways to avoid
1591
0
    // trying to find the top content pres context in future interactions.
1592
0
    interactionTime = TimeStamp::Now();
1593
0
    return;
1594
0
  }
1595
0
1596
0
  if (topContentPresContext->mFirstNonBlankPaintTime.IsNull() ||
1597
0
      topContentPresContext->mFirstNonBlankPaintTime > aTimeStamp) {
1598
0
    // Top content pres context has not had a non-blank paint yet
1599
0
    // or the event timestamp is before the first non-blank paint,
1600
0
    // so don't record interaction time.
1601
0
    return;
1602
0
  }
1603
0
1604
0
  // Check if we are recording the first of any of the interaction types.
1605
0
  bool isFirstInteraction = true;
1606
0
  for (TimeStamp nsPresContext::* memberPtr : interactionTimes) {
1607
0
    TimeStamp& timeStamp = this->*(memberPtr);
1608
0
    if (!timeStamp.IsNull()) {
1609
0
      isFirstInteraction = false;
1610
0
      break;
1611
0
    }
1612
0
  }
1613
0
1614
0
  interactionTime = TimeStamp::Now();
1615
0
  // Only the top level content pres context reports first interaction
1616
0
  // time to telemetry (if it hasn't already done so).
1617
0
  if (this == topContentPresContext) {
1618
0
    if (Telemetry::CanRecordExtended()) {
1619
0
       double millis =
1620
0
         (interactionTime - mFirstNonBlankPaintTime).ToMilliseconds();
1621
0
       Telemetry::Accumulate(histogramIds[static_cast<uint32_t>(aType)],
1622
0
                             millis);
1623
0
1624
0
       if (isFirstInteraction) {
1625
0
         Telemetry::Accumulate(Telemetry::TIME_TO_FIRST_INTERACTION_MS, millis);
1626
0
       }
1627
0
    }
1628
0
  } else {
1629
0
    topContentPresContext->RecordInteractionTime(aType, aTimeStamp);
1630
0
  }
1631
0
}
1632
1633
nsITheme*
1634
nsPresContext::GetTheme()
1635
0
{
1636
0
  if (!sNoTheme && !mTheme) {
1637
0
    mTheme = do_GetNativeTheme();
1638
0
    if (!mTheme)
1639
0
      sNoTheme = true;
1640
0
  }
1641
0
1642
0
  return mTheme;
1643
0
}
1644
1645
void
1646
nsPresContext::ThemeChanged()
1647
0
{
1648
0
  if (!mPendingThemeChanged) {
1649
0
    sLookAndFeelChanged = true;
1650
0
    sThemeChanged = true;
1651
0
1652
0
    nsCOMPtr<nsIRunnable> ev =
1653
0
      NewRunnableMethod("nsPresContext::ThemeChangedInternal",
1654
0
                        this,
1655
0
                        &nsPresContext::ThemeChangedInternal);
1656
0
    nsresult rv = Document()->Dispatch(TaskCategory::Other, ev.forget());
1657
0
    if (NS_SUCCEEDED(rv)) {
1658
0
      mPendingThemeChanged = true;
1659
0
    }
1660
0
  }
1661
0
}
1662
1663
static bool
1664
NotifyThemeChanged(TabParent* aTabParent, void* aArg)
1665
0
{
1666
0
  aTabParent->ThemeChanged();
1667
0
  return false;
1668
0
}
1669
1670
void
1671
nsPresContext::ThemeChangedInternal()
1672
0
{
1673
0
  mPendingThemeChanged = false;
1674
0
1675
0
  // Tell the theme that it changed, so it can flush any handles to stale theme
1676
0
  // data.
1677
0
  if (mTheme && sThemeChanged) {
1678
0
    mTheme->ThemeChanged();
1679
0
    sThemeChanged = false;
1680
0
  }
1681
0
1682
0
  if (sLookAndFeelChanged) {
1683
0
    // Clear all cached LookAndFeel colors.
1684
0
    LookAndFeel::Refresh();
1685
0
    sLookAndFeelChanged = false;
1686
0
1687
0
    // Vector images (SVG) may be using theme colors so we discard all cached
1688
0
    // surfaces. (We could add a vector image only version of DiscardAll, but
1689
0
    // in bug 940625 we decided theme changes are rare enough not to bother.)
1690
0
    image::SurfaceCacheUtils::DiscardAll();
1691
0
  }
1692
0
1693
0
  RefreshSystemMetrics();
1694
0
1695
0
  // Recursively notify all remote leaf descendants that the
1696
0
  // system theme has changed.
1697
0
  if (nsPIDOMWindowOuter* window = mDocument->GetWindow()) {
1698
0
    nsContentUtils::CallOnAllRemoteChildren(window,
1699
0
                                            NotifyThemeChanged, nullptr);
1700
0
  }
1701
0
}
1702
1703
void
1704
nsPresContext::SysColorChanged()
1705
0
{
1706
0
  if (!mPendingSysColorChanged) {
1707
0
    sLookAndFeelChanged = true;
1708
0
    nsCOMPtr<nsIRunnable> ev =
1709
0
      NewRunnableMethod("nsPresContext::SysColorChangedInternal",
1710
0
                        this,
1711
0
                        &nsPresContext::SysColorChangedInternal);
1712
0
    nsresult rv = Document()->Dispatch(TaskCategory::Other, ev.forget());
1713
0
    if (NS_SUCCEEDED(rv)) {
1714
0
      mPendingSysColorChanged = true;
1715
0
    }
1716
0
  }
1717
0
}
1718
1719
void
1720
nsPresContext::SysColorChangedInternal()
1721
0
{
1722
0
  mPendingSysColorChanged = false;
1723
0
1724
0
  if (sLookAndFeelChanged) {
1725
0
     // Don't use the cached values for the system colors
1726
0
    LookAndFeel::Refresh();
1727
0
    sLookAndFeelChanged = false;
1728
0
  }
1729
0
1730
0
  // Invalidate cached '-moz-windows-accent-color-applies' media query:
1731
0
  RefreshSystemMetrics();
1732
0
1733
0
  // Reset default background and foreground colors for the document since
1734
0
  // they may be using system colors
1735
0
  GetDocumentColorPreferences();
1736
0
1737
0
  // The system color values are computed to colors in the style data,
1738
0
  // so normal style data comparison is sufficient here.
1739
0
  RebuildAllStyleData(nsChangeHint(0), nsRestyleHint(0));
1740
0
}
1741
1742
void
1743
nsPresContext::RefreshSystemMetrics()
1744
0
{
1745
0
  // This will force the system metrics to be generated the next time they're
1746
0
  // used.
1747
0
  nsMediaFeatures::FreeSystemMetrics();
1748
0
1749
0
  // Changes to system metrics can change media queries on them.
1750
0
  //
1751
0
  // Changes in theme can change system colors (whose changes are
1752
0
  // properly reflected in computed style data), system fonts (whose
1753
0
  // changes are not), and -moz-appearance (whose changes likewise are
1754
0
  // not), so we need to recascade for the first, and reflow for the rest.
1755
0
  MediaFeatureValuesChangedAllDocuments({
1756
0
    eRestyle_ForceDescendants,
1757
0
    NS_STYLE_HINT_REFLOW,
1758
0
    MediaFeatureChangeReason::SystemMetricsChange,
1759
0
  });
1760
0
}
1761
1762
void
1763
nsPresContext::UIResolutionChanged()
1764
0
{
1765
0
  if (!mPendingUIResolutionChanged) {
1766
0
    nsCOMPtr<nsIRunnable> ev =
1767
0
      NewRunnableMethod("nsPresContext::UIResolutionChangedInternal",
1768
0
                        this,
1769
0
                        &nsPresContext::UIResolutionChangedInternal);
1770
0
    nsresult rv =
1771
0
      Document()->Dispatch(TaskCategory::Other, ev.forget());
1772
0
    if (NS_SUCCEEDED(rv)) {
1773
0
      mPendingUIResolutionChanged = true;
1774
0
    }
1775
0
  }
1776
0
}
1777
1778
void
1779
nsPresContext::UIResolutionChangedSync()
1780
0
{
1781
0
  if (!mPendingUIResolutionChanged) {
1782
0
    mPendingUIResolutionChanged = true;
1783
0
    UIResolutionChangedInternalScale(0.0);
1784
0
  }
1785
0
}
1786
1787
/*static*/ bool
1788
nsPresContext::UIResolutionChangedSubdocumentCallback(nsIDocument* aDocument,
1789
                                                      void* aData)
1790
0
{
1791
0
  nsPresContext* pc = aDocument->GetPresContext();
1792
0
  if (pc) {
1793
0
    // For subdocuments, we want to apply the parent's scale, because there
1794
0
    // are cases where the subdoc's device context is connected to a widget
1795
0
    // that has an out-of-date resolution (it's on a different screen, but
1796
0
    // currently hidden, and will not be updated until shown): bug 1249279.
1797
0
    double scale = *static_cast<double*>(aData);
1798
0
    pc->UIResolutionChangedInternalScale(scale);
1799
0
  }
1800
0
  return true;
1801
0
}
1802
1803
static void
1804
NotifyTabUIResolutionChanged(TabParent* aTab, void *aArg)
1805
0
{
1806
0
  aTab->UIResolutionChanged();
1807
0
}
1808
1809
static void
1810
NotifyChildrenUIResolutionChanged(nsPIDOMWindowOuter* aWindow)
1811
0
{
1812
0
  nsCOMPtr<nsIDocument> doc = aWindow->GetExtantDoc();
1813
0
  RefPtr<nsPIWindowRoot> topLevelWin = nsContentUtils::GetWindowRoot(doc);
1814
0
  if (!topLevelWin) {
1815
0
    return;
1816
0
  }
1817
0
  topLevelWin->EnumerateBrowsers(NotifyTabUIResolutionChanged, nullptr);
1818
0
}
1819
1820
void
1821
nsPresContext::UIResolutionChangedInternal()
1822
0
{
1823
0
  UIResolutionChangedInternalScale(0.0);
1824
0
}
1825
1826
void
1827
nsPresContext::UIResolutionChangedInternalScale(double aScale)
1828
0
{
1829
0
  mPendingUIResolutionChanged = false;
1830
0
1831
0
  mDeviceContext->CheckDPIChange(&aScale);
1832
0
  if (mCurAppUnitsPerDevPixel != AppUnitsPerDevPixel()) {
1833
0
    AppUnitsPerDevPixelChanged();
1834
0
  }
1835
0
1836
0
  // Recursively notify all remote leaf descendants of the change.
1837
0
  if (nsPIDOMWindowOuter* window = mDocument->GetWindow()) {
1838
0
    NotifyChildrenUIResolutionChanged(window);
1839
0
  }
1840
0
1841
0
  mDocument->EnumerateSubDocuments(UIResolutionChangedSubdocumentCallback,
1842
0
                                   &aScale);
1843
0
}
1844
1845
void
1846
nsPresContext::EmulateMedium(const nsAString& aMediaType)
1847
0
{
1848
0
  nsAtom* previousMedium = Medium();
1849
0
  mIsEmulatingMedia = true;
1850
0
1851
0
  nsAutoString mediaType;
1852
0
  nsContentUtils::ASCIIToLower(aMediaType, mediaType);
1853
0
1854
0
  mMediaEmulated = NS_Atomize(mediaType);
1855
0
  if (mMediaEmulated != previousMedium && mShell) {
1856
0
    MediaFeatureValuesChanged({ MediaFeatureChangeReason::MediumChange });
1857
0
  }
1858
0
}
1859
1860
void nsPresContext::StopEmulatingMedium()
1861
0
{
1862
0
  nsAtom* previousMedium = Medium();
1863
0
  mIsEmulatingMedia = false;
1864
0
  if (Medium() != previousMedium) {
1865
0
    MediaFeatureValuesChanged({ MediaFeatureChangeReason::MediumChange });
1866
0
  }
1867
0
}
1868
1869
void
1870
nsPresContext::ForceCacheLang(nsAtom *aLanguage)
1871
0
{
1872
0
  // force it to be cached
1873
0
  GetDefaultFont(kPresContext_DefaultVariableFont_ID, aLanguage);
1874
0
  mLanguagesUsed.PutEntry(aLanguage);
1875
0
}
1876
1877
void
1878
nsPresContext::CacheAllLangs()
1879
0
{
1880
0
  if (mFontGroupCacheDirty) {
1881
0
    RefPtr<nsAtom> thisLang = nsStyleFont::GetLanguage(this);
1882
0
    GetDefaultFont(kPresContext_DefaultVariableFont_ID, thisLang.get());
1883
0
    GetDefaultFont(kPresContext_DefaultVariableFont_ID, nsGkAtoms::x_math);
1884
0
    // https://bugzilla.mozilla.org/show_bug.cgi?id=1362599#c12
1885
0
    GetDefaultFont(kPresContext_DefaultVariableFont_ID, nsGkAtoms::Unicode);
1886
0
    for (auto iter = mLanguagesUsed.Iter(); !iter.Done(); iter.Next()) {
1887
0
1888
0
      GetDefaultFont(kPresContext_DefaultVariableFont_ID, iter.Get()->GetKey());
1889
0
    }
1890
0
  }
1891
0
  mFontGroupCacheDirty = false;
1892
0
}
1893
1894
void
1895
nsPresContext::RebuildAllStyleData(nsChangeHint aExtraHint,
1896
                                   nsRestyleHint aRestyleHint)
1897
0
{
1898
0
  if (!mShell) {
1899
0
    // We must have been torn down. Nothing to do here.
1900
0
    return;
1901
0
  }
1902
0
1903
0
  // FIXME(emilio): Why is it safe to reset mUsesRootEMUnits / mUsesEXChUnits
1904
0
  // here if there's no restyle hint? That looks pretty bogus.
1905
0
  mUsesRootEMUnits = false;
1906
0
  mUsesExChUnits = false;
1907
0
1908
0
  // TODO(emilio): It's unclear to me why would these three calls below be
1909
0
  // needed. In particular, RebuildAllStyleData doesn't rebuild rules or
1910
0
  // specified style information and such (note the comment in
1911
0
  // RestyleManager::RebuildAllStyleData re. the funny semantics), so I
1912
0
  // don't know why should we rebuild the user font set / counter styles /
1913
0
  // etc...
1914
0
  mDocument->MarkUserFontSetDirty();
1915
0
  MarkCounterStylesDirty();
1916
0
  MarkFontFeatureValuesDirty();
1917
0
1918
0
  RestyleManager()->RebuildAllStyleData(aExtraHint, aRestyleHint);
1919
0
}
1920
1921
void
1922
nsPresContext::PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint,
1923
                                            nsRestyleHint aRestyleHint)
1924
0
{
1925
0
  if (!mShell) {
1926
0
    // We must have been torn down. Nothing to do here.
1927
0
    return;
1928
0
  }
1929
0
  RestyleManager()->PostRebuildAllStyleDataEvent(aExtraHint, aRestyleHint);
1930
0
}
1931
1932
struct MediaFeatureHints
1933
{
1934
  nsRestyleHint restyleHint;
1935
  nsChangeHint changeHint;
1936
};
1937
1938
static bool
1939
MediaFeatureValuesChangedAllDocumentsCallback(nsIDocument* aDocument, void* aChange)
1940
0
{
1941
0
  auto* change = static_cast<const MediaFeatureChange*>(aChange);
1942
0
  if (nsPresContext* pc = aDocument->GetPresContext()) {
1943
0
    pc->MediaFeatureValuesChangedAllDocuments(*change);
1944
0
  }
1945
0
  return true;
1946
0
}
1947
1948
void
1949
nsPresContext::MediaFeatureValuesChangedAllDocuments(
1950
    const MediaFeatureChange& aChange)
1951
0
{
1952
0
    MediaFeatureValuesChanged(aChange);
1953
0
    mDocument->EnumerateSubDocuments(
1954
0
      MediaFeatureValuesChangedAllDocumentsCallback,
1955
0
      const_cast<MediaFeatureChange*>(&aChange));
1956
0
}
1957
1958
void
1959
nsPresContext::FlushPendingMediaFeatureValuesChanged()
1960
0
{
1961
0
  if (!mPendingMediaFeatureValuesChange) {
1962
0
    return;
1963
0
  }
1964
0
1965
0
  MediaFeatureChange change = *mPendingMediaFeatureValuesChange;
1966
0
  mPendingMediaFeatureValuesChange.reset();
1967
0
1968
0
  // MediumFeaturesChanged updates the applied rules, so it always gets called.
1969
0
  if (mShell) {
1970
0
    change.mRestyleHint |=
1971
0
      mShell->StyleSet()->MediumFeaturesChanged(change.mReason);
1972
0
  }
1973
0
1974
0
  if (change.mRestyleHint || change.mChangeHint) {
1975
0
    RebuildAllStyleData(change.mChangeHint, change.mRestyleHint);
1976
0
  }
1977
0
1978
0
  if (!mShell || !mShell->DidInitialize()) {
1979
0
    return;
1980
0
  }
1981
0
1982
0
  if (mDocument->IsBeingUsedAsImage()) {
1983
0
    MOZ_ASSERT(mDocument->MediaQueryLists().isEmpty());
1984
0
    return;
1985
0
  }
1986
0
1987
0
  mDocument->NotifyMediaFeatureValuesChanged();
1988
0
1989
0
  MOZ_DIAGNOSTIC_ASSERT(nsContentUtils::IsSafeToRunScript());
1990
0
1991
0
  // Media query list listeners should be notified from a queued task
1992
0
  // (in HTML5 terms), although we also want to notify them on certain
1993
0
  // flushes.  (We're already running off an event.)
1994
0
  //
1995
0
  // Note that we do this after the new style from media queries in
1996
0
  // style sheets has been computed.
1997
0
1998
0
  if (mDocument->MediaQueryLists().isEmpty()) {
1999
0
    return;
2000
0
  }
2001
0
2002
0
  // We build a list of all the notifications we're going to send
2003
0
  // before we send any of them.
2004
0
2005
0
  // Copy pointers to all the lists into a new array, in case one of our
2006
0
  // notifications modifies the list.
2007
0
  nsTArray<RefPtr<mozilla::dom::MediaQueryList>> localMediaQueryLists;
2008
0
  for (MediaQueryList* mql = mDocument->MediaQueryLists().getFirst(); mql;
2009
0
       mql = static_cast<LinkedListElement<MediaQueryList>*>(mql)->getNext()) {
2010
0
    localMediaQueryLists.AppendElement(mql);
2011
0
  }
2012
0
2013
0
  // Now iterate our local array of the lists.
2014
0
  for (const auto& mql : localMediaQueryLists) {
2015
0
    nsAutoMicroTask mt;
2016
0
    mql->MaybeNotify();
2017
0
  }
2018
0
}
2019
2020
static bool
2021
NotifyTabSizeModeChanged(TabParent* aTab, void* aArg)
2022
0
{
2023
0
  nsSizeMode* sizeMode = static_cast<nsSizeMode*>(aArg);
2024
0
  aTab->SizeModeChanged(*sizeMode);
2025
0
  return false;
2026
0
}
2027
2028
void
2029
nsPresContext::SizeModeChanged(nsSizeMode aSizeMode)
2030
0
{
2031
0
  if (nsPIDOMWindowOuter* window = mDocument->GetWindow()) {
2032
0
    nsContentUtils::CallOnAllRemoteChildren(window,
2033
0
                                            NotifyTabSizeModeChanged,
2034
0
                                            &aSizeMode);
2035
0
  }
2036
0
  MediaFeatureValuesChangedAllDocuments({ MediaFeatureChangeReason::SizeModeChange });
2037
0
}
2038
2039
nsCompatibility
2040
nsPresContext::CompatibilityMode() const
2041
0
{
2042
0
  return Document()->GetCompatibilityMode();
2043
0
}
2044
2045
void
2046
nsPresContext::SetPaginatedScrolling(bool aPaginated)
2047
0
{
2048
0
  if (mType == eContext_PrintPreview || mType == eContext_PageLayout)
2049
0
    mCanPaginatedScroll = aPaginated;
2050
0
}
2051
2052
void
2053
nsPresContext::SetPrintSettings(nsIPrintSettings *aPrintSettings)
2054
0
{
2055
0
  if (mMedium == nsGkAtoms::print)
2056
0
    mPrintSettings = aPrintSettings;
2057
0
}
2058
2059
bool
2060
nsPresContext::EnsureVisible()
2061
0
{
2062
0
  nsCOMPtr<nsIDocShell> docShell(mContainer);
2063
0
  if (docShell) {
2064
0
    nsCOMPtr<nsIContentViewer> cv;
2065
0
    docShell->GetContentViewer(getter_AddRefs(cv));
2066
0
    // Make sure this is the content viewer we belong with
2067
0
    if (cv) {
2068
0
      RefPtr<nsPresContext> currentPresContext;
2069
0
      cv->GetPresContext(getter_AddRefs(currentPresContext));
2070
0
      if (currentPresContext == this) {
2071
0
        // OK, this is us.  We want to call Show() on the content viewer.
2072
0
        nsresult result = cv->Show();
2073
0
        if (NS_SUCCEEDED(result)) {
2074
0
          return true;
2075
0
        }
2076
0
      }
2077
0
    }
2078
0
  }
2079
0
  return false;
2080
0
}
2081
2082
#ifdef MOZ_REFLOW_PERF
2083
void
2084
nsPresContext::CountReflows(const char * aName, nsIFrame * aFrame)
2085
{
2086
  if (mShell) {
2087
    mShell->CountReflows(aName, aFrame);
2088
  }
2089
}
2090
#endif
2091
2092
void
2093
nsPresContext::UpdateIsChrome()
2094
0
{
2095
0
  mIsChrome = mContainer &&
2096
0
              nsIDocShellTreeItem::typeChrome == mContainer->ItemType();
2097
0
}
2098
2099
bool
2100
nsPresContext::HasAuthorSpecifiedRules(const nsIFrame* aFrame,
2101
                                       uint32_t aRuleTypeMask) const
2102
0
{
2103
0
  Element* elem = aFrame->GetContent()->AsElement();
2104
0
2105
0
  // We need to handle non-generated content pseudos too, so we use
2106
0
  // the parent of generated content pseudo to be consistent.
2107
0
  if (elem->GetPseudoElementType() != CSSPseudoElementType::NotPseudo) {
2108
0
    MOZ_ASSERT(elem->GetParent(), "Pseudo element has no parent element?");
2109
0
    elem = elem->GetParent()->AsElement();
2110
0
  }
2111
0
  if (MOZ_UNLIKELY(!elem->HasServoData())) {
2112
0
    // Probably shouldn't happen, but does. See bug 1387953
2113
0
    return false;
2114
0
  }
2115
0
2116
0
  ComputedStyle* computedStyle = aFrame->Style();
2117
0
  CSSPseudoElementType pseudoType = computedStyle->GetPseudoType();
2118
0
  // Anonymous boxes are more complicated, and we just assume that they
2119
0
  // cannot have any author-specified rules here.
2120
0
  if (pseudoType == CSSPseudoElementType::InheritingAnonBox ||
2121
0
      pseudoType == CSSPseudoElementType::NonInheritingAnonBox) {
2122
0
    return false;
2123
0
  }
2124
0
  return Servo_HasAuthorSpecifiedRules(computedStyle,
2125
0
                                       elem, pseudoType,
2126
0
                                       aRuleTypeMask,
2127
0
                                       UseDocumentColors());
2128
0
}
2129
2130
gfxUserFontSet*
2131
nsPresContext::GetUserFontSet(bool aFlushUserFontSet)
2132
0
{
2133
0
  return mDocument->GetUserFontSet(aFlushUserFontSet);
2134
0
}
2135
2136
void
2137
nsPresContext::UserFontSetUpdated(gfxUserFontEntry* aUpdatedFont)
2138
0
{
2139
0
  if (!mShell)
2140
0
    return;
2141
0
2142
0
  // Note: this method is called without a font when rules in the userfont set
2143
0
  // are updated, which may occur during reflow as a result of the lazy
2144
0
  // initialization of the userfont set. It would be better to avoid a full
2145
0
  // restyle but until this method is only called outside of reflow, schedule a
2146
0
  // full restyle in these cases.
2147
0
  if (!aUpdatedFont) {
2148
0
    PostRebuildAllStyleDataEvent(NS_STYLE_HINT_REFLOW, eRestyle_ForceDescendants);
2149
0
    return;
2150
0
  }
2151
0
2152
0
  // Special case - if either the 'ex' or 'ch' units are used, these
2153
0
  // depend upon font metrics. Updating this information requires
2154
0
  // rebuilding the rule tree from the top, avoiding the reuse of cached
2155
0
  // data even when no style rules have changed.
2156
0
  if (UsesExChUnits()) {
2157
0
    PostRebuildAllStyleDataEvent(nsChangeHint(0), eRestyle_ForceDescendants);
2158
0
  }
2159
0
2160
0
  // Iterate over the frame tree looking for frames associated with the
2161
0
  // downloadable font family in question. If a frame's nsStyleFont has
2162
0
  // the name, check the font group associated with the metrics to see if
2163
0
  // it contains that specific font (i.e. the one chosen within the family
2164
0
  // given the weight, width, and slant from the nsStyleFont). If it does,
2165
0
  // mark that frame dirty and skip inspecting its descendants.
2166
0
  nsIFrame* root = mShell->GetRootFrame();
2167
0
  if (root) {
2168
0
    nsFontFaceUtils::MarkDirtyForFontChange(root, aUpdatedFont);
2169
0
  }
2170
0
}
2171
2172
class CounterStyleCleaner final : public nsAPostRefreshObserver
2173
{
2174
public:
2175
  CounterStyleCleaner(nsRefreshDriver* aRefreshDriver,
2176
                      CounterStyleManager* aCounterStyleManager)
2177
    : mRefreshDriver(aRefreshDriver)
2178
    , mCounterStyleManager(aCounterStyleManager)
2179
0
  {
2180
0
  }
2181
0
  virtual ~CounterStyleCleaner() {}
2182
2183
  void DidRefresh() final
2184
0
  {
2185
0
    mRefreshDriver->RemovePostRefreshObserver(this);
2186
0
    mCounterStyleManager->CleanRetiredStyles();
2187
0
    delete this;
2188
0
  }
2189
2190
private:
2191
  RefPtr<nsRefreshDriver> mRefreshDriver;
2192
  RefPtr<CounterStyleManager> mCounterStyleManager;
2193
};
2194
2195
void
2196
nsPresContext::FlushCounterStyles()
2197
0
{
2198
0
  if (!mShell) {
2199
0
    return; // we've been torn down
2200
0
  }
2201
0
  if (mCounterStyleManager->IsInitial()) {
2202
0
    // Still in its initial state, no need to clean.
2203
0
    return;
2204
0
  }
2205
0
2206
0
  if (mCounterStylesDirty) {
2207
0
    bool changed = mCounterStyleManager->NotifyRuleChanged();
2208
0
    if (changed) {
2209
0
      PresShell()->NotifyCounterStylesAreDirty();
2210
0
      PostRebuildAllStyleDataEvent(NS_STYLE_HINT_REFLOW,
2211
0
                                   eRestyle_ForceDescendants);
2212
0
      RefreshDriver()->AddPostRefreshObserver(
2213
0
        new CounterStyleCleaner(RefreshDriver(), mCounterStyleManager));
2214
0
    }
2215
0
    mCounterStylesDirty = false;
2216
0
  }
2217
0
}
2218
2219
void
2220
nsPresContext::MarkCounterStylesDirty()
2221
0
{
2222
0
  if (mCounterStyleManager->IsInitial()) {
2223
0
    // Still in its initial state, no need to touch anything.
2224
0
    return;
2225
0
  }
2226
0
2227
0
  mCounterStylesDirty = true;
2228
0
}
2229
2230
void
2231
nsPresContext::NotifyMissingFonts()
2232
0
{
2233
0
  if (mMissingFonts) {
2234
0
    mMissingFonts->Flush();
2235
0
  }
2236
0
}
2237
2238
void
2239
nsPresContext::EnsureSafeToHandOutCSSRules()
2240
0
{
2241
0
  if (!mShell->StyleSet()->EnsureUniqueInnerOnCSSSheets()) {
2242
0
    // Nothing to do.
2243
0
    return;
2244
0
  }
2245
0
2246
0
  RebuildAllStyleData(nsChangeHint(0), eRestyle_Subtree);
2247
0
}
2248
2249
void
2250
nsPresContext::FireDOMPaintEvent(nsTArray<nsRect>* aList,
2251
                                 TransactionId aTransactionId,
2252
                                 mozilla::TimeStamp aTimeStamp /* = mozilla::TimeStamp() */)
2253
0
{
2254
0
  nsPIDOMWindowInner* ourWindow = mDocument->GetInnerWindow();
2255
0
  if (!ourWindow)
2256
0
    return;
2257
0
2258
0
  nsCOMPtr<EventTarget> dispatchTarget = do_QueryInterface(ourWindow);
2259
0
  nsCOMPtr<EventTarget> eventTarget = dispatchTarget;
2260
0
  if (!IsChrome() && !mSendAfterPaintToContent) {
2261
0
    // Don't tell the window about this event, it should not know that
2262
0
    // something happened in a subdocument. Tell only the chrome event handler.
2263
0
    // (Events sent to the window get propagated to the chrome event handler
2264
0
    // automatically.)
2265
0
    dispatchTarget = do_QueryInterface(ourWindow->GetParentTarget());
2266
0
    if (!dispatchTarget) {
2267
0
      return;
2268
0
    }
2269
0
  }
2270
0
2271
0
  if (aTimeStamp.IsNull()) {
2272
0
    aTimeStamp = mozilla::TimeStamp::Now();
2273
0
  }
2274
0
  DOMHighResTimeStamp timeStamp = 0;
2275
0
  if (ourWindow) {
2276
0
    mozilla::dom::Performance* perf = ourWindow->GetPerformance();
2277
0
    if (perf) {
2278
0
      timeStamp = perf->GetDOMTiming()->TimeStampToDOMHighRes(aTimeStamp);
2279
0
    }
2280
0
  }
2281
0
2282
0
  // Events sent to the window get propagated to the chrome event handler
2283
0
  // automatically.
2284
0
  //
2285
0
  // This will empty our list in case dispatching the event causes more damage
2286
0
  // (hopefully it won't, or we're likely to get an infinite loop! At least
2287
0
  // it won't be blocking app execution though).
2288
0
  RefPtr<NotifyPaintEvent> event =
2289
0
    NS_NewDOMNotifyPaintEvent(eventTarget, this, nullptr, eAfterPaint, aList,
2290
0
                              uint64_t(aTransactionId), timeStamp);
2291
0
2292
0
  // Even if we're not telling the window about the event (so eventTarget is
2293
0
  // the chrome event handler, not the window), the window is still
2294
0
  // logically the event target.
2295
0
  event->SetTarget(eventTarget);
2296
0
  event->SetTrusted(true);
2297
0
  EventDispatcher::DispatchDOMEvent(dispatchTarget, nullptr,
2298
0
                                    static_cast<Event*>(event), this, nullptr);
2299
0
}
2300
2301
static bool
2302
MayHavePaintEventListenerSubdocumentCallback(nsIDocument* aDocument, void* aData)
2303
0
{
2304
0
  bool *result = static_cast<bool*>(aData);
2305
0
  nsPresContext* pc = aDocument->GetPresContext();
2306
0
  if (pc) {
2307
0
    *result = pc->MayHavePaintEventListenerInSubDocument();
2308
0
2309
0
    // If we found a paint event listener, then we can stop enumerating
2310
0
    // sub documents.
2311
0
    return !*result;
2312
0
  }
2313
0
  return true;
2314
0
}
2315
2316
static bool
2317
MayHavePaintEventListener(nsPIDOMWindowInner* aInnerWindow)
2318
0
{
2319
0
  if (!aInnerWindow)
2320
0
    return false;
2321
0
  if (aInnerWindow->HasPaintEventListeners())
2322
0
    return true;
2323
0
2324
0
  EventTarget* parentTarget = aInnerWindow->GetParentTarget();
2325
0
  if (!parentTarget)
2326
0
    return false;
2327
0
2328
0
  EventListenerManager* manager = nullptr;
2329
0
  if ((manager = parentTarget->GetExistingListenerManager()) &&
2330
0
      manager->MayHavePaintEventListener()) {
2331
0
    return true;
2332
0
  }
2333
0
2334
0
  nsCOMPtr<nsINode> node;
2335
0
  if (parentTarget != aInnerWindow->GetChromeEventHandler()) {
2336
0
    nsCOMPtr<nsIInProcessContentFrameMessageManager> mm =
2337
0
      do_QueryInterface(parentTarget);
2338
0
    if (mm) {
2339
0
      node = mm->GetOwnerContent();
2340
0
    }
2341
0
  }
2342
0
2343
0
  if (!node) {
2344
0
    node = do_QueryInterface(parentTarget);
2345
0
  }
2346
0
  if (node)
2347
0
    return MayHavePaintEventListener(node->OwnerDoc()->GetInnerWindow());
2348
0
2349
0
  nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(parentTarget);
2350
0
  if (window)
2351
0
    return MayHavePaintEventListener(window);
2352
0
2353
0
  nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(parentTarget);
2354
0
  EventTarget* tabChildGlobal;
2355
0
  return root &&
2356
0
         (tabChildGlobal = root->GetParentTarget()) &&
2357
0
         (manager = tabChildGlobal->GetExistingListenerManager()) &&
2358
0
         manager->MayHavePaintEventListener();
2359
0
}
2360
2361
bool
2362
nsPresContext::MayHavePaintEventListener()
2363
0
{
2364
0
  return ::MayHavePaintEventListener(mDocument->GetInnerWindow());
2365
0
}
2366
2367
bool
2368
nsPresContext::MayHavePaintEventListenerInSubDocument()
2369
0
{
2370
0
  if (MayHavePaintEventListener()) {
2371
0
    return true;
2372
0
  }
2373
0
2374
0
  bool result = false;
2375
0
  mDocument->EnumerateSubDocuments(MayHavePaintEventListenerSubdocumentCallback, &result);
2376
0
  return result;
2377
0
}
2378
2379
void
2380
nsPresContext::NotifyInvalidation(TransactionId aTransactionId, const nsIntRect& aRect)
2381
0
{
2382
0
  // Prevent values from overflow after DevPixelsToAppUnits().
2383
0
  //
2384
0
  // DevPixelsTopAppUnits() will multiple a factor (60) to the value,
2385
0
  // it may make the result value over the edge (overflow) of max or
2386
0
  // min value of int32_t. Compute the max sized dev pixel rect that
2387
0
  // we can support and intersect with it.
2388
0
  nsIntRect clampedRect = nsIntRect::MaxIntRect();
2389
0
  clampedRect.ScaleInverseRoundIn(AppUnitsPerDevPixel());
2390
0
2391
0
  clampedRect = clampedRect.Intersect(aRect);
2392
0
2393
0
  nsRect rect(DevPixelsToAppUnits(clampedRect.x),
2394
0
              DevPixelsToAppUnits(clampedRect.y),
2395
0
              DevPixelsToAppUnits(clampedRect.width),
2396
0
              DevPixelsToAppUnits(clampedRect.height));
2397
0
  NotifyInvalidation(aTransactionId, rect);
2398
0
}
2399
2400
nsPresContext::TransactionInvalidations*
2401
nsPresContext::GetInvalidations(TransactionId aTransactionId)
2402
0
{
2403
0
  for (TransactionInvalidations& t : mTransactions) {
2404
0
    if (t.mTransactionId == aTransactionId) {
2405
0
      return &t;
2406
0
    }
2407
0
  }
2408
0
  return nullptr;
2409
0
}
2410
2411
void
2412
nsPresContext::NotifyInvalidation(TransactionId aTransactionId, const nsRect& aRect)
2413
0
{
2414
0
  MOZ_ASSERT(GetContainerWeak(), "Invalidation in detached pres context");
2415
0
2416
0
  // If there is no paint event listener, then we don't need to fire
2417
0
  // the asynchronous event. We don't even need to record invalidation.
2418
0
  // MayHavePaintEventListener is pretty cheap and we could make it
2419
0
  // even cheaper by providing a more efficient
2420
0
  // nsPIDOMWindow::GetListenerManager.
2421
0
2422
0
  nsPresContext* pc;
2423
0
  for (pc = this; pc; pc = pc->GetParentPresContext()) {
2424
0
    TransactionInvalidations* transaction = pc->GetInvalidations(aTransactionId);
2425
0
    if (transaction) {
2426
0
      break;
2427
0
    } else {
2428
0
      transaction = pc->mTransactions.AppendElement();
2429
0
      transaction->mTransactionId = aTransactionId;
2430
0
    }
2431
0
  }
2432
0
2433
0
  TransactionInvalidations* transaction = GetInvalidations(aTransactionId);
2434
0
  MOZ_ASSERT(transaction);
2435
0
  transaction->mInvalidations.AppendElement(aRect);
2436
0
}
2437
2438
/* static */ void
2439
nsPresContext::NotifySubDocInvalidation(ContainerLayer* aContainer,
2440
                                        const nsIntRegion* aRegion)
2441
0
{
2442
0
  ContainerLayerPresContext *data =
2443
0
    static_cast<ContainerLayerPresContext*>(
2444
0
      aContainer->GetUserData(&gNotifySubDocInvalidationData));
2445
0
  if (!data) {
2446
0
    return;
2447
0
  }
2448
0
2449
0
  TransactionId transactionId = aContainer->Manager()->GetLastTransactionId();
2450
0
  IntRect visibleBounds = aContainer->GetVisibleRegion().GetBounds().ToUnknownRect();
2451
0
2452
0
  if (!aRegion) {
2453
0
    IntRect rect(IntPoint(0, 0), visibleBounds.Size());
2454
0
    data->mPresContext->NotifyInvalidation(transactionId, rect);
2455
0
    return;
2456
0
  }
2457
0
2458
0
  nsIntPoint topLeft = visibleBounds.TopLeft();
2459
0
  for (auto iter = aRegion->RectIter(); !iter.Done(); iter.Next()) {
2460
0
    nsIntRect rect(iter.Get());
2461
0
    //PresContext coordinate space is relative to the start of our visible
2462
0
    // region. Is this really true? This feels like the wrong way to get the right
2463
0
    // answer.
2464
0
    rect.MoveBy(-topLeft);
2465
0
    data->mPresContext->NotifyInvalidation(transactionId, rect);
2466
0
  }
2467
0
}
2468
2469
void
2470
nsPresContext::SetNotifySubDocInvalidationData(ContainerLayer* aContainer)
2471
0
{
2472
0
  ContainerLayerPresContext* pres = new ContainerLayerPresContext;
2473
0
  pres->mPresContext = this;
2474
0
  aContainer->SetUserData(&gNotifySubDocInvalidationData, pres);
2475
0
}
2476
2477
/* static */ void
2478
nsPresContext::ClearNotifySubDocInvalidationData(ContainerLayer* aContainer)
2479
0
{
2480
0
  aContainer->SetUserData(&gNotifySubDocInvalidationData, nullptr);
2481
0
}
2482
2483
struct NotifyDidPaintSubdocumentCallbackClosure {
2484
  TransactionId mTransactionId;
2485
  const mozilla::TimeStamp& mTimeStamp;
2486
};
2487
/* static */ bool
2488
nsPresContext::NotifyDidPaintSubdocumentCallback(nsIDocument* aDocument, void* aData)
2489
0
{
2490
0
  NotifyDidPaintSubdocumentCallbackClosure* closure =
2491
0
    static_cast<NotifyDidPaintSubdocumentCallbackClosure*>(aData);
2492
0
  nsPresContext* pc = aDocument->GetPresContext();
2493
0
  if (pc) {
2494
0
    pc->NotifyDidPaintForSubtree(closure->mTransactionId,
2495
0
                                 closure->mTimeStamp);
2496
0
  }
2497
0
  return true;
2498
0
}
2499
2500
/* static */ bool
2501
nsPresContext::NotifyRevokingDidPaintSubdocumentCallback(nsIDocument* aDocument, void* aData)
2502
0
{
2503
0
  NotifyDidPaintSubdocumentCallbackClosure* closure =
2504
0
    static_cast<NotifyDidPaintSubdocumentCallbackClosure*>(aData);
2505
0
  nsPresContext* pc = aDocument->GetPresContext();
2506
0
  if (pc) {
2507
0
    pc->NotifyRevokingDidPaint(closure->mTransactionId);
2508
0
  }
2509
0
  return true;
2510
0
}
2511
2512
class DelayedFireDOMPaintEvent : public Runnable {
2513
public:
2514
  DelayedFireDOMPaintEvent(
2515
    nsPresContext* aPresContext,
2516
    nsTArray<nsRect>* aList,
2517
    TransactionId aTransactionId,
2518
    const mozilla::TimeStamp& aTimeStamp = mozilla::TimeStamp())
2519
    : mozilla::Runnable("DelayedFireDOMPaintEvent")
2520
    , mPresContext(aPresContext)
2521
    , mTransactionId(aTransactionId)
2522
    , mTimeStamp(aTimeStamp)
2523
0
  {
2524
0
    MOZ_ASSERT(mPresContext->GetContainerWeak(),
2525
0
               "DOMPaintEvent requested for a detached pres context");
2526
0
    mList.SwapElements(*aList);
2527
0
  }
2528
  NS_IMETHOD Run() override
2529
0
  {
2530
0
    // The pres context might have been detached during the delay -
2531
0
    // that's fine, just don't fire the event.
2532
0
    if (mPresContext->GetContainerWeak()) {
2533
0
      mPresContext->FireDOMPaintEvent(&mList, mTransactionId, mTimeStamp);
2534
0
    }
2535
0
    return NS_OK;
2536
0
  }
2537
2538
  RefPtr<nsPresContext> mPresContext;
2539
  TransactionId mTransactionId;
2540
  const mozilla::TimeStamp mTimeStamp;
2541
  nsTArray<nsRect> mList;
2542
};
2543
2544
void
2545
nsPresContext::NotifyRevokingDidPaint(TransactionId aTransactionId)
2546
0
 {
2547
0
   if ((IsRoot() || !PresShell()->IsVisible()) && mTransactions.IsEmpty()) {
2548
0
     return;
2549
0
   }
2550
0
2551
0
  TransactionInvalidations* transaction = nullptr;
2552
0
  for (auto& t : mTransactions) {
2553
0
    if (t.mTransactionId == aTransactionId) {
2554
0
      transaction = &t;
2555
0
      break;
2556
0
    }
2557
0
  }
2558
0
  // If there are no transaction invalidations (which imply callers waiting
2559
0
  // on the event) for this revoked id, then we don't need to fire a
2560
0
  // MozAfterPaint.
2561
0
  if (!transaction) {
2562
0
    return;
2563
0
  }
2564
0
2565
0
  // If there are queued transactions with an earlier id, we can't send
2566
0
  // our event now since it will arrive out of order. Set the waiting for
2567
0
  // previous transaction flag to true, and we'll send the event when
2568
0
  // the others are completed.
2569
0
  // If this is the only transaction, then we can send it immediately.
2570
0
  if (mTransactions.Length() == 1) {
2571
0
    nsCOMPtr<nsIRunnable> ev =
2572
0
      new DelayedFireDOMPaintEvent(this, &transaction->mInvalidations,
2573
0
                                   transaction->mTransactionId, mozilla::TimeStamp());
2574
0
    nsContentUtils::AddScriptRunner(ev);
2575
0
    mTransactions.RemoveElementAt(0);
2576
0
  } else {
2577
0
    transaction->mIsWaitingForPreviousTransaction = true;
2578
0
  }
2579
0
2580
0
  NotifyDidPaintSubdocumentCallbackClosure closure = { aTransactionId, mozilla::TimeStamp() };
2581
0
  mDocument->EnumerateSubDocuments(nsPresContext::NotifyRevokingDidPaintSubdocumentCallback, &closure);
2582
0
}
2583
2584
void
2585
nsPresContext::NotifyDidPaintForSubtree(TransactionId aTransactionId,
2586
                                        const mozilla::TimeStamp& aTimeStamp)
2587
0
{
2588
0
  if (IsRoot() && mTransactions.IsEmpty()) {
2589
0
    return;
2590
0
  }
2591
0
2592
0
  if (!PresShell()->IsVisible() && mTransactions.IsEmpty()) {
2593
0
    return;
2594
0
  }
2595
0
2596
0
  // Non-root prescontexts fire MozAfterPaint to all their descendants
2597
0
  // unconditionally, even if no invalidations have been collected. This is
2598
0
  // because we don't want to eat the cost of collecting invalidations for
2599
0
  // every subdocument (which would require putting every subdocument in its
2600
0
  // own layer).
2601
0
2602
0
  bool sent = false;
2603
0
  uint32_t i = 0;
2604
0
  while (i < mTransactions.Length()) {
2605
0
    if (mTransactions[i].mTransactionId <= aTransactionId) {
2606
0
      if (!mTransactions[i].mInvalidations.IsEmpty()) {
2607
0
        nsCOMPtr<nsIRunnable> ev =
2608
0
          new DelayedFireDOMPaintEvent(this, &mTransactions[i].mInvalidations,
2609
0
                                       mTransactions[i].mTransactionId, aTimeStamp);
2610
0
        nsContentUtils::AddScriptRunner(ev);
2611
0
        sent = true;
2612
0
      }
2613
0
      mTransactions.RemoveElementAt(i);
2614
0
    } else {
2615
0
      // If there are transaction which is waiting for this transaction,
2616
0
      // we should fire a MozAfterPaint immediately.
2617
0
      if (sent && mTransactions[i].mIsWaitingForPreviousTransaction) {
2618
0
        nsCOMPtr<nsIRunnable> ev =
2619
0
          new DelayedFireDOMPaintEvent(this, &mTransactions[i].mInvalidations,
2620
0
                                       mTransactions[i].mTransactionId, aTimeStamp);
2621
0
        nsContentUtils::AddScriptRunner(ev);
2622
0
        sent = true;
2623
0
        mTransactions.RemoveElementAt(i);
2624
0
        continue;
2625
0
      }
2626
0
      i++;
2627
0
    }
2628
0
  }
2629
0
2630
0
  if (!sent) {
2631
0
    nsTArray<nsRect> dummy;
2632
0
    nsCOMPtr<nsIRunnable> ev =
2633
0
      new DelayedFireDOMPaintEvent(this, &dummy,
2634
0
                                   aTransactionId, aTimeStamp);
2635
0
    nsContentUtils::AddScriptRunner(ev);
2636
0
  }
2637
0
2638
0
  NotifyDidPaintSubdocumentCallbackClosure closure = { aTransactionId, aTimeStamp };
2639
0
  mDocument->EnumerateSubDocuments(nsPresContext::NotifyDidPaintSubdocumentCallback, &closure);
2640
0
}
2641
2642
already_AddRefed<nsITimer>
2643
nsPresContext::CreateTimer(nsTimerCallbackFunc aCallback,
2644
                           const char* aName,
2645
                           uint32_t aDelay)
2646
0
{
2647
0
  nsCOMPtr<nsITimer> timer;
2648
0
  NS_NewTimerWithFuncCallback(getter_AddRefs(timer),
2649
0
                              aCallback, this, aDelay,
2650
0
                              nsITimer::TYPE_ONE_SHOT,
2651
0
                              aName,
2652
0
                              Document()->EventTargetFor(TaskCategory::Other));
2653
0
  return timer.forget();
2654
0
}
2655
2656
static bool sGotInterruptEnv = false;
2657
enum InterruptMode {
2658
  ModeRandom,
2659
  ModeCounter,
2660
  ModeEvent
2661
};
2662
// Controlled by the GECKO_REFLOW_INTERRUPT_MODE env var; allowed values are
2663
// "random" (except on Windows) or "counter".  If neither is used, the mode is
2664
// ModeEvent.
2665
static InterruptMode sInterruptMode = ModeEvent;
2666
#ifndef XP_WIN
2667
// Used for the "random" mode.  Controlled by the GECKO_REFLOW_INTERRUPT_SEED
2668
// env var.
2669
static uint32_t sInterruptSeed = 1;
2670
#endif
2671
// Used for the "counter" mode.  This is the number of unskipped interrupt
2672
// checks that have to happen before we interrupt.  Controlled by the
2673
// GECKO_REFLOW_INTERRUPT_FREQUENCY env var.
2674
static uint32_t sInterruptMaxCounter = 10;
2675
// Used for the "counter" mode.  This counts up to sInterruptMaxCounter and is
2676
// then reset to 0.
2677
static uint32_t sInterruptCounter;
2678
// Number of interrupt checks to skip before really trying to interrupt.
2679
// Controlled by the GECKO_REFLOW_INTERRUPT_CHECKS_TO_SKIP env var.
2680
static uint32_t sInterruptChecksToSkip = 200;
2681
// Number of milliseconds that a reflow should be allowed to run for before we
2682
// actually allow interruption.  Controlled by the
2683
// GECKO_REFLOW_MIN_NOINTERRUPT_DURATION env var.  Can't be initialized here,
2684
// because TimeDuration/TimeStamp is not safe to use in static constructors..
2685
static TimeDuration sInterruptTimeout;
2686
2687
static void GetInterruptEnv()
2688
0
{
2689
0
  char *ev = PR_GetEnv("GECKO_REFLOW_INTERRUPT_MODE");
2690
0
  if (ev) {
2691
0
#ifndef XP_WIN
2692
0
    if (PL_strcasecmp(ev, "random") == 0) {
2693
0
      ev = PR_GetEnv("GECKO_REFLOW_INTERRUPT_SEED");
2694
0
      if (ev) {
2695
0
        sInterruptSeed = atoi(ev);
2696
0
      }
2697
0
      srandom(sInterruptSeed);
2698
0
      sInterruptMode = ModeRandom;
2699
0
    } else
2700
0
#endif
2701
0
      if (PL_strcasecmp(ev, "counter") == 0) {
2702
0
      ev = PR_GetEnv("GECKO_REFLOW_INTERRUPT_FREQUENCY");
2703
0
      if (ev) {
2704
0
        sInterruptMaxCounter = atoi(ev);
2705
0
      }
2706
0
      sInterruptCounter = 0;
2707
0
      sInterruptMode = ModeCounter;
2708
0
    }
2709
0
  }
2710
0
  ev = PR_GetEnv("GECKO_REFLOW_INTERRUPT_CHECKS_TO_SKIP");
2711
0
  if (ev) {
2712
0
    sInterruptChecksToSkip = atoi(ev);
2713
0
  }
2714
0
2715
0
  ev = PR_GetEnv("GECKO_REFLOW_MIN_NOINTERRUPT_DURATION");
2716
0
  int duration_ms = ev ? atoi(ev) : 100;
2717
0
  sInterruptTimeout = TimeDuration::FromMilliseconds(duration_ms);
2718
0
}
2719
2720
bool
2721
nsPresContext::HavePendingInputEvent()
2722
0
{
2723
0
  switch (sInterruptMode) {
2724
0
#ifndef XP_WIN
2725
0
    case ModeRandom:
2726
0
      return (random() & 1);
2727
0
#endif
2728
0
    case ModeCounter:
2729
0
      if (sInterruptCounter < sInterruptMaxCounter) {
2730
0
        ++sInterruptCounter;
2731
0
        return false;
2732
0
      }
2733
0
      sInterruptCounter = 0;
2734
0
      return true;
2735
0
    default:
2736
0
    case ModeEvent: {
2737
0
      nsIFrame* f = PresShell()->GetRootFrame();
2738
0
      if (f) {
2739
0
        nsIWidget* w = f->GetNearestWidget();
2740
0
        if (w) {
2741
0
          return w->HasPendingInputEvent();
2742
0
        }
2743
0
      }
2744
0
      return false;
2745
0
    }
2746
0
  }
2747
0
}
2748
2749
bool
2750
nsPresContext::HasPendingRestyleOrReflow()
2751
0
{
2752
0
  nsIPresShell* shell = PresShell();
2753
0
  return shell->NeedStyleFlush() || shell->HasPendingReflow();
2754
0
}
2755
2756
void
2757
nsPresContext::ReflowStarted(bool aInterruptible)
2758
0
{
2759
#ifdef NOISY_INTERRUPTIBLE_REFLOW
2760
  if (!aInterruptible) {
2761
    printf("STARTING NONINTERRUPTIBLE REFLOW\n");
2762
  }
2763
#endif
2764
  // We don't support interrupting in paginated contexts, since page
2765
0
  // sequences only handle initial reflow
2766
0
  mInterruptsEnabled = aInterruptible && !IsPaginated() &&
2767
0
                       nsLayoutUtils::InterruptibleReflowEnabled();
2768
0
2769
0
  // Don't set mHasPendingInterrupt based on HavePendingInputEvent() here.  If
2770
0
  // we ever change that, then we need to update the code in
2771
0
  // PresShell::DoReflow to only add the just-reflown root to dirty roots if
2772
0
  // it's actually dirty.  Otherwise we can end up adding a root that has no
2773
0
  // interruptible descendants, just because we detected an interrupt at reflow
2774
0
  // start.
2775
0
  mHasPendingInterrupt = false;
2776
0
2777
0
  mInterruptChecksToSkip = sInterruptChecksToSkip;
2778
0
2779
0
  if (mInterruptsEnabled) {
2780
0
    mReflowStartTime = TimeStamp::Now();
2781
0
  }
2782
0
}
2783
2784
bool
2785
nsPresContext::CheckForInterrupt(nsIFrame* aFrame)
2786
0
{
2787
0
  if (mHasPendingInterrupt) {
2788
0
    mShell->FrameNeedsToContinueReflow(aFrame);
2789
0
    return true;
2790
0
  }
2791
0
2792
0
  if (!sGotInterruptEnv) {
2793
0
    sGotInterruptEnv = true;
2794
0
    GetInterruptEnv();
2795
0
  }
2796
0
2797
0
  if (!mInterruptsEnabled) {
2798
0
    return false;
2799
0
  }
2800
0
2801
0
  if (mInterruptChecksToSkip > 0) {
2802
0
    --mInterruptChecksToSkip;
2803
0
    return false;
2804
0
  }
2805
0
  mInterruptChecksToSkip = sInterruptChecksToSkip;
2806
0
2807
0
  // Don't interrupt if it's been less than sInterruptTimeout since we started
2808
0
  // the reflow.
2809
0
  mHasPendingInterrupt =
2810
0
    TimeStamp::Now() - mReflowStartTime > sInterruptTimeout &&
2811
0
    HavePendingInputEvent() &&
2812
0
    !IsChrome();
2813
0
2814
0
  if (mPendingInterruptFromTest) {
2815
0
    mPendingInterruptFromTest = false;
2816
0
    mHasPendingInterrupt = true;
2817
0
  }
2818
0
2819
0
  if (mHasPendingInterrupt) {
2820
#ifdef NOISY_INTERRUPTIBLE_REFLOW
2821
    printf("*** DETECTED pending interrupt (time=%lld)\n", PR_Now());
2822
#endif /* NOISY_INTERRUPTIBLE_REFLOW */
2823
    mShell->FrameNeedsToContinueReflow(aFrame);
2824
0
  }
2825
0
  return mHasPendingInterrupt;
2826
0
}
2827
2828
nsIFrame*
2829
nsPresContext::GetPrimaryFrameFor(nsIContent* aContent)
2830
0
{
2831
0
  MOZ_ASSERT(aContent, "Don't do that");
2832
0
  if (GetPresShell() &&
2833
0
      GetPresShell()->GetDocument() == aContent->GetComposedDoc()) {
2834
0
    return aContent->GetPrimaryFrame();
2835
0
  }
2836
0
  return nullptr;
2837
0
}
2838
2839
size_t
2840
nsPresContext::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
2841
0
{
2842
0
  return mLangGroupFontPrefs.SizeOfExcludingThis(aMallocSizeOf);
2843
0
2844
0
  // Measurement of other members may be added later if DMD finds it is
2845
0
  // worthwhile.
2846
0
}
2847
2848
bool
2849
nsPresContext::IsRootContentDocument() const
2850
0
{
2851
0
  // We are a root content document if: we are not a resource doc, we are
2852
0
  // not chrome, and we either have no parent or our parent is chrome.
2853
0
  if (mDocument->IsResourceDoc()) {
2854
0
    return false;
2855
0
  }
2856
0
  if (IsChrome()) {
2857
0
    return false;
2858
0
  }
2859
0
  // We may not have a root frame, so use views.
2860
0
  nsView* view = PresShell()->GetViewManager()->GetRootView();
2861
0
  if (!view) {
2862
0
    return false;
2863
0
  }
2864
0
  view = view->GetParent(); // anonymous inner view
2865
0
  if (!view) {
2866
0
    return true;
2867
0
  }
2868
0
  view = view->GetParent(); // subdocumentframe's view
2869
0
  if (!view) {
2870
0
    return true;
2871
0
  }
2872
0
2873
0
  nsIFrame* f = view->GetFrame();
2874
0
  return (f && f->PresContext()->IsChrome());
2875
0
}
2876
2877
void
2878
nsPresContext::NotifyNonBlankPaint()
2879
0
{
2880
0
  MOZ_ASSERT(!mHadNonBlankPaint);
2881
0
  mHadNonBlankPaint = true;
2882
0
  if (IsRootContentDocument()) {
2883
0
    RefPtr<nsDOMNavigationTiming> timing = mDocument->GetNavigationTiming();
2884
0
    if (timing) {
2885
0
      timing->NotifyNonBlankPaintForRootContentDocument();
2886
0
    }
2887
0
2888
0
    mFirstNonBlankPaintTime = TimeStamp::Now();
2889
0
  }
2890
0
}
2891
2892
void
2893
nsPresContext::NotifyDOMContentFlushed()
2894
0
{
2895
0
  NS_ENSURE_TRUE_VOID(mShell);
2896
0
  if (IsRootContentDocument()) {
2897
0
    RefPtr<nsDOMNavigationTiming> timing = mDocument->GetNavigationTiming();
2898
0
    if (timing) {
2899
0
      timing->NotifyDOMContentFlushedForRootContentDocument();
2900
0
    }
2901
0
  }
2902
0
}
2903
2904
bool nsPresContext::GetPaintFlashing() const
2905
0
{
2906
0
  if (!mPaintFlashingInitialized) {
2907
0
    bool pref = Preferences::GetBool("nglayout.debug.paint_flashing");
2908
0
    if (!pref && IsChrome()) {
2909
0
      pref = Preferences::GetBool("nglayout.debug.paint_flashing_chrome");
2910
0
    }
2911
0
    mPaintFlashing = pref;
2912
0
    mPaintFlashingInitialized = true;
2913
0
  }
2914
0
  return mPaintFlashing;
2915
0
}
2916
2917
int32_t
2918
nsPresContext::AppUnitsPerDevPixel() const
2919
0
{
2920
0
  return mDeviceContext->AppUnitsPerDevPixel();
2921
0
}
2922
2923
nscoord
2924
nsPresContext::GfxUnitsToAppUnits(gfxFloat aGfxUnits) const
2925
0
{
2926
0
  return mDeviceContext->GfxUnitsToAppUnits(aGfxUnits);
2927
0
}
2928
2929
gfxFloat
2930
nsPresContext::AppUnitsToGfxUnits(nscoord aAppUnits) const
2931
0
{
2932
0
  return mDeviceContext->AppUnitsToGfxUnits(aAppUnits);
2933
0
}
2934
2935
nscoord
2936
nsPresContext::PhysicalMillimetersToAppUnits(float aMM) const
2937
0
{
2938
0
  float inches = aMM / MM_PER_INCH_FLOAT;
2939
0
  return NSToCoordFloorClamped(
2940
0
      inches * float(DeviceContext()->AppUnitsPerPhysicalInch()));
2941
0
}
2942
2943
bool
2944
nsPresContext::IsDeviceSizePageSize()
2945
0
{
2946
0
  bool isDeviceSizePageSize = false;
2947
0
  nsCOMPtr<nsIDocShell> docShell(mContainer);
2948
0
  if (docShell) {
2949
0
    isDeviceSizePageSize = docShell->GetDeviceSizeIsPageSize();
2950
0
  }
2951
0
  return isDeviceSizePageSize;
2952
0
}
2953
2954
uint64_t
2955
nsPresContext::GetRestyleGeneration() const
2956
0
{
2957
0
  if (!mRestyleManager) {
2958
0
    return 0;
2959
0
  }
2960
0
  return mRestyleManager->GetRestyleGeneration();
2961
0
}
2962
2963
uint64_t
2964
nsPresContext::GetUndisplayedRestyleGeneration() const
2965
0
{
2966
0
  if (!mRestyleManager) {
2967
0
    return 0;
2968
0
  }
2969
0
  return mRestyleManager->GetUndisplayedRestyleGeneration();
2970
0
}
2971
2972
nsBidi&
2973
nsPresContext::GetBidiEngine()
2974
0
{
2975
0
  MOZ_ASSERT(NS_IsMainThread());
2976
0
2977
0
  if (!mBidiEngine) {
2978
0
    mBidiEngine.reset(new nsBidi());
2979
0
  }
2980
0
  return *mBidiEngine;
2981
0
}
2982
2983
void
2984
nsPresContext::FlushFontFeatureValues()
2985
0
{
2986
0
  if (!mShell) {
2987
0
    return; // we've been torn down
2988
0
  }
2989
0
2990
0
  if (mFontFeatureValuesDirty) {
2991
0
    ServoStyleSet* styleSet = mShell->StyleSet();
2992
0
    mFontFeatureValuesLookup = styleSet->BuildFontFeatureValueSet();
2993
0
    mFontFeatureValuesDirty = false;
2994
0
  }
2995
0
}
2996
2997
nsRootPresContext::nsRootPresContext(nsIDocument* aDocument,
2998
                                     nsPresContextType aType)
2999
  : nsPresContext(aDocument, aType)
3000
0
{
3001
0
}
3002
3003
nsRootPresContext::~nsRootPresContext()
3004
0
{
3005
0
  NS_ASSERTION(mRegisteredPlugins.Count() == 0,
3006
0
               "All plugins should have been unregistered");
3007
0
  CancelApplyPluginGeometryTimer();
3008
0
}
3009
3010
/* virtual */ void
3011
nsRootPresContext::Detach()
3012
0
{
3013
0
  // XXXmats maybe also CancelApplyPluginGeometryTimer(); ?
3014
0
  nsPresContext::Detach();
3015
0
}
3016
3017
void
3018
nsRootPresContext::RegisterPluginForGeometryUpdates(nsIContent* aPlugin)
3019
0
{
3020
0
  mRegisteredPlugins.PutEntry(aPlugin);
3021
0
}
3022
3023
void
3024
nsRootPresContext::UnregisterPluginForGeometryUpdates(nsIContent* aPlugin)
3025
0
{
3026
0
  mRegisteredPlugins.RemoveEntry(aPlugin);
3027
0
}
3028
3029
void
3030
nsRootPresContext::ComputePluginGeometryUpdates(nsIFrame* aFrame,
3031
                                                nsDisplayListBuilder* aBuilder,
3032
                                                nsDisplayList* aList)
3033
0
{
3034
0
  if (mRegisteredPlugins.Count() == 0) {
3035
0
    return;
3036
0
  }
3037
0
3038
0
  // Initially make the next state for each plugin descendant of aFrame be
3039
0
  // "hidden". Plugins that are visible will have their next state set to
3040
0
  // unhidden by nsDisplayPlugin::ComputeVisibility.
3041
0
  for (auto iter = mRegisteredPlugins.Iter(); !iter.Done(); iter.Next()) {
3042
0
    auto f = static_cast<nsPluginFrame*>(iter.Get()->GetKey()->GetPrimaryFrame());
3043
0
    if (!f) {
3044
0
      NS_WARNING("Null frame in ComputePluginGeometryUpdates");
3045
0
      continue;
3046
0
    }
3047
0
    if (!nsLayoutUtils::IsAncestorFrameCrossDoc(aFrame, f)) {
3048
0
      // f is not managed by this frame so we should ignore it.
3049
0
      continue;
3050
0
    }
3051
0
    f->SetEmptyWidgetConfiguration();
3052
0
  }
3053
0
3054
0
  if (aBuilder) {
3055
0
    MOZ_ASSERT(aList);
3056
0
    nsIFrame* rootFrame = mShell->GetRootFrame();
3057
0
3058
0
    if (rootFrame && aBuilder->ContainsPluginItem()) {
3059
0
      aBuilder->SetForPluginGeometry(true);
3060
0
      // Merging and flattening has already been done and we should not do it
3061
0
      // again. nsDisplayScroll(Info)Layer doesn't support trying to flatten
3062
0
      // again.
3063
0
      aBuilder->SetAllowMergingAndFlattening(false);
3064
0
      nsRegion region = rootFrame->GetVisualOverflowRectRelativeToSelf();
3065
0
      // nsDisplayPlugin::ComputeVisibility will automatically set a non-hidden
3066
0
      // widget configuration for the plugin, if it's visible.
3067
0
      aList->ComputeVisibilityForRoot(aBuilder, &region);
3068
0
      aBuilder->SetForPluginGeometry(false);
3069
0
    }
3070
0
  }
3071
0
3072
#ifdef XP_MACOSX
3073
  // We control painting of Mac plugins, so just apply geometry updates now.
3074
  // This is not happening during a paint event.
3075
  ApplyPluginGeometryUpdates();
3076
#else
3077
0
  if (XRE_IsParentProcess()) {
3078
0
    InitApplyPluginGeometryTimer();
3079
0
  }
3080
0
#endif
3081
0
}
3082
3083
static void
3084
ApplyPluginGeometryUpdatesCallback(nsITimer *aTimer, void *aClosure)
3085
0
{
3086
0
  static_cast<nsRootPresContext*>(aClosure)->ApplyPluginGeometryUpdates();
3087
0
}
3088
3089
void
3090
nsRootPresContext::InitApplyPluginGeometryTimer()
3091
0
{
3092
0
  if (mApplyPluginGeometryTimer) {
3093
0
    return;
3094
0
  }
3095
0
3096
0
  // We'll apply the plugin geometry updates during the next compositing paint in this
3097
0
  // presContext (either from nsPresShell::WillPaintWindow or from
3098
0
  // nsPresShell::DidPaintWindow, depending on the platform).  But paints might
3099
0
  // get optimized away if the old plugin geometry covers the invalid region,
3100
0
  // so set a backup timer to do this too.  We want to make sure this
3101
0
  // won't fire before our normal paint notifications, if those would
3102
0
  // update the geometry, so set it for double the refresh driver interval.
3103
0
  mApplyPluginGeometryTimer = CreateTimer(ApplyPluginGeometryUpdatesCallback,
3104
0
                                          "ApplyPluginGeometryUpdatesCallback",
3105
0
                                          nsRefreshDriver::DefaultInterval() * 2);
3106
0
}
3107
3108
void
3109
nsRootPresContext::CancelApplyPluginGeometryTimer()
3110
0
{
3111
0
  if (mApplyPluginGeometryTimer) {
3112
0
    mApplyPluginGeometryTimer->Cancel();
3113
0
    mApplyPluginGeometryTimer = nullptr;
3114
0
  }
3115
0
}
3116
3117
#ifndef XP_MACOSX
3118
3119
static bool
3120
HasOverlap(const LayoutDeviceIntPoint& aOffset1,
3121
           const nsTArray<LayoutDeviceIntRect>& aClipRects1,
3122
           const LayoutDeviceIntPoint& aOffset2,
3123
           const nsTArray<LayoutDeviceIntRect>& aClipRects2)
3124
0
{
3125
0
  LayoutDeviceIntPoint offsetDelta = aOffset1 - aOffset2;
3126
0
  for (uint32_t i = 0; i < aClipRects1.Length(); ++i) {
3127
0
    for (uint32_t j = 0; j < aClipRects2.Length(); ++j) {
3128
0
      if ((aClipRects1[i] + offsetDelta).Intersects(aClipRects2[j])) {
3129
0
        return true;
3130
0
      }
3131
0
    }
3132
0
  }
3133
0
  return false;
3134
0
}
3135
3136
/**
3137
 * Given a list of plugin windows to move to new locations, sort the list
3138
 * so that for each window move, the window moves to a location that
3139
 * does not intersect other windows. This minimizes flicker and repainting.
3140
 * It's not always possible to do this perfectly, since in general
3141
 * we might have cycles. But we do our best.
3142
 * We need to take into account that windows are clipped to particular
3143
 * regions and the clip regions change as the windows are moved.
3144
 */
3145
static void
3146
SortConfigurations(nsTArray<nsIWidget::Configuration>* aConfigurations)
3147
0
{
3148
0
  if (aConfigurations->Length() > 10) {
3149
0
    // Give up, we don't want to get bogged down here
3150
0
    return;
3151
0
  }
3152
0
3153
0
  nsTArray<nsIWidget::Configuration> pluginsToMove;
3154
0
  pluginsToMove.SwapElements(*aConfigurations);
3155
0
3156
0
  // Our algorithm is quite naive. At each step we try to identify
3157
0
  // a window that can be moved to its new location that won't overlap
3158
0
  // any other windows at the new location. If there is no such
3159
0
  // window, we just move the last window in the list anyway.
3160
0
  while (!pluginsToMove.IsEmpty()) {
3161
0
    // Find a window whose destination does not overlap any other window
3162
0
    uint32_t i;
3163
0
    for (i = 0; i + 1 < pluginsToMove.Length(); ++i) {
3164
0
      nsIWidget::Configuration* config = &pluginsToMove[i];
3165
0
      bool foundOverlap = false;
3166
0
      for (uint32_t j = 0; j < pluginsToMove.Length(); ++j) {
3167
0
        if (i == j)
3168
0
          continue;
3169
0
        LayoutDeviceIntRect bounds = pluginsToMove[j].mChild->GetBounds();
3170
0
        AutoTArray<LayoutDeviceIntRect,1> clipRects;
3171
0
        pluginsToMove[j].mChild->GetWindowClipRegion(&clipRects);
3172
0
        if (HasOverlap(bounds.TopLeft(), clipRects,
3173
0
                       config->mBounds.TopLeft(),
3174
0
                       config->mClipRegion)) {
3175
0
          foundOverlap = true;
3176
0
          break;
3177
0
        }
3178
0
      }
3179
0
      if (!foundOverlap)
3180
0
        break;
3181
0
    }
3182
0
    // Note that we always move the last plugin in pluginsToMove, if we
3183
0
    // can't find any other plugin to move
3184
0
    aConfigurations->AppendElement(pluginsToMove[i]);
3185
0
    pluginsToMove.RemoveElementAt(i);
3186
0
  }
3187
0
}
3188
3189
static void
3190
PluginGetGeometryUpdate(nsTHashtable<nsRefPtrHashKey<nsIContent>>& aPlugins,
3191
                        nsTArray<nsIWidget::Configuration>* aConfigurations)
3192
0
{
3193
0
  for (auto iter = aPlugins.Iter(); !iter.Done(); iter.Next()) {
3194
0
    auto f = static_cast<nsPluginFrame*>(iter.Get()->GetKey()->GetPrimaryFrame());
3195
0
    if (!f) {
3196
0
      NS_WARNING("Null frame in PluginGeometryUpdate");
3197
0
      continue;
3198
0
    }
3199
0
    f->GetWidgetConfiguration(aConfigurations);
3200
0
  }
3201
0
}
3202
3203
#endif  // #ifndef XP_MACOSX
3204
3205
static void
3206
PluginDidSetGeometry(nsTHashtable<nsRefPtrHashKey<nsIContent>>& aPlugins)
3207
0
{
3208
0
  for (auto iter = aPlugins.Iter(); !iter.Done(); iter.Next()) {
3209
0
    auto f = static_cast<nsPluginFrame*>(iter.Get()->GetKey()->GetPrimaryFrame());
3210
0
    if (!f) {
3211
0
      NS_WARNING("Null frame in PluginDidSetGeometry");
3212
0
      continue;
3213
0
    }
3214
0
    f->DidSetWidgetGeometry();
3215
0
  }
3216
0
}
3217
3218
void
3219
nsRootPresContext::ApplyPluginGeometryUpdates()
3220
0
{
3221
0
#ifndef XP_MACOSX
3222
0
  CancelApplyPluginGeometryTimer();
3223
0
3224
0
  nsTArray<nsIWidget::Configuration> configurations;
3225
0
  PluginGetGeometryUpdate(mRegisteredPlugins, &configurations);
3226
0
  // Walk mRegisteredPlugins and ask each plugin for its configuration
3227
0
  if (!configurations.IsEmpty()) {
3228
0
    nsIWidget* widget = configurations[0].mChild->GetParent();
3229
0
    NS_ASSERTION(widget, "Plugins must have a parent window");
3230
0
    SortConfigurations(&configurations);
3231
0
    widget->ConfigureChildren(configurations);
3232
0
  }
3233
0
#endif  // #ifndef XP_MACOSX
3234
0
3235
0
  PluginDidSetGeometry(mRegisteredPlugins);
3236
0
}
3237
3238
void
3239
nsRootPresContext::CollectPluginGeometryUpdates(LayerManager* aLayerManager)
3240
0
{
3241
0
#ifndef XP_MACOSX
3242
0
  // Collect and pass plugin widget configurations down to the compositor
3243
0
  // for transmission to the chrome process.
3244
0
  NS_ASSERTION(aLayerManager, "layer manager is invalid!");
3245
0
  mozilla::layers::ClientLayerManager* clm = aLayerManager->AsClientLayerManager();
3246
0
3247
0
  nsTArray<nsIWidget::Configuration> configurations;
3248
0
  // If there aren't any plugins to configure, clear the plugin data cache
3249
0
  // in the layer system.
3250
0
  if (!mRegisteredPlugins.Count() && clm) {
3251
0
    clm->StorePluginWidgetConfigurations(configurations);
3252
0
    return;
3253
0
  }
3254
0
  PluginGetGeometryUpdate(mRegisteredPlugins, &configurations);
3255
0
  if (configurations.IsEmpty()) {
3256
0
    PluginDidSetGeometry(mRegisteredPlugins);
3257
0
    return;
3258
0
  }
3259
0
  SortConfigurations(&configurations);
3260
0
  if (clm) {
3261
0
    clm->StorePluginWidgetConfigurations(configurations);
3262
0
  }
3263
0
  PluginDidSetGeometry(mRegisteredPlugins);
3264
0
#endif  // #ifndef XP_MACOSX
3265
0
}
3266
3267
void
3268
nsRootPresContext::AddWillPaintObserver(nsIRunnable* aRunnable)
3269
0
{
3270
0
  if (!mWillPaintFallbackEvent.IsPending()) {
3271
0
    mWillPaintFallbackEvent = new RunWillPaintObservers(this);
3272
0
    Document()->Dispatch(TaskCategory::Other,
3273
0
                         do_AddRef(mWillPaintFallbackEvent));
3274
0
  }
3275
0
  mWillPaintObservers.AppendElement(aRunnable);
3276
0
}
3277
3278
/**
3279
 * Run all runnables that need to get called before the next paint.
3280
 */
3281
void
3282
nsRootPresContext::FlushWillPaintObservers()
3283
0
{
3284
0
  mWillPaintFallbackEvent = nullptr;
3285
0
  nsTArray<nsCOMPtr<nsIRunnable> > observers;
3286
0
  observers.SwapElements(mWillPaintObservers);
3287
0
  for (uint32_t i = 0; i < observers.Length(); ++i) {
3288
0
    observers[i]->Run();
3289
0
  }
3290
0
}
3291
3292
size_t
3293
nsRootPresContext::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
3294
0
{
3295
0
  return nsPresContext::SizeOfExcludingThis(aMallocSizeOf);
3296
0
3297
0
  // Measurement of the following members may be added later if DMD finds it is
3298
0
  // worthwhile:
3299
0
  // - mRegisteredPlugins
3300
0
  // - mWillPaintObservers
3301
0
  // - mWillPaintFallbackEvent
3302
0
}