Bumping manifests a=b2g-bump
[gecko.git] / layout / base / nsPresContext.cpp
blob10699bcbc4cf1d234a6e9867112df7089aef1933
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 /* a presentation of a document, part 1 */
8 #include "mozilla/ArrayUtils.h"
9 #include "mozilla/DebugOnly.h"
10 #include "mozilla/EventDispatcher.h"
11 #include "mozilla/EventStateManager.h"
13 #include "base/basictypes.h"
15 #include "nsCOMPtr.h"
16 #include "nsPresContext.h"
17 #include "nsIPresShell.h"
18 #include "nsDocShell.h"
19 #include "nsIContentViewer.h"
20 #include "nsPIDOMWindow.h"
21 #include "nsStyleSet.h"
22 #include "nsIContent.h"
23 #include "nsIFrame.h"
24 #include "nsIDocument.h"
25 #include "nsIPrintSettings.h"
26 #include "nsILanguageAtomService.h"
27 #include "mozilla/LookAndFeel.h"
28 #include "nsIInterfaceRequestorUtils.h"
29 #include "nsIWeakReferenceUtils.h"
30 #include "nsAutoPtr.h"
31 #include "nsThreadUtils.h"
32 #include "nsFrameManager.h"
33 #include "nsLayoutUtils.h"
34 #include "nsViewManager.h"
35 #include "RestyleManager.h"
36 #include "SurfaceCache.h"
37 #include "nsCSSRuleProcessor.h"
38 #include "nsRuleNode.h"
39 #include "gfxPlatform.h"
40 #include "nsCSSRules.h"
41 #include "nsFontFaceLoader.h"
42 #include "mozilla/EventListenerManager.h"
43 #include "prenv.h"
44 #include "nsObjectFrame.h"
45 #include "nsTransitionManager.h"
46 #include "nsAnimationManager.h"
47 #include "CounterStyleManager.h"
48 #include "mozilla/MemoryReporting.h"
49 #include "mozilla/dom/Element.h"
50 #include "nsIMessageManager.h"
51 #include "mozilla/dom/MediaQueryList.h"
52 #include "nsSMILAnimationController.h"
53 #include "mozilla/css/ImageLoader.h"
54 #include "mozilla/dom/PBrowserParent.h"
55 #include "mozilla/dom/TabChild.h"
56 #include "mozilla/dom/TabParent.h"
57 #include "nsRefreshDriver.h"
58 #include "Layers.h"
59 #include "nsIDOMEvent.h"
60 #include "gfxPrefs.h"
61 #include "nsIDOMChromeWindow.h"
62 #include "nsFrameLoader.h"
64 #include "nsContentUtils.h"
65 #include "nsPIWindowRoot.h"
66 #include "mozilla/Preferences.h"
68 // Needed for Start/Stop of Image Animation
69 #include "imgIContainer.h"
70 #include "nsIImageLoadingContent.h"
72 #include "nsCSSParser.h"
73 #include "nsBidiUtils.h"
74 #include "nsServiceManagerUtils.h"
76 #include "URL.h"
78 using namespace mozilla;
79 using namespace mozilla::dom;
80 using namespace mozilla::layers;
82 uint8_t gNotifySubDocInvalidationData;
84 /**
85 * Layer UserData for ContainerLayers that want to be notified
86 * of local invalidations of them and their descendant layers.
87 * Pass a callback to ComputeDifferences to have these called.
89 class ContainerLayerPresContext : public LayerUserData {
90 public:
91 nsPresContext* mPresContext;
94 namespace {
96 class CharSetChangingRunnable : public nsRunnable
98 public:
99 CharSetChangingRunnable(nsPresContext* aPresContext,
100 const nsCString& aCharSet)
101 : mPresContext(aPresContext),
102 mCharSet(aCharSet)
106 NS_IMETHOD Run()
108 mPresContext->DoChangeCharSet(mCharSet);
109 return NS_OK;
112 private:
113 nsRefPtr<nsPresContext> mPresContext;
114 nsCString mCharSet;
117 } // anonymous namespace
119 nscolor
120 nsPresContext::MakeColorPref(const nsString& aColor)
122 nsCSSParser parser;
123 nsCSSValue value;
124 if (!parser.ParseColorString(aColor, nullptr, 0, value)) {
125 // Any better choices?
126 return NS_RGB(0, 0, 0);
129 nscolor color;
130 return nsRuleNode::ComputeColor(value, this, nullptr, color)
131 ? color
132 : NS_RGB(0, 0, 0);
135 bool
136 nsPresContext::IsDOMPaintEventPending()
138 if (mFireAfterPaintEvents) {
139 return true;
141 if (GetDisplayRootPresContext()->GetRootPresContext()->mRefreshDriver->ViewManagerFlushIsPending()) {
142 // Since we're promising that there will be a MozAfterPaint event
143 // fired, we record an empty invalidation in case display list
144 // invalidation doesn't invalidate anything further.
145 NotifyInvalidation(nsRect(0, 0, 0, 0), 0);
146 NS_ASSERTION(mFireAfterPaintEvents, "Why aren't we planning to fire the event?");
147 return true;
149 return false;
152 void
153 nsPresContext::PrefChangedCallback(const char* aPrefName, void* instance_data)
155 nsRefPtr<nsPresContext> presContext =
156 static_cast<nsPresContext*>(instance_data);
158 NS_ASSERTION(nullptr != presContext, "bad instance data");
159 if (nullptr != presContext) {
160 presContext->PreferenceChanged(aPrefName);
164 void
165 nsPresContext::PrefChangedUpdateTimerCallback(nsITimer *aTimer, void *aClosure)
167 nsPresContext* presContext = (nsPresContext*)aClosure;
168 NS_ASSERTION(presContext != nullptr, "bad instance data");
169 if (presContext)
170 presContext->UpdateAfterPreferencesChanged();
173 static bool
174 IsVisualCharset(const nsCString& aCharset)
176 if (aCharset.LowerCaseEqualsLiteral("ibm862") // Hebrew
177 || aCharset.LowerCaseEqualsLiteral("iso-8859-8") ) { // Hebrew
178 return true; // visual text type
180 else {
181 return false; // logical text type
185 // NOTE! nsPresContext::operator new() zeroes out all members, so don't
186 // bother initializing members to 0.
188 nsPresContext::nsPresContext(nsIDocument* aDocument, nsPresContextType aType)
189 : mType(aType), mDocument(aDocument), mBaseMinFontSize(0),
190 mTextZoom(1.0), mFullZoom(1.0), mLastFontInflationScreenWidth(-1.0),
191 mPageSize(-1, -1), mPPScale(1.0f),
192 mViewportStyleOverflow(NS_STYLE_OVERFLOW_AUTO, NS_STYLE_OVERFLOW_AUTO),
193 mImageAnimationModePref(imgIContainer::kNormalAnimMode),
194 mAllInvalidated(false),
195 mPaintFlashing(false), mPaintFlashingInitialized(false)
197 // NOTE! nsPresContext::operator new() zeroes out all members, so don't
198 // bother initializing members to 0.
200 mDoScaledTwips = true;
202 SetBackgroundImageDraw(true); // always draw the background
203 SetBackgroundColorDraw(true);
205 mBackgroundColor = NS_RGB(0xFF, 0xFF, 0xFF);
207 mUseDocumentColors = true;
208 mUseDocumentFonts = true;
210 // the minimum font-size is unconstrained by default
212 mLinkColor = NS_RGB(0x00, 0x00, 0xEE);
213 mActiveLinkColor = NS_RGB(0xEE, 0x00, 0x00);
214 mVisitedLinkColor = NS_RGB(0x55, 0x1A, 0x8B);
215 mUnderlineLinks = true;
216 mSendAfterPaintToContent = false;
218 mFocusTextColor = mDefaultColor;
219 mFocusBackgroundColor = mBackgroundColor;
220 mFocusRingWidth = 1;
222 mBodyTextColor = mDefaultColor;
224 if (aType == eContext_Galley) {
225 mMedium = nsGkAtoms::screen;
226 } else {
227 mMedium = nsGkAtoms::print;
228 mPaginated = true;
230 mMediaEmulated = mMedium;
232 if (!IsDynamic()) {
233 mImageAnimationMode = imgIContainer::kDontAnimMode;
234 mNeverAnimate = true;
235 } else {
236 mImageAnimationMode = imgIContainer::kNormalAnimMode;
237 mNeverAnimate = false;
239 NS_ASSERTION(mDocument, "Null document");
240 mUserFontSet = nullptr;
241 mUserFontSetDirty = true;
243 mCounterStylesDirty = true;
245 // if text perf logging enabled, init stats struct
246 PRLogModuleInfo *log = gfxPlatform::GetLog(eGfxLog_textperf);
247 if (log && log->level >= PR_LOG_WARNING) {
248 mTextPerf = new gfxTextPerfMetrics();
251 PR_INIT_CLIST(&mDOMMediaQueryLists);
254 nsPresContext::~nsPresContext()
256 NS_PRECONDITION(!mShell, "Presshell forgot to clear our mShell pointer");
257 SetShell(nullptr);
259 NS_ABORT_IF_FALSE(PR_CLIST_IS_EMPTY(&mDOMMediaQueryLists),
260 "must not have media query lists left");
262 // Disconnect the refresh driver *after* the transition manager, which
263 // needs it.
264 if (mRefreshDriver && mRefreshDriver->PresContext() == this) {
265 mRefreshDriver->Disconnect();
268 if (mEventManager) {
269 // unclear if these are needed, but can't hurt
270 mEventManager->NotifyDestroyPresContext(this);
271 mEventManager->SetPresContext(nullptr);
274 if (mPrefChangedTimer)
276 mPrefChangedTimer->Cancel();
277 mPrefChangedTimer = nullptr;
280 // Unregister preference callbacks
281 Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
282 "font.",
283 this);
284 Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
285 "browser.display.",
286 this);
287 Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
288 "browser.underline_anchors",
289 this);
290 Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
291 "browser.anchor_color",
292 this);
293 Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
294 "browser.active_color",
295 this);
296 Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
297 "browser.visited_color",
298 this);
299 Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
300 "image.animation_mode",
301 this);
302 Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
303 "bidi.",
304 this);
305 Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
306 "dom.send_after_paint_to_content",
307 this);
308 Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
309 "gfx.font_rendering.",
310 this);
311 Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
312 "layout.css.dpi",
313 this);
314 Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
315 "layout.css.devPixelsPerPx",
316 this);
317 Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
318 "nglayout.debug.paint_flashing",
319 this);
320 Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
321 "nglayout.debug.paint_flashing_chrome",
322 this);
325 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsPresContext)
326 NS_INTERFACE_MAP_ENTRY(nsISupports)
327 NS_INTERFACE_MAP_ENTRY(nsIObserver)
328 NS_INTERFACE_MAP_END
330 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsPresContext)
331 NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(nsPresContext, LastRelease())
333 void
334 nsPresContext::LastRelease()
336 if (IsRoot()) {
337 static_cast<nsRootPresContext*>(this)->CancelDidPaintTimer();
341 NS_IMPL_CYCLE_COLLECTION_CLASS(nsPresContext)
343 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsPresContext)
344 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument);
345 // NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mDeviceContext); // not xpcom
346 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEventManager);
347 // NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mLanguage); // an atom
349 // We own only the items in mDOMMediaQueryLists that have listeners;
350 // this reference is managed by their AddListener and RemoveListener
351 // methods.
352 for (PRCList *l = PR_LIST_HEAD(&tmp->mDOMMediaQueryLists);
353 l != &tmp->mDOMMediaQueryLists; l = PR_NEXT_LINK(l)) {
354 MediaQueryList *mql = static_cast<MediaQueryList*>(l);
355 if (mql->HasListeners()) {
356 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mDOMMediaQueryLists item");
357 cb.NoteXPCOMChild(mql);
361 // NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTheme); // a service
362 // NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLangService); // a service
363 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrintSettings);
364 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrefChangedTimer);
365 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
367 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsPresContext)
368 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument);
369 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDeviceContext); // worth bothering?
370 if (tmp->mEventManager) {
371 // unclear if these are needed, but can't hurt
372 tmp->mEventManager->NotifyDestroyPresContext(tmp);
373 tmp->mEventManager->SetPresContext(nullptr);
374 tmp->mEventManager = nullptr;
377 // We own only the items in mDOMMediaQueryLists that have listeners;
378 // this reference is managed by their AddListener and RemoveListener
379 // methods.
380 for (PRCList *l = PR_LIST_HEAD(&tmp->mDOMMediaQueryLists);
381 l != &tmp->mDOMMediaQueryLists; ) {
382 PRCList *next = PR_NEXT_LINK(l);
383 MediaQueryList *mql = static_cast<MediaQueryList*>(l);
384 mql->RemoveAllListeners();
385 l = next;
388 // NS_RELEASE(tmp->mLanguage); // an atom
390 // NS_IMPL_CYCLE_COLLECTION_UNLINK(mTheme); // a service
391 // NS_IMPL_CYCLE_COLLECTION_UNLINK(mLangService); // a service
392 NS_IMPL_CYCLE_COLLECTION_UNLINK(mPrintSettings);
393 if (tmp->mPrefChangedTimer)
395 tmp->mPrefChangedTimer->Cancel();
396 tmp->mPrefChangedTimer = nullptr;
398 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
401 #define MAKE_FONT_PREF_KEY(_pref, _s0, _s1) \
402 _pref.Assign(_s0); \
403 _pref.Append(_s1);
405 static const char* const kGenericFont[] = {
406 ".variable.",
407 ".fixed.",
408 ".serif.",
409 ".sans-serif.",
410 ".monospace.",
411 ".cursive.",
412 ".fantasy."
415 // whether no native theme service exists;
416 // if this gets set to true, we'll stop asking for it.
417 static bool sNoTheme = false;
419 // Set to true when LookAndFeelChanged needs to be called. This is used
420 // because the look and feel is a service, so there's no need to notify it from
421 // more than one prescontext.
422 static bool sLookAndFeelChanged;
424 // Set to true when ThemeChanged needs to be called on mTheme. This is used
425 // because mTheme is a service, so there's no need to notify it from more than
426 // one prescontext.
427 static bool sThemeChanged;
429 const nsPresContext::LangGroupFontPrefs*
430 nsPresContext::GetFontPrefsForLang(nsIAtom *aLanguage) const
432 // Get language group for aLanguage:
434 nsresult rv = NS_OK;
435 nsIAtom *langGroupAtom = nullptr;
436 if (!aLanguage) {
437 aLanguage = mLanguage;
439 if (aLanguage && mLangService) {
440 langGroupAtom = mLangService->GetLanguageGroup(aLanguage, &rv);
442 if (NS_FAILED(rv) || !langGroupAtom) {
443 langGroupAtom = nsGkAtoms::x_western; // Assume x-western is safe...
446 // Look for cached prefs for this lang group.
447 // Most documents will only use one (or very few) language groups. Rather
448 // than have the overhead of a hash lookup, we simply look along what will
449 // typically be a very short (usually of length 1) linked list. There are 31
450 // language groups, so in the worst case scenario we'll need to traverse 31
451 // link items.
453 LangGroupFontPrefs *prefs =
454 const_cast<LangGroupFontPrefs*>(&mLangGroupFontPrefs);
455 if (prefs->mLangGroup) { // if initialized
456 DebugOnly<uint32_t> count = 0;
457 for (;;) {
458 NS_ASSERTION(++count < 35, "Lang group count exceeded!!!");
459 if (prefs->mLangGroup == langGroupAtom) {
460 return prefs;
462 if (!prefs->mNext) {
463 break;
465 prefs = prefs->mNext;
468 // nothing cached, so go on and fetch the prefs for this lang group:
469 prefs = prefs->mNext = new LangGroupFontPrefs;
472 prefs->mLangGroup = langGroupAtom;
474 /* Fetch the font prefs to be used -- see bug 61883 for details.
475 Not all prefs are needed upfront. Some are fallback prefs intended
476 for the GFX font sub-system...
478 1) unit : assumed to be the same for all language groups -------------
479 font.size.unit = px | pt XXX could be folded in the size... bug 90440
481 2) attributes for generic fonts --------------------------------------
482 font.default.[langGroup] = serif | sans-serif - fallback generic font
483 font.name.[generic].[langGroup] = current user' selected font on the pref dialog
484 font.name-list.[generic].[langGroup] = fontname1, fontname2, ... [factory pre-built list]
485 font.size.[generic].[langGroup] = integer - settable by the user
486 font.size-adjust.[generic].[langGroup] = "float" - settable by the user
487 font.minimum-size.[langGroup] = integer - settable by the user
490 nsAutoCString langGroup;
491 langGroupAtom->ToUTF8String(langGroup);
493 prefs->mDefaultVariableFont.size = CSSPixelsToAppUnits(16);
494 prefs->mDefaultFixedFont.size = CSSPixelsToAppUnits(13);
496 nsAutoCString pref;
498 // get the current applicable font-size unit
499 enum {eUnit_unknown = -1, eUnit_px, eUnit_pt};
500 int32_t unit = eUnit_px;
502 nsAdoptingCString cvalue =
503 Preferences::GetCString("font.size.unit");
505 if (!cvalue.IsEmpty()) {
506 if (cvalue.EqualsLiteral("px")) {
507 unit = eUnit_px;
509 else if (cvalue.EqualsLiteral("pt")) {
510 unit = eUnit_pt;
512 else {
513 // XXX should really send this warning to the user (Error Console?).
514 // And just default to unit = eUnit_px?
515 NS_WARNING("unexpected font-size unit -- expected: 'px' or 'pt'");
516 unit = eUnit_unknown;
520 // get font.minimum-size.[langGroup]
522 MAKE_FONT_PREF_KEY(pref, "font.minimum-size.", langGroup);
524 int32_t size = Preferences::GetInt(pref.get());
525 if (unit == eUnit_px) {
526 prefs->mMinimumFontSize = CSSPixelsToAppUnits(size);
528 else if (unit == eUnit_pt) {
529 prefs->mMinimumFontSize = CSSPointsToAppUnits(size);
532 nsFont* fontTypes[] = {
533 &prefs->mDefaultVariableFont,
534 &prefs->mDefaultFixedFont,
535 &prefs->mDefaultSerifFont,
536 &prefs->mDefaultSansSerifFont,
537 &prefs->mDefaultMonospaceFont,
538 &prefs->mDefaultCursiveFont,
539 &prefs->mDefaultFantasyFont
541 static_assert(MOZ_ARRAY_LENGTH(fontTypes) == eDefaultFont_COUNT,
542 "FontTypes array count is not correct");
544 // Get attributes specific to each generic font. We do not get the user's
545 // generic-font-name-to-specific-family-name preferences because its the
546 // generic name that should be fed into the cascade. It is up to the GFX
547 // code to look up the font prefs to convert generic names to specific
548 // family names as necessary.
549 nsAutoCString generic_dot_langGroup;
550 for (uint32_t eType = 0; eType < ArrayLength(fontTypes); ++eType) {
551 generic_dot_langGroup.Assign(kGenericFont[eType]);
552 generic_dot_langGroup.Append(langGroup);
554 nsFont* font = fontTypes[eType];
556 // set the default variable font (the other fonts are seen as 'generic' fonts
557 // in GFX and will be queried there when hunting for alternative fonts)
558 if (eType == eDefaultFont_Variable) {
559 MAKE_FONT_PREF_KEY(pref, "font.name.variable.", langGroup);
561 nsAdoptingString value = Preferences::GetString(pref.get());
562 if (!value.IsEmpty()) {
563 FontFamilyName defaultVariableName = FontFamilyName::Convert(value);
564 FontFamilyType defaultType = defaultVariableName.mType;
565 NS_ASSERTION(defaultType == eFamily_serif ||
566 defaultType == eFamily_sans_serif,
567 "default type must be serif or sans-serif");
568 prefs->mDefaultVariableFont.fontlist = FontFamilyList(defaultType);
570 else {
571 MAKE_FONT_PREF_KEY(pref, "font.default.", langGroup);
572 value = Preferences::GetString(pref.get());
573 if (!value.IsEmpty()) {
574 FontFamilyName defaultVariableName = FontFamilyName::Convert(value);
575 FontFamilyType defaultType = defaultVariableName.mType;
576 NS_ASSERTION(defaultType == eFamily_serif ||
577 defaultType == eFamily_sans_serif,
578 "default type must be serif or sans-serif");
579 prefs->mDefaultVariableFont.fontlist = FontFamilyList(defaultType);
583 else {
584 if (eType == eDefaultFont_Monospace) {
585 // This takes care of the confusion whereby people often expect "monospace"
586 // to have the same default font-size as "-moz-fixed" (this tentative
587 // size may be overwritten with the specific value for "monospace" when
588 // "font.size.monospace.[langGroup]" is read -- see below)
589 prefs->mDefaultMonospaceFont.size = prefs->mDefaultFixedFont.size;
591 else if (eType != eDefaultFont_Fixed) {
592 // all the other generic fonts are initialized with the size of the
593 // variable font, but their specific size can supersede later -- see below
594 font->size = prefs->mDefaultVariableFont.size;
598 // Bug 84398: for spec purists, a different font-size only applies to the
599 // .variable. and .fixed. fonts and the other fonts should get |font-size-adjust|.
600 // The problem is that only GfxWin has the support for |font-size-adjust|. So for
601 // parity, we enable the ability to set a different font-size on all platforms.
603 // get font.size.[generic].[langGroup]
604 // size=0 means 'Auto', i.e., generic fonts retain the size of the variable font
605 MAKE_FONT_PREF_KEY(pref, "font.size", generic_dot_langGroup);
606 size = Preferences::GetInt(pref.get());
607 if (size > 0) {
608 if (unit == eUnit_px) {
609 font->size = CSSPixelsToAppUnits(size);
611 else if (unit == eUnit_pt) {
612 font->size = CSSPointsToAppUnits(size);
616 // get font.size-adjust.[generic].[langGroup]
617 // XXX only applicable on GFX ports that handle |font-size-adjust|
618 MAKE_FONT_PREF_KEY(pref, "font.size-adjust", generic_dot_langGroup);
619 cvalue = Preferences::GetCString(pref.get());
620 if (!cvalue.IsEmpty()) {
621 font->sizeAdjust = (float)atof(cvalue.get());
624 #ifdef DEBUG_rbs
625 printf("%s Family-list:%s size:%d sizeAdjust:%.2f\n",
626 generic_dot_langGroup.get(),
627 NS_ConvertUTF16toUTF8(font->name).get(), font->size,
628 font->sizeAdjust);
629 #endif
632 return prefs;
635 void
636 nsPresContext::GetDocumentColorPreferences()
638 // Make sure the preferences are initialized. In the normal run,
639 // they would already be, because gfxPlatform would have been created,
640 // but in some reference tests, that is not the case.
641 gfxPrefs::GetSingleton();
643 int32_t useAccessibilityTheme = 0;
644 bool usePrefColors = true;
645 bool isChromeDocShell = false;
647 nsIDocument* doc = mDocument->GetDisplayDocument();
648 if (doc && doc->GetDocShell()) {
649 isChromeDocShell = nsIDocShellTreeItem::typeChrome ==
650 doc->GetDocShell()->ItemType();
651 } else {
652 nsCOMPtr<nsIDocShellTreeItem> docShell(mContainer);
653 if (docShell) {
654 isChromeDocShell = nsIDocShellTreeItem::typeChrome == docShell->ItemType();
658 mIsChromeOriginImage = mDocument->IsBeingUsedAsImage() &&
659 IsChromeURI(mDocument->GetDocumentURI());
661 if (isChromeDocShell || mIsChromeOriginImage) {
662 usePrefColors = false;
663 } else {
664 useAccessibilityTheme =
665 LookAndFeel::GetInt(LookAndFeel::eIntID_UseAccessibilityTheme, 0);
666 usePrefColors = !useAccessibilityTheme;
668 if (usePrefColors) {
669 usePrefColors =
670 !Preferences::GetBool("browser.display.use_system_colors", false);
673 if (usePrefColors) {
674 nsAdoptingString colorStr =
675 Preferences::GetString("browser.display.foreground_color");
677 if (!colorStr.IsEmpty()) {
678 mDefaultColor = MakeColorPref(colorStr);
681 colorStr = Preferences::GetString("browser.display.background_color");
683 if (!colorStr.IsEmpty()) {
684 mBackgroundColor = MakeColorPref(colorStr);
687 else {
688 mDefaultColor =
689 LookAndFeel::GetColor(LookAndFeel::eColorID_WindowForeground,
690 NS_RGB(0x00, 0x00, 0x00));
691 mBackgroundColor =
692 LookAndFeel::GetColor(LookAndFeel::eColorID_WindowBackground,
693 NS_RGB(0xFF, 0xFF, 0xFF));
696 // Wherever we got the default background color from, ensure it is
697 // opaque.
698 mBackgroundColor = NS_ComposeColors(NS_RGB(0xFF, 0xFF, 0xFF),
699 mBackgroundColor);
701 mUseDocumentColors = !useAccessibilityTheme &&
702 Preferences::GetBool("browser.display.use_document_colors",
703 mUseDocumentColors);
706 void
707 nsPresContext::GetUserPreferences()
709 if (!GetPresShell()) {
710 // No presshell means nothing to do here. We'll do this when we
711 // get a presshell.
712 return;
715 mAutoQualityMinFontSizePixelsPref =
716 Preferences::GetInt("browser.display.auto_quality_min_font_size");
718 // * document colors
719 GetDocumentColorPreferences();
721 mSendAfterPaintToContent =
722 Preferences::GetBool("dom.send_after_paint_to_content",
723 mSendAfterPaintToContent);
725 // * link colors
726 mUnderlineLinks =
727 Preferences::GetBool("browser.underline_anchors", mUnderlineLinks);
729 nsAdoptingString colorStr = Preferences::GetString("browser.anchor_color");
731 if (!colorStr.IsEmpty()) {
732 mLinkColor = MakeColorPref(colorStr);
735 colorStr = Preferences::GetString("browser.active_color");
737 if (!colorStr.IsEmpty()) {
738 mActiveLinkColor = MakeColorPref(colorStr);
741 colorStr = Preferences::GetString("browser.visited_color");
743 if (!colorStr.IsEmpty()) {
744 mVisitedLinkColor = MakeColorPref(colorStr);
747 mUseFocusColors =
748 Preferences::GetBool("browser.display.use_focus_colors", mUseFocusColors);
750 mFocusTextColor = mDefaultColor;
751 mFocusBackgroundColor = mBackgroundColor;
753 colorStr = Preferences::GetString("browser.display.focus_text_color");
755 if (!colorStr.IsEmpty()) {
756 mFocusTextColor = MakeColorPref(colorStr);
759 colorStr = Preferences::GetString("browser.display.focus_background_color");
761 if (!colorStr.IsEmpty()) {
762 mFocusBackgroundColor = MakeColorPref(colorStr);
765 mFocusRingWidth =
766 Preferences::GetInt("browser.display.focus_ring_width", mFocusRingWidth);
768 mFocusRingOnAnything =
769 Preferences::GetBool("browser.display.focus_ring_on_anything",
770 mFocusRingOnAnything);
772 mFocusRingStyle =
773 Preferences::GetInt("browser.display.focus_ring_style", mFocusRingStyle);
775 mBodyTextColor = mDefaultColor;
777 // * use fonts?
778 mUseDocumentFonts =
779 Preferences::GetInt("browser.display.use_document_fonts") != 0;
781 mPrefScrollbarSide = Preferences::GetInt("layout.scrollbar.side");
783 ResetCachedFontPrefs();
785 // * image animation
786 const nsAdoptingCString& animatePref =
787 Preferences::GetCString("image.animation_mode");
788 if (animatePref.EqualsLiteral("normal"))
789 mImageAnimationModePref = imgIContainer::kNormalAnimMode;
790 else if (animatePref.EqualsLiteral("none"))
791 mImageAnimationModePref = imgIContainer::kDontAnimMode;
792 else if (animatePref.EqualsLiteral("once"))
793 mImageAnimationModePref = imgIContainer::kLoopOnceAnimMode;
794 else // dynamic change to invalid value should act like it does initially
795 mImageAnimationModePref = imgIContainer::kNormalAnimMode;
797 uint32_t bidiOptions = GetBidi();
799 int32_t prefInt =
800 Preferences::GetInt(IBMBIDI_TEXTDIRECTION_STR,
801 GET_BIDI_OPTION_DIRECTION(bidiOptions));
802 SET_BIDI_OPTION_DIRECTION(bidiOptions, prefInt);
803 mPrefBidiDirection = prefInt;
805 prefInt =
806 Preferences::GetInt(IBMBIDI_TEXTTYPE_STR,
807 GET_BIDI_OPTION_TEXTTYPE(bidiOptions));
808 SET_BIDI_OPTION_TEXTTYPE(bidiOptions, prefInt);
810 prefInt =
811 Preferences::GetInt(IBMBIDI_NUMERAL_STR,
812 GET_BIDI_OPTION_NUMERAL(bidiOptions));
813 SET_BIDI_OPTION_NUMERAL(bidiOptions, prefInt);
815 prefInt =
816 Preferences::GetInt(IBMBIDI_SUPPORTMODE_STR,
817 GET_BIDI_OPTION_SUPPORT(bidiOptions));
818 SET_BIDI_OPTION_SUPPORT(bidiOptions, prefInt);
820 // We don't need to force reflow: either we are initializing a new
821 // prescontext or we are being called from UpdateAfterPreferencesChanged()
822 // which triggers a reflow anyway.
823 SetBidi(bidiOptions, false);
826 void
827 nsPresContext::InvalidateThebesLayers()
829 if (!mShell)
830 return;
831 nsIFrame* rootFrame = mShell->FrameManager()->GetRootFrame();
832 if (rootFrame) {
833 // FrameLayerBuilder caches invalidation-related values that depend on the
834 // appunits-per-dev-pixel ratio, so ensure that all ThebesLayer drawing
835 // is completely flushed.
836 rootFrame->InvalidateFrameSubtree();
840 void
841 nsPresContext::AppUnitsPerDevPixelChanged()
843 InvalidateThebesLayers();
845 if (mDeviceContext) {
846 mDeviceContext->FlushFontCache();
849 if (HasCachedStyleData()) {
850 // All cached style data must be recomputed.
851 MediaFeatureValuesChanged(eAlwaysRebuildStyle, NS_STYLE_HINT_REFLOW);
854 mCurAppUnitsPerDevPixel = AppUnitsPerDevPixel();
857 void
858 nsPresContext::PreferenceChanged(const char* aPrefName)
860 nsDependentCString prefName(aPrefName);
861 if (prefName.EqualsLiteral("layout.css.dpi") ||
862 prefName.EqualsLiteral("layout.css.devPixelsPerPx")) {
863 int32_t oldAppUnitsPerDevPixel = AppUnitsPerDevPixel();
864 if (mDeviceContext->CheckDPIChange() && mShell) {
865 nsCOMPtr<nsIPresShell> shell = mShell;
866 // Re-fetch the view manager's window dimensions in case there's a deferred
867 // resize which hasn't affected our mVisibleArea yet
868 nscoord oldWidthAppUnits, oldHeightAppUnits;
869 nsRefPtr<nsViewManager> vm = shell->GetViewManager();
870 if (!vm) {
871 return;
873 vm->GetWindowDimensions(&oldWidthAppUnits, &oldHeightAppUnits);
874 float oldWidthDevPixels = oldWidthAppUnits/oldAppUnitsPerDevPixel;
875 float oldHeightDevPixels = oldHeightAppUnits/oldAppUnitsPerDevPixel;
877 nscoord width = NSToCoordRound(oldWidthDevPixels*AppUnitsPerDevPixel());
878 nscoord height = NSToCoordRound(oldHeightDevPixels*AppUnitsPerDevPixel());
879 vm->SetWindowDimensions(width, height);
881 AppUnitsPerDevPixelChanged();
883 return;
885 if (StringBeginsWith(prefName, NS_LITERAL_CSTRING("font."))) {
886 // Changes to font family preferences don't change anything in the
887 // computed style data, so the style system won't generate a reflow
888 // hint for us. We need to do that manually.
890 // FIXME We could probably also handle changes to
891 // browser.display.auto_quality_min_font_size here, but that
892 // probably also requires clearing the text run cache, so don't
893 // bother (yet, anyway).
894 mPrefChangePendingNeedsReflow = true;
896 if (StringBeginsWith(prefName, NS_LITERAL_CSTRING("bidi."))) {
897 // Changes to bidi prefs need to trigger a reflow (see bug 443629)
898 mPrefChangePendingNeedsReflow = true;
900 // Changes to bidi.numeral also needs to empty the text run cache.
901 // This is handled in gfxTextRunWordCache.cpp.
903 if (StringBeginsWith(prefName, NS_LITERAL_CSTRING("gfx.font_rendering."))) {
904 // Changes to font_rendering prefs need to trigger a reflow
905 mPrefChangePendingNeedsReflow = true;
907 // we use a zero-delay timer to coalesce multiple pref updates
908 if (!mPrefChangedTimer)
910 mPrefChangedTimer = do_CreateInstance("@mozilla.org/timer;1");
911 if (!mPrefChangedTimer)
912 return;
913 mPrefChangedTimer->InitWithFuncCallback(nsPresContext::PrefChangedUpdateTimerCallback, (void*)this, 0, nsITimer::TYPE_ONE_SHOT);
915 if (prefName.EqualsLiteral("nglayout.debug.paint_flashing") ||
916 prefName.EqualsLiteral("nglayout.debug.paint_flashing_chrome")) {
917 mPaintFlashingInitialized = false;
918 return;
922 void
923 nsPresContext::UpdateAfterPreferencesChanged()
925 mPrefChangedTimer = nullptr;
927 nsCOMPtr<nsIDocShellTreeItem> docShell(mContainer);
928 if (docShell && nsIDocShellTreeItem::typeChrome == docShell->ItemType()) {
929 return;
932 // Initialize our state from the user preferences
933 GetUserPreferences();
935 // update the presShell: tell it to set the preference style rules up
936 if (mShell) {
937 mShell->SetPreferenceStyleRules(true);
940 InvalidateThebesLayers();
941 mDeviceContext->FlushFontCache();
943 nsChangeHint hint = nsChangeHint(0);
945 if (mPrefChangePendingNeedsReflow) {
946 NS_UpdateHint(hint, NS_STYLE_HINT_REFLOW);
949 RebuildAllStyleData(hint);
952 nsresult
953 nsPresContext::Init(nsDeviceContext* aDeviceContext)
955 NS_ASSERTION(!mInitialized, "attempt to reinit pres context");
956 NS_ENSURE_ARG(aDeviceContext);
958 mDeviceContext = aDeviceContext;
960 if (mDeviceContext->SetPixelScale(mFullZoom))
961 mDeviceContext->FlushFontCache();
962 mCurAppUnitsPerDevPixel = AppUnitsPerDevPixel();
964 mEventManager = new mozilla::EventStateManager();
966 mTransitionManager = new nsTransitionManager(this);
968 mAnimationManager = new nsAnimationManager(this);
970 if (mDocument->GetDisplayDocument()) {
971 NS_ASSERTION(mDocument->GetDisplayDocument()->GetShell() &&
972 mDocument->GetDisplayDocument()->GetShell()->GetPresContext(),
973 "Why are we being initialized?");
974 mRefreshDriver = mDocument->GetDisplayDocument()->GetShell()->
975 GetPresContext()->RefreshDriver();
976 } else {
977 nsIDocument* parent = mDocument->GetParentDocument();
978 // Unfortunately, sometimes |parent| here has no presshell because
979 // printing screws up things. Assert that in other cases it does,
980 // but whenever the shell is null just fall back on using our own
981 // refresh driver.
982 NS_ASSERTION(!parent || mDocument->IsStaticDocument() || parent->GetShell(),
983 "How did we end up with a presshell if our parent doesn't "
984 "have one?");
985 if (parent && parent->GetShell()) {
986 NS_ASSERTION(parent->GetShell()->GetPresContext(),
987 "How did we get a presshell?");
989 // We don't have our container set yet at this point
990 nsCOMPtr<nsIDocShellTreeItem> ourItem = mDocument->GetDocShell();
991 if (ourItem) {
992 nsCOMPtr<nsIDocShellTreeItem> parentItem;
993 ourItem->GetSameTypeParent(getter_AddRefs(parentItem));
994 if (parentItem) {
995 Element* containingElement =
996 parent->FindContentForSubDocument(mDocument);
997 if (!containingElement->IsXUL() ||
998 !containingElement->
999 HasAttr(kNameSpaceID_None,
1000 nsGkAtoms::forceOwnRefreshDriver)) {
1001 mRefreshDriver = parent->GetShell()->GetPresContext()->RefreshDriver();
1007 if (!mRefreshDriver) {
1008 mRefreshDriver = new nsRefreshDriver(this);
1012 // Initialise refresh tick counters for OMTA
1013 mLastStyleUpdateForAllAnimations = mRefreshDriver->MostRecentRefresh();
1015 // Initialize restyle manager after initializing the refresh driver.
1016 // Since RestyleManager is also the name of a method of nsPresContext,
1017 // it is necessary to prefix the class with the mozilla namespace
1018 // here.
1019 mRestyleManager = new mozilla::RestyleManager(this);
1021 mLangService = do_GetService(NS_LANGUAGEATOMSERVICE_CONTRACTID);
1023 // Register callbacks so we're notified when the preferences change
1024 Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
1025 "font.",
1026 this);
1027 Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
1028 "browser.display.",
1029 this);
1030 Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
1031 "browser.underline_anchors",
1032 this);
1033 Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
1034 "browser.anchor_color",
1035 this);
1036 Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
1037 "browser.active_color",
1038 this);
1039 Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
1040 "browser.visited_color",
1041 this);
1042 Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
1043 "image.animation_mode",
1044 this);
1045 Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
1046 "bidi.",
1047 this);
1048 Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
1049 "dom.send_after_paint_to_content",
1050 this);
1051 Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
1052 "gfx.font_rendering.",
1053 this);
1054 Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
1055 "layout.css.dpi",
1056 this);
1057 Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
1058 "layout.css.devPixelsPerPx",
1059 this);
1060 Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
1061 "nglayout.debug.paint_flashing",
1062 this);
1063 Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
1064 "nglayout.debug.paint_flashing_chrome",
1065 this);
1067 nsresult rv = mEventManager->Init();
1068 NS_ENSURE_SUCCESS(rv, rv);
1070 mEventManager->SetPresContext(this);
1072 #ifdef DEBUG
1073 mInitialized = true;
1074 #endif
1076 mBorderWidthTable[NS_STYLE_BORDER_WIDTH_THIN] = CSSPixelsToAppUnits(1);
1077 mBorderWidthTable[NS_STYLE_BORDER_WIDTH_MEDIUM] = CSSPixelsToAppUnits(3);
1078 mBorderWidthTable[NS_STYLE_BORDER_WIDTH_THICK] = CSSPixelsToAppUnits(5);
1080 return NS_OK;
1083 // Note: We don't hold a reference on the shell; it has a reference to
1084 // us
1085 void
1086 nsPresContext::SetShell(nsIPresShell* aShell)
1088 if (mUserFontSet) {
1089 // Clear out user font set if we have one
1090 mUserFontSet->Destroy();
1091 NS_RELEASE(mUserFontSet);
1093 if (mCounterStyleManager) {
1094 mCounterStyleManager->Disconnect();
1095 mCounterStyleManager = nullptr;
1098 if (mShell) {
1099 // Remove ourselves as the charset observer from the shell's doc, because
1100 // this shell may be going away for good.
1101 nsIDocument *doc = mShell->GetDocument();
1102 if (doc) {
1103 doc->RemoveCharSetObserver(this);
1107 mShell = aShell;
1109 if (mShell) {
1110 // Since CounterStyleManager is also the name of a method of
1111 // nsPresContext, it is necessary to prefix the class with the mozilla
1112 // namespace here.
1113 mCounterStyleManager = new mozilla::CounterStyleManager(this);
1115 nsIDocument *doc = mShell->GetDocument();
1116 NS_ASSERTION(doc, "expect document here");
1117 if (doc) {
1118 // Have to update PresContext's mDocument before calling any other methods.
1119 mDocument = doc;
1121 // Initialize our state from the user preferences, now that we
1122 // have a presshell, and hence a document.
1123 GetUserPreferences();
1125 if (doc) {
1126 nsIURI *docURI = doc->GetDocumentURI();
1128 if (IsDynamic() && docURI) {
1129 bool isChrome = false;
1130 bool isRes = false;
1131 docURI->SchemeIs("chrome", &isChrome);
1132 docURI->SchemeIs("resource", &isRes);
1134 if (!isChrome && !isRes)
1135 mImageAnimationMode = mImageAnimationModePref;
1136 else
1137 mImageAnimationMode = imgIContainer::kNormalAnimMode;
1140 if (mLangService) {
1141 doc->AddCharSetObserver(this);
1142 UpdateCharSet(doc->GetDocumentCharacterSet());
1145 } else {
1146 if (mTransitionManager) {
1147 mTransitionManager->Disconnect();
1148 mTransitionManager = nullptr;
1150 if (mAnimationManager) {
1151 mAnimationManager->Disconnect();
1152 mAnimationManager = nullptr;
1154 if (mRestyleManager) {
1155 mRestyleManager->Disconnect();
1156 mRestyleManager = nullptr;
1159 if (IsRoot()) {
1160 // Have to cancel our plugin geometry timer, because the
1161 // callback for that depends on a non-null presshell.
1162 static_cast<nsRootPresContext*>(this)->CancelApplyPluginGeometryTimer();
1167 void
1168 nsPresContext::DoChangeCharSet(const nsCString& aCharSet)
1170 UpdateCharSet(aCharSet);
1171 mDeviceContext->FlushFontCache();
1172 RebuildAllStyleData(NS_STYLE_HINT_REFLOW);
1175 void
1176 nsPresContext::UpdateCharSet(const nsCString& aCharSet)
1178 if (mLangService) {
1179 mLanguage = mLangService->LookupCharSet(aCharSet);
1180 // this will be a language group (or script) code rather than a true language code
1182 // bug 39570: moved from nsLanguageAtomService::LookupCharSet()
1183 if (mLanguage == nsGkAtoms::Unicode) {
1184 mLanguage = mLangService->GetLocaleLanguage();
1186 ResetCachedFontPrefs();
1189 switch (GET_BIDI_OPTION_TEXTTYPE(GetBidi())) {
1191 case IBMBIDI_TEXTTYPE_LOGICAL:
1192 SetVisualMode(false);
1193 break;
1195 case IBMBIDI_TEXTTYPE_VISUAL:
1196 SetVisualMode(true);
1197 break;
1199 case IBMBIDI_TEXTTYPE_CHARSET:
1200 default:
1201 SetVisualMode(IsVisualCharset(aCharSet));
1205 NS_IMETHODIMP
1206 nsPresContext::Observe(nsISupports* aSubject,
1207 const char* aTopic,
1208 const char16_t* aData)
1210 if (!nsCRT::strcmp(aTopic, "charset")) {
1211 nsRefPtr<CharSetChangingRunnable> runnable =
1212 new CharSetChangingRunnable(this, NS_LossyConvertUTF16toASCII(aData));
1213 return NS_DispatchToCurrentThread(runnable);
1216 NS_WARNING("unrecognized topic in nsPresContext::Observe");
1217 return NS_ERROR_FAILURE;
1220 nsPresContext*
1221 nsPresContext::GetParentPresContext()
1223 nsIPresShell* shell = GetPresShell();
1224 if (shell) {
1225 nsViewManager* viewManager = shell->GetViewManager();
1226 if (viewManager) {
1227 nsView* view = viewManager->GetRootView();
1228 if (view) {
1229 view = view->GetParent(); // anonymous inner view
1230 if (view) {
1231 view = view->GetParent(); // subdocumentframe's view
1232 if (view) {
1233 nsIFrame* f = view->GetFrame();
1234 if (f) {
1235 return f->PresContext();
1242 return nullptr;
1245 nsPresContext*
1246 nsPresContext::GetToplevelContentDocumentPresContext()
1248 if (IsChrome())
1249 return nullptr;
1250 nsPresContext* pc = this;
1251 for (;;) {
1252 nsPresContext* parent = pc->GetParentPresContext();
1253 if (!parent || parent->IsChrome())
1254 return pc;
1255 pc = parent;
1259 nsIWidget*
1260 nsPresContext::GetNearestWidget(nsPoint* aOffset)
1262 NS_ENSURE_TRUE(mShell, nullptr);
1263 nsIFrame* frame = mShell->GetRootFrame();
1264 NS_ENSURE_TRUE(frame, nullptr);
1265 return frame->GetView()->GetNearestWidget(aOffset);
1268 nsIWidget*
1269 nsPresContext::GetRootWidget()
1271 NS_ENSURE_TRUE(mShell, nullptr);
1272 nsViewManager* vm = mShell->GetViewManager();
1273 if (!vm) {
1274 return nullptr;
1276 nsCOMPtr<nsIWidget> widget;
1277 vm->GetRootWidget(getter_AddRefs(widget));
1278 return widget.get();
1281 // We may want to replace this with something faster, maybe caching the root prescontext
1282 nsRootPresContext*
1283 nsPresContext::GetRootPresContext()
1285 nsPresContext* pc = this;
1286 for (;;) {
1287 nsPresContext* parent = pc->GetParentPresContext();
1288 if (!parent)
1289 break;
1290 pc = parent;
1292 return pc->IsRoot() ? static_cast<nsRootPresContext*>(pc) : nullptr;
1295 nsRootPresContext*
1296 nsPresContext::GetDisplayRootPresContext()
1298 nsPresContext* pc = this;
1299 for (;;) {
1300 nsPresContext* parent = pc->GetParentPresContext();
1301 if (!parent) {
1302 // Not sure if this is always strictly the parent, but it works for GetRootPresContext
1303 // where the current pres context has no frames.
1304 nsIDocument *doc = pc->Document();
1305 if (doc) {
1306 doc = doc->GetParentDocument();
1307 if (doc) {
1308 nsIPresShell* shell = doc->GetShell();
1309 if (shell) {
1310 parent = shell->GetPresContext();
1315 if (!parent || parent == pc)
1316 break;
1317 pc = parent;
1319 return pc->IsRoot() ? static_cast<nsRootPresContext*>(pc) : nullptr;
1322 void
1323 nsPresContext::CompatibilityModeChanged()
1325 if (!mShell)
1326 return;
1328 // enable/disable the QuirkSheet
1329 mShell->StyleSet()->
1330 EnableQuirkStyleSheet(CompatibilityMode() == eCompatibility_NavQuirks);
1333 // Helper function for setting Anim Mode on image
1334 static void SetImgAnimModeOnImgReq(imgIRequest* aImgReq, uint16_t aMode)
1336 if (aImgReq) {
1337 nsCOMPtr<imgIContainer> imgCon;
1338 aImgReq->GetImage(getter_AddRefs(imgCon));
1339 if (imgCon) {
1340 imgCon->SetAnimationMode(aMode);
1345 // IMPORTANT: Assumption is that all images for a Presentation
1346 // have the same Animation Mode (pavlov said this was OK)
1348 // Walks content and set the animation mode
1349 // this is a way to turn on/off image animations
1350 void nsPresContext::SetImgAnimations(nsIContent *aParent, uint16_t aMode)
1352 nsCOMPtr<nsIImageLoadingContent> imgContent(do_QueryInterface(aParent));
1353 if (imgContent) {
1354 nsCOMPtr<imgIRequest> imgReq;
1355 imgContent->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
1356 getter_AddRefs(imgReq));
1357 SetImgAnimModeOnImgReq(imgReq, aMode);
1360 uint32_t count = aParent->GetChildCount();
1361 for (uint32_t i = 0; i < count; ++i) {
1362 SetImgAnimations(aParent->GetChildAt(i), aMode);
1366 void
1367 nsPresContext::SetSMILAnimations(nsIDocument *aDoc, uint16_t aNewMode,
1368 uint16_t aOldMode)
1370 if (aDoc->HasAnimationController()) {
1371 nsSMILAnimationController* controller = aDoc->GetAnimationController();
1372 switch (aNewMode)
1374 case imgIContainer::kNormalAnimMode:
1375 case imgIContainer::kLoopOnceAnimMode:
1376 if (aOldMode == imgIContainer::kDontAnimMode)
1377 controller->Resume(nsSMILTimeContainer::PAUSE_USERPREF);
1378 break;
1380 case imgIContainer::kDontAnimMode:
1381 if (aOldMode != imgIContainer::kDontAnimMode)
1382 controller->Pause(nsSMILTimeContainer::PAUSE_USERPREF);
1383 break;
1388 void
1389 nsPresContext::SetImageAnimationModeInternal(uint16_t aMode)
1391 NS_ASSERTION(aMode == imgIContainer::kNormalAnimMode ||
1392 aMode == imgIContainer::kDontAnimMode ||
1393 aMode == imgIContainer::kLoopOnceAnimMode, "Wrong Animation Mode is being set!");
1395 // Image animation mode cannot be changed when rendering to a printer.
1396 if (!IsDynamic())
1397 return;
1399 // Now walk the content tree and set the animation mode
1400 // on all the images.
1401 if (mShell != nullptr) {
1402 nsIDocument *doc = mShell->GetDocument();
1403 if (doc) {
1404 doc->StyleImageLoader()->SetAnimationMode(aMode);
1406 Element *rootElement = doc->GetRootElement();
1407 if (rootElement) {
1408 SetImgAnimations(rootElement, aMode);
1410 SetSMILAnimations(doc, aMode, mImageAnimationMode);
1414 mImageAnimationMode = aMode;
1417 void
1418 nsPresContext::SetImageAnimationModeExternal(uint16_t aMode)
1420 SetImageAnimationModeInternal(aMode);
1423 const nsFont*
1424 nsPresContext::GetDefaultFont(uint8_t aFontID, nsIAtom *aLanguage) const
1426 const LangGroupFontPrefs *prefs = GetFontPrefsForLang(aLanguage);
1428 const nsFont *font;
1429 switch (aFontID) {
1430 // Special (our default variable width font and fixed width font)
1431 case kPresContext_DefaultVariableFont_ID:
1432 font = &prefs->mDefaultVariableFont;
1433 break;
1434 case kPresContext_DefaultFixedFont_ID:
1435 font = &prefs->mDefaultFixedFont;
1436 break;
1437 // CSS
1438 case kGenericFont_serif:
1439 font = &prefs->mDefaultSerifFont;
1440 break;
1441 case kGenericFont_sans_serif:
1442 font = &prefs->mDefaultSansSerifFont;
1443 break;
1444 case kGenericFont_monospace:
1445 font = &prefs->mDefaultMonospaceFont;
1446 break;
1447 case kGenericFont_cursive:
1448 font = &prefs->mDefaultCursiveFont;
1449 break;
1450 case kGenericFont_fantasy:
1451 font = &prefs->mDefaultFantasyFont;
1452 break;
1453 default:
1454 font = nullptr;
1455 NS_ERROR("invalid arg");
1456 break;
1458 return font;
1461 void
1462 nsPresContext::SetFullZoom(float aZoom)
1464 if (!mShell || mFullZoom == aZoom) {
1465 return;
1468 // Re-fetch the view manager's window dimensions in case there's a deferred
1469 // resize which hasn't affected our mVisibleArea yet
1470 nscoord oldWidthAppUnits, oldHeightAppUnits;
1471 mShell->GetViewManager()->GetWindowDimensions(&oldWidthAppUnits, &oldHeightAppUnits);
1472 float oldWidthDevPixels = oldWidthAppUnits / float(mCurAppUnitsPerDevPixel);
1473 float oldHeightDevPixels = oldHeightAppUnits / float(mCurAppUnitsPerDevPixel);
1474 mDeviceContext->SetPixelScale(aZoom);
1476 NS_ASSERTION(!mSupressResizeReflow, "two zooms happening at the same time? impossible!");
1477 mSupressResizeReflow = true;
1479 mFullZoom = aZoom;
1480 mShell->GetViewManager()->
1481 SetWindowDimensions(NSToCoordRound(oldWidthDevPixels * AppUnitsPerDevPixel()),
1482 NSToCoordRound(oldHeightDevPixels * AppUnitsPerDevPixel()));
1484 AppUnitsPerDevPixelChanged();
1486 mSupressResizeReflow = false;
1489 float
1490 nsPresContext::ScreenWidthInchesForFontInflation(bool* aChanged)
1492 if (aChanged) {
1493 *aChanged = false;
1496 nsDeviceContext *dx = DeviceContext();
1497 nsRect clientRect;
1498 dx->GetClientRect(clientRect); // FIXME: GetClientRect looks expensive
1499 float deviceWidthInches =
1500 float(clientRect.width) / float(dx->AppUnitsPerPhysicalInch());
1502 if (mLastFontInflationScreenWidth == -1.0) {
1503 mLastFontInflationScreenWidth = deviceWidthInches;
1506 if (deviceWidthInches != mLastFontInflationScreenWidth && aChanged) {
1507 *aChanged = true;
1508 mLastFontInflationScreenWidth = deviceWidthInches;
1511 return deviceWidthInches;
1514 void
1515 nsPresContext::SetContainer(nsIDocShell* aDocShell)
1517 if (aDocShell) {
1518 mContainer = static_cast<nsDocShell*>(aDocShell);
1519 } else {
1520 mContainer = WeakPtr<nsDocShell>();
1522 UpdateIsChrome();
1523 if (mContainer) {
1524 GetDocumentColorPreferences();
1528 nsISupports*
1529 nsPresContext::GetContainerWeakInternal() const
1531 return static_cast<nsIDocShell*>(mContainer);
1534 nsISupports*
1535 nsPresContext::GetContainerWeakExternal() const
1537 return GetContainerWeakInternal();
1540 nsIDocShell*
1541 nsPresContext::GetDocShell() const
1543 return mContainer;
1546 /* virtual */ void
1547 nsPresContext::Detach()
1549 SetContainer(nullptr);
1550 SetLinkHandler(nullptr);
1551 if (mShell) {
1552 mShell->CancelInvalidatePresShellIfHidden();
1556 bool
1557 nsPresContext::StyleUpdateForAllAnimationsIsUpToDate()
1559 return mLastStyleUpdateForAllAnimations == mRefreshDriver->MostRecentRefresh();
1562 void
1563 nsPresContext::TickLastStyleUpdateForAllAnimations()
1565 mLastStyleUpdateForAllAnimations = mRefreshDriver->MostRecentRefresh();
1568 bool
1569 nsPresContext::BidiEnabledExternal() const
1571 return BidiEnabledInternal();
1574 bool
1575 nsPresContext::BidiEnabledInternal() const
1577 return Document()->GetBidiEnabled();
1580 void
1581 nsPresContext::SetBidiEnabled() const
1583 if (mShell) {
1584 nsIDocument *doc = mShell->GetDocument();
1585 if (doc) {
1586 doc->SetBidiEnabled();
1591 void
1592 nsPresContext::SetBidi(uint32_t aSource, bool aForceRestyle)
1594 // Don't do all this stuff unless the options have changed.
1595 if (aSource == GetBidi()) {
1596 return;
1599 NS_ASSERTION(!(aForceRestyle && (GetBidi() == 0)),
1600 "ForceReflow on new prescontext");
1602 Document()->SetBidiOptions(aSource);
1603 if (IBMBIDI_TEXTDIRECTION_RTL == GET_BIDI_OPTION_DIRECTION(aSource)
1604 || IBMBIDI_NUMERAL_HINDI == GET_BIDI_OPTION_NUMERAL(aSource)) {
1605 SetBidiEnabled();
1607 if (IBMBIDI_TEXTTYPE_VISUAL == GET_BIDI_OPTION_TEXTTYPE(aSource)) {
1608 SetVisualMode(true);
1610 else if (IBMBIDI_TEXTTYPE_LOGICAL == GET_BIDI_OPTION_TEXTTYPE(aSource)) {
1611 SetVisualMode(false);
1613 else {
1614 nsIDocument* doc = mShell->GetDocument();
1615 if (doc) {
1616 SetVisualMode(IsVisualCharset(doc->GetDocumentCharacterSet()));
1619 if (aForceRestyle && mShell) {
1620 // Reconstruct the root document element's frame and its children,
1621 // because we need to trigger frame reconstruction for direction change.
1622 RebuildUserFontSet();
1623 mShell->ReconstructFrames();
1627 uint32_t
1628 nsPresContext::GetBidi() const
1630 return Document()->GetBidiOptions();
1633 bool
1634 nsPresContext::IsTopLevelWindowInactive()
1636 nsCOMPtr<nsIDocShellTreeItem> treeItem(mContainer);
1637 if (!treeItem)
1638 return false;
1640 nsCOMPtr<nsIDocShellTreeItem> rootItem;
1641 treeItem->GetRootTreeItem(getter_AddRefs(rootItem));
1642 if (!rootItem) {
1643 return false;
1646 nsCOMPtr<nsPIDOMWindow> domWindow = rootItem->GetWindow();
1648 return domWindow && !domWindow->IsActive();
1651 nsITheme*
1652 nsPresContext::GetTheme()
1654 if (!sNoTheme && !mTheme) {
1655 mTheme = do_GetService("@mozilla.org/chrome/chrome-native-theme;1");
1656 if (!mTheme)
1657 sNoTheme = true;
1660 return mTheme;
1663 void
1664 nsPresContext::ThemeChanged()
1666 if (!mPendingThemeChanged) {
1667 sLookAndFeelChanged = true;
1668 sThemeChanged = true;
1670 nsCOMPtr<nsIRunnable> ev =
1671 NS_NewRunnableMethod(this, &nsPresContext::ThemeChangedInternal);
1672 if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) {
1673 mPendingThemeChanged = true;
1678 void
1679 nsPresContext::ThemeChangedInternal()
1681 mPendingThemeChanged = false;
1683 // Tell the theme that it changed, so it can flush any handles to stale theme
1684 // data.
1685 if (mTheme && sThemeChanged) {
1686 mTheme->ThemeChanged();
1687 sThemeChanged = false;
1690 if (sLookAndFeelChanged) {
1691 // Clear all cached LookAndFeel colors.
1692 LookAndFeel::Refresh();
1693 sLookAndFeelChanged = false;
1695 // Vector images (SVG) may be using theme colors so we discard all cached
1696 // surfaces. (We could add a vector image only version of DiscardAll, but
1697 // in bug 940625 we decided theme changes are rare enough not to bother.)
1698 mozilla::image::SurfaceCache::DiscardAll();
1701 // This will force the system metrics to be generated the next time they're used
1702 nsCSSRuleProcessor::FreeSystemMetrics();
1704 // Changes to system metrics can change media queries on them.
1705 // Changes in theme can change system colors (whose changes are
1706 // properly reflected in computed style data), system fonts (whose
1707 // changes are not), and -moz-appearance (whose changes likewise are
1708 // not), so we need to reflow.
1709 MediaFeatureValuesChanged(eAlwaysRebuildStyle, NS_STYLE_HINT_REFLOW);
1712 void
1713 nsPresContext::SysColorChanged()
1715 if (!mPendingSysColorChanged) {
1716 sLookAndFeelChanged = true;
1717 nsCOMPtr<nsIRunnable> ev =
1718 NS_NewRunnableMethod(this, &nsPresContext::SysColorChangedInternal);
1719 if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) {
1720 mPendingSysColorChanged = true;
1725 void
1726 nsPresContext::SysColorChangedInternal()
1728 mPendingSysColorChanged = false;
1730 if (sLookAndFeelChanged) {
1731 // Don't use the cached values for the system colors
1732 LookAndFeel::Refresh();
1733 sLookAndFeelChanged = false;
1736 // Reset default background and foreground colors for the document since
1737 // they may be using system colors
1738 GetDocumentColorPreferences();
1740 // The system color values are computed to colors in the style data,
1741 // so normal style data comparison is sufficient here.
1742 RebuildAllStyleData(nsChangeHint(0));
1745 void
1746 nsPresContext::UIResolutionChanged()
1748 if (!mPendingUIResolutionChanged) {
1749 nsCOMPtr<nsIRunnable> ev =
1750 NS_NewRunnableMethod(this, &nsPresContext::UIResolutionChangedInternal);
1751 if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) {
1752 mPendingUIResolutionChanged = true;
1757 /*static*/ bool
1758 nsPresContext::UIResolutionChangedSubdocumentCallback(nsIDocument* aDocument,
1759 void* aData)
1761 nsIPresShell* shell = aDocument->GetShell();
1762 if (shell) {
1763 nsPresContext* pc = shell->GetPresContext();
1764 if (pc) {
1765 pc->UIResolutionChangedInternal();
1768 return true;
1771 void
1772 nsPresContext::UIResolutionChangedInternal()
1774 mPendingUIResolutionChanged = false;
1776 mDeviceContext->CheckDPIChange();
1777 if (mCurAppUnitsPerDevPixel != AppUnitsPerDevPixel()) {
1778 AppUnitsPerDevPixelChanged();
1781 nsCOMPtr<nsIDOMChromeWindow> chromeWindow(do_QueryInterface(mDocument->GetWindow()));
1782 nsCOMPtr<nsIMessageBroadcaster> windowMM;
1783 if (chromeWindow) {
1784 chromeWindow->GetMessageManager(getter_AddRefs(windowMM));
1786 if (windowMM) {
1787 NotifyUIResolutionChanged(windowMM);
1790 mDocument->EnumerateSubDocuments(UIResolutionChangedSubdocumentCallback,
1791 nullptr);
1794 void
1795 nsPresContext::NotifyUIResolutionChanged(nsIMessageBroadcaster* aManager)
1797 uint32_t tabChildCount = 0;
1798 aManager->GetChildCount(&tabChildCount);
1799 for (uint32_t j = 0; j < tabChildCount; ++j) {
1800 nsCOMPtr<nsIMessageListenerManager> childMM;
1801 aManager->GetChildAt(j, getter_AddRefs(childMM));
1802 if (!childMM) {
1803 continue;
1806 nsCOMPtr<nsIMessageBroadcaster> nonLeafMM = do_QueryInterface(childMM);
1807 if (nonLeafMM) {
1808 NotifyUIResolutionChanged(nonLeafMM);
1809 continue;
1812 nsCOMPtr<nsIMessageSender> tabMM = do_QueryInterface(childMM);
1814 mozilla::dom::ipc::MessageManagerCallback* cb =
1815 static_cast<nsFrameMessageManager*>(tabMM.get())->GetCallback();
1816 if (cb) {
1817 nsFrameLoader* fl = static_cast<nsFrameLoader*>(cb);
1818 PBrowserParent* remoteBrowser = fl->GetRemoteBrowser();
1819 TabParent* remote = static_cast<TabParent*>(remoteBrowser);
1820 if (remote) {
1821 remote->UIResolutionChanged();
1827 void
1828 nsPresContext::EmulateMedium(const nsAString& aMediaType)
1830 nsIAtom* previousMedium = Medium();
1831 mIsEmulatingMedia = true;
1833 nsAutoString mediaType;
1834 nsContentUtils::ASCIIToLower(aMediaType, mediaType);
1836 mMediaEmulated = do_GetAtom(mediaType);
1837 if (mMediaEmulated != previousMedium && mShell) {
1838 MediaFeatureValuesChanged(eRebuildStyleIfNeeded, nsChangeHint(0));
1842 void nsPresContext::StopEmulatingMedium()
1844 nsIAtom* previousMedium = Medium();
1845 mIsEmulatingMedia = false;
1846 if (Medium() != previousMedium) {
1847 MediaFeatureValuesChanged(eRebuildStyleIfNeeded, nsChangeHint(0));
1851 void
1852 nsPresContext::RebuildAllStyleData(nsChangeHint aExtraHint)
1854 if (!mShell) {
1855 // We must have been torn down. Nothing to do here.
1856 return;
1859 mUsesRootEMUnits = false;
1860 mUsesViewportUnits = false;
1861 RebuildUserFontSet();
1862 RebuildCounterStyles();
1864 RestyleManager()->RebuildAllStyleData(aExtraHint);
1867 void
1868 nsPresContext::PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint)
1870 if (!mShell) {
1871 // We must have been torn down. Nothing to do here.
1872 return;
1874 RestyleManager()->PostRebuildAllStyleDataEvent(aExtraHint);
1877 void
1878 nsPresContext::MediaFeatureValuesChanged(StyleRebuildType aShouldRebuild,
1879 nsChangeHint aChangeHint)
1881 NS_ASSERTION(aShouldRebuild == eAlwaysRebuildStyle || aChangeHint == 0,
1882 "If you don't know if we need a rebuild, how can you provide a hint?");
1884 mPendingMediaFeatureValuesChanged = false;
1886 // MediumFeaturesChanged updates the applied rules, so it always gets called.
1887 bool mediaFeaturesDidChange = mShell ? mShell->StyleSet()->MediumFeaturesChanged(this)
1888 : false;
1890 if (aShouldRebuild == eAlwaysRebuildStyle ||
1891 mediaFeaturesDidChange ||
1892 (mUsesViewportUnits && mPendingViewportChange)) {
1893 RebuildAllStyleData(aChangeHint);
1896 mPendingViewportChange = false;
1898 if (mDocument->IsBeingUsedAsImage()) {
1899 MOZ_ASSERT(PR_CLIST_IS_EMPTY(&mDOMMediaQueryLists));
1900 return;
1903 MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
1905 // Media query list listeners should be notified from a queued task
1906 // (in HTML5 terms), although we also want to notify them on certain
1907 // flushes. (We're already running off an event.)
1909 // Note that we do this after the new style from media queries in
1910 // style sheets has been computed.
1912 if (!PR_CLIST_IS_EMPTY(&mDOMMediaQueryLists)) {
1913 // We build a list of all the notifications we're going to send
1914 // before we send any of them. (The spec says the notifications
1915 // should be a queued task, so any removals that happen during the
1916 // notifications shouldn't affect what gets notified.) Furthermore,
1917 // we hold strong pointers to everything we're going to make
1918 // notification calls to, since each notification involves calling
1919 // arbitrary script that might otherwise destroy these objects, or,
1920 // for that matter, |this|.
1922 // Note that we intentionally send the notifications to media query
1923 // list in the order they were created and, for each list, to the
1924 // listeners in the order added.
1925 MediaQueryList::NotifyList notifyList;
1926 for (PRCList *l = PR_LIST_HEAD(&mDOMMediaQueryLists);
1927 l != &mDOMMediaQueryLists; l = PR_NEXT_LINK(l)) {
1928 MediaQueryList *mql = static_cast<MediaQueryList*>(l);
1929 mql->MediumFeaturesChanged(notifyList);
1932 if (!notifyList.IsEmpty()) {
1933 for (uint32_t i = 0, i_end = notifyList.Length(); i != i_end; ++i) {
1934 nsAutoMicroTask mt;
1935 MediaQueryList::HandleChangeData &d = notifyList[i];
1936 ErrorResult result;
1937 d.callback->Call(*d.mql, result);
1941 // NOTE: When |notifyList| goes out of scope, our destructor could run.
1945 void
1946 nsPresContext::PostMediaFeatureValuesChangedEvent()
1948 // FIXME: We should probably replace this event with use of
1949 // nsRefreshDriver::AddStyleFlushObserver (except the pres shell would
1950 // need to track whether it's been added).
1951 if (!mPendingMediaFeatureValuesChanged) {
1952 nsCOMPtr<nsIRunnable> ev =
1953 NS_NewRunnableMethod(this, &nsPresContext::HandleMediaFeatureValuesChangedEvent);
1954 if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) {
1955 mPendingMediaFeatureValuesChanged = true;
1956 mDocument->SetNeedStyleFlush();
1961 void
1962 nsPresContext::HandleMediaFeatureValuesChangedEvent()
1964 // Null-check mShell in case the shell has been destroyed (and the
1965 // event is the only thing holding the pres context alive).
1966 if (mPendingMediaFeatureValuesChanged && mShell) {
1967 MediaFeatureValuesChanged(eRebuildStyleIfNeeded);
1971 already_AddRefed<MediaQueryList>
1972 nsPresContext::MatchMedia(const nsAString& aMediaQueryList)
1974 nsRefPtr<MediaQueryList> result = new MediaQueryList(this, aMediaQueryList);
1976 // Insert the new item at the end of the linked list.
1977 PR_INSERT_BEFORE(result, &mDOMMediaQueryLists);
1979 return result.forget();
1982 nsCompatibility
1983 nsPresContext::CompatibilityMode() const
1985 return Document()->GetCompatibilityMode();
1988 void
1989 nsPresContext::SetPaginatedScrolling(bool aPaginated)
1991 if (mType == eContext_PrintPreview || mType == eContext_PageLayout)
1992 mCanPaginatedScroll = aPaginated;
1995 void
1996 nsPresContext::SetPrintSettings(nsIPrintSettings *aPrintSettings)
1998 if (mMedium == nsGkAtoms::print)
1999 mPrintSettings = aPrintSettings;
2002 bool
2003 nsPresContext::EnsureVisible()
2005 nsCOMPtr<nsIDocShell> docShell(mContainer);
2006 if (docShell) {
2007 nsCOMPtr<nsIContentViewer> cv;
2008 docShell->GetContentViewer(getter_AddRefs(cv));
2009 // Make sure this is the content viewer we belong with
2010 if (cv) {
2011 nsRefPtr<nsPresContext> currentPresContext;
2012 cv->GetPresContext(getter_AddRefs(currentPresContext));
2013 if (currentPresContext == this) {
2014 // OK, this is us. We want to call Show() on the content viewer.
2015 nsresult result = cv->Show();
2016 if (NS_SUCCEEDED(result)) {
2017 return true;
2022 return false;
2025 #ifdef MOZ_REFLOW_PERF
2026 void
2027 nsPresContext::CountReflows(const char * aName, nsIFrame * aFrame)
2029 if (mShell) {
2030 mShell->CountReflows(aName, aFrame);
2033 #endif
2035 void
2036 nsPresContext::UpdateIsChrome()
2038 mIsChrome = mContainer &&
2039 nsIDocShellTreeItem::typeChrome == mContainer->ItemType();
2042 /* virtual */ bool
2043 nsPresContext::HasAuthorSpecifiedRules(nsIFrame *aFrame, uint32_t ruleTypeMask) const
2045 return
2046 nsRuleNode::HasAuthorSpecifiedRules(aFrame->StyleContext(),
2047 ruleTypeMask,
2048 UseDocumentColors());
2051 gfxUserFontSet*
2052 nsPresContext::GetUserFontSetInternal()
2054 // We want to initialize the user font set lazily the first time the
2055 // user asks for it, rather than building it too early and forcing
2056 // rule cascade creation. Thus we try to enforce the invariant that
2057 // we *never* build the user font set until the first call to
2058 // GetUserFontSet. However, once it's been requested, we can't wait
2059 // for somebody to call GetUserFontSet in order to rebuild it (see
2060 // comments below in RebuildUserFontSet for why).
2061 #ifdef DEBUG
2062 bool userFontSetGottenBefore = mGetUserFontSetCalled;
2063 #endif
2064 // Set mGetUserFontSetCalled up front, so that FlushUserFontSet will actually
2065 // flush.
2066 mGetUserFontSetCalled = true;
2067 if (mUserFontSetDirty) {
2068 // If this assertion fails, and there have actually been changes to
2069 // @font-face rules, then we will call StyleChangeReflow in
2070 // FlushUserFontSet. If we're in the middle of reflow,
2071 // that's a bad thing to do, and the caller was responsible for
2072 // flushing first. If we're not (e.g., in frame construction), it's
2073 // ok.
2074 NS_ASSERTION(!userFontSetGottenBefore || !mShell->IsReflowLocked(),
2075 "FlushUserFontSet should have been called first");
2076 FlushUserFontSet();
2079 return mUserFontSet;
2082 gfxUserFontSet*
2083 nsPresContext::GetUserFontSetExternal()
2085 return GetUserFontSetInternal();
2088 void
2089 nsPresContext::FlushUserFontSet()
2091 if (!mShell) {
2092 return; // we've been torn down
2095 if (!mGetUserFontSetCalled) {
2096 return; // No one cares about this font set yet, but we want to be careful
2097 // to not unset our mUserFontSetDirty bit, so when someone really
2098 // does we'll create it.
2101 if (mUserFontSetDirty) {
2102 if (gfxPlatform::GetPlatform()->DownloadableFontsEnabled()) {
2103 nsTArray<nsFontFaceRuleContainer> rules;
2104 if (!mShell->StyleSet()->AppendFontFaceRules(this, rules)) {
2105 if (mUserFontSet) {
2106 mUserFontSet->Destroy();
2107 NS_RELEASE(mUserFontSet);
2109 return;
2112 bool changed = false;
2114 if (rules.Length() == 0) {
2115 if (mUserFontSet) {
2116 mUserFontSet->Destroy();
2117 NS_RELEASE(mUserFontSet);
2118 changed = true;
2120 } else {
2121 if (!mUserFontSet) {
2122 mUserFontSet = new nsUserFontSet(this);
2123 NS_ADDREF(mUserFontSet);
2125 changed = mUserFontSet->UpdateRules(rules);
2128 // We need to enqueue a style change reflow (for later) to
2129 // reflect that we're modifying @font-face rules. (However,
2130 // without a reflow, nothing will happen to start any downloads
2131 // that are needed.)
2132 if (changed) {
2133 UserFontSetUpdated();
2137 mUserFontSetDirty = false;
2141 void
2142 nsPresContext::RebuildUserFontSet()
2144 if (!mGetUserFontSetCalled) {
2145 // We want to lazily build the user font set the first time it's
2146 // requested (so we don't force creation of rule cascades too
2147 // early), so don't do anything now.
2148 return;
2151 mUserFontSetDirty = true;
2152 mDocument->SetNeedStyleFlush();
2154 // Somebody has already asked for the user font set, so we need to
2155 // post an event to rebuild it. Setting the user font set to be dirty
2156 // and lazily rebuilding it isn't sufficient, since it is only the act
2157 // of rebuilding it that will trigger the style change reflow that
2158 // calls GetUserFontSet. (This reflow causes rebuilding of text runs,
2159 // which starts font loads, whose completion causes another style
2160 // change reflow).
2161 if (!mPostedFlushUserFontSet) {
2162 nsCOMPtr<nsIRunnable> ev =
2163 NS_NewRunnableMethod(this, &nsPresContext::HandleRebuildUserFontSet);
2164 if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) {
2165 mPostedFlushUserFontSet = true;
2170 void
2171 nsPresContext::UserFontSetUpdated()
2173 if (!mShell)
2174 return;
2176 // Changes to the set of available fonts can cause updates to layout by:
2178 // 1. Changing the font used for text, which changes anything that
2179 // depends on text measurement, including line breaking and
2180 // intrinsic widths, and any other parts of layout that depend on
2181 // font metrics. This requires a style change reflow to update.
2183 // 2. Changing the value of the 'ex' and 'ch' units in style data,
2184 // which also depend on font metrics. Updating this information
2185 // requires rebuilding the rule tree from the top, avoiding the
2186 // reuse of cached data even when no style rules have changed.
2188 PostRebuildAllStyleDataEvent(NS_STYLE_HINT_REFLOW);
2191 void
2192 nsPresContext::FlushCounterStyles()
2194 if (!mShell) {
2195 return; // we've been torn down
2197 if (mCounterStyleManager->IsInitial()) {
2198 // Still in its initial state, no need to clean.
2199 return;
2202 if (mCounterStylesDirty) {
2203 bool changed = mCounterStyleManager->NotifyRuleChanged();
2204 if (changed) {
2205 PresShell()->NotifyCounterStylesAreDirty();
2206 PostRebuildAllStyleDataEvent(NS_STYLE_HINT_REFLOW);
2208 mCounterStylesDirty = false;
2212 void
2213 nsPresContext::RebuildCounterStyles()
2215 if (mCounterStyleManager->IsInitial()) {
2216 // Still in its initial state, no need to reset.
2217 return;
2220 mCounterStylesDirty = true;
2221 mDocument->SetNeedStyleFlush();
2222 if (!mPostedFlushCounterStyles) {
2223 nsCOMPtr<nsIRunnable> ev =
2224 NS_NewRunnableMethod(this, &nsPresContext::HandleRebuildCounterStyles);
2225 if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) {
2226 mPostedFlushCounterStyles = true;
2231 void
2232 nsPresContext::EnsureSafeToHandOutCSSRules()
2234 CSSStyleSheet::EnsureUniqueInnerResult res =
2235 mShell->StyleSet()->EnsureUniqueInnerOnCSSSheets();
2236 if (res == CSSStyleSheet::eUniqueInner_AlreadyUnique) {
2237 // Nothing to do.
2238 return;
2241 MOZ_ASSERT(res == CSSStyleSheet::eUniqueInner_ClonedInner);
2242 RebuildAllStyleData(nsChangeHint(0));
2245 void
2246 nsPresContext::FireDOMPaintEvent(nsInvalidateRequestList* aList)
2248 nsPIDOMWindow* ourWindow = mDocument->GetWindow();
2249 if (!ourWindow)
2250 return;
2252 nsCOMPtr<EventTarget> dispatchTarget = do_QueryInterface(ourWindow);
2253 nsCOMPtr<EventTarget> eventTarget = dispatchTarget;
2254 if (!IsChrome() && !mSendAfterPaintToContent) {
2255 // Don't tell the window about this event, it should not know that
2256 // something happened in a subdocument. Tell only the chrome event handler.
2257 // (Events sent to the window get propagated to the chrome event handler
2258 // automatically.)
2259 dispatchTarget = do_QueryInterface(ourWindow->GetParentTarget());
2260 if (!dispatchTarget) {
2261 return;
2264 // Events sent to the window get propagated to the chrome event handler
2265 // automatically.
2266 nsCOMPtr<nsIDOMEvent> event;
2267 // This will empty our list in case dispatching the event causes more damage
2268 // (hopefully it won't, or we're likely to get an infinite loop! At least
2269 // it won't be blocking app execution though).
2270 NS_NewDOMNotifyPaintEvent(getter_AddRefs(event), eventTarget, this, nullptr,
2271 NS_AFTERPAINT, aList);
2272 if (!event) {
2273 return;
2276 // Even if we're not telling the window about the event (so eventTarget is
2277 // the chrome event handler, not the window), the window is still
2278 // logically the event target.
2279 event->SetTarget(eventTarget);
2280 event->SetTrusted(true);
2281 EventDispatcher::DispatchDOMEvent(dispatchTarget, nullptr, event, this,
2282 nullptr);
2285 static bool
2286 MayHavePaintEventListenerSubdocumentCallback(nsIDocument* aDocument, void* aData)
2288 bool *result = static_cast<bool*>(aData);
2289 nsIPresShell* shell = aDocument->GetShell();
2290 if (shell) {
2291 nsPresContext* pc = shell->GetPresContext();
2292 if (pc) {
2293 *result = pc->MayHavePaintEventListenerInSubDocument();
2295 // If we found a paint event listener, then we can stop enumerating
2296 // sub documents.
2297 return !*result;
2300 return true;
2303 static bool
2304 MayHavePaintEventListener(nsPIDOMWindow* aInnerWindow)
2306 if (!aInnerWindow)
2307 return false;
2308 if (aInnerWindow->HasPaintEventListeners())
2309 return true;
2311 EventTarget* parentTarget = aInnerWindow->GetParentTarget();
2312 if (!parentTarget)
2313 return false;
2315 EventListenerManager* manager = nullptr;
2316 if ((manager = parentTarget->GetExistingListenerManager()) &&
2317 manager->MayHavePaintEventListener()) {
2318 return true;
2321 nsCOMPtr<nsINode> node;
2322 if (parentTarget != aInnerWindow->GetChromeEventHandler()) {
2323 nsCOMPtr<nsIInProcessContentFrameMessageManager> mm =
2324 do_QueryInterface(parentTarget);
2325 if (mm) {
2326 node = mm->GetOwnerContent();
2330 if (!node) {
2331 node = do_QueryInterface(parentTarget);
2333 if (node)
2334 return MayHavePaintEventListener(node->OwnerDoc()->GetInnerWindow());
2336 nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(parentTarget);
2337 if (window)
2338 return MayHavePaintEventListener(window);
2340 nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(parentTarget);
2341 EventTarget* tabChildGlobal;
2342 return root &&
2343 (tabChildGlobal = root->GetParentTarget()) &&
2344 (manager = tabChildGlobal->GetExistingListenerManager()) &&
2345 manager->MayHavePaintEventListener();
2348 bool
2349 nsPresContext::MayHavePaintEventListener()
2351 return ::MayHavePaintEventListener(mDocument->GetInnerWindow());
2354 bool
2355 nsPresContext::MayHavePaintEventListenerInSubDocument()
2357 if (MayHavePaintEventListener()) {
2358 return true;
2361 bool result = false;
2362 mDocument->EnumerateSubDocuments(MayHavePaintEventListenerSubdocumentCallback, &result);
2363 return result;
2366 void
2367 nsPresContext::NotifyInvalidation(uint32_t aFlags)
2369 nsIFrame* rootFrame = PresShell()->FrameManager()->GetRootFrame();
2370 NotifyInvalidation(rootFrame->GetVisualOverflowRect(), aFlags);
2371 mAllInvalidated = true;
2374 void
2375 nsPresContext::NotifyInvalidation(const nsIntRect& aRect, uint32_t aFlags)
2377 nsRect rect(DevPixelsToAppUnits(aRect.x),
2378 DevPixelsToAppUnits(aRect.y),
2379 DevPixelsToAppUnits(aRect.width),
2380 DevPixelsToAppUnits(aRect.height));
2381 NotifyInvalidation(rect, aFlags);
2384 void
2385 nsPresContext::NotifyInvalidation(const nsRect& aRect, uint32_t aFlags)
2387 MOZ_ASSERT(GetContainerWeak(), "Invalidation in detached pres context");
2389 // If there is no paint event listener, then we don't need to fire
2390 // the asynchronous event. We don't even need to record invalidation.
2391 // MayHavePaintEventListener is pretty cheap and we could make it
2392 // even cheaper by providing a more efficient
2393 // nsPIDOMWindow::GetListenerManager.
2395 if (mAllInvalidated) {
2396 return;
2399 nsPresContext* pc;
2400 for (pc = this; pc; pc = pc->GetParentPresContext()) {
2401 if (pc->mFireAfterPaintEvents)
2402 break;
2403 pc->mFireAfterPaintEvents = true;
2405 if (!pc) {
2406 nsRootPresContext* rpc = GetRootPresContext();
2407 if (rpc) {
2408 rpc->EnsureEventualDidPaintEvent();
2412 nsInvalidateRequestList::Request* request =
2413 mInvalidateRequestsSinceLastPaint.mRequests.AppendElement();
2414 if (!request)
2415 return;
2417 request->mRect = aRect;
2418 request->mFlags = aFlags;
2421 /* static */ void
2422 nsPresContext::NotifySubDocInvalidation(ContainerLayer* aContainer,
2423 const nsIntRegion& aRegion)
2425 ContainerLayerPresContext *data =
2426 static_cast<ContainerLayerPresContext*>(
2427 aContainer->GetUserData(&gNotifySubDocInvalidationData));
2428 if (!data) {
2429 return;
2432 nsIntPoint topLeft = aContainer->GetVisibleRegion().GetBounds().TopLeft();
2434 nsIntRegionRectIterator iter(aRegion);
2435 while (const nsIntRect* r = iter.Next()) {
2436 nsIntRect rect = *r;
2437 //PresContext coordinate space is relative to the start of our visible
2438 // region. Is this really true? This feels like the wrong way to get the right
2439 // answer.
2440 rect.MoveBy(-topLeft);
2441 data->mPresContext->NotifyInvalidation(rect, 0);
2445 void
2446 nsPresContext::SetNotifySubDocInvalidationData(ContainerLayer* aContainer)
2448 ContainerLayerPresContext* pres = new ContainerLayerPresContext;
2449 pres->mPresContext = this;
2450 aContainer->SetUserData(&gNotifySubDocInvalidationData, pres);
2453 /* static */ void
2454 nsPresContext::ClearNotifySubDocInvalidationData(ContainerLayer* aContainer)
2456 aContainer->SetUserData(&gNotifySubDocInvalidationData, nullptr);
2459 struct NotifyDidPaintSubdocumentCallbackClosure {
2460 uint32_t mFlags;
2461 bool mNeedsAnotherDidPaintNotification;
2463 static bool
2464 NotifyDidPaintSubdocumentCallback(nsIDocument* aDocument, void* aData)
2466 NotifyDidPaintSubdocumentCallbackClosure* closure =
2467 static_cast<NotifyDidPaintSubdocumentCallbackClosure*>(aData);
2468 nsIPresShell* shell = aDocument->GetShell();
2469 if (shell) {
2470 nsPresContext* pc = shell->GetPresContext();
2471 if (pc) {
2472 pc->NotifyDidPaintForSubtree(closure->mFlags);
2473 if (pc->IsDOMPaintEventPending()) {
2474 closure->mNeedsAnotherDidPaintNotification = true;
2478 return true;
2481 class DelayedFireDOMPaintEvent : public nsRunnable {
2482 public:
2483 DelayedFireDOMPaintEvent(nsPresContext* aPresContext,
2484 nsInvalidateRequestList* aList)
2485 : mPresContext(aPresContext)
2487 MOZ_ASSERT(mPresContext->GetContainerWeak(),
2488 "DOMPaintEvent requested for a detached pres context");
2489 mList.TakeFrom(aList);
2491 NS_IMETHOD Run() MOZ_OVERRIDE
2493 // The pres context might have been detached during the delay -
2494 // that's fine, just don't fire the event.
2495 if (mPresContext->GetContainerWeak()) {
2496 mPresContext->FireDOMPaintEvent(&mList);
2498 return NS_OK;
2501 nsRefPtr<nsPresContext> mPresContext;
2502 nsInvalidateRequestList mList;
2505 void
2506 nsPresContext::NotifyDidPaintForSubtree(uint32_t aFlags)
2508 if (IsRoot()) {
2509 static_cast<nsRootPresContext*>(this)->CancelDidPaintTimer();
2511 if (!mFireAfterPaintEvents) {
2512 return;
2515 // Non-root prescontexts fire MozAfterPaint to all their descendants
2516 // unconditionally, even if no invalidations have been collected. This is
2517 // because we don't want to eat the cost of collecting invalidations for
2518 // every subdocument (which would require putting every subdocument in its
2519 // own layer).
2521 if (aFlags & nsIPresShell::PAINT_LAYERS) {
2522 mUndeliveredInvalidateRequestsBeforeLastPaint.TakeFrom(
2523 &mInvalidateRequestsSinceLastPaint);
2524 mAllInvalidated = false;
2526 if (aFlags & nsIPresShell::PAINT_COMPOSITE) {
2527 nsCOMPtr<nsIRunnable> ev =
2528 new DelayedFireDOMPaintEvent(this, &mUndeliveredInvalidateRequestsBeforeLastPaint);
2529 nsContentUtils::AddScriptRunner(ev);
2532 NotifyDidPaintSubdocumentCallbackClosure closure = { aFlags, false };
2533 mDocument->EnumerateSubDocuments(NotifyDidPaintSubdocumentCallback, &closure);
2535 if (!closure.mNeedsAnotherDidPaintNotification &&
2536 mInvalidateRequestsSinceLastPaint.IsEmpty() &&
2537 mUndeliveredInvalidateRequestsBeforeLastPaint.IsEmpty()) {
2538 // Nothing more to do for the moment.
2539 mFireAfterPaintEvents = false;
2540 } else {
2541 if (IsRoot()) {
2542 static_cast<nsRootPresContext*>(this)->EnsureEventualDidPaintEvent();
2547 bool
2548 nsPresContext::HasCachedStyleData()
2550 return mShell && mShell->StyleSet()->HasCachedStyleData();
2553 static bool sGotInterruptEnv = false;
2554 enum InterruptMode {
2555 ModeRandom,
2556 ModeCounter,
2557 ModeEvent
2559 // Controlled by the GECKO_REFLOW_INTERRUPT_MODE env var; allowed values are
2560 // "random" (except on Windows) or "counter". If neither is used, the mode is
2561 // ModeEvent.
2562 static InterruptMode sInterruptMode = ModeEvent;
2563 #ifndef XP_WIN
2564 // Used for the "random" mode. Controlled by the GECKO_REFLOW_INTERRUPT_SEED
2565 // env var.
2566 static uint32_t sInterruptSeed = 1;
2567 #endif
2568 // Used for the "counter" mode. This is the number of unskipped interrupt
2569 // checks that have to happen before we interrupt. Controlled by the
2570 // GECKO_REFLOW_INTERRUPT_FREQUENCY env var.
2571 static uint32_t sInterruptMaxCounter = 10;
2572 // Used for the "counter" mode. This counts up to sInterruptMaxCounter and is
2573 // then reset to 0.
2574 static uint32_t sInterruptCounter;
2575 // Number of interrupt checks to skip before really trying to interrupt.
2576 // Controlled by the GECKO_REFLOW_INTERRUPT_CHECKS_TO_SKIP env var.
2577 static uint32_t sInterruptChecksToSkip = 200;
2578 // Number of milliseconds that a reflow should be allowed to run for before we
2579 // actually allow interruption. Controlled by the
2580 // GECKO_REFLOW_MIN_NOINTERRUPT_DURATION env var. Can't be initialized here,
2581 // because TimeDuration/TimeStamp is not safe to use in static constructors..
2582 static TimeDuration sInterruptTimeout;
2584 static void GetInterruptEnv()
2586 char *ev = PR_GetEnv("GECKO_REFLOW_INTERRUPT_MODE");
2587 if (ev) {
2588 #ifndef XP_WIN
2589 if (PL_strcasecmp(ev, "random") == 0) {
2590 ev = PR_GetEnv("GECKO_REFLOW_INTERRUPT_SEED");
2591 if (ev) {
2592 sInterruptSeed = atoi(ev);
2594 srandom(sInterruptSeed);
2595 sInterruptMode = ModeRandom;
2596 } else
2597 #endif
2598 if (PL_strcasecmp(ev, "counter") == 0) {
2599 ev = PR_GetEnv("GECKO_REFLOW_INTERRUPT_FREQUENCY");
2600 if (ev) {
2601 sInterruptMaxCounter = atoi(ev);
2603 sInterruptCounter = 0;
2604 sInterruptMode = ModeCounter;
2607 ev = PR_GetEnv("GECKO_REFLOW_INTERRUPT_CHECKS_TO_SKIP");
2608 if (ev) {
2609 sInterruptChecksToSkip = atoi(ev);
2612 ev = PR_GetEnv("GECKO_REFLOW_MIN_NOINTERRUPT_DURATION");
2613 int duration_ms = ev ? atoi(ev) : 100;
2614 sInterruptTimeout = TimeDuration::FromMilliseconds(duration_ms);
2617 bool
2618 nsPresContext::HavePendingInputEvent()
2620 switch (sInterruptMode) {
2621 #ifndef XP_WIN
2622 case ModeRandom:
2623 return (random() & 1);
2624 #endif
2625 case ModeCounter:
2626 if (sInterruptCounter < sInterruptMaxCounter) {
2627 ++sInterruptCounter;
2628 return false;
2630 sInterruptCounter = 0;
2631 return true;
2632 default:
2633 case ModeEvent: {
2634 nsIFrame* f = PresShell()->GetRootFrame();
2635 if (f) {
2636 nsIWidget* w = f->GetNearestWidget();
2637 if (w) {
2638 return w->HasPendingInputEvent();
2641 return false;
2646 void
2647 nsPresContext::ReflowStarted(bool aInterruptible)
2649 #ifdef NOISY_INTERRUPTIBLE_REFLOW
2650 if (!aInterruptible) {
2651 printf("STARTING NONINTERRUPTIBLE REFLOW\n");
2653 #endif
2654 // We don't support interrupting in paginated contexts, since page
2655 // sequences only handle initial reflow
2656 mInterruptsEnabled = aInterruptible && !IsPaginated() &&
2657 nsLayoutUtils::InterruptibleReflowEnabled();
2659 // Don't set mHasPendingInterrupt based on HavePendingInputEvent() here. If
2660 // we ever change that, then we need to update the code in
2661 // PresShell::DoReflow to only add the just-reflown root to dirty roots if
2662 // it's actually dirty. Otherwise we can end up adding a root that has no
2663 // interruptible descendants, just because we detected an interrupt at reflow
2664 // start.
2665 mHasPendingInterrupt = false;
2667 mInterruptChecksToSkip = sInterruptChecksToSkip;
2669 if (mInterruptsEnabled) {
2670 mReflowStartTime = TimeStamp::Now();
2674 bool
2675 nsPresContext::CheckForInterrupt(nsIFrame* aFrame)
2677 if (mHasPendingInterrupt) {
2678 mShell->FrameNeedsToContinueReflow(aFrame);
2679 return true;
2682 if (!sGotInterruptEnv) {
2683 sGotInterruptEnv = true;
2684 GetInterruptEnv();
2687 if (!mInterruptsEnabled) {
2688 return false;
2691 if (mInterruptChecksToSkip > 0) {
2692 --mInterruptChecksToSkip;
2693 return false;
2695 mInterruptChecksToSkip = sInterruptChecksToSkip;
2697 // Don't interrupt if it's been less than sInterruptTimeout since we started
2698 // the reflow.
2699 mHasPendingInterrupt =
2700 TimeStamp::Now() - mReflowStartTime > sInterruptTimeout &&
2701 HavePendingInputEvent() &&
2702 !IsChrome();
2703 if (mHasPendingInterrupt) {
2704 #ifdef NOISY_INTERRUPTIBLE_REFLOW
2705 printf("*** DETECTED pending interrupt (time=%lld)\n", PR_Now());
2706 #endif /* NOISY_INTERRUPTIBLE_REFLOW */
2707 mShell->FrameNeedsToContinueReflow(aFrame);
2709 return mHasPendingInterrupt;
2712 nsIFrame*
2713 nsPresContext::GetPrimaryFrameFor(nsIContent* aContent)
2715 NS_PRECONDITION(aContent, "Don't do that");
2716 if (GetPresShell() &&
2717 GetPresShell()->GetDocument() == aContent->GetComposedDoc()) {
2718 return aContent->GetPrimaryFrame();
2720 return nullptr;
2724 size_t
2725 nsPresContext::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
2727 return mPropertyTable.SizeOfExcludingThis(aMallocSizeOf);
2728 mLangGroupFontPrefs.SizeOfExcludingThis(aMallocSizeOf);
2730 // Measurement of other members may be added later if DMD finds it is
2731 // worthwhile.
2734 bool
2735 nsPresContext::IsRootContentDocument()
2737 // We are a root content document if: we are not a resource doc, we are
2738 // not chrome, and we either have no parent or our parent is chrome.
2739 if (mDocument->IsResourceDoc()) {
2740 return false;
2742 if (IsChrome()) {
2743 return false;
2745 // We may not have a root frame, so use views.
2746 nsView* view = PresShell()->GetViewManager()->GetRootView();
2747 if (!view) {
2748 return false;
2750 view = view->GetParent(); // anonymous inner view
2751 if (!view) {
2752 return true;
2754 view = view->GetParent(); // subdocumentframe's view
2755 if (!view) {
2756 return true;
2759 nsIFrame* f = view->GetFrame();
2760 return (f && f->PresContext()->IsChrome());
2763 bool
2764 nsPresContext::IsCrossProcessRootContentDocument()
2766 if (!IsRootContentDocument()) {
2767 return false;
2770 if (XRE_GetProcessType() == GeckoProcessType_Default) {
2771 return true;
2774 TabChild* tabChild = TabChild::GetFrom(mShell);
2775 return (tabChild && tabChild->IsRootContentDocument());
2778 bool nsPresContext::GetPaintFlashing() const
2780 if (!mPaintFlashingInitialized) {
2781 bool pref = Preferences::GetBool("nglayout.debug.paint_flashing");
2782 if (!pref && IsChrome()) {
2783 pref = Preferences::GetBool("nglayout.debug.paint_flashing_chrome");
2785 mPaintFlashing = pref;
2786 mPaintFlashingInitialized = true;
2788 return mPaintFlashing;
2791 int32_t
2792 nsPresContext::AppUnitsPerDevPixel() const
2794 return mDeviceContext->AppUnitsPerDevPixel();
2797 nscoord
2798 nsPresContext::GfxUnitsToAppUnits(gfxFloat aGfxUnits) const
2800 return mDeviceContext->GfxUnitsToAppUnits(aGfxUnits);
2803 gfxFloat
2804 nsPresContext::AppUnitsToGfxUnits(nscoord aAppUnits) const
2806 return mDeviceContext->AppUnitsToGfxUnits(aAppUnits);
2809 bool
2810 nsPresContext::IsDeviceSizePageSize()
2812 bool isDeviceSizePageSize = false;
2813 nsCOMPtr<nsIDocShell> docShell(mContainer);
2814 if (docShell) {
2815 isDeviceSizePageSize = docShell->GetDeviceSizeIsPageSize();
2817 return isDeviceSizePageSize;
2820 nsRootPresContext::nsRootPresContext(nsIDocument* aDocument,
2821 nsPresContextType aType)
2822 : nsPresContext(aDocument, aType),
2823 mDOMGeneration(0)
2827 nsRootPresContext::~nsRootPresContext()
2829 NS_ASSERTION(mRegisteredPlugins.Count() == 0,
2830 "All plugins should have been unregistered");
2831 CancelDidPaintTimer();
2832 CancelApplyPluginGeometryTimer();
2835 /* virtual */ void
2836 nsRootPresContext::Detach()
2838 CancelDidPaintTimer();
2839 // XXXmats maybe also CancelApplyPluginGeometryTimer(); ?
2840 nsPresContext::Detach();
2843 void
2844 nsRootPresContext::RegisterPluginForGeometryUpdates(nsIContent* aPlugin)
2846 mRegisteredPlugins.PutEntry(aPlugin);
2849 void
2850 nsRootPresContext::UnregisterPluginForGeometryUpdates(nsIContent* aPlugin)
2852 mRegisteredPlugins.RemoveEntry(aPlugin);
2855 static PLDHashOperator
2856 SetPluginHidden(nsRefPtrHashKey<nsIContent>* aEntry, void* userArg)
2858 nsIFrame* root = static_cast<nsIFrame*>(userArg);
2859 nsObjectFrame* f = static_cast<nsObjectFrame*>(aEntry->GetKey()->GetPrimaryFrame());
2860 if (!f) {
2861 NS_WARNING("Null frame in SetPluginHidden");
2862 return PL_DHASH_NEXT;
2864 if (!nsLayoutUtils::IsAncestorFrameCrossDoc(root, f)) {
2865 // f is not managed by this frame so we should ignore it.
2866 return PL_DHASH_NEXT;
2868 f->SetEmptyWidgetConfiguration();
2869 return PL_DHASH_NEXT;
2872 void
2873 nsRootPresContext::ComputePluginGeometryUpdates(nsIFrame* aFrame,
2874 nsDisplayListBuilder* aBuilder,
2875 nsDisplayList* aList)
2877 if (mRegisteredPlugins.Count() == 0) {
2878 return;
2881 // Initially make the next state for each plugin descendant of aFrame be
2882 // "hidden". Plugins that are visible will have their next state set to
2883 // unhidden by nsDisplayPlugin::ComputeVisibility.
2884 mRegisteredPlugins.EnumerateEntries(SetPluginHidden, aFrame);
2886 nsIFrame* rootFrame = FrameManager()->GetRootFrame();
2888 if (rootFrame && aBuilder->ContainsPluginItem()) {
2889 aBuilder->SetForPluginGeometry();
2890 aBuilder->SetAccurateVisibleRegions();
2891 // Merging and flattening has already been done and we should not do it
2892 // again. nsDisplayScroll(Info)Layer doesn't support trying to flatten
2893 // again.
2894 aBuilder->SetAllowMergingAndFlattening(false);
2895 nsRegion region = rootFrame->GetVisualOverflowRectRelativeToSelf();
2896 // nsDisplayPlugin::ComputeVisibility will automatically set a non-hidden
2897 // widget configuration for the plugin, if it's visible.
2898 aList->ComputeVisibilityForRoot(aBuilder, &region);
2901 #ifdef XP_MACOSX
2902 // We control painting of Mac plugins, so just apply geometry updates now.
2903 // This is not happening during a paint event.
2904 ApplyPluginGeometryUpdates();
2905 #else
2906 InitApplyPluginGeometryTimer();
2907 #endif
2910 static void
2911 ApplyPluginGeometryUpdatesCallback(nsITimer *aTimer, void *aClosure)
2913 static_cast<nsRootPresContext*>(aClosure)->ApplyPluginGeometryUpdates();
2916 void
2917 nsRootPresContext::InitApplyPluginGeometryTimer()
2919 if (mApplyPluginGeometryTimer) {
2920 return;
2923 // We'll apply the plugin geometry updates during the next compositing paint in this
2924 // presContext (either from nsPresShell::WillPaintWindow or from
2925 // nsPresShell::DidPaintWindow, depending on the platform). But paints might
2926 // get optimized away if the old plugin geometry covers the invalid region,
2927 // so set a backup timer to do this too. We want to make sure this
2928 // won't fire before our normal paint notifications, if those would
2929 // update the geometry, so set it for double the refresh driver interval.
2930 mApplyPluginGeometryTimer = do_CreateInstance("@mozilla.org/timer;1");
2931 if (mApplyPluginGeometryTimer) {
2932 mApplyPluginGeometryTimer->
2933 InitWithFuncCallback(ApplyPluginGeometryUpdatesCallback, this,
2934 nsRefreshDriver::DefaultInterval() * 2,
2935 nsITimer::TYPE_ONE_SHOT);
2939 void
2940 nsRootPresContext::CancelApplyPluginGeometryTimer()
2942 if (mApplyPluginGeometryTimer) {
2943 mApplyPluginGeometryTimer->Cancel();
2944 mApplyPluginGeometryTimer = nullptr;
2948 static bool
2949 HasOverlap(const nsIntPoint& aOffset1, const nsTArray<nsIntRect>& aClipRects1,
2950 const nsIntPoint& aOffset2, const nsTArray<nsIntRect>& aClipRects2)
2952 nsIntPoint offsetDelta = aOffset1 - aOffset2;
2953 for (uint32_t i = 0; i < aClipRects1.Length(); ++i) {
2954 for (uint32_t j = 0; j < aClipRects2.Length(); ++j) {
2955 if ((aClipRects1[i] + offsetDelta).Intersects(aClipRects2[j]))
2956 return true;
2959 return false;
2963 * Given a list of plugin windows to move to new locations, sort the list
2964 * so that for each window move, the window moves to a location that
2965 * does not intersect other windows. This minimizes flicker and repainting.
2966 * It's not always possible to do this perfectly, since in general
2967 * we might have cycles. But we do our best.
2968 * We need to take into account that windows are clipped to particular
2969 * regions and the clip regions change as the windows are moved.
2971 static void
2972 SortConfigurations(nsTArray<nsIWidget::Configuration>* aConfigurations)
2974 if (aConfigurations->Length() > 10) {
2975 // Give up, we don't want to get bogged down here
2976 return;
2979 nsTArray<nsIWidget::Configuration> pluginsToMove;
2980 pluginsToMove.SwapElements(*aConfigurations);
2982 // Our algorithm is quite naive. At each step we try to identify
2983 // a window that can be moved to its new location that won't overlap
2984 // any other windows at the new location. If there is no such
2985 // window, we just move the last window in the list anyway.
2986 while (!pluginsToMove.IsEmpty()) {
2987 // Find a window whose destination does not overlap any other window
2988 uint32_t i;
2989 for (i = 0; i + 1 < pluginsToMove.Length(); ++i) {
2990 nsIWidget::Configuration* config = &pluginsToMove[i];
2991 bool foundOverlap = false;
2992 for (uint32_t j = 0; j < pluginsToMove.Length(); ++j) {
2993 if (i == j)
2994 continue;
2995 nsIntRect bounds;
2996 pluginsToMove[j].mChild->GetBounds(bounds);
2997 nsAutoTArray<nsIntRect,1> clipRects;
2998 pluginsToMove[j].mChild->GetWindowClipRegion(&clipRects);
2999 if (HasOverlap(bounds.TopLeft(), clipRects,
3000 config->mBounds.TopLeft(),
3001 config->mClipRegion)) {
3002 foundOverlap = true;
3003 break;
3006 if (!foundOverlap)
3007 break;
3009 // Note that we always move the last plugin in pluginsToMove, if we
3010 // can't find any other plugin to move
3011 aConfigurations->AppendElement(pluginsToMove[i]);
3012 pluginsToMove.RemoveElementAt(i);
3016 static PLDHashOperator
3017 PluginDidSetGeometryEnumerator(nsRefPtrHashKey<nsIContent>* aEntry, void* userArg)
3019 nsObjectFrame* f = static_cast<nsObjectFrame*>(aEntry->GetKey()->GetPrimaryFrame());
3020 if (!f) {
3021 NS_WARNING("Null frame in PluginDidSetGeometryEnumerator");
3022 return PL_DHASH_NEXT;
3024 f->DidSetWidgetGeometry();
3025 return PL_DHASH_NEXT;
3028 struct PluginGetGeometryUpdateClosure {
3029 nsTArray<nsIWidget::Configuration> mConfigurations;
3031 static PLDHashOperator
3032 PluginGetGeometryUpdate(nsRefPtrHashKey<nsIContent>* aEntry, void* userArg)
3034 PluginGetGeometryUpdateClosure* closure =
3035 static_cast<PluginGetGeometryUpdateClosure*>(userArg);
3036 nsObjectFrame* f = static_cast<nsObjectFrame*>(aEntry->GetKey()->GetPrimaryFrame());
3037 if (!f) {
3038 NS_WARNING("Null frame in GetPluginGeometryUpdate");
3039 return PL_DHASH_NEXT;
3041 f->GetWidgetConfiguration(&closure->mConfigurations);
3042 return PL_DHASH_NEXT;
3045 void
3046 nsRootPresContext::ApplyPluginGeometryUpdates()
3048 CancelApplyPluginGeometryTimer();
3050 PluginGetGeometryUpdateClosure closure;
3051 mRegisteredPlugins.EnumerateEntries(PluginGetGeometryUpdate, &closure);
3052 // Walk mRegisteredPlugins and ask each plugin for its configuration
3053 if (!closure.mConfigurations.IsEmpty()) {
3054 nsIWidget* widget = closure.mConfigurations[0].mChild->GetParent();
3055 NS_ASSERTION(widget, "Plugins must have a parent window");
3056 SortConfigurations(&closure.mConfigurations);
3057 widget->ConfigureChildren(closure.mConfigurations);
3059 mRegisteredPlugins.EnumerateEntries(PluginDidSetGeometryEnumerator, nullptr);
3062 static void
3063 NotifyDidPaintForSubtreeCallback(nsITimer *aTimer, void *aClosure)
3065 nsPresContext* presContext = (nsPresContext*)aClosure;
3066 nsAutoScriptBlocker blockScripts;
3067 // This is a fallback if we don't get paint events for some reason
3068 // so we'll just pretend both layer painting and compositing happened.
3069 presContext->NotifyDidPaintForSubtree(
3070 nsIPresShell::PAINT_LAYERS | nsIPresShell::PAINT_COMPOSITE);
3073 void
3074 nsRootPresContext::EnsureEventualDidPaintEvent()
3076 if (mNotifyDidPaintTimer)
3077 return;
3078 mNotifyDidPaintTimer = do_CreateInstance("@mozilla.org/timer;1");
3079 if (!mNotifyDidPaintTimer)
3080 return;
3081 mNotifyDidPaintTimer->InitWithFuncCallback(NotifyDidPaintForSubtreeCallback,
3082 (void*)this, 100, nsITimer::TYPE_ONE_SHOT);
3085 void
3086 nsRootPresContext::AddWillPaintObserver(nsIRunnable* aRunnable)
3088 if (!mWillPaintFallbackEvent.IsPending()) {
3089 mWillPaintFallbackEvent = new RunWillPaintObservers(this);
3090 NS_DispatchToMainThread(mWillPaintFallbackEvent.get());
3092 mWillPaintObservers.AppendElement(aRunnable);
3096 * Run all runnables that need to get called before the next paint.
3098 void
3099 nsRootPresContext::FlushWillPaintObservers()
3101 mWillPaintFallbackEvent = nullptr;
3102 nsTArray<nsCOMPtr<nsIRunnable> > observers;
3103 observers.SwapElements(mWillPaintObservers);
3104 for (uint32_t i = 0; i < observers.Length(); ++i) {
3105 observers[i]->Run();
3109 size_t
3110 nsRootPresContext::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
3112 return nsPresContext::SizeOfExcludingThis(aMallocSizeOf);
3114 // Measurement of the following members may be added later if DMD finds it is
3115 // worthwhile:
3116 // - mNotifyDidPaintTimer
3117 // - mRegisteredPlugins
3118 // - mWillPaintObservers
3119 // - mWillPaintFallbackEvent