layout/base/nsPresContext.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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 "nsCSSRuleProcessor.h"
    37 #include "nsRuleNode.h"
    38 #include "gfxPlatform.h"
    39 #include "nsCSSRules.h"
    40 #include "nsFontFaceLoader.h"
    41 #include "mozilla/EventListenerManager.h"
    42 #include "prenv.h"
    43 #include "nsObjectFrame.h"
    44 #include "nsTransitionManager.h"
    45 #include "nsAnimationManager.h"
    46 #include "mozilla/MemoryReporting.h"
    47 #include "mozilla/dom/Element.h"
    48 #include "nsIMessageManager.h"
    49 #include "mozilla/dom/MediaQueryList.h"
    50 #include "nsSMILAnimationController.h"
    51 #include "mozilla/css/ImageLoader.h"
    52 #include "mozilla/dom/TabChild.h"
    53 #include "nsRefreshDriver.h"
    54 #include "Layers.h"
    55 #include "nsIDOMEvent.h"
    56 #include "gfxPrefs.h"
    57 #include "nsString.h"
    58 #include "nsUnicharUtils.h"
    60 #include "nsContentUtils.h"
    61 #include "nsCxPusher.h"
    62 #include "nsPIWindowRoot.h"
    63 #include "mozilla/Preferences.h"
    65 // Needed for Start/Stop of Image Animation
    66 #include "imgIContainer.h"
    67 #include "nsIImageLoadingContent.h"
    69 #include "nsCSSParser.h"
    70 #include "nsBidiUtils.h"
    71 #include "nsServiceManagerUtils.h"
    73 #include "URL.h"
    75 using namespace mozilla;
    76 using namespace mozilla::dom;
    77 using namespace mozilla::layers;
    79 uint8_t gNotifySubDocInvalidationData;
    81 /**
    82  * Layer UserData for ContainerLayers that want to be notified
    83  * of local invalidations of them and their descendant layers.
    84  * Pass a callback to ComputeDifferences to have these called.
    85  */
    86 class ContainerLayerPresContext : public LayerUserData {
    87 public:
    88   nsPresContext* mPresContext;
    89 };
    91 namespace {
    93 class CharSetChangingRunnable : public nsRunnable
    94 {
    95 public:
    96   CharSetChangingRunnable(nsPresContext* aPresContext,
    97                           const nsCString& aCharSet)
    98     : mPresContext(aPresContext),
    99       mCharSet(aCharSet)
   100   {
   101   }
   103   NS_IMETHOD Run()
   104   {
   105     mPresContext->DoChangeCharSet(mCharSet);
   106     return NS_OK;
   107   }
   109 private:
   110   nsRefPtr<nsPresContext> mPresContext;
   111   nsCString mCharSet;
   112 };
   114 } // anonymous namespace
   116 nscolor
   117 nsPresContext::MakeColorPref(const nsString& aColor)
   118 {
   119   nsCSSParser parser;
   120   nsCSSValue value;
   121   if (!parser.ParseColorString(aColor, nullptr, 0, value)) {
   122     // Any better choices?
   123     return NS_RGB(0, 0, 0);
   124   }
   126   nscolor color;
   127   return nsRuleNode::ComputeColor(value, this, nullptr, color)
   128     ? color
   129     : NS_RGB(0, 0, 0);
   130 }
   132 bool
   133 nsPresContext::IsDOMPaintEventPending()
   134 {
   135   if (mFireAfterPaintEvents) {
   136     return true;
   137   }
   138   if (GetDisplayRootPresContext()->GetRootPresContext()->mRefreshDriver->ViewManagerFlushIsPending()) {
   139     // Since we're promising that there will be a MozAfterPaint event
   140     // fired, we record an empty invalidation in case display list
   141     // invalidation doesn't invalidate anything further.
   142     NotifyInvalidation(nsRect(0, 0, 0, 0), 0);
   143     NS_ASSERTION(mFireAfterPaintEvents, "Why aren't we planning to fire the event?");
   144     return true;
   145   }
   146   return false;
   147 }
   149 void
   150 nsPresContext::PrefChangedCallback(const char* aPrefName, void* instance_data)
   151 {
   152   nsRefPtr<nsPresContext>  presContext =
   153     static_cast<nsPresContext*>(instance_data);
   155   NS_ASSERTION(nullptr != presContext, "bad instance data");
   156   if (nullptr != presContext) {
   157     presContext->PreferenceChanged(aPrefName);
   158   }
   159 }
   161 void
   162 nsPresContext::PrefChangedUpdateTimerCallback(nsITimer *aTimer, void *aClosure)
   163 {
   164   nsPresContext*  presContext = (nsPresContext*)aClosure;
   165   NS_ASSERTION(presContext != nullptr, "bad instance data");
   166   if (presContext)
   167     presContext->UpdateAfterPreferencesChanged();
   168 }
   170 static bool
   171 IsVisualCharset(const nsCString& aCharset)
   172 {
   173   if (aCharset.LowerCaseEqualsLiteral("ibm862")             // Hebrew
   174       || aCharset.LowerCaseEqualsLiteral("iso-8859-8") ) {  // Hebrew
   175     return true; // visual text type
   176   }
   177   else {
   178     return false; // logical text type
   179   }
   180 }
   182   // NOTE! nsPresContext::operator new() zeroes out all members, so don't
   183   // bother initializing members to 0.
   185 nsPresContext::nsPresContext(nsIDocument* aDocument, nsPresContextType aType)
   186   : mType(aType), mDocument(aDocument), mBaseMinFontSize(0),
   187     mTextZoom(1.0), mFullZoom(1.0), mLastFontInflationScreenWidth(-1.0),
   188     mPageSize(-1, -1), mPPScale(1.0f),
   189     mViewportStyleOverflow(NS_STYLE_OVERFLOW_AUTO, NS_STYLE_OVERFLOW_AUTO),
   190     mImageAnimationModePref(imgIContainer::kNormalAnimMode),
   191     mAllInvalidated(false),
   192     mPaintFlashing(false), mPaintFlashingInitialized(false)
   193 {
   194   // NOTE! nsPresContext::operator new() zeroes out all members, so don't
   195   // bother initializing members to 0.
   197   mDoScaledTwips = true;
   199   SetBackgroundImageDraw(true);		// always draw the background
   200   SetBackgroundColorDraw(true);
   202   mBackgroundColor = NS_RGB(0xFF, 0xFF, 0xFF);
   204   mUseDocumentColors = true;
   205   mUseDocumentFonts = true;
   207   // the minimum font-size is unconstrained by default
   209   mLinkColor = NS_RGB(0x00, 0x00, 0xEE);
   210   mActiveLinkColor = NS_RGB(0xEE, 0x00, 0x00);
   211   mVisitedLinkColor = NS_RGB(0x55, 0x1A, 0x8B);
   212   mUnderlineLinks = true;
   213   mSendAfterPaintToContent = false;
   215   mFocusTextColor = mDefaultColor;
   216   mFocusBackgroundColor = mBackgroundColor;
   217   mFocusRingWidth = 1;
   219   mBodyTextColor = mDefaultColor;
   221   if (aType == eContext_Galley) {
   222     mMedium = nsGkAtoms::screen;
   223   } else {
   224     mMedium = nsGkAtoms::print;
   225     mPaginated = true;
   226   }
   227   mMediaEmulated = mMedium;
   229   if (!IsDynamic()) {
   230     mImageAnimationMode = imgIContainer::kDontAnimMode;
   231     mNeverAnimate = true;
   232   } else {
   233     mImageAnimationMode = imgIContainer::kNormalAnimMode;
   234     mNeverAnimate = false;
   235   }
   236   NS_ASSERTION(mDocument, "Null document");
   237   mUserFontSet = nullptr;
   238   mUserFontSetDirty = true;
   240   // if text perf logging enabled, init stats struct
   241   PRLogModuleInfo *log = gfxPlatform::GetLog(eGfxLog_textperf);
   242   if (log && log->level >= PR_LOG_WARNING) {
   243     mTextPerf = new gfxTextPerfMetrics();
   244   }
   246   PR_INIT_CLIST(&mDOMMediaQueryLists);
   247 }
   249 nsPresContext::~nsPresContext()
   250 {
   251   NS_PRECONDITION(!mShell, "Presshell forgot to clear our mShell pointer");
   252   SetShell(nullptr);
   254   NS_ABORT_IF_FALSE(PR_CLIST_IS_EMPTY(&mDOMMediaQueryLists),
   255                     "must not have media query lists left");
   257   // Disconnect the refresh driver *after* the transition manager, which
   258   // needs it.
   259   if (mRefreshDriver && mRefreshDriver->PresContext() == this) {
   260     mRefreshDriver->Disconnect();
   261   }
   263   if (mEventManager) {
   264     // unclear if these are needed, but can't hurt
   265     mEventManager->NotifyDestroyPresContext(this);
   266     mEventManager->SetPresContext(nullptr);
   267   }
   269   if (mPrefChangedTimer)
   270   {
   271     mPrefChangedTimer->Cancel();
   272     mPrefChangedTimer = nullptr;
   273   }
   275   // Unregister preference callbacks
   276   Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
   277                                   "font.",
   278                                   this);
   279   Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
   280                                   "browser.display.",
   281                                   this);
   282   Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
   283                                   "browser.underline_anchors",
   284                                   this);
   285   Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
   286                                   "browser.anchor_color",
   287                                   this);
   288   Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
   289                                   "browser.active_color",
   290                                   this);
   291   Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
   292                                   "browser.visited_color",
   293                                   this);
   294   Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
   295                                   "image.animation_mode",
   296                                   this);
   297   Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
   298                                   "bidi.",
   299                                   this);
   300   Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
   301                                   "dom.send_after_paint_to_content",
   302                                   this);
   303   Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
   304                                   "gfx.font_rendering.",
   305                                   this);
   306   Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
   307                                   "layout.css.dpi",
   308                                   this);
   309   Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
   310                                   "layout.css.devPixelsPerPx",
   311                                   this);
   312   Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
   313                                   "nglayout.debug.paint_flashing",
   314                                   this);
   315   Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
   316                                   "nglayout.debug.paint_flashing_chrome",
   317                                   this);
   318 }
   320 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsPresContext)
   321    NS_INTERFACE_MAP_ENTRY(nsISupports)
   322    NS_INTERFACE_MAP_ENTRY(nsIObserver)
   323 NS_INTERFACE_MAP_END
   325 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsPresContext)
   326 NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(nsPresContext, LastRelease())
   328 void
   329 nsPresContext::LastRelease()
   330 {
   331   if (IsRoot()) {
   332     static_cast<nsRootPresContext*>(this)->CancelDidPaintTimer();
   333   }
   334 }
   336 NS_IMPL_CYCLE_COLLECTION_CLASS(nsPresContext)
   338 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsPresContext)
   339   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument);
   340   // NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mDeviceContext); // not xpcom
   341   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEventManager);
   342   // NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mLanguage); // an atom
   344   // We own only the items in mDOMMediaQueryLists that have listeners;
   345   // this reference is managed by their AddListener and RemoveListener
   346   // methods.
   347   for (PRCList *l = PR_LIST_HEAD(&tmp->mDOMMediaQueryLists);
   348        l != &tmp->mDOMMediaQueryLists; l = PR_NEXT_LINK(l)) {
   349     MediaQueryList *mql = static_cast<MediaQueryList*>(l);
   350     if (mql->HasListeners()) {
   351       NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mDOMMediaQueryLists item");
   352       cb.NoteXPCOMChild(mql);
   353     }
   354   }
   356   // NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTheme); // a service
   357   // NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLangService); // a service
   358   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrintSettings);
   359   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrefChangedTimer);
   360 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
   362 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsPresContext)
   363   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument);
   364   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDeviceContext); // worth bothering?
   365   if (tmp->mEventManager) {
   366     // unclear if these are needed, but can't hurt
   367     tmp->mEventManager->NotifyDestroyPresContext(tmp);
   368     tmp->mEventManager->SetPresContext(nullptr);
   369     tmp->mEventManager = nullptr;
   370   }
   372   // We own only the items in mDOMMediaQueryLists that have listeners;
   373   // this reference is managed by their AddListener and RemoveListener
   374   // methods.
   375   for (PRCList *l = PR_LIST_HEAD(&tmp->mDOMMediaQueryLists);
   376        l != &tmp->mDOMMediaQueryLists; ) {
   377     PRCList *next = PR_NEXT_LINK(l);
   378     MediaQueryList *mql = static_cast<MediaQueryList*>(l);
   379     mql->RemoveAllListeners();
   380     l = next;
   381   }
   383   // NS_RELEASE(tmp->mLanguage); // an atom
   385   // NS_IMPL_CYCLE_COLLECTION_UNLINK(mTheme); // a service
   386   // NS_IMPL_CYCLE_COLLECTION_UNLINK(mLangService); // a service
   387   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPrintSettings);
   388   if (tmp->mPrefChangedTimer)
   389   {
   390     tmp->mPrefChangedTimer->Cancel();
   391     tmp->mPrefChangedTimer = nullptr;
   392   }
   393 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
   396 #define MAKE_FONT_PREF_KEY(_pref, _s0, _s1) \
   397  _pref.Assign(_s0); \
   398  _pref.Append(_s1);
   400 static const char* const kGenericFont[] = {
   401   ".variable.",
   402   ".fixed.",
   403   ".serif.",
   404   ".sans-serif.",
   405   ".monospace.",
   406   ".cursive.",
   407   ".fantasy."
   408 };
   410 // whether no native theme service exists;
   411 // if this gets set to true, we'll stop asking for it.
   412 static bool sNoTheme = false;
   414 // Set to true when LookAndFeelChanged needs to be called.  This is used
   415 // because the look and feel is a service, so there's no need to notify it from
   416 // more than one prescontext.
   417 static bool sLookAndFeelChanged;
   419 // Set to true when ThemeChanged needs to be called on mTheme.  This is used
   420 // because mTheme is a service, so there's no need to notify it from more than
   421 // one prescontext.
   422 static bool sThemeChanged;
   424 const nsPresContext::LangGroupFontPrefs*
   425 nsPresContext::GetFontPrefsForLang(nsIAtom *aLanguage) const
   426 {
   427   // Get language group for aLanguage:
   429   nsresult rv = NS_OK;
   430   nsIAtom *langGroupAtom = nullptr;
   431   if (!aLanguage) {
   432     aLanguage = mLanguage;
   433   }
   434   if (aLanguage && mLangService) {
   435     langGroupAtom = mLangService->GetLanguageGroup(aLanguage, &rv);
   436   }
   437   if (NS_FAILED(rv) || !langGroupAtom) {
   438     langGroupAtom = nsGkAtoms::x_western; // Assume x-western is safe...
   439   }
   441   // Look for cached prefs for this lang group.
   442   // Most documents will only use one (or very few) language groups. Rather
   443   // than have the overhead of a hash lookup, we simply look along what will
   444   // typically be a very short (usually of length 1) linked list. There are 31
   445   // language groups, so in the worst case scenario we'll need to traverse 31
   446   // link items.
   448   LangGroupFontPrefs *prefs =
   449     const_cast<LangGroupFontPrefs*>(&mLangGroupFontPrefs);
   450   if (prefs->mLangGroup) { // if initialized
   451     DebugOnly<uint32_t> count = 0;
   452     for (;;) {
   453       NS_ASSERTION(++count < 35, "Lang group count exceeded!!!");
   454       if (prefs->mLangGroup == langGroupAtom) {
   455         return prefs;
   456       }
   457       if (!prefs->mNext) {
   458         break;
   459       }
   460       prefs = prefs->mNext;
   461     }
   463     // nothing cached, so go on and fetch the prefs for this lang group:
   464     prefs = prefs->mNext = new LangGroupFontPrefs;
   465   }
   467   prefs->mLangGroup = langGroupAtom;
   469   /* Fetch the font prefs to be used -- see bug 61883 for details.
   470      Not all prefs are needed upfront. Some are fallback prefs intended
   471      for the GFX font sub-system...
   473   1) unit : assumed to be the same for all language groups -------------
   474   font.size.unit = px | pt    XXX could be folded in the size... bug 90440
   476   2) attributes for generic fonts --------------------------------------
   477   font.default.[langGroup] = serif | sans-serif - fallback generic font
   478   font.name.[generic].[langGroup] = current user' selected font on the pref dialog
   479   font.name-list.[generic].[langGroup] = fontname1, fontname2, ... [factory pre-built list]
   480   font.size.[generic].[langGroup] = integer - settable by the user
   481   font.size-adjust.[generic].[langGroup] = "float" - settable by the user
   482   font.minimum-size.[langGroup] = integer - settable by the user
   483   */
   485   nsAutoCString langGroup;
   486   langGroupAtom->ToUTF8String(langGroup);
   488   prefs->mDefaultVariableFont.size = CSSPixelsToAppUnits(16);
   489   prefs->mDefaultFixedFont.size = CSSPixelsToAppUnits(13);
   491   nsAutoCString pref;
   493   // get the current applicable font-size unit
   494   enum {eUnit_unknown = -1, eUnit_px, eUnit_pt};
   495   int32_t unit = eUnit_px;
   497   nsAdoptingCString cvalue =
   498     Preferences::GetCString("font.size.unit");
   500   if (!cvalue.IsEmpty()) {
   501     if (cvalue.Equals("px")) {
   502       unit = eUnit_px;
   503     }
   504     else if (cvalue.Equals("pt")) {
   505       unit = eUnit_pt;
   506     }
   507     else {
   508       // XXX should really send this warning to the user (Error Console?).
   509       // And just default to unit = eUnit_px?
   510       NS_WARNING("unexpected font-size unit -- expected: 'px' or 'pt'");
   511       unit = eUnit_unknown;
   512     }
   513   }
   515   // get font.minimum-size.[langGroup]
   517   MAKE_FONT_PREF_KEY(pref, "font.minimum-size.", langGroup);
   519   int32_t size = Preferences::GetInt(pref.get());
   520   if (unit == eUnit_px) {
   521     prefs->mMinimumFontSize = CSSPixelsToAppUnits(size);
   522   }
   523   else if (unit == eUnit_pt) {
   524     prefs->mMinimumFontSize = CSSPointsToAppUnits(size);
   525   }
   527   nsFont* fontTypes[] = {
   528     &prefs->mDefaultVariableFont,
   529     &prefs->mDefaultFixedFont,
   530     &prefs->mDefaultSerifFont,
   531     &prefs->mDefaultSansSerifFont,
   532     &prefs->mDefaultMonospaceFont,
   533     &prefs->mDefaultCursiveFont,
   534     &prefs->mDefaultFantasyFont
   535   };
   536   static_assert(MOZ_ARRAY_LENGTH(fontTypes) == eDefaultFont_COUNT,
   537                 "FontTypes array count is not correct");
   539   // Get attributes specific to each generic font. We do not get the user's
   540   // generic-font-name-to-specific-family-name preferences because its the
   541   // generic name that should be fed into the cascade. It is up to the GFX
   542   // code to look up the font prefs to convert generic names to specific
   543   // family names as necessary.
   544   nsAutoCString generic_dot_langGroup;
   545   for (uint32_t eType = 0; eType < ArrayLength(fontTypes); ++eType) {
   546     generic_dot_langGroup.Assign(kGenericFont[eType]);
   547     generic_dot_langGroup.Append(langGroup);
   549     nsFont* font = fontTypes[eType];
   551     // set the default variable font (the other fonts are seen as 'generic' fonts
   552     // in GFX and will be queried there when hunting for alternative fonts)
   553     if (eType == eDefaultFont_Variable) {
   554       MAKE_FONT_PREF_KEY(pref, "font.name.variable.", langGroup);
   556       nsAdoptingString value = Preferences::GetString(pref.get());
   557       if (!value.IsEmpty()) {
   558         prefs->mDefaultVariableFont.name.Assign(value);
   559       }
   560       else {
   561         MAKE_FONT_PREF_KEY(pref, "font.default.", langGroup);
   562         value = Preferences::GetString(pref.get());
   563         if (!value.IsEmpty()) {
   564           prefs->mDefaultVariableFont.name.Assign(value);
   565         }
   566       }
   567     }
   568     else {
   569       if (eType == eDefaultFont_Monospace) {
   570         // This takes care of the confusion whereby people often expect "monospace"
   571         // to have the same default font-size as "-moz-fixed" (this tentative
   572         // size may be overwritten with the specific value for "monospace" when
   573         // "font.size.monospace.[langGroup]" is read -- see below)
   574         prefs->mDefaultMonospaceFont.size = prefs->mDefaultFixedFont.size;
   575       }
   576       else if (eType != eDefaultFont_Fixed) {
   577         // all the other generic fonts are initialized with the size of the
   578         // variable font, but their specific size can supersede later -- see below
   579         font->size = prefs->mDefaultVariableFont.size;
   580       }
   581     }
   583     // Bug 84398: for spec purists, a different font-size only applies to the
   584     // .variable. and .fixed. fonts and the other fonts should get |font-size-adjust|.
   585     // The problem is that only GfxWin has the support for |font-size-adjust|. So for
   586     // parity, we enable the ability to set a different font-size on all platforms.
   588     // get font.size.[generic].[langGroup]
   589     // size=0 means 'Auto', i.e., generic fonts retain the size of the variable font
   590     MAKE_FONT_PREF_KEY(pref, "font.size", generic_dot_langGroup);
   591     size = Preferences::GetInt(pref.get());
   592     if (size > 0) {
   593       if (unit == eUnit_px) {
   594         font->size = CSSPixelsToAppUnits(size);
   595       }
   596       else if (unit == eUnit_pt) {
   597         font->size = CSSPointsToAppUnits(size);
   598       }
   599     }
   601     // get font.size-adjust.[generic].[langGroup]
   602     // XXX only applicable on GFX ports that handle |font-size-adjust|
   603     MAKE_FONT_PREF_KEY(pref, "font.size-adjust", generic_dot_langGroup);
   604     cvalue = Preferences::GetCString(pref.get());
   605     if (!cvalue.IsEmpty()) {
   606       font->sizeAdjust = (float)atof(cvalue.get());
   607     }
   609 #ifdef DEBUG_rbs
   610     printf("%s Family-list:%s size:%d sizeAdjust:%.2f\n",
   611            generic_dot_langGroup.get(),
   612            NS_ConvertUTF16toUTF8(font->name).get(), font->size,
   613            font->sizeAdjust);
   614 #endif
   615   }
   617   return prefs;
   618 }
   620 void
   621 nsPresContext::GetDocumentColorPreferences()
   622 {
   623   // Make sure the preferences are initialized.  In the normal run,
   624   // they would already be, because gfxPlatform would have been created,
   625   // but in some reference tests, that is not the case.
   626   gfxPrefs::GetSingleton();
   628   int32_t useAccessibilityTheme = 0;
   629   bool usePrefColors = true;
   630   bool isChromeDocShell = false;
   632   nsIDocument* doc = mDocument->GetDisplayDocument();
   633   if (doc && doc->GetDocShell()) {
   634     isChromeDocShell = nsIDocShellTreeItem::typeChrome ==
   635                        doc->GetDocShell()->ItemType();
   636   } else {
   637     nsCOMPtr<nsIDocShellTreeItem> docShell(mContainer);
   638     if (docShell) {
   639       isChromeDocShell = nsIDocShellTreeItem::typeChrome == docShell->ItemType();
   640     }
   641   }
   643   mIsChromeOriginImage = mDocument->IsBeingUsedAsImage() &&
   644                          IsChromeURI(mDocument->GetDocumentURI());
   646   if (isChromeDocShell || mIsChromeOriginImage) {
   647     usePrefColors = false;
   648   } else {
   649     useAccessibilityTheme =
   650       LookAndFeel::GetInt(LookAndFeel::eIntID_UseAccessibilityTheme, 0);
   651     usePrefColors = !useAccessibilityTheme;
   652   }
   653   if (usePrefColors) {
   654     usePrefColors =
   655       !Preferences::GetBool("browser.display.use_system_colors", false);
   656   }
   658   if (usePrefColors) {
   659     nsAdoptingString colorStr =
   660       Preferences::GetString("browser.display.foreground_color");
   662     if (!colorStr.IsEmpty()) {
   663       mDefaultColor = MakeColorPref(colorStr);
   664     }
   666     colorStr = Preferences::GetString("browser.display.background_color");
   668     if (!colorStr.IsEmpty()) {
   669       mBackgroundColor = MakeColorPref(colorStr);
   670     }
   671   }
   672   else {
   673     mDefaultColor =
   674       LookAndFeel::GetColor(LookAndFeel::eColorID_WindowForeground,
   675                             NS_RGB(0x00, 0x00, 0x00));
   676     mBackgroundColor =
   677       LookAndFeel::GetColor(LookAndFeel::eColorID_WindowBackground,
   678                             NS_RGB(0xFF, 0xFF, 0xFF));
   679   }
   681   // Wherever we got the default background color from, ensure it is
   682   // opaque.
   683   mBackgroundColor = NS_ComposeColors(NS_RGB(0xFF, 0xFF, 0xFF),
   684                                       mBackgroundColor);
   686   mUseDocumentColors = !useAccessibilityTheme &&
   687     Preferences::GetBool("browser.display.use_document_colors",
   688                          mUseDocumentColors);
   689 }
   691 void
   692 nsPresContext::GetUserPreferences()
   693 {
   694   if (!GetPresShell()) {
   695     // No presshell means nothing to do here.  We'll do this when we
   696     // get a presshell.
   697     return;
   698   }
   700   mAutoQualityMinFontSizePixelsPref =
   701     Preferences::GetInt("browser.display.auto_quality_min_font_size");
   703   // * document colors
   704   GetDocumentColorPreferences();
   706   mSendAfterPaintToContent =
   707     Preferences::GetBool("dom.send_after_paint_to_content",
   708                          mSendAfterPaintToContent);
   710   // * link colors
   711   mUnderlineLinks =
   712     Preferences::GetBool("browser.underline_anchors", mUnderlineLinks);
   714   nsAdoptingString colorStr = Preferences::GetString("browser.anchor_color");
   716   if (!colorStr.IsEmpty()) {
   717     mLinkColor = MakeColorPref(colorStr);
   718   }
   720   colorStr = Preferences::GetString("browser.active_color");
   722   if (!colorStr.IsEmpty()) {
   723     mActiveLinkColor = MakeColorPref(colorStr);
   724   }
   726   colorStr = Preferences::GetString("browser.visited_color");
   728   if (!colorStr.IsEmpty()) {
   729     mVisitedLinkColor = MakeColorPref(colorStr);
   730   }
   732   mUseFocusColors =
   733     Preferences::GetBool("browser.display.use_focus_colors", mUseFocusColors);
   735   mFocusTextColor = mDefaultColor;
   736   mFocusBackgroundColor = mBackgroundColor;
   738   colorStr = Preferences::GetString("browser.display.focus_text_color");
   740   if (!colorStr.IsEmpty()) {
   741     mFocusTextColor = MakeColorPref(colorStr);
   742   }
   744   colorStr = Preferences::GetString("browser.display.focus_background_color");
   746   if (!colorStr.IsEmpty()) {
   747     mFocusBackgroundColor = MakeColorPref(colorStr);
   748   }
   750   mFocusRingWidth =
   751     Preferences::GetInt("browser.display.focus_ring_width", mFocusRingWidth);
   753   mFocusRingOnAnything =
   754     Preferences::GetBool("browser.display.focus_ring_on_anything",
   755                          mFocusRingOnAnything);
   757   mFocusRingStyle =
   758     Preferences::GetInt("browser.display.focus_ring_style", mFocusRingStyle);
   760   mBodyTextColor = mDefaultColor;
   762   // * use fonts?
   763   mUseDocumentFonts =
   764     Preferences::GetInt("browser.display.use_document_fonts") != 0;
   766   mMaxFonts =
   767     Preferences::GetInt("browser.display.max_font_count", -1);
   769   mMaxFontAttempts =
   770     Preferences::GetInt("browser.display.max_font_attempts", -1);
   772   mPrefScrollbarSide = Preferences::GetInt("layout.scrollbar.side");
   774   ResetCachedFontPrefs();
   776   // * image animation
   777   const nsAdoptingCString& animatePref =
   778     Preferences::GetCString("image.animation_mode");
   779   if (animatePref.Equals("normal"))
   780     mImageAnimationModePref = imgIContainer::kNormalAnimMode;
   781   else if (animatePref.Equals("none"))
   782     mImageAnimationModePref = imgIContainer::kDontAnimMode;
   783   else if (animatePref.Equals("once"))
   784     mImageAnimationModePref = imgIContainer::kLoopOnceAnimMode;
   785   else // dynamic change to invalid value should act like it does initially
   786     mImageAnimationModePref = imgIContainer::kNormalAnimMode;
   788   uint32_t bidiOptions = GetBidi();
   790   int32_t prefInt =
   791     Preferences::GetInt(IBMBIDI_TEXTDIRECTION_STR,
   792                         GET_BIDI_OPTION_DIRECTION(bidiOptions));
   793   SET_BIDI_OPTION_DIRECTION(bidiOptions, prefInt);
   794   mPrefBidiDirection = prefInt;
   796   prefInt =
   797     Preferences::GetInt(IBMBIDI_TEXTTYPE_STR,
   798                         GET_BIDI_OPTION_TEXTTYPE(bidiOptions));
   799   SET_BIDI_OPTION_TEXTTYPE(bidiOptions, prefInt);
   801   prefInt =
   802     Preferences::GetInt(IBMBIDI_NUMERAL_STR,
   803                         GET_BIDI_OPTION_NUMERAL(bidiOptions));
   804   SET_BIDI_OPTION_NUMERAL(bidiOptions, prefInt);
   806   prefInt =
   807     Preferences::GetInt(IBMBIDI_SUPPORTMODE_STR,
   808                         GET_BIDI_OPTION_SUPPORT(bidiOptions));
   809   SET_BIDI_OPTION_SUPPORT(bidiOptions, prefInt);
   811   // We don't need to force reflow: either we are initializing a new
   812   // prescontext or we are being called from UpdateAfterPreferencesChanged()
   813   // which triggers a reflow anyway.
   814   SetBidi(bidiOptions, false);
   815 }
   817 void
   818 nsPresContext::InvalidateThebesLayers()
   819 {
   820   if (!mShell)
   821     return;
   822   nsIFrame* rootFrame = mShell->FrameManager()->GetRootFrame();
   823   if (rootFrame) {
   824     // FrameLayerBuilder caches invalidation-related values that depend on the
   825     // appunits-per-dev-pixel ratio, so ensure that all ThebesLayer drawing
   826     // is completely flushed.
   827     rootFrame->InvalidateFrameSubtree();
   828   }
   829 }
   831 void
   832 nsPresContext::AppUnitsPerDevPixelChanged()
   833 {
   834   InvalidateThebesLayers();
   836   if (mDeviceContext) {
   837     mDeviceContext->FlushFontCache();
   838   }
   840   if (HasCachedStyleData()) {
   841     // All cached style data must be recomputed.
   842     MediaFeatureValuesChanged(eAlwaysRebuildStyle, NS_STYLE_HINT_REFLOW);
   843   }
   845   mCurAppUnitsPerDevPixel = AppUnitsPerDevPixel();
   846 }
   848 void
   849 nsPresContext::PreferenceChanged(const char* aPrefName)
   850 {
   851   nsDependentCString prefName(aPrefName);
   852   if (prefName.EqualsLiteral("layout.css.dpi") ||
   853       prefName.EqualsLiteral("layout.css.devPixelsPerPx")) {
   854     int32_t oldAppUnitsPerDevPixel = AppUnitsPerDevPixel();
   855     if (mDeviceContext->CheckDPIChange() && mShell) {
   856       nsCOMPtr<nsIPresShell> shell = mShell;
   857       // Re-fetch the view manager's window dimensions in case there's a deferred
   858       // resize which hasn't affected our mVisibleArea yet
   859       nscoord oldWidthAppUnits, oldHeightAppUnits;
   860       nsRefPtr<nsViewManager> vm = shell->GetViewManager();
   861       if (!vm) {
   862         return;
   863       }
   864       vm->GetWindowDimensions(&oldWidthAppUnits, &oldHeightAppUnits);
   865       float oldWidthDevPixels = oldWidthAppUnits/oldAppUnitsPerDevPixel;
   866       float oldHeightDevPixels = oldHeightAppUnits/oldAppUnitsPerDevPixel;
   868       nscoord width = NSToCoordRound(oldWidthDevPixels*AppUnitsPerDevPixel());
   869       nscoord height = NSToCoordRound(oldHeightDevPixels*AppUnitsPerDevPixel());
   870       vm->SetWindowDimensions(width, height);
   872       AppUnitsPerDevPixelChanged();
   873     }
   874     return;
   875   }
   876   if (StringBeginsWith(prefName, NS_LITERAL_CSTRING("font."))) {
   877     // Changes to font family preferences don't change anything in the
   878     // computed style data, so the style system won't generate a reflow
   879     // hint for us.  We need to do that manually.
   881     // FIXME We could probably also handle changes to
   882     // browser.display.auto_quality_min_font_size here, but that
   883     // probably also requires clearing the text run cache, so don't
   884     // bother (yet, anyway).
   885     mPrefChangePendingNeedsReflow = true;
   886   }
   887   if (StringBeginsWith(prefName, NS_LITERAL_CSTRING("bidi."))) {
   888     // Changes to bidi prefs need to trigger a reflow (see bug 443629)
   889     mPrefChangePendingNeedsReflow = true;
   891     // Changes to bidi.numeral also needs to empty the text run cache.
   892     // This is handled in gfxTextRunWordCache.cpp.
   893   }
   894   if (StringBeginsWith(prefName, NS_LITERAL_CSTRING("gfx.font_rendering."))) {
   895     // Changes to font_rendering prefs need to trigger a reflow
   896     mPrefChangePendingNeedsReflow = true;
   897   }
   898   // we use a zero-delay timer to coalesce multiple pref updates
   899   if (!mPrefChangedTimer)
   900   {
   901     mPrefChangedTimer = do_CreateInstance("@mozilla.org/timer;1");
   902     if (!mPrefChangedTimer)
   903       return;
   904     mPrefChangedTimer->InitWithFuncCallback(nsPresContext::PrefChangedUpdateTimerCallback, (void*)this, 0, nsITimer::TYPE_ONE_SHOT);
   905   }
   906   if (prefName.EqualsLiteral("nglayout.debug.paint_flashing") ||
   907       prefName.EqualsLiteral("nglayout.debug.paint_flashing_chrome")) {
   908     mPaintFlashingInitialized = false;
   909     return;
   910   }
   911 }
   913 void
   914 nsPresContext::UpdateAfterPreferencesChanged()
   915 {
   916   mPrefChangedTimer = nullptr;
   918   nsCOMPtr<nsIDocShellTreeItem> docShell(mContainer);
   919   if (docShell && nsIDocShellTreeItem::typeChrome == docShell->ItemType()) {
   920     return;
   921   }
   923   // Initialize our state from the user preferences
   924   GetUserPreferences();
   926   // update the presShell: tell it to set the preference style rules up
   927   if (mShell) {
   928     mShell->SetPreferenceStyleRules(true);
   929   }
   931   InvalidateThebesLayers();
   932   mDeviceContext->FlushFontCache();
   934   nsChangeHint hint = nsChangeHint(0);
   936   if (mPrefChangePendingNeedsReflow) {
   937     NS_UpdateHint(hint, NS_STYLE_HINT_REFLOW);
   938   }
   940   RebuildAllStyleData(hint);
   941 }
   943 nsresult
   944 nsPresContext::Init(nsDeviceContext* aDeviceContext)
   945 {
   946   NS_ASSERTION(!mInitialized, "attempt to reinit pres context");
   947   NS_ENSURE_ARG(aDeviceContext);
   949   mDeviceContext = aDeviceContext;
   951   if (mDeviceContext->SetPixelScale(mFullZoom))
   952     mDeviceContext->FlushFontCache();
   953   mCurAppUnitsPerDevPixel = AppUnitsPerDevPixel();
   955   mEventManager = new mozilla::EventStateManager();
   957   mTransitionManager = new nsTransitionManager(this);
   959   mAnimationManager = new nsAnimationManager(this);
   961   // FIXME: Why is mozilla:: needed?
   962   mRestyleManager = new mozilla::RestyleManager(this);
   964   if (mDocument->GetDisplayDocument()) {
   965     NS_ASSERTION(mDocument->GetDisplayDocument()->GetShell() &&
   966                  mDocument->GetDisplayDocument()->GetShell()->GetPresContext(),
   967                  "Why are we being initialized?");
   968     mRefreshDriver = mDocument->GetDisplayDocument()->GetShell()->
   969       GetPresContext()->RefreshDriver();
   970   } else {
   971     nsIDocument* parent = mDocument->GetParentDocument();
   972     // Unfortunately, sometimes |parent| here has no presshell because
   973     // printing screws up things.  Assert that in other cases it does,
   974     // but whenever the shell is null just fall back on using our own
   975     // refresh driver.
   976     NS_ASSERTION(!parent || mDocument->IsStaticDocument() || parent->GetShell(),
   977                  "How did we end up with a presshell if our parent doesn't "
   978                  "have one?");
   979     if (parent && parent->GetShell()) {
   980       NS_ASSERTION(parent->GetShell()->GetPresContext(),
   981                    "How did we get a presshell?");
   983       // We don't have our container set yet at this point
   984       nsCOMPtr<nsIDocShellTreeItem> ourItem = mDocument->GetDocShell();
   985       if (ourItem) {
   986         nsCOMPtr<nsIDocShellTreeItem> parentItem;
   987         ourItem->GetSameTypeParent(getter_AddRefs(parentItem));
   988         if (parentItem) {
   989           Element* containingElement =
   990             parent->FindContentForSubDocument(mDocument);
   991           if (!containingElement->IsXUL() ||
   992               !containingElement->
   993                 HasAttr(kNameSpaceID_None,
   994                         nsGkAtoms::forceOwnRefreshDriver)) {
   995             mRefreshDriver = parent->GetShell()->GetPresContext()->RefreshDriver();
   996           }
   997         }
   998       }
   999     }
  1001     if (!mRefreshDriver) {
  1002       mRefreshDriver = new nsRefreshDriver(this);
  1006   // Initialise refresh tick counters for OMTA
  1007   mLastStyleUpdateForAllAnimations =
  1008     mLastUpdateThrottledAnimationStyle =
  1009     mLastUpdateThrottledTransitionStyle = mRefreshDriver->MostRecentRefresh();
  1011   mLangService = do_GetService(NS_LANGUAGEATOMSERVICE_CONTRACTID);
  1013   // Register callbacks so we're notified when the preferences change
  1014   Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
  1015                                 "font.",
  1016                                 this);
  1017   Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
  1018                                 "browser.display.",
  1019                                 this);
  1020   Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
  1021                                 "browser.underline_anchors",
  1022                                 this);
  1023   Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
  1024                                 "browser.anchor_color",
  1025                                 this);
  1026   Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
  1027                                 "browser.active_color",
  1028                                 this);
  1029   Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
  1030                                 "browser.visited_color",
  1031                                 this);
  1032   Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
  1033                                 "image.animation_mode",
  1034                                 this);
  1035   Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
  1036                                 "bidi.",
  1037                                 this);
  1038   Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
  1039                                 "dom.send_after_paint_to_content",
  1040                                 this);
  1041   Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
  1042                                 "gfx.font_rendering.",
  1043                                 this);
  1044   Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
  1045                                 "layout.css.dpi",
  1046                                 this);
  1047   Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
  1048                                 "layout.css.devPixelsPerPx",
  1049                                 this);
  1050   Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
  1051                                 "nglayout.debug.paint_flashing",
  1052                                 this);
  1053   Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
  1054                                 "nglayout.debug.paint_flashing_chrome",
  1055                                 this);
  1057   nsresult rv = mEventManager->Init();
  1058   NS_ENSURE_SUCCESS(rv, rv);
  1060   mEventManager->SetPresContext(this);
  1062 #ifdef DEBUG
  1063   mInitialized = true;
  1064 #endif
  1066   mBorderWidthTable[NS_STYLE_BORDER_WIDTH_THIN] = CSSPixelsToAppUnits(1);
  1067   mBorderWidthTable[NS_STYLE_BORDER_WIDTH_MEDIUM] = CSSPixelsToAppUnits(3);
  1068   mBorderWidthTable[NS_STYLE_BORDER_WIDTH_THICK] = CSSPixelsToAppUnits(5);
  1070   return NS_OK;
  1073 // Note: We don't hold a reference on the shell; it has a reference to
  1074 // us
  1075 void
  1076 nsPresContext::SetShell(nsIPresShell* aShell)
  1078   if (mUserFontSet) {
  1079     // Clear out user font set if we have one
  1080     mUserFontSet->Destroy();
  1081     NS_RELEASE(mUserFontSet);
  1084   if (mShell) {
  1085     // Remove ourselves as the charset observer from the shell's doc, because
  1086     // this shell may be going away for good.
  1087     nsIDocument *doc = mShell->GetDocument();
  1088     if (doc) {
  1089       doc->RemoveCharSetObserver(this);
  1093   mShell = aShell;
  1095   if (mShell) {
  1096     nsIDocument *doc = mShell->GetDocument();
  1097     NS_ASSERTION(doc, "expect document here");
  1098     if (doc) {
  1099       // Have to update PresContext's mDocument before calling any other methods.
  1100       mDocument = doc;
  1102     // Initialize our state from the user preferences, now that we
  1103     // have a presshell, and hence a document.
  1104     GetUserPreferences();
  1106     if (doc) {
  1107       nsIURI *docURI = doc->GetDocumentURI();
  1109       if (IsDynamic() && docURI) {
  1110         bool isChrome = false;
  1111         bool isRes = false;
  1112         docURI->SchemeIs("chrome", &isChrome);
  1113         docURI->SchemeIs("resource", &isRes);
  1115         if (!isChrome && !isRes)
  1116           mImageAnimationMode = mImageAnimationModePref;
  1117         else
  1118           mImageAnimationMode = imgIContainer::kNormalAnimMode;
  1121       if (mLangService) {
  1122         doc->AddCharSetObserver(this);
  1123         UpdateCharSet(doc->GetDocumentCharacterSet());
  1126   } else {
  1127     if (mTransitionManager) {
  1128       mTransitionManager->Disconnect();
  1129       mTransitionManager = nullptr;
  1131     if (mAnimationManager) {
  1132       mAnimationManager->Disconnect();
  1133       mAnimationManager = nullptr;
  1135     if (mRestyleManager) {
  1136       mRestyleManager->Disconnect();
  1137       mRestyleManager = nullptr;
  1140     if (IsRoot()) {
  1141       // Have to cancel our plugin geometry timer, because the
  1142       // callback for that depends on a non-null presshell.
  1143       static_cast<nsRootPresContext*>(this)->CancelApplyPluginGeometryTimer();
  1148 void
  1149 nsPresContext::DoChangeCharSet(const nsCString& aCharSet)
  1151   UpdateCharSet(aCharSet);
  1152   mDeviceContext->FlushFontCache();
  1153   RebuildAllStyleData(NS_STYLE_HINT_REFLOW);
  1156 void
  1157 nsPresContext::UpdateCharSet(const nsCString& aCharSet)
  1159   if (mLangService) {
  1160     mLanguage = mLangService->LookupCharSet(aCharSet.get());
  1161     // this will be a language group (or script) code rather than a true language code
  1163     // bug 39570: moved from nsLanguageAtomService::LookupCharSet()
  1164     if (mLanguage == nsGkAtoms::Unicode) {
  1165       mLanguage = mLangService->GetLocaleLanguage();
  1167     ResetCachedFontPrefs();
  1170   switch (GET_BIDI_OPTION_TEXTTYPE(GetBidi())) {
  1172     case IBMBIDI_TEXTTYPE_LOGICAL:
  1173       SetVisualMode(false);
  1174       break;
  1176     case IBMBIDI_TEXTTYPE_VISUAL:
  1177       SetVisualMode(true);
  1178       break;
  1180     case IBMBIDI_TEXTTYPE_CHARSET:
  1181     default:
  1182       SetVisualMode(IsVisualCharset(aCharSet));
  1186 NS_IMETHODIMP
  1187 nsPresContext::Observe(nsISupports* aSubject,
  1188                         const char* aTopic,
  1189                         const char16_t* aData)
  1191   if (!nsCRT::strcmp(aTopic, "charset")) {
  1192     nsRefPtr<CharSetChangingRunnable> runnable =
  1193       new CharSetChangingRunnable(this, NS_LossyConvertUTF16toASCII(aData));
  1194     return NS_DispatchToCurrentThread(runnable);
  1197   NS_WARNING("unrecognized topic in nsPresContext::Observe");
  1198   return NS_ERROR_FAILURE;
  1201 nsPresContext*
  1202 nsPresContext::GetParentPresContext()
  1204   nsIPresShell* shell = GetPresShell();
  1205   if (shell) {
  1206     nsViewManager* viewManager = shell->GetViewManager();
  1207     if (viewManager) {
  1208       nsView* view = viewManager->GetRootView();
  1209       if (view) {
  1210         view = view->GetParent(); // anonymous inner view
  1211         if (view) {
  1212           view = view->GetParent(); // subdocumentframe's view
  1213           if (view) {
  1214             nsIFrame* f = view->GetFrame();
  1215             if (f) {
  1216               return f->PresContext();
  1223   return nullptr;
  1226 nsPresContext*
  1227 nsPresContext::GetToplevelContentDocumentPresContext()
  1229   if (IsChrome())
  1230     return nullptr;
  1231   nsPresContext* pc = this;
  1232   for (;;) {
  1233     nsPresContext* parent = pc->GetParentPresContext();
  1234     if (!parent || parent->IsChrome())
  1235       return pc;
  1236     pc = parent;
  1240 nsIWidget*
  1241 nsPresContext::GetNearestWidget(nsPoint* aOffset)
  1243   NS_ENSURE_TRUE(mShell, nullptr);
  1244   nsIFrame* frame = mShell->GetRootFrame();
  1245   NS_ENSURE_TRUE(frame, nullptr);
  1246   return frame->GetView()->GetNearestWidget(aOffset);
  1249 nsIWidget*
  1250 nsPresContext::GetRootWidget()
  1252   NS_ENSURE_TRUE(mShell, nullptr);
  1253   nsViewManager* vm = mShell->GetViewManager();
  1254   if (!vm) {
  1255     return nullptr;
  1257   nsCOMPtr<nsIWidget> widget;
  1258   vm->GetRootWidget(getter_AddRefs(widget));
  1259   return widget.get();
  1262 // We may want to replace this with something faster, maybe caching the root prescontext
  1263 nsRootPresContext*
  1264 nsPresContext::GetRootPresContext()
  1266   nsPresContext* pc = this;
  1267   for (;;) {
  1268     nsPresContext* parent = pc->GetParentPresContext();
  1269     if (!parent)
  1270       break;
  1271     pc = parent;
  1273   return pc->IsRoot() ? static_cast<nsRootPresContext*>(pc) : nullptr;
  1276 nsRootPresContext*
  1277 nsPresContext::GetDisplayRootPresContext()
  1279   nsPresContext* pc = this;
  1280   for (;;) {
  1281     nsPresContext* parent = pc->GetParentPresContext();
  1282     if (!parent) {
  1283       // Not sure if this is always strictly the parent, but it works for GetRootPresContext
  1284       // where the current pres context has no frames.
  1285       nsIDocument *doc = pc->Document();
  1286       if (doc) {
  1287         doc = doc->GetParentDocument();
  1288         if (doc) {
  1289           nsIPresShell* shell = doc->GetShell();
  1290           if (shell) {
  1291             parent = shell->GetPresContext();
  1296     if (!parent || parent == pc)
  1297       break;
  1298     pc = parent;
  1300   return pc->IsRoot() ? static_cast<nsRootPresContext*>(pc) : nullptr;
  1303 void
  1304 nsPresContext::CompatibilityModeChanged()
  1306   if (!mShell)
  1307     return;
  1309   // enable/disable the QuirkSheet
  1310   mShell->StyleSet()->
  1311     EnableQuirkStyleSheet(CompatibilityMode() == eCompatibility_NavQuirks);
  1314 // Helper function for setting Anim Mode on image
  1315 static void SetImgAnimModeOnImgReq(imgIRequest* aImgReq, uint16_t aMode)
  1317   if (aImgReq) {
  1318     nsCOMPtr<imgIContainer> imgCon;
  1319     aImgReq->GetImage(getter_AddRefs(imgCon));
  1320     if (imgCon) {
  1321       imgCon->SetAnimationMode(aMode);
  1326 // IMPORTANT: Assumption is that all images for a Presentation
  1327 // have the same Animation Mode (pavlov said this was OK)
  1328 //
  1329 // Walks content and set the animation mode
  1330 // this is a way to turn on/off image animations
  1331 void nsPresContext::SetImgAnimations(nsIContent *aParent, uint16_t aMode)
  1333   nsCOMPtr<nsIImageLoadingContent> imgContent(do_QueryInterface(aParent));
  1334   if (imgContent) {
  1335     nsCOMPtr<imgIRequest> imgReq;
  1336     imgContent->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
  1337                            getter_AddRefs(imgReq));
  1338     SetImgAnimModeOnImgReq(imgReq, aMode);
  1341   uint32_t count = aParent->GetChildCount();
  1342   for (uint32_t i = 0; i < count; ++i) {
  1343     SetImgAnimations(aParent->GetChildAt(i), aMode);
  1347 void
  1348 nsPresContext::SetSMILAnimations(nsIDocument *aDoc, uint16_t aNewMode,
  1349                                  uint16_t aOldMode)
  1351   if (aDoc->HasAnimationController()) {
  1352     nsSMILAnimationController* controller = aDoc->GetAnimationController();
  1353     switch (aNewMode)
  1355       case imgIContainer::kNormalAnimMode:
  1356       case imgIContainer::kLoopOnceAnimMode:
  1357         if (aOldMode == imgIContainer::kDontAnimMode)
  1358           controller->Resume(nsSMILTimeContainer::PAUSE_USERPREF);
  1359         break;
  1361       case imgIContainer::kDontAnimMode:
  1362         if (aOldMode != imgIContainer::kDontAnimMode)
  1363           controller->Pause(nsSMILTimeContainer::PAUSE_USERPREF);
  1364         break;
  1369 void
  1370 nsPresContext::SetImageAnimationModeInternal(uint16_t aMode)
  1372   NS_ASSERTION(aMode == imgIContainer::kNormalAnimMode ||
  1373                aMode == imgIContainer::kDontAnimMode ||
  1374                aMode == imgIContainer::kLoopOnceAnimMode, "Wrong Animation Mode is being set!");
  1376   // Image animation mode cannot be changed when rendering to a printer.
  1377   if (!IsDynamic())
  1378     return;
  1380   // Now walk the content tree and set the animation mode
  1381   // on all the images.
  1382   if (mShell != nullptr) {
  1383     nsIDocument *doc = mShell->GetDocument();
  1384     if (doc) {
  1385       doc->StyleImageLoader()->SetAnimationMode(aMode);
  1387       Element *rootElement = doc->GetRootElement();
  1388       if (rootElement) {
  1389         SetImgAnimations(rootElement, aMode);
  1391       SetSMILAnimations(doc, aMode, mImageAnimationMode);
  1395   mImageAnimationMode = aMode;
  1398 void
  1399 nsPresContext::SetImageAnimationModeExternal(uint16_t aMode)
  1401   SetImageAnimationModeInternal(aMode);
  1404 const nsFont*
  1405 nsPresContext::GetDefaultFont(uint8_t aFontID, nsIAtom *aLanguage) const
  1407   const LangGroupFontPrefs *prefs = GetFontPrefsForLang(aLanguage);
  1409   const nsFont *font;
  1410   switch (aFontID) {
  1411     // Special (our default variable width font and fixed width font)
  1412     case kPresContext_DefaultVariableFont_ID:
  1413       font = &prefs->mDefaultVariableFont;
  1414       break;
  1415     case kPresContext_DefaultFixedFont_ID:
  1416       font = &prefs->mDefaultFixedFont;
  1417       break;
  1418     // CSS
  1419     case kGenericFont_serif:
  1420       font = &prefs->mDefaultSerifFont;
  1421       break;
  1422     case kGenericFont_sans_serif:
  1423       font = &prefs->mDefaultSansSerifFont;
  1424       break;
  1425     case kGenericFont_monospace:
  1426       font = &prefs->mDefaultMonospaceFont;
  1427       break;
  1428     case kGenericFont_cursive:
  1429       font = &prefs->mDefaultCursiveFont;
  1430       break;
  1431     case kGenericFont_fantasy:
  1432       font = &prefs->mDefaultFantasyFont;
  1433       break;
  1434     default:
  1435       font = nullptr;
  1436       NS_ERROR("invalid arg");
  1437       break;
  1439   return font;
  1442 PRBool
  1443 nsPresContext::FontUseCountReached(const nsFont &font) {
  1444   if (mMaxFonts < 0) {
  1445     return PR_FALSE;
  1448   for (PRUint32 i = 0; i < mFontsUsed.Length(); i++) {
  1449     if (mFontsUsed[i].name.Equals(font.name,
  1450                                   nsCaseInsensitiveStringComparator())
  1451         // XXX: Style is sometimes filled with garbage??
  1452         /*&& mFontsUsed[i].style == font.style*/) {
  1453       // seen it before: OK
  1454       return PR_FALSE;
  1458   if (mFontsUsed.Length() >= (unsigned)mMaxFonts) {
  1459     return PR_TRUE;
  1462   return PR_FALSE;
  1465 PRBool
  1466 nsPresContext::FontAttemptCountReached(const nsFont &font) {
  1467   if (mMaxFontAttempts < 0) {
  1468     return PR_FALSE;
  1471   for (PRUint32 i = 0; i < mFontsTried.Length(); i++) {
  1472     if (mFontsTried[i].name.Equals(font.name,
  1473                                   nsCaseInsensitiveStringComparator())
  1474         // XXX: Style is sometimes filled with garbage??
  1475         /*&& mFontsTried[i].style == font.style*/) {
  1476       // seen it before: OK
  1477       return PR_FALSE;
  1481   if (mFontsTried.Length() >= (unsigned)mMaxFontAttempts) {
  1482     return PR_TRUE;
  1485   return PR_FALSE;
  1488 void
  1489 nsPresContext::AddFontUse(const nsFont &font) {
  1490   if (mMaxFonts < 0) {
  1491     return;
  1494   for (PRUint32 i = 0; i < mFontsUsed.Length(); i++) {
  1495     if (mFontsUsed[i].name.Equals(font.name,
  1496                                   nsCaseInsensitiveStringComparator())
  1497         // XXX: Style is sometimes filled with garbage??
  1498         /*&& mFontsUsed[i].style == font.style*/) {
  1499       // seen it before: OK
  1500       return;
  1504   if (mFontsUsed.Length() >= (unsigned)mMaxFonts) {
  1505     return;
  1508   mFontsUsed.AppendElement(font);
  1509   return;
  1512 void
  1513 nsPresContext::AddFontAttempt(const nsFont &font) {
  1514   if (mMaxFontAttempts < 0) {
  1515     return;
  1518   for (PRUint32 i = 0; i < mFontsTried.Length(); i++) {
  1519     if (mFontsTried[i].name.Equals(font.name,
  1520                                   nsCaseInsensitiveStringComparator())
  1521         // XXX: Style is sometimes filled with garbage??
  1522         /*&& mFontsTried[i].style == font.style*/) {
  1523       // seen it before: OK
  1524       return;
  1528   if (mFontsTried.Length() >= (unsigned)mMaxFontAttempts) {
  1529     return;
  1532   mFontsTried.AppendElement(font);
  1533   return;
  1536 void
  1537 nsPresContext::SetFullZoom(float aZoom)
  1539   if (!mShell || mFullZoom == aZoom) {
  1540     return;
  1543   // Re-fetch the view manager's window dimensions in case there's a deferred
  1544   // resize which hasn't affected our mVisibleArea yet
  1545   nscoord oldWidthAppUnits, oldHeightAppUnits;
  1546   mShell->GetViewManager()->GetWindowDimensions(&oldWidthAppUnits, &oldHeightAppUnits);
  1547   float oldWidthDevPixels = oldWidthAppUnits / float(mCurAppUnitsPerDevPixel);
  1548   float oldHeightDevPixels = oldHeightAppUnits / float(mCurAppUnitsPerDevPixel);
  1549   mDeviceContext->SetPixelScale(aZoom);
  1551   NS_ASSERTION(!mSupressResizeReflow, "two zooms happening at the same time? impossible!");
  1552   mSupressResizeReflow = true;
  1554   mFullZoom = aZoom;
  1555   mShell->GetViewManager()->
  1556     SetWindowDimensions(NSToCoordRound(oldWidthDevPixels * AppUnitsPerDevPixel()),
  1557                         NSToCoordRound(oldHeightDevPixels * AppUnitsPerDevPixel()));
  1559   AppUnitsPerDevPixelChanged();
  1561   mSupressResizeReflow = false;
  1564 float
  1565 nsPresContext::ScreenWidthInchesForFontInflation(bool* aChanged)
  1567   if (aChanged) {
  1568     *aChanged = false;
  1571   nsDeviceContext *dx = DeviceContext();
  1572   nsRect clientRect;
  1573   dx->GetClientRect(clientRect); // FIXME: GetClientRect looks expensive
  1574   float deviceWidthInches =
  1575     float(clientRect.width) / float(dx->AppUnitsPerPhysicalInch());
  1577   if (mLastFontInflationScreenWidth == -1.0) {
  1578     mLastFontInflationScreenWidth = deviceWidthInches;
  1581   if (deviceWidthInches != mLastFontInflationScreenWidth && aChanged) {
  1582     *aChanged = true;
  1583     mLastFontInflationScreenWidth = deviceWidthInches;
  1586   return deviceWidthInches;
  1589 void
  1590 nsPresContext::SetContainer(nsIDocShell* aDocShell)
  1592   if (aDocShell) {
  1593     mContainer = static_cast<nsDocShell*>(aDocShell)->asWeakPtr();
  1594   } else {
  1595     mContainer = WeakPtr<nsDocShell>();
  1597   UpdateIsChrome();
  1598   if (mContainer) {
  1599     GetDocumentColorPreferences();
  1603 nsISupports*
  1604 nsPresContext::GetContainerWeakInternal() const
  1606   return static_cast<nsIDocShell*>(mContainer);
  1609 nsISupports*
  1610 nsPresContext::GetContainerWeakExternal() const
  1612   return GetContainerWeakInternal();
  1615 nsIDocShell*
  1616 nsPresContext::GetDocShell() const
  1618   return mContainer;
  1621 /* virtual */ void
  1622 nsPresContext::Detach()
  1624   SetContainer(nullptr);
  1625   SetLinkHandler(nullptr);
  1626   if (mShell) {
  1627     mShell->CancelInvalidatePresShellIfHidden();
  1631 bool
  1632 nsPresContext::ThrottledTransitionStyleIsUpToDate() const
  1634   return
  1635     mLastUpdateThrottledTransitionStyle == mRefreshDriver->MostRecentRefresh();
  1638 void
  1639 nsPresContext::TickLastUpdateThrottledTransitionStyle()
  1641   mLastUpdateThrottledTransitionStyle = mRefreshDriver->MostRecentRefresh();
  1644 bool
  1645 nsPresContext::ThrottledAnimationStyleIsUpToDate() const
  1647   return
  1648     mLastUpdateThrottledAnimationStyle == mRefreshDriver->MostRecentRefresh();
  1651 void
  1652 nsPresContext::TickLastUpdateThrottledAnimationStyle()
  1654   mLastUpdateThrottledAnimationStyle = mRefreshDriver->MostRecentRefresh();
  1657 bool
  1658 nsPresContext::StyleUpdateForAllAnimationsIsUpToDate()
  1660   return mLastStyleUpdateForAllAnimations == mRefreshDriver->MostRecentRefresh();
  1663 void
  1664 nsPresContext::TickLastStyleUpdateForAllAnimations()
  1666   mLastStyleUpdateForAllAnimations = mRefreshDriver->MostRecentRefresh();
  1669 bool
  1670 nsPresContext::BidiEnabledExternal() const
  1672   return BidiEnabledInternal();
  1675 bool
  1676 nsPresContext::BidiEnabledInternal() const
  1678   return Document()->GetBidiEnabled();
  1681 void
  1682 nsPresContext::SetBidiEnabled() const
  1684   if (mShell) {
  1685     nsIDocument *doc = mShell->GetDocument();
  1686     if (doc) {
  1687       doc->SetBidiEnabled();
  1692 void
  1693 nsPresContext::SetBidi(uint32_t aSource, bool aForceRestyle)
  1695   // Don't do all this stuff unless the options have changed.
  1696   if (aSource == GetBidi()) {
  1697     return;
  1700   NS_ASSERTION(!(aForceRestyle && (GetBidi() == 0)),
  1701                "ForceReflow on new prescontext");
  1703   Document()->SetBidiOptions(aSource);
  1704   if (IBMBIDI_TEXTDIRECTION_RTL == GET_BIDI_OPTION_DIRECTION(aSource)
  1705       || IBMBIDI_NUMERAL_HINDI == GET_BIDI_OPTION_NUMERAL(aSource)) {
  1706     SetBidiEnabled();
  1708   if (IBMBIDI_TEXTTYPE_VISUAL == GET_BIDI_OPTION_TEXTTYPE(aSource)) {
  1709     SetVisualMode(true);
  1711   else if (IBMBIDI_TEXTTYPE_LOGICAL == GET_BIDI_OPTION_TEXTTYPE(aSource)) {
  1712     SetVisualMode(false);
  1714   else {
  1715     nsIDocument* doc = mShell->GetDocument();
  1716     if (doc) {
  1717       SetVisualMode(IsVisualCharset(doc->GetDocumentCharacterSet()));
  1720   if (aForceRestyle && mShell) {
  1721     // Reconstruct the root document element's frame and its children,
  1722     // because we need to trigger frame reconstruction for direction change.
  1723     RebuildUserFontSet();
  1724     mShell->ReconstructFrames();
  1728 uint32_t
  1729 nsPresContext::GetBidi() const
  1731   return Document()->GetBidiOptions();
  1734 bool
  1735 nsPresContext::IsTopLevelWindowInactive()
  1737   nsCOMPtr<nsIDocShellTreeItem> treeItem(mContainer);
  1738   if (!treeItem)
  1739     return false;
  1741   nsCOMPtr<nsIDocShellTreeItem> rootItem;
  1742   treeItem->GetRootTreeItem(getter_AddRefs(rootItem));
  1743   nsCOMPtr<nsPIDOMWindow> domWindow(do_GetInterface(rootItem));
  1745   return domWindow && !domWindow->IsActive();
  1748 nsITheme*
  1749 nsPresContext::GetTheme()
  1751   if (!sNoTheme && !mTheme) {
  1752     mTheme = do_GetService("@mozilla.org/chrome/chrome-native-theme;1");
  1753     if (!mTheme)
  1754       sNoTheme = true;
  1757   return mTheme;
  1760 void
  1761 nsPresContext::ThemeChanged()
  1763   if (!mPendingThemeChanged) {
  1764     sLookAndFeelChanged = true;
  1765     sThemeChanged = true;
  1767     nsCOMPtr<nsIRunnable> ev =
  1768       NS_NewRunnableMethod(this, &nsPresContext::ThemeChangedInternal);
  1769     if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) {
  1770       mPendingThemeChanged = true;
  1775 void
  1776 nsPresContext::ThemeChangedInternal()
  1778   mPendingThemeChanged = false;
  1780   // Tell the theme that it changed, so it can flush any handles to stale theme
  1781   // data.
  1782   if (mTheme && sThemeChanged) {
  1783     mTheme->ThemeChanged();
  1784     sThemeChanged = false;
  1787   // Clear all cached LookAndFeel colors.
  1788   if (sLookAndFeelChanged) {
  1789     LookAndFeel::Refresh();
  1790     sLookAndFeelChanged = false;
  1793   // This will force the system metrics to be generated the next time they're used
  1794   nsCSSRuleProcessor::FreeSystemMetrics();
  1796   // Changes to system metrics can change media queries on them.
  1797   // Changes in theme can change system colors (whose changes are
  1798   // properly reflected in computed style data), system fonts (whose
  1799   // changes are not), and -moz-appearance (whose changes likewise are
  1800   // not), so we need to reflow.
  1801   MediaFeatureValuesChanged(eAlwaysRebuildStyle, NS_STYLE_HINT_REFLOW);
  1804 void
  1805 nsPresContext::SysColorChanged()
  1807   if (!mPendingSysColorChanged) {
  1808     sLookAndFeelChanged = true;
  1809     nsCOMPtr<nsIRunnable> ev =
  1810       NS_NewRunnableMethod(this, &nsPresContext::SysColorChangedInternal);
  1811     if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) {
  1812       mPendingSysColorChanged = true;
  1817 void
  1818 nsPresContext::SysColorChangedInternal()
  1820   mPendingSysColorChanged = false;
  1822   if (sLookAndFeelChanged) {
  1823      // Don't use the cached values for the system colors
  1824     LookAndFeel::Refresh();
  1825     sLookAndFeelChanged = false;
  1828   // Reset default background and foreground colors for the document since
  1829   // they may be using system colors
  1830   GetDocumentColorPreferences();
  1832   // The system color values are computed to colors in the style data,
  1833   // so normal style data comparison is sufficient here.
  1834   RebuildAllStyleData(nsChangeHint(0));
  1837 void
  1838 nsPresContext::UIResolutionChanged()
  1840   if (!mPendingUIResolutionChanged) {
  1841     nsCOMPtr<nsIRunnable> ev =
  1842       NS_NewRunnableMethod(this, &nsPresContext::UIResolutionChangedInternal);
  1843     if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) {
  1844       mPendingUIResolutionChanged = true;
  1849 /*static*/ bool
  1850 nsPresContext::UIResolutionChangedSubdocumentCallback(nsIDocument* aDocument,
  1851                                                       void* aData)
  1853   nsIPresShell* shell = aDocument->GetShell();
  1854   if (shell) {
  1855     nsPresContext* pc = shell->GetPresContext();
  1856     if (pc) {
  1857       pc->UIResolutionChangedInternal();
  1860   return true;
  1863 void
  1864 nsPresContext::UIResolutionChangedInternal()
  1866   mPendingUIResolutionChanged = false;
  1868   mDeviceContext->CheckDPIChange();
  1869   if (mCurAppUnitsPerDevPixel != AppUnitsPerDevPixel()) {
  1870     AppUnitsPerDevPixelChanged();
  1873   mDocument->EnumerateSubDocuments(UIResolutionChangedSubdocumentCallback,
  1874                                    nullptr);
  1877 void
  1878 nsPresContext::EmulateMedium(const nsAString& aMediaType)
  1880   nsIAtom* previousMedium = Medium();
  1881   mIsEmulatingMedia = true;
  1883   nsAutoString mediaType;
  1884   nsContentUtils::ASCIIToLower(aMediaType, mediaType);
  1886   mMediaEmulated = do_GetAtom(mediaType);
  1887   if (mMediaEmulated != previousMedium && mShell) {
  1888     MediaFeatureValuesChanged(eRebuildStyleIfNeeded, nsChangeHint(0));
  1892 void nsPresContext::StopEmulatingMedium()
  1894   nsIAtom* previousMedium = Medium();
  1895   mIsEmulatingMedia = false;
  1896   if (Medium() != previousMedium) {
  1897     MediaFeatureValuesChanged(eRebuildStyleIfNeeded, nsChangeHint(0));
  1901 void
  1902 nsPresContext::RebuildAllStyleData(nsChangeHint aExtraHint)
  1904   if (!mShell) {
  1905     // We must have been torn down. Nothing to do here.
  1906     return;
  1909   mUsesRootEMUnits = false;
  1910   mUsesViewportUnits = false;
  1911   RebuildUserFontSet();
  1913   RestyleManager()->RebuildAllStyleData(aExtraHint);
  1916 void
  1917 nsPresContext::PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint)
  1919   if (!mShell) {
  1920     // We must have been torn down. Nothing to do here.
  1921     return;
  1923   RestyleManager()->PostRebuildAllStyleDataEvent(aExtraHint);
  1926 void
  1927 nsPresContext::MediaFeatureValuesChanged(StyleRebuildType aShouldRebuild,
  1928                                          nsChangeHint aChangeHint)
  1930   NS_ASSERTION(aShouldRebuild == eAlwaysRebuildStyle || aChangeHint == 0,
  1931                "If you don't know if we need a rebuild, how can you provide a hint?");
  1933   mPendingMediaFeatureValuesChanged = false;
  1935   // MediumFeaturesChanged updates the applied rules, so it always gets called.
  1936   bool mediaFeaturesDidChange = mShell ? mShell->StyleSet()->MediumFeaturesChanged(this)
  1937                                        : false;
  1939   if (aShouldRebuild == eAlwaysRebuildStyle ||
  1940       mediaFeaturesDidChange ||
  1941       (mUsesViewportUnits && mPendingViewportChange)) {
  1942     RebuildAllStyleData(aChangeHint);
  1945   mPendingViewportChange = false;
  1947   if (!nsContentUtils::IsSafeToRunScript()) {
  1948     NS_ABORT_IF_FALSE(mDocument->IsBeingUsedAsImage(),
  1949                       "How did we get here?  Are we failing to notify "
  1950                       "listeners that we should notify?");
  1951     return;
  1954   // Media query list listeners should be notified from a queued task
  1955   // (in HTML5 terms), although we also want to notify them on certain
  1956   // flushes.  (We're already running off an event.)
  1957   //
  1958   // Note that we do this after the new style from media queries in
  1959   // style sheets has been computed.
  1961   if (!PR_CLIST_IS_EMPTY(&mDOMMediaQueryLists)) {
  1962     // We build a list of all the notifications we're going to send
  1963     // before we send any of them.  (The spec says the notifications
  1964     // should be a queued task, so any removals that happen during the
  1965     // notifications shouldn't affect what gets notified.)  Furthermore,
  1966     // we hold strong pointers to everything we're going to make
  1967     // notification calls to, since each notification involves calling
  1968     // arbitrary script that might otherwise destroy these objects, or,
  1969     // for that matter, |this|.
  1970     //
  1971     // Note that we intentionally send the notifications to media query
  1972     // list in the order they were created and, for each list, to the
  1973     // listeners in the order added.
  1974     MediaQueryList::NotifyList notifyList;
  1975     for (PRCList *l = PR_LIST_HEAD(&mDOMMediaQueryLists);
  1976          l != &mDOMMediaQueryLists; l = PR_NEXT_LINK(l)) {
  1977       MediaQueryList *mql = static_cast<MediaQueryList*>(l);
  1978       mql->MediumFeaturesChanged(notifyList);
  1981     if (!notifyList.IsEmpty()) {
  1982       nsPIDOMWindow *win = mDocument->GetInnerWindow();
  1983       nsCOMPtr<EventTarget> et = do_QueryInterface(win);
  1984       nsCxPusher pusher;
  1986       for (uint32_t i = 0, i_end = notifyList.Length(); i != i_end; ++i) {
  1987         if (pusher.RePush(et)) {
  1988           nsAutoMicroTask mt;
  1989           MediaQueryList::HandleChangeData &d = notifyList[i];
  1990           ErrorResult result;
  1991           d.callback->Call(*d.mql, result);
  1996     // NOTE:  When |notifyList| goes out of scope, our destructor could run.
  2000 void
  2001 nsPresContext::PostMediaFeatureValuesChangedEvent()
  2003   // FIXME: We should probably replace this event with use of
  2004   // nsRefreshDriver::AddStyleFlushObserver (except the pres shell would
  2005   // need to track whether it's been added).
  2006   if (!mPendingMediaFeatureValuesChanged) {
  2007     nsCOMPtr<nsIRunnable> ev =
  2008       NS_NewRunnableMethod(this, &nsPresContext::HandleMediaFeatureValuesChangedEvent);
  2009     if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) {
  2010       mPendingMediaFeatureValuesChanged = true;
  2011       mDocument->SetNeedStyleFlush();
  2016 void
  2017 nsPresContext::HandleMediaFeatureValuesChangedEvent()
  2019   // Null-check mShell in case the shell has been destroyed (and the
  2020   // event is the only thing holding the pres context alive).
  2021   if (mPendingMediaFeatureValuesChanged && mShell) {
  2022     MediaFeatureValuesChanged(eRebuildStyleIfNeeded);
  2026 already_AddRefed<MediaQueryList>
  2027 nsPresContext::MatchMedia(const nsAString& aMediaQueryList)
  2029   nsRefPtr<MediaQueryList> result = new MediaQueryList(this, aMediaQueryList);
  2031   // Insert the new item at the end of the linked list.
  2032   PR_INSERT_BEFORE(result, &mDOMMediaQueryLists);
  2034   return result.forget();
  2037 nsCompatibility
  2038 nsPresContext::CompatibilityMode() const
  2040   return Document()->GetCompatibilityMode();
  2043 void
  2044 nsPresContext::SetPaginatedScrolling(bool aPaginated)
  2046   if (mType == eContext_PrintPreview || mType == eContext_PageLayout)
  2047     mCanPaginatedScroll = aPaginated;
  2050 void
  2051 nsPresContext::SetPrintSettings(nsIPrintSettings *aPrintSettings)
  2053   if (mMedium == nsGkAtoms::print)
  2054     mPrintSettings = aPrintSettings;
  2057 bool
  2058 nsPresContext::EnsureVisible()
  2060   nsCOMPtr<nsIDocShell> docShell(mContainer);
  2061   if (docShell) {
  2062     nsCOMPtr<nsIContentViewer> cv;
  2063     docShell->GetContentViewer(getter_AddRefs(cv));
  2064     // Make sure this is the content viewer we belong with
  2065     if (cv) {
  2066       nsRefPtr<nsPresContext> currentPresContext;
  2067       cv->GetPresContext(getter_AddRefs(currentPresContext));
  2068       if (currentPresContext == this) {
  2069         // OK, this is us.  We want to call Show() on the content viewer.
  2070         nsresult result = cv->Show();
  2071         if (NS_SUCCEEDED(result)) {
  2072           return true;
  2077   return false;
  2080 #ifdef MOZ_REFLOW_PERF
  2081 void
  2082 nsPresContext::CountReflows(const char * aName, nsIFrame * aFrame)
  2084   if (mShell) {
  2085     mShell->CountReflows(aName, aFrame);
  2088 #endif
  2090 void
  2091 nsPresContext::UpdateIsChrome()
  2093   mIsChrome = mContainer &&
  2094               nsIDocShellTreeItem::typeChrome == mContainer->ItemType();
  2097 /* virtual */ bool
  2098 nsPresContext::HasAuthorSpecifiedRules(nsIFrame *aFrame, uint32_t ruleTypeMask) const
  2100   return
  2101     nsRuleNode::HasAuthorSpecifiedRules(aFrame->StyleContext(),
  2102                                         ruleTypeMask,
  2103                                         UseDocumentColors());
  2106 gfxUserFontSet*
  2107 nsPresContext::GetUserFontSetInternal()
  2109   // We want to initialize the user font set lazily the first time the
  2110   // user asks for it, rather than building it too early and forcing
  2111   // rule cascade creation.  Thus we try to enforce the invariant that
  2112   // we *never* build the user font set until the first call to
  2113   // GetUserFontSet.  However, once it's been requested, we can't wait
  2114   // for somebody to call GetUserFontSet in order to rebuild it (see
  2115   // comments below in RebuildUserFontSet for why).
  2116 #ifdef DEBUG
  2117   bool userFontSetGottenBefore = mGetUserFontSetCalled;
  2118 #endif
  2119   // Set mGetUserFontSetCalled up front, so that FlushUserFontSet will actually
  2120   // flush.
  2121   mGetUserFontSetCalled = true;
  2122   if (mUserFontSetDirty) {
  2123     // If this assertion fails, and there have actually been changes to
  2124     // @font-face rules, then we will call StyleChangeReflow in
  2125     // FlushUserFontSet.  If we're in the middle of reflow,
  2126     // that's a bad thing to do, and the caller was responsible for
  2127     // flushing first.  If we're not (e.g., in frame construction), it's
  2128     // ok.
  2129     NS_ASSERTION(!userFontSetGottenBefore || !mShell->IsReflowLocked(),
  2130                  "FlushUserFontSet should have been called first");
  2131     FlushUserFontSet();
  2134   return mUserFontSet;
  2137 gfxUserFontSet*
  2138 nsPresContext::GetUserFontSetExternal()
  2140   return GetUserFontSetInternal();
  2143 void
  2144 nsPresContext::FlushUserFontSet()
  2146   if (!mShell) {
  2147     return; // we've been torn down
  2150   if (!mGetUserFontSetCalled) {
  2151     return; // No one cares about this font set yet, but we want to be careful
  2152             // to not unset our mUserFontSetDirty bit, so when someone really
  2153             // does we'll create it.
  2156   if (mUserFontSetDirty) {
  2157     if (gfxPlatform::GetPlatform()->DownloadableFontsEnabled()) {
  2158       nsTArray<nsFontFaceRuleContainer> rules;
  2159       if (!mShell->StyleSet()->AppendFontFaceRules(this, rules)) {
  2160         if (mUserFontSet) {
  2161           mUserFontSet->Destroy();
  2162           NS_RELEASE(mUserFontSet);
  2164         return;
  2167       bool changed = false;
  2169       if (rules.Length() == 0) {
  2170         if (mUserFontSet) {
  2171           mUserFontSet->Destroy();
  2172           NS_RELEASE(mUserFontSet);
  2173           changed = true;
  2175       } else {
  2176         if (!mUserFontSet) {
  2177           mUserFontSet = new nsUserFontSet(this);
  2178           NS_ADDREF(mUserFontSet);
  2180         changed = mUserFontSet->UpdateRules(rules);
  2183       // We need to enqueue a style change reflow (for later) to
  2184       // reflect that we're modifying @font-face rules.  (However,
  2185       // without a reflow, nothing will happen to start any downloads
  2186       // that are needed.)
  2187       if (changed) {
  2188         UserFontSetUpdated();
  2192     mUserFontSetDirty = false;
  2196 void
  2197 nsPresContext::RebuildUserFontSet()
  2199   if (!mGetUserFontSetCalled) {
  2200     // We want to lazily build the user font set the first time it's
  2201     // requested (so we don't force creation of rule cascades too
  2202     // early), so don't do anything now.
  2203     return;
  2206   mUserFontSetDirty = true;
  2207   mDocument->SetNeedStyleFlush();
  2209   // Somebody has already asked for the user font set, so we need to
  2210   // post an event to rebuild it.  Setting the user font set to be dirty
  2211   // and lazily rebuilding it isn't sufficient, since it is only the act
  2212   // of rebuilding it that will trigger the style change reflow that
  2213   // calls GetUserFontSet.  (This reflow causes rebuilding of text runs,
  2214   // which starts font loads, whose completion causes another style
  2215   // change reflow).
  2216   if (!mPostedFlushUserFontSet) {
  2217     nsCOMPtr<nsIRunnable> ev =
  2218       NS_NewRunnableMethod(this, &nsPresContext::HandleRebuildUserFontSet);
  2219     if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) {
  2220       mPostedFlushUserFontSet = true;
  2225 void
  2226 nsPresContext::UserFontSetUpdated()
  2228   if (!mShell)
  2229     return;
  2231   // Changes to the set of available fonts can cause updates to layout by:
  2232   //
  2233   //   1. Changing the font used for text, which changes anything that
  2234   //      depends on text measurement, including line breaking and
  2235   //      intrinsic widths, and any other parts of layout that depend on
  2236   //      font metrics.  This requires a style change reflow to update.
  2237   //
  2238   //   2. Changing the value of the 'ex' and 'ch' units in style data,
  2239   //      which also depend on font metrics.  Updating this information
  2240   //      requires rebuilding the rule tree from the top, avoiding the
  2241   //      reuse of cached data even when no style rules have changed.
  2243   PostRebuildAllStyleDataEvent(NS_STYLE_HINT_REFLOW);
  2246 void
  2247 nsPresContext::EnsureSafeToHandOutCSSRules()
  2249   nsCSSStyleSheet::EnsureUniqueInnerResult res =
  2250     mShell->StyleSet()->EnsureUniqueInnerOnCSSSheets();
  2251   if (res == nsCSSStyleSheet::eUniqueInner_AlreadyUnique) {
  2252     // Nothing to do.
  2253     return;
  2256   MOZ_ASSERT(res == nsCSSStyleSheet::eUniqueInner_ClonedInner);
  2257   RebuildAllStyleData(nsChangeHint(0));
  2260 void
  2261 nsPresContext::FireDOMPaintEvent(nsInvalidateRequestList* aList)
  2263   nsPIDOMWindow* ourWindow = mDocument->GetWindow();
  2264   if (!ourWindow)
  2265     return;
  2267   nsCOMPtr<EventTarget> dispatchTarget = do_QueryInterface(ourWindow);
  2268   nsCOMPtr<EventTarget> eventTarget = dispatchTarget;
  2269   if (!IsChrome() && !mSendAfterPaintToContent) {
  2270     // Don't tell the window about this event, it should not know that
  2271     // something happened in a subdocument. Tell only the chrome event handler.
  2272     // (Events sent to the window get propagated to the chrome event handler
  2273     // automatically.)
  2274     dispatchTarget = do_QueryInterface(ourWindow->GetParentTarget());
  2275     if (!dispatchTarget) {
  2276       return;
  2279   // Events sent to the window get propagated to the chrome event handler
  2280   // automatically.
  2281   nsCOMPtr<nsIDOMEvent> event;
  2282   // This will empty our list in case dispatching the event causes more damage
  2283   // (hopefully it won't, or we're likely to get an infinite loop! At least
  2284   // it won't be blocking app execution though).
  2285   NS_NewDOMNotifyPaintEvent(getter_AddRefs(event), eventTarget, this, nullptr,
  2286                             NS_AFTERPAINT, aList);
  2287   if (!event) {
  2288     return;
  2291   // Even if we're not telling the window about the event (so eventTarget is
  2292   // the chrome event handler, not the window), the window is still
  2293   // logically the event target.
  2294   event->SetTarget(eventTarget);
  2295   event->SetTrusted(true);
  2296   EventDispatcher::DispatchDOMEvent(dispatchTarget, nullptr, event, this,
  2297                                     nullptr);
  2300 static bool
  2301 MayHavePaintEventListenerSubdocumentCallback(nsIDocument* aDocument, void* aData)
  2303   bool *result = static_cast<bool*>(aData);
  2304   nsIPresShell* shell = aDocument->GetShell();
  2305   if (shell) {
  2306     nsPresContext* pc = shell->GetPresContext();
  2307     if (pc) {
  2308       *result = pc->MayHavePaintEventListenerInSubDocument();
  2310       // If we found a paint event listener, then we can stop enumerating
  2311       // sub documents.
  2312       return !*result;
  2315   return true;
  2318 static bool
  2319 MayHavePaintEventListener(nsPIDOMWindow* aInnerWindow)
  2321   if (!aInnerWindow)
  2322     return false;
  2323   if (aInnerWindow->HasPaintEventListeners())
  2324     return true;
  2326   EventTarget* parentTarget = aInnerWindow->GetParentTarget();
  2327   if (!parentTarget)
  2328     return false;
  2330   EventListenerManager* manager = nullptr;
  2331   if ((manager = parentTarget->GetExistingListenerManager()) &&
  2332       manager->MayHavePaintEventListener()) {
  2333     return true;
  2336   nsCOMPtr<nsINode> node;
  2337   if (parentTarget != aInnerWindow->GetChromeEventHandler()) {
  2338     nsCOMPtr<nsIInProcessContentFrameMessageManager> mm =
  2339       do_QueryInterface(parentTarget);
  2340     if (mm) {
  2341       node = mm->GetOwnerContent();
  2345   if (!node) {
  2346     node = do_QueryInterface(parentTarget);
  2348   if (node)
  2349     return MayHavePaintEventListener(node->OwnerDoc()->GetInnerWindow());
  2351   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(parentTarget);
  2352   if (window)
  2353     return MayHavePaintEventListener(window);
  2355   nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(parentTarget);
  2356   EventTarget* tabChildGlobal;
  2357   return root &&
  2358          (tabChildGlobal = root->GetParentTarget()) &&
  2359          (manager = tabChildGlobal->GetExistingListenerManager()) &&
  2360          manager->MayHavePaintEventListener();
  2363 bool
  2364 nsPresContext::MayHavePaintEventListener()
  2366   return ::MayHavePaintEventListener(mDocument->GetInnerWindow());
  2369 bool
  2370 nsPresContext::MayHavePaintEventListenerInSubDocument()
  2372   if (MayHavePaintEventListener()) {
  2373     return true;
  2376   bool result = false;
  2377   mDocument->EnumerateSubDocuments(MayHavePaintEventListenerSubdocumentCallback, &result);
  2378   return result;
  2381 void
  2382 nsPresContext::NotifyInvalidation(uint32_t aFlags)
  2384   nsIFrame* rootFrame = PresShell()->FrameManager()->GetRootFrame();
  2385   NotifyInvalidation(rootFrame->GetVisualOverflowRect(), aFlags);
  2386   mAllInvalidated = true;
  2389 void
  2390 nsPresContext::NotifyInvalidation(const nsIntRect& aRect, uint32_t aFlags)
  2392   nsRect rect(DevPixelsToAppUnits(aRect.x),
  2393               DevPixelsToAppUnits(aRect.y),
  2394               DevPixelsToAppUnits(aRect.width),
  2395               DevPixelsToAppUnits(aRect.height));
  2396   NotifyInvalidation(rect, aFlags);
  2399 void
  2400 nsPresContext::NotifyInvalidation(const nsRect& aRect, uint32_t aFlags)
  2402   MOZ_ASSERT(GetContainerWeak(), "Invalidation in detached pres context");
  2404   // If there is no paint event listener, then we don't need to fire
  2405   // the asynchronous event. We don't even need to record invalidation.
  2406   // MayHavePaintEventListener is pretty cheap and we could make it
  2407   // even cheaper by providing a more efficient
  2408   // nsPIDOMWindow::GetListenerManager.
  2410   if (mAllInvalidated) {
  2411     return;
  2414   nsPresContext* pc;
  2415   for (pc = this; pc; pc = pc->GetParentPresContext()) {
  2416     if (pc->mFireAfterPaintEvents)
  2417       break;
  2418     pc->mFireAfterPaintEvents = true;
  2420   if (!pc) {
  2421     nsRootPresContext* rpc = GetRootPresContext();
  2422     if (rpc) {
  2423       rpc->EnsureEventualDidPaintEvent();
  2427   nsInvalidateRequestList::Request* request =
  2428     mInvalidateRequestsSinceLastPaint.mRequests.AppendElement();
  2429   if (!request)
  2430     return;
  2432   request->mRect = aRect;
  2433   request->mFlags = aFlags;
  2436 /* static */ void
  2437 nsPresContext::NotifySubDocInvalidation(ContainerLayer* aContainer,
  2438                                         const nsIntRegion& aRegion)
  2440   ContainerLayerPresContext *data =
  2441     static_cast<ContainerLayerPresContext*>(
  2442       aContainer->GetUserData(&gNotifySubDocInvalidationData));
  2443   if (!data) {
  2444     return;
  2447   nsIntPoint topLeft = aContainer->GetVisibleRegion().GetBounds().TopLeft();
  2449   nsIntRegionRectIterator iter(aRegion);
  2450   while (const nsIntRect* r = iter.Next()) {
  2451     nsIntRect rect = *r;
  2452     //PresContext coordinate space is relative to the start of our visible
  2453     // region. Is this really true? This feels like the wrong way to get the right
  2454     // answer.
  2455     rect.MoveBy(-topLeft);
  2456     data->mPresContext->NotifyInvalidation(rect, 0);
  2460 void
  2461 nsPresContext::SetNotifySubDocInvalidationData(ContainerLayer* aContainer)
  2463   ContainerLayerPresContext* pres = new ContainerLayerPresContext;
  2464   pres->mPresContext = this;
  2465   aContainer->SetUserData(&gNotifySubDocInvalidationData, pres);
  2468 /* static */ void
  2469 nsPresContext::ClearNotifySubDocInvalidationData(ContainerLayer* aContainer)
  2471   aContainer->SetUserData(&gNotifySubDocInvalidationData, nullptr);
  2474 struct NotifyDidPaintSubdocumentCallbackClosure {
  2475   uint32_t mFlags;
  2476   bool mNeedsAnotherDidPaintNotification;
  2477 };
  2478 static bool
  2479 NotifyDidPaintSubdocumentCallback(nsIDocument* aDocument, void* aData)
  2481   NotifyDidPaintSubdocumentCallbackClosure* closure =
  2482     static_cast<NotifyDidPaintSubdocumentCallbackClosure*>(aData);
  2483   nsIPresShell* shell = aDocument->GetShell();
  2484   if (shell) {
  2485     nsPresContext* pc = shell->GetPresContext();
  2486     if (pc) {
  2487       pc->NotifyDidPaintForSubtree(closure->mFlags);
  2488       if (pc->IsDOMPaintEventPending()) {
  2489         closure->mNeedsAnotherDidPaintNotification = true;
  2493   return true;
  2496 class DelayedFireDOMPaintEvent : public nsRunnable {
  2497 public:
  2498   DelayedFireDOMPaintEvent(nsPresContext* aPresContext,
  2499                            nsInvalidateRequestList* aList)
  2500     : mPresContext(aPresContext)
  2502     MOZ_ASSERT(mPresContext->GetContainerWeak(),
  2503                "DOMPaintEvent requested for a detached pres context");
  2504     mList.TakeFrom(aList);
  2506   NS_IMETHOD Run() MOZ_OVERRIDE
  2508     // The pres context might have been detached during the delay -
  2509     // that's fine, just don't fire the event.
  2510     if (mPresContext->GetContainerWeak()) {
  2511       mPresContext->FireDOMPaintEvent(&mList);
  2513     return NS_OK;
  2516   nsRefPtr<nsPresContext> mPresContext;
  2517   nsInvalidateRequestList mList;
  2518 };
  2520 void
  2521 nsPresContext::NotifyDidPaintForSubtree(uint32_t aFlags)
  2523   if (IsRoot()) {
  2524     static_cast<nsRootPresContext*>(this)->CancelDidPaintTimer();
  2526     if (!mFireAfterPaintEvents) {
  2527       return;
  2530   // Non-root prescontexts fire MozAfterPaint to all their descendants
  2531   // unconditionally, even if no invalidations have been collected. This is
  2532   // because we don't want to eat the cost of collecting invalidations for
  2533   // every subdocument (which would require putting every subdocument in its
  2534   // own layer).
  2536   if (aFlags & nsIPresShell::PAINT_LAYERS) {
  2537     mUndeliveredInvalidateRequestsBeforeLastPaint.TakeFrom(
  2538         &mInvalidateRequestsSinceLastPaint);
  2539     mAllInvalidated = false;
  2541   if (aFlags & nsIPresShell::PAINT_COMPOSITE) {
  2542     nsCOMPtr<nsIRunnable> ev =
  2543       new DelayedFireDOMPaintEvent(this, &mUndeliveredInvalidateRequestsBeforeLastPaint);
  2544     nsContentUtils::AddScriptRunner(ev);
  2547   NotifyDidPaintSubdocumentCallbackClosure closure = { aFlags, false };
  2548   mDocument->EnumerateSubDocuments(NotifyDidPaintSubdocumentCallback, &closure);
  2550   if (!closure.mNeedsAnotherDidPaintNotification &&
  2551       mInvalidateRequestsSinceLastPaint.IsEmpty() &&
  2552       mUndeliveredInvalidateRequestsBeforeLastPaint.IsEmpty()) {
  2553     // Nothing more to do for the moment.
  2554     mFireAfterPaintEvents = false;
  2555   } else {
  2556     if (IsRoot()) {
  2557       static_cast<nsRootPresContext*>(this)->EnsureEventualDidPaintEvent();
  2562 bool
  2563 nsPresContext::HasCachedStyleData()
  2565   return mShell && mShell->StyleSet()->HasCachedStyleData();
  2568 static bool sGotInterruptEnv = false;
  2569 enum InterruptMode {
  2570   ModeRandom,
  2571   ModeCounter,
  2572   ModeEvent
  2573 };
  2574 // Controlled by the GECKO_REFLOW_INTERRUPT_MODE env var; allowed values are
  2575 // "random" (except on Windows) or "counter".  If neither is used, the mode is
  2576 // ModeEvent.
  2577 static InterruptMode sInterruptMode = ModeEvent;
  2578 #ifndef XP_WIN
  2579 // Used for the "random" mode.  Controlled by the GECKO_REFLOW_INTERRUPT_SEED
  2580 // env var.
  2581 static uint32_t sInterruptSeed = 1;
  2582 #endif
  2583 // Used for the "counter" mode.  This is the number of unskipped interrupt
  2584 // checks that have to happen before we interrupt.  Controlled by the
  2585 // GECKO_REFLOW_INTERRUPT_FREQUENCY env var.
  2586 static uint32_t sInterruptMaxCounter = 10;
  2587 // Used for the "counter" mode.  This counts up to sInterruptMaxCounter and is
  2588 // then reset to 0.
  2589 static uint32_t sInterruptCounter;
  2590 // Number of interrupt checks to skip before really trying to interrupt.
  2591 // Controlled by the GECKO_REFLOW_INTERRUPT_CHECKS_TO_SKIP env var.
  2592 static uint32_t sInterruptChecksToSkip = 200;
  2593 // Number of milliseconds that a reflow should be allowed to run for before we
  2594 // actually allow interruption.  Controlled by the
  2595 // GECKO_REFLOW_MIN_NOINTERRUPT_DURATION env var.  Can't be initialized here,
  2596 // because TimeDuration/TimeStamp is not safe to use in static constructors..
  2597 static TimeDuration sInterruptTimeout;
  2599 static void GetInterruptEnv()
  2601   char *ev = PR_GetEnv("GECKO_REFLOW_INTERRUPT_MODE");
  2602   if (ev) {
  2603 #ifndef XP_WIN
  2604     if (PL_strcasecmp(ev, "random") == 0) {
  2605       ev = PR_GetEnv("GECKO_REFLOW_INTERRUPT_SEED");
  2606       if (ev) {
  2607         sInterruptSeed = atoi(ev);
  2609       srandom(sInterruptSeed);
  2610       sInterruptMode = ModeRandom;
  2611     } else
  2612 #endif
  2613       if (PL_strcasecmp(ev, "counter") == 0) {
  2614       ev = PR_GetEnv("GECKO_REFLOW_INTERRUPT_FREQUENCY");
  2615       if (ev) {
  2616         sInterruptMaxCounter = atoi(ev);
  2618       sInterruptCounter = 0;
  2619       sInterruptMode = ModeCounter;
  2622   ev = PR_GetEnv("GECKO_REFLOW_INTERRUPT_CHECKS_TO_SKIP");
  2623   if (ev) {
  2624     sInterruptChecksToSkip = atoi(ev);
  2627   ev = PR_GetEnv("GECKO_REFLOW_MIN_NOINTERRUPT_DURATION");
  2628   int duration_ms = ev ? atoi(ev) : 100;
  2629   sInterruptTimeout = TimeDuration::FromMilliseconds(duration_ms);
  2632 bool
  2633 nsPresContext::HavePendingInputEvent()
  2635   switch (sInterruptMode) {
  2636 #ifndef XP_WIN
  2637     case ModeRandom:
  2638       return (random() & 1);
  2639 #endif
  2640     case ModeCounter:
  2641       if (sInterruptCounter < sInterruptMaxCounter) {
  2642         ++sInterruptCounter;
  2643         return false;
  2645       sInterruptCounter = 0;
  2646       return true;
  2647     default:
  2648     case ModeEvent: {
  2649       nsIFrame* f = PresShell()->GetRootFrame();
  2650       if (f) {
  2651         nsIWidget* w = f->GetNearestWidget();
  2652         if (w) {
  2653           return w->HasPendingInputEvent();
  2656       return false;
  2661 void
  2662 nsPresContext::ReflowStarted(bool aInterruptible)
  2664 #ifdef NOISY_INTERRUPTIBLE_REFLOW
  2665   if (!aInterruptible) {
  2666     printf("STARTING NONINTERRUPTIBLE REFLOW\n");
  2668 #endif
  2669   // We don't support interrupting in paginated contexts, since page
  2670   // sequences only handle initial reflow
  2671   mInterruptsEnabled = aInterruptible && !IsPaginated() &&
  2672                        nsLayoutUtils::InterruptibleReflowEnabled();
  2674   // Don't set mHasPendingInterrupt based on HavePendingInputEvent() here.  If
  2675   // we ever change that, then we need to update the code in
  2676   // PresShell::DoReflow to only add the just-reflown root to dirty roots if
  2677   // it's actually dirty.  Otherwise we can end up adding a root that has no
  2678   // interruptible descendants, just because we detected an interrupt at reflow
  2679   // start.
  2680   mHasPendingInterrupt = false;
  2682   mInterruptChecksToSkip = sInterruptChecksToSkip;
  2684   if (mInterruptsEnabled) {
  2685     mReflowStartTime = TimeStamp::Now();
  2689 bool
  2690 nsPresContext::CheckForInterrupt(nsIFrame* aFrame)
  2692   if (mHasPendingInterrupt) {
  2693     mShell->FrameNeedsToContinueReflow(aFrame);
  2694     return true;
  2697   if (!sGotInterruptEnv) {
  2698     sGotInterruptEnv = true;
  2699     GetInterruptEnv();
  2702   if (!mInterruptsEnabled) {
  2703     return false;
  2706   if (mInterruptChecksToSkip > 0) {
  2707     --mInterruptChecksToSkip;
  2708     return false;
  2710   mInterruptChecksToSkip = sInterruptChecksToSkip;
  2712   // Don't interrupt if it's been less than sInterruptTimeout since we started
  2713   // the reflow.
  2714   mHasPendingInterrupt =
  2715     TimeStamp::Now() - mReflowStartTime > sInterruptTimeout &&
  2716     HavePendingInputEvent() &&
  2717     !IsChrome();
  2718   if (mHasPendingInterrupt) {
  2719 #ifdef NOISY_INTERRUPTIBLE_REFLOW
  2720     printf("*** DETECTED pending interrupt (time=%lld)\n", PR_Now());
  2721 #endif /* NOISY_INTERRUPTIBLE_REFLOW */
  2722     mShell->FrameNeedsToContinueReflow(aFrame);
  2724   return mHasPendingInterrupt;
  2727 nsIFrame*
  2728 nsPresContext::GetPrimaryFrameFor(nsIContent* aContent)
  2730   NS_PRECONDITION(aContent, "Don't do that");
  2731   if (GetPresShell() &&
  2732       GetPresShell()->GetDocument() == aContent->GetCurrentDoc()) {
  2733     return aContent->GetPrimaryFrame();
  2735   return nullptr;
  2739 size_t
  2740 nsPresContext::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
  2742   return mPropertyTable.SizeOfExcludingThis(aMallocSizeOf);
  2743          mLangGroupFontPrefs.SizeOfExcludingThis(aMallocSizeOf);
  2745   // Measurement of other members may be added later if DMD finds it is
  2746   // worthwhile.
  2749 bool
  2750 nsPresContext::IsRootContentDocument()
  2752   // We are a root content document if: we are not a resource doc, we are
  2753   // not chrome, and we either have no parent or our parent is chrome.
  2754   if (mDocument->IsResourceDoc()) {
  2755     return false;
  2757   if (IsChrome()) {
  2758     return false;
  2760   // We may not have a root frame, so use views.
  2761   nsView* view = PresShell()->GetViewManager()->GetRootView();
  2762   if (!view) {
  2763     return false;
  2765   view = view->GetParent(); // anonymous inner view
  2766   if (!view) {
  2767     return true;
  2769   view = view->GetParent(); // subdocumentframe's view
  2770   if (!view) {
  2771     return true;
  2774   nsIFrame* f = view->GetFrame();
  2775   return (f && f->PresContext()->IsChrome());
  2778 bool
  2779 nsPresContext::IsCrossProcessRootContentDocument()
  2781   if (!IsRootContentDocument()) {
  2782     return false;
  2785   if (XRE_GetProcessType() == GeckoProcessType_Default) {
  2786     return true;
  2789   TabChild* tabChild = TabChild::GetFrom(mShell);
  2790   return (tabChild && tabChild->IsRootContentDocument());
  2793 bool nsPresContext::GetPaintFlashing() const
  2795   if (!mPaintFlashingInitialized) {
  2796     bool pref = Preferences::GetBool("nglayout.debug.paint_flashing");
  2797     if (!pref && IsChrome()) {
  2798       pref = Preferences::GetBool("nglayout.debug.paint_flashing_chrome");
  2800     mPaintFlashing = pref;
  2801     mPaintFlashingInitialized = true;
  2803   return mPaintFlashing;
  2806 int32_t
  2807 nsPresContext::AppUnitsPerDevPixel() const
  2809   return mDeviceContext->AppUnitsPerDevPixel();
  2812 nscoord
  2813 nsPresContext::GfxUnitsToAppUnits(gfxFloat aGfxUnits) const
  2815   return mDeviceContext->GfxUnitsToAppUnits(aGfxUnits);
  2818 gfxFloat
  2819 nsPresContext::AppUnitsToGfxUnits(nscoord aAppUnits) const
  2821   return mDeviceContext->AppUnitsToGfxUnits(aAppUnits);
  2824 bool
  2825 nsPresContext::IsDeviceSizePageSize()
  2827   bool isDeviceSizePageSize = false;
  2828   nsCOMPtr<nsIDocShell> docShell(mContainer);
  2829   if (docShell) {
  2830     isDeviceSizePageSize = docShell->GetDeviceSizeIsPageSize();
  2832   return isDeviceSizePageSize;
  2835 nsRootPresContext::nsRootPresContext(nsIDocument* aDocument,
  2836                                      nsPresContextType aType)
  2837   : nsPresContext(aDocument, aType),
  2838     mDOMGeneration(0)
  2842 nsRootPresContext::~nsRootPresContext()
  2844   NS_ASSERTION(mRegisteredPlugins.Count() == 0,
  2845                "All plugins should have been unregistered");
  2846   CancelDidPaintTimer();
  2847   CancelApplyPluginGeometryTimer();
  2850 /* virtual */ void
  2851 nsRootPresContext::Detach()
  2853   CancelDidPaintTimer();
  2854   // XXXmats maybe also CancelApplyPluginGeometryTimer(); ?
  2855   nsPresContext::Detach();
  2858 void
  2859 nsRootPresContext::RegisterPluginForGeometryUpdates(nsIContent* aPlugin)
  2861   mRegisteredPlugins.PutEntry(aPlugin);
  2864 void
  2865 nsRootPresContext::UnregisterPluginForGeometryUpdates(nsIContent* aPlugin)
  2867   mRegisteredPlugins.RemoveEntry(aPlugin);
  2870 static PLDHashOperator
  2871 SetPluginHidden(nsRefPtrHashKey<nsIContent>* aEntry, void* userArg)
  2873   nsIFrame* root = static_cast<nsIFrame*>(userArg);
  2874   nsObjectFrame* f = static_cast<nsObjectFrame*>(aEntry->GetKey()->GetPrimaryFrame());
  2875   if (!f) {
  2876     NS_WARNING("Null frame in SetPluginHidden");
  2877     return PL_DHASH_NEXT;
  2879   if (!nsLayoutUtils::IsAncestorFrameCrossDoc(root, f)) {
  2880     // f is not managed by this frame so we should ignore it.
  2881     return PL_DHASH_NEXT;
  2883   f->SetEmptyWidgetConfiguration();
  2884   return PL_DHASH_NEXT;
  2887 void
  2888 nsRootPresContext::ComputePluginGeometryUpdates(nsIFrame* aFrame,
  2889                                                 nsDisplayListBuilder* aBuilder,
  2890                                                 nsDisplayList* aList)
  2892   if (mRegisteredPlugins.Count() == 0) {
  2893     return;
  2896   // Initially make the next state for each plugin descendant of aFrame be
  2897   // "hidden". Plugins that are visible will have their next state set to
  2898   // unhidden by nsDisplayPlugin::ComputeVisibility.
  2899   mRegisteredPlugins.EnumerateEntries(SetPluginHidden, aFrame);
  2901   nsIFrame* rootFrame = FrameManager()->GetRootFrame();
  2903   if (rootFrame && aBuilder->ContainsPluginItem()) {
  2904     aBuilder->SetForPluginGeometry();
  2905     aBuilder->SetAccurateVisibleRegions();
  2906     // Merging and flattening has already been done and we should not do it
  2907     // again. nsDisplayScroll(Info)Layer doesn't support trying to flatten
  2908     // again.
  2909     aBuilder->SetAllowMergingAndFlattening(false);
  2910     nsRegion region = rootFrame->GetVisualOverflowRectRelativeToSelf();
  2911     // nsDisplayPlugin::ComputeVisibility will automatically set a non-hidden
  2912     // widget configuration for the plugin, if it's visible.
  2913     aList->ComputeVisibilityForRoot(aBuilder, &region);
  2916 #ifdef XP_MACOSX
  2917   // We control painting of Mac plugins, so just apply geometry updates now.
  2918   // This is not happening during a paint event.
  2919   ApplyPluginGeometryUpdates();
  2920 #else
  2921   InitApplyPluginGeometryTimer();
  2922 #endif
  2925 static void
  2926 ApplyPluginGeometryUpdatesCallback(nsITimer *aTimer, void *aClosure)
  2928   static_cast<nsRootPresContext*>(aClosure)->ApplyPluginGeometryUpdates();
  2931 void
  2932 nsRootPresContext::InitApplyPluginGeometryTimer()
  2934   if (mApplyPluginGeometryTimer) {
  2935     return;
  2938   // We'll apply the plugin geometry updates during the next compositing paint in this
  2939   // presContext (either from nsPresShell::WillPaintWindow or from
  2940   // nsPresShell::DidPaintWindow, depending on the platform).  But paints might
  2941   // get optimized away if the old plugin geometry covers the invalid region,
  2942   // so set a backup timer to do this too.  We want to make sure this
  2943   // won't fire before our normal paint notifications, if those would
  2944   // update the geometry, so set it for double the refresh driver interval.
  2945   mApplyPluginGeometryTimer = do_CreateInstance("@mozilla.org/timer;1");
  2946   if (mApplyPluginGeometryTimer) {
  2947     mApplyPluginGeometryTimer->
  2948       InitWithFuncCallback(ApplyPluginGeometryUpdatesCallback, this,
  2949                            nsRefreshDriver::DefaultInterval() * 2,
  2950                            nsITimer::TYPE_ONE_SHOT);
  2954 void
  2955 nsRootPresContext::CancelApplyPluginGeometryTimer()
  2957   if (mApplyPluginGeometryTimer) {
  2958     mApplyPluginGeometryTimer->Cancel();
  2959     mApplyPluginGeometryTimer = nullptr;
  2963 static bool
  2964 HasOverlap(const nsIntPoint& aOffset1, const nsTArray<nsIntRect>& aClipRects1,
  2965            const nsIntPoint& aOffset2, const nsTArray<nsIntRect>& aClipRects2)
  2967   nsIntPoint offsetDelta = aOffset1 - aOffset2;
  2968   for (uint32_t i = 0; i < aClipRects1.Length(); ++i) {
  2969     for (uint32_t j = 0; j < aClipRects2.Length(); ++j) {
  2970       if ((aClipRects1[i] + offsetDelta).Intersects(aClipRects2[j]))
  2971         return true;
  2974   return false;
  2977 /**
  2978  * Given a list of plugin windows to move to new locations, sort the list
  2979  * so that for each window move, the window moves to a location that
  2980  * does not intersect other windows. This minimizes flicker and repainting.
  2981  * It's not always possible to do this perfectly, since in general
  2982  * we might have cycles. But we do our best.
  2983  * We need to take into account that windows are clipped to particular
  2984  * regions and the clip regions change as the windows are moved.
  2985  */
  2986 static void
  2987 SortConfigurations(nsTArray<nsIWidget::Configuration>* aConfigurations)
  2989   if (aConfigurations->Length() > 10) {
  2990     // Give up, we don't want to get bogged down here
  2991     return;
  2994   nsTArray<nsIWidget::Configuration> pluginsToMove;
  2995   pluginsToMove.SwapElements(*aConfigurations);
  2997   // Our algorithm is quite naive. At each step we try to identify
  2998   // a window that can be moved to its new location that won't overlap
  2999   // any other windows at the new location. If there is no such
  3000   // window, we just move the last window in the list anyway.
  3001   while (!pluginsToMove.IsEmpty()) {
  3002     // Find a window whose destination does not overlap any other window
  3003     uint32_t i;
  3004     for (i = 0; i + 1 < pluginsToMove.Length(); ++i) {
  3005       nsIWidget::Configuration* config = &pluginsToMove[i];
  3006       bool foundOverlap = false;
  3007       for (uint32_t j = 0; j < pluginsToMove.Length(); ++j) {
  3008         if (i == j)
  3009           continue;
  3010         nsIntRect bounds;
  3011         pluginsToMove[j].mChild->GetBounds(bounds);
  3012         nsAutoTArray<nsIntRect,1> clipRects;
  3013         pluginsToMove[j].mChild->GetWindowClipRegion(&clipRects);
  3014         if (HasOverlap(bounds.TopLeft(), clipRects,
  3015                        config->mBounds.TopLeft(),
  3016                        config->mClipRegion)) {
  3017           foundOverlap = true;
  3018           break;
  3021       if (!foundOverlap)
  3022         break;
  3024     // Note that we always move the last plugin in pluginsToMove, if we
  3025     // can't find any other plugin to move
  3026     aConfigurations->AppendElement(pluginsToMove[i]);
  3027     pluginsToMove.RemoveElementAt(i);
  3031 static PLDHashOperator
  3032 PluginDidSetGeometryEnumerator(nsRefPtrHashKey<nsIContent>* aEntry, void* userArg)
  3034   nsObjectFrame* f = static_cast<nsObjectFrame*>(aEntry->GetKey()->GetPrimaryFrame());
  3035   if (!f) {
  3036     NS_WARNING("Null frame in PluginDidSetGeometryEnumerator");
  3037     return PL_DHASH_NEXT;
  3039   f->DidSetWidgetGeometry();
  3040   return PL_DHASH_NEXT;
  3043 struct PluginGetGeometryUpdateClosure {
  3044   nsTArray<nsIWidget::Configuration> mConfigurations;
  3045 };
  3046 static PLDHashOperator
  3047 PluginGetGeometryUpdate(nsRefPtrHashKey<nsIContent>* aEntry, void* userArg)
  3049   PluginGetGeometryUpdateClosure* closure =
  3050     static_cast<PluginGetGeometryUpdateClosure*>(userArg);
  3051   nsObjectFrame* f = static_cast<nsObjectFrame*>(aEntry->GetKey()->GetPrimaryFrame());
  3052   if (!f) {
  3053     NS_WARNING("Null frame in GetPluginGeometryUpdate");
  3054     return PL_DHASH_NEXT;
  3056   f->GetWidgetConfiguration(&closure->mConfigurations);
  3057   return PL_DHASH_NEXT;
  3060 void
  3061 nsRootPresContext::ApplyPluginGeometryUpdates()
  3063   CancelApplyPluginGeometryTimer();
  3065   PluginGetGeometryUpdateClosure closure;
  3066   mRegisteredPlugins.EnumerateEntries(PluginGetGeometryUpdate, &closure);
  3067   // Walk mRegisteredPlugins and ask each plugin for its configuration
  3068   if (!closure.mConfigurations.IsEmpty()) {
  3069     nsIWidget* widget = closure.mConfigurations[0].mChild->GetParent();
  3070     NS_ASSERTION(widget, "Plugins must have a parent window");
  3071     SortConfigurations(&closure.mConfigurations);
  3072     widget->ConfigureChildren(closure.mConfigurations);
  3074   mRegisteredPlugins.EnumerateEntries(PluginDidSetGeometryEnumerator, nullptr);
  3077 static void
  3078 NotifyDidPaintForSubtreeCallback(nsITimer *aTimer, void *aClosure)
  3080   nsPresContext* presContext = (nsPresContext*)aClosure;
  3081   nsAutoScriptBlocker blockScripts;
  3082   // This is a fallback if we don't get paint events for some reason
  3083   // so we'll just pretend both layer painting and compositing happened.
  3084   presContext->NotifyDidPaintForSubtree(
  3085       nsIPresShell::PAINT_LAYERS | nsIPresShell::PAINT_COMPOSITE);
  3088 void
  3089 nsRootPresContext::EnsureEventualDidPaintEvent()
  3091   if (mNotifyDidPaintTimer)
  3092     return;
  3093   mNotifyDidPaintTimer = do_CreateInstance("@mozilla.org/timer;1");
  3094   if (!mNotifyDidPaintTimer)
  3095     return;
  3096   mNotifyDidPaintTimer->InitWithFuncCallback(NotifyDidPaintForSubtreeCallback,
  3097                                              (void*)this, 100, nsITimer::TYPE_ONE_SHOT);
  3100 void
  3101 nsRootPresContext::AddWillPaintObserver(nsIRunnable* aRunnable)
  3103   if (!mWillPaintFallbackEvent.IsPending()) {
  3104     mWillPaintFallbackEvent = new RunWillPaintObservers(this);
  3105     NS_DispatchToMainThread(mWillPaintFallbackEvent.get());
  3107   mWillPaintObservers.AppendElement(aRunnable);
  3110 /**
  3111  * Run all runnables that need to get called before the next paint.
  3112  */
  3113 void
  3114 nsRootPresContext::FlushWillPaintObservers()
  3116   mWillPaintFallbackEvent = nullptr;
  3117   nsTArray<nsCOMPtr<nsIRunnable> > observers;
  3118   observers.SwapElements(mWillPaintObservers);
  3119   for (uint32_t i = 0; i < observers.Length(); ++i) {
  3120     observers[i]->Run();
  3124 size_t
  3125 nsRootPresContext::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
  3127   return nsPresContext::SizeOfExcludingThis(aMallocSizeOf);
  3129   // Measurement of the following members may be added later if DMD finds it is
  3130   // worthwhile:
  3131   // - mNotifyDidPaintTimer
  3132   // - mRegisteredPlugins
  3133   // - mWillPaintObservers
  3134   // - mWillPaintFallbackEvent

mercurial