layout/base/nsPresContext.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/layout/base/nsPresContext.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,3135 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +/* a presentation of a document, part 1 */
    1.10 +
    1.11 +#include "mozilla/ArrayUtils.h"
    1.12 +#include "mozilla/DebugOnly.h"
    1.13 +#include "mozilla/EventDispatcher.h"
    1.14 +#include "mozilla/EventStateManager.h"
    1.15 +
    1.16 +#include "base/basictypes.h"
    1.17 +
    1.18 +#include "nsCOMPtr.h"
    1.19 +#include "nsPresContext.h"
    1.20 +#include "nsIPresShell.h"
    1.21 +#include "nsDocShell.h"
    1.22 +#include "nsIContentViewer.h"
    1.23 +#include "nsPIDOMWindow.h"
    1.24 +#include "nsStyleSet.h"
    1.25 +#include "nsIContent.h"
    1.26 +#include "nsIFrame.h"
    1.27 +#include "nsIDocument.h"
    1.28 +#include "nsIPrintSettings.h"
    1.29 +#include "nsILanguageAtomService.h"
    1.30 +#include "mozilla/LookAndFeel.h"
    1.31 +#include "nsIInterfaceRequestorUtils.h"
    1.32 +#include "nsIWeakReferenceUtils.h"
    1.33 +#include "nsAutoPtr.h"
    1.34 +#include "nsThreadUtils.h"
    1.35 +#include "nsFrameManager.h"
    1.36 +#include "nsLayoutUtils.h"
    1.37 +#include "nsViewManager.h"
    1.38 +#include "RestyleManager.h"
    1.39 +#include "nsCSSRuleProcessor.h"
    1.40 +#include "nsRuleNode.h"
    1.41 +#include "gfxPlatform.h"
    1.42 +#include "nsCSSRules.h"
    1.43 +#include "nsFontFaceLoader.h"
    1.44 +#include "mozilla/EventListenerManager.h"
    1.45 +#include "prenv.h"
    1.46 +#include "nsObjectFrame.h"
    1.47 +#include "nsTransitionManager.h"
    1.48 +#include "nsAnimationManager.h"
    1.49 +#include "mozilla/MemoryReporting.h"
    1.50 +#include "mozilla/dom/Element.h"
    1.51 +#include "nsIMessageManager.h"
    1.52 +#include "mozilla/dom/MediaQueryList.h"
    1.53 +#include "nsSMILAnimationController.h"
    1.54 +#include "mozilla/css/ImageLoader.h"
    1.55 +#include "mozilla/dom/TabChild.h"
    1.56 +#include "nsRefreshDriver.h"
    1.57 +#include "Layers.h"
    1.58 +#include "nsIDOMEvent.h"
    1.59 +#include "gfxPrefs.h"
    1.60 +#include "nsString.h"
    1.61 +#include "nsUnicharUtils.h"
    1.62 +
    1.63 +#include "nsContentUtils.h"
    1.64 +#include "nsCxPusher.h"
    1.65 +#include "nsPIWindowRoot.h"
    1.66 +#include "mozilla/Preferences.h"
    1.67 +
    1.68 +// Needed for Start/Stop of Image Animation
    1.69 +#include "imgIContainer.h"
    1.70 +#include "nsIImageLoadingContent.h"
    1.71 +
    1.72 +#include "nsCSSParser.h"
    1.73 +#include "nsBidiUtils.h"
    1.74 +#include "nsServiceManagerUtils.h"
    1.75 +
    1.76 +#include "URL.h"
    1.77 +
    1.78 +using namespace mozilla;
    1.79 +using namespace mozilla::dom;
    1.80 +using namespace mozilla::layers;
    1.81 +
    1.82 +uint8_t gNotifySubDocInvalidationData;
    1.83 +
    1.84 +/**
    1.85 + * Layer UserData for ContainerLayers that want to be notified
    1.86 + * of local invalidations of them and their descendant layers.
    1.87 + * Pass a callback to ComputeDifferences to have these called.
    1.88 + */
    1.89 +class ContainerLayerPresContext : public LayerUserData {
    1.90 +public:
    1.91 +  nsPresContext* mPresContext;
    1.92 +};
    1.93 +
    1.94 +namespace {
    1.95 +
    1.96 +class CharSetChangingRunnable : public nsRunnable
    1.97 +{
    1.98 +public:
    1.99 +  CharSetChangingRunnable(nsPresContext* aPresContext,
   1.100 +                          const nsCString& aCharSet)
   1.101 +    : mPresContext(aPresContext),
   1.102 +      mCharSet(aCharSet)
   1.103 +  {
   1.104 +  }
   1.105 +
   1.106 +  NS_IMETHOD Run()
   1.107 +  {
   1.108 +    mPresContext->DoChangeCharSet(mCharSet);
   1.109 +    return NS_OK;
   1.110 +  }
   1.111 +
   1.112 +private:
   1.113 +  nsRefPtr<nsPresContext> mPresContext;
   1.114 +  nsCString mCharSet;
   1.115 +};
   1.116 +
   1.117 +} // anonymous namespace
   1.118 +
   1.119 +nscolor
   1.120 +nsPresContext::MakeColorPref(const nsString& aColor)
   1.121 +{
   1.122 +  nsCSSParser parser;
   1.123 +  nsCSSValue value;
   1.124 +  if (!parser.ParseColorString(aColor, nullptr, 0, value)) {
   1.125 +    // Any better choices?
   1.126 +    return NS_RGB(0, 0, 0);
   1.127 +  }
   1.128 +
   1.129 +  nscolor color;
   1.130 +  return nsRuleNode::ComputeColor(value, this, nullptr, color)
   1.131 +    ? color
   1.132 +    : NS_RGB(0, 0, 0);
   1.133 +}
   1.134 +
   1.135 +bool
   1.136 +nsPresContext::IsDOMPaintEventPending()
   1.137 +{
   1.138 +  if (mFireAfterPaintEvents) {
   1.139 +    return true;
   1.140 +  }
   1.141 +  if (GetDisplayRootPresContext()->GetRootPresContext()->mRefreshDriver->ViewManagerFlushIsPending()) {
   1.142 +    // Since we're promising that there will be a MozAfterPaint event
   1.143 +    // fired, we record an empty invalidation in case display list
   1.144 +    // invalidation doesn't invalidate anything further.
   1.145 +    NotifyInvalidation(nsRect(0, 0, 0, 0), 0);
   1.146 +    NS_ASSERTION(mFireAfterPaintEvents, "Why aren't we planning to fire the event?");
   1.147 +    return true;
   1.148 +  }
   1.149 +  return false;
   1.150 +}
   1.151 +
   1.152 +void
   1.153 +nsPresContext::PrefChangedCallback(const char* aPrefName, void* instance_data)
   1.154 +{
   1.155 +  nsRefPtr<nsPresContext>  presContext =
   1.156 +    static_cast<nsPresContext*>(instance_data);
   1.157 +
   1.158 +  NS_ASSERTION(nullptr != presContext, "bad instance data");
   1.159 +  if (nullptr != presContext) {
   1.160 +    presContext->PreferenceChanged(aPrefName);
   1.161 +  }
   1.162 +}
   1.163 +
   1.164 +void
   1.165 +nsPresContext::PrefChangedUpdateTimerCallback(nsITimer *aTimer, void *aClosure)
   1.166 +{
   1.167 +  nsPresContext*  presContext = (nsPresContext*)aClosure;
   1.168 +  NS_ASSERTION(presContext != nullptr, "bad instance data");
   1.169 +  if (presContext)
   1.170 +    presContext->UpdateAfterPreferencesChanged();
   1.171 +}
   1.172 +
   1.173 +static bool
   1.174 +IsVisualCharset(const nsCString& aCharset)
   1.175 +{
   1.176 +  if (aCharset.LowerCaseEqualsLiteral("ibm862")             // Hebrew
   1.177 +      || aCharset.LowerCaseEqualsLiteral("iso-8859-8") ) {  // Hebrew
   1.178 +    return true; // visual text type
   1.179 +  }
   1.180 +  else {
   1.181 +    return false; // logical text type
   1.182 +  }
   1.183 +}
   1.184 +
   1.185 +  // NOTE! nsPresContext::operator new() zeroes out all members, so don't
   1.186 +  // bother initializing members to 0.
   1.187 +
   1.188 +nsPresContext::nsPresContext(nsIDocument* aDocument, nsPresContextType aType)
   1.189 +  : mType(aType), mDocument(aDocument), mBaseMinFontSize(0),
   1.190 +    mTextZoom(1.0), mFullZoom(1.0), mLastFontInflationScreenWidth(-1.0),
   1.191 +    mPageSize(-1, -1), mPPScale(1.0f),
   1.192 +    mViewportStyleOverflow(NS_STYLE_OVERFLOW_AUTO, NS_STYLE_OVERFLOW_AUTO),
   1.193 +    mImageAnimationModePref(imgIContainer::kNormalAnimMode),
   1.194 +    mAllInvalidated(false),
   1.195 +    mPaintFlashing(false), mPaintFlashingInitialized(false)
   1.196 +{
   1.197 +  // NOTE! nsPresContext::operator new() zeroes out all members, so don't
   1.198 +  // bother initializing members to 0.
   1.199 +
   1.200 +  mDoScaledTwips = true;
   1.201 +
   1.202 +  SetBackgroundImageDraw(true);		// always draw the background
   1.203 +  SetBackgroundColorDraw(true);
   1.204 +
   1.205 +  mBackgroundColor = NS_RGB(0xFF, 0xFF, 0xFF);
   1.206 +
   1.207 +  mUseDocumentColors = true;
   1.208 +  mUseDocumentFonts = true;
   1.209 +
   1.210 +  // the minimum font-size is unconstrained by default
   1.211 +
   1.212 +  mLinkColor = NS_RGB(0x00, 0x00, 0xEE);
   1.213 +  mActiveLinkColor = NS_RGB(0xEE, 0x00, 0x00);
   1.214 +  mVisitedLinkColor = NS_RGB(0x55, 0x1A, 0x8B);
   1.215 +  mUnderlineLinks = true;
   1.216 +  mSendAfterPaintToContent = false;
   1.217 +
   1.218 +  mFocusTextColor = mDefaultColor;
   1.219 +  mFocusBackgroundColor = mBackgroundColor;
   1.220 +  mFocusRingWidth = 1;
   1.221 +
   1.222 +  mBodyTextColor = mDefaultColor;
   1.223 +
   1.224 +  if (aType == eContext_Galley) {
   1.225 +    mMedium = nsGkAtoms::screen;
   1.226 +  } else {
   1.227 +    mMedium = nsGkAtoms::print;
   1.228 +    mPaginated = true;
   1.229 +  }
   1.230 +  mMediaEmulated = mMedium;
   1.231 +
   1.232 +  if (!IsDynamic()) {
   1.233 +    mImageAnimationMode = imgIContainer::kDontAnimMode;
   1.234 +    mNeverAnimate = true;
   1.235 +  } else {
   1.236 +    mImageAnimationMode = imgIContainer::kNormalAnimMode;
   1.237 +    mNeverAnimate = false;
   1.238 +  }
   1.239 +  NS_ASSERTION(mDocument, "Null document");
   1.240 +  mUserFontSet = nullptr;
   1.241 +  mUserFontSetDirty = true;
   1.242 +
   1.243 +  // if text perf logging enabled, init stats struct
   1.244 +  PRLogModuleInfo *log = gfxPlatform::GetLog(eGfxLog_textperf);
   1.245 +  if (log && log->level >= PR_LOG_WARNING) {
   1.246 +    mTextPerf = new gfxTextPerfMetrics();
   1.247 +  }
   1.248 +
   1.249 +  PR_INIT_CLIST(&mDOMMediaQueryLists);
   1.250 +}
   1.251 +
   1.252 +nsPresContext::~nsPresContext()
   1.253 +{
   1.254 +  NS_PRECONDITION(!mShell, "Presshell forgot to clear our mShell pointer");
   1.255 +  SetShell(nullptr);
   1.256 +
   1.257 +  NS_ABORT_IF_FALSE(PR_CLIST_IS_EMPTY(&mDOMMediaQueryLists),
   1.258 +                    "must not have media query lists left");
   1.259 +
   1.260 +  // Disconnect the refresh driver *after* the transition manager, which
   1.261 +  // needs it.
   1.262 +  if (mRefreshDriver && mRefreshDriver->PresContext() == this) {
   1.263 +    mRefreshDriver->Disconnect();
   1.264 +  }
   1.265 +
   1.266 +  if (mEventManager) {
   1.267 +    // unclear if these are needed, but can't hurt
   1.268 +    mEventManager->NotifyDestroyPresContext(this);
   1.269 +    mEventManager->SetPresContext(nullptr);
   1.270 +  }
   1.271 +
   1.272 +  if (mPrefChangedTimer)
   1.273 +  {
   1.274 +    mPrefChangedTimer->Cancel();
   1.275 +    mPrefChangedTimer = nullptr;
   1.276 +  }
   1.277 +
   1.278 +  // Unregister preference callbacks
   1.279 +  Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
   1.280 +                                  "font.",
   1.281 +                                  this);
   1.282 +  Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
   1.283 +                                  "browser.display.",
   1.284 +                                  this);
   1.285 +  Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
   1.286 +                                  "browser.underline_anchors",
   1.287 +                                  this);
   1.288 +  Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
   1.289 +                                  "browser.anchor_color",
   1.290 +                                  this);
   1.291 +  Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
   1.292 +                                  "browser.active_color",
   1.293 +                                  this);
   1.294 +  Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
   1.295 +                                  "browser.visited_color",
   1.296 +                                  this);
   1.297 +  Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
   1.298 +                                  "image.animation_mode",
   1.299 +                                  this);
   1.300 +  Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
   1.301 +                                  "bidi.",
   1.302 +                                  this);
   1.303 +  Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
   1.304 +                                  "dom.send_after_paint_to_content",
   1.305 +                                  this);
   1.306 +  Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
   1.307 +                                  "gfx.font_rendering.",
   1.308 +                                  this);
   1.309 +  Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
   1.310 +                                  "layout.css.dpi",
   1.311 +                                  this);
   1.312 +  Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
   1.313 +                                  "layout.css.devPixelsPerPx",
   1.314 +                                  this);
   1.315 +  Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
   1.316 +                                  "nglayout.debug.paint_flashing",
   1.317 +                                  this);
   1.318 +  Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
   1.319 +                                  "nglayout.debug.paint_flashing_chrome",
   1.320 +                                  this);
   1.321 +}
   1.322 +
   1.323 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsPresContext)
   1.324 +   NS_INTERFACE_MAP_ENTRY(nsISupports)
   1.325 +   NS_INTERFACE_MAP_ENTRY(nsIObserver)
   1.326 +NS_INTERFACE_MAP_END
   1.327 +
   1.328 +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsPresContext)
   1.329 +NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(nsPresContext, LastRelease())
   1.330 +
   1.331 +void
   1.332 +nsPresContext::LastRelease()
   1.333 +{
   1.334 +  if (IsRoot()) {
   1.335 +    static_cast<nsRootPresContext*>(this)->CancelDidPaintTimer();
   1.336 +  }
   1.337 +}
   1.338 +
   1.339 +NS_IMPL_CYCLE_COLLECTION_CLASS(nsPresContext)
   1.340 +
   1.341 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsPresContext)
   1.342 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument);
   1.343 +  // NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mDeviceContext); // not xpcom
   1.344 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEventManager);
   1.345 +  // NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mLanguage); // an atom
   1.346 +
   1.347 +  // We own only the items in mDOMMediaQueryLists that have listeners;
   1.348 +  // this reference is managed by their AddListener and RemoveListener
   1.349 +  // methods.
   1.350 +  for (PRCList *l = PR_LIST_HEAD(&tmp->mDOMMediaQueryLists);
   1.351 +       l != &tmp->mDOMMediaQueryLists; l = PR_NEXT_LINK(l)) {
   1.352 +    MediaQueryList *mql = static_cast<MediaQueryList*>(l);
   1.353 +    if (mql->HasListeners()) {
   1.354 +      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mDOMMediaQueryLists item");
   1.355 +      cb.NoteXPCOMChild(mql);
   1.356 +    }
   1.357 +  }
   1.358 +
   1.359 +  // NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTheme); // a service
   1.360 +  // NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLangService); // a service
   1.361 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrintSettings);
   1.362 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrefChangedTimer);
   1.363 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
   1.364 +
   1.365 +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsPresContext)
   1.366 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument);
   1.367 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDeviceContext); // worth bothering?
   1.368 +  if (tmp->mEventManager) {
   1.369 +    // unclear if these are needed, but can't hurt
   1.370 +    tmp->mEventManager->NotifyDestroyPresContext(tmp);
   1.371 +    tmp->mEventManager->SetPresContext(nullptr);
   1.372 +    tmp->mEventManager = nullptr;
   1.373 +  }
   1.374 +
   1.375 +  // We own only the items in mDOMMediaQueryLists that have listeners;
   1.376 +  // this reference is managed by their AddListener and RemoveListener
   1.377 +  // methods.
   1.378 +  for (PRCList *l = PR_LIST_HEAD(&tmp->mDOMMediaQueryLists);
   1.379 +       l != &tmp->mDOMMediaQueryLists; ) {
   1.380 +    PRCList *next = PR_NEXT_LINK(l);
   1.381 +    MediaQueryList *mql = static_cast<MediaQueryList*>(l);
   1.382 +    mql->RemoveAllListeners();
   1.383 +    l = next;
   1.384 +  }
   1.385 +
   1.386 +  // NS_RELEASE(tmp->mLanguage); // an atom
   1.387 +
   1.388 +  // NS_IMPL_CYCLE_COLLECTION_UNLINK(mTheme); // a service
   1.389 +  // NS_IMPL_CYCLE_COLLECTION_UNLINK(mLangService); // a service
   1.390 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mPrintSettings);
   1.391 +  if (tmp->mPrefChangedTimer)
   1.392 +  {
   1.393 +    tmp->mPrefChangedTimer->Cancel();
   1.394 +    tmp->mPrefChangedTimer = nullptr;
   1.395 +  }
   1.396 +NS_IMPL_CYCLE_COLLECTION_UNLINK_END
   1.397 +
   1.398 +
   1.399 +#define MAKE_FONT_PREF_KEY(_pref, _s0, _s1) \
   1.400 + _pref.Assign(_s0); \
   1.401 + _pref.Append(_s1);
   1.402 +
   1.403 +static const char* const kGenericFont[] = {
   1.404 +  ".variable.",
   1.405 +  ".fixed.",
   1.406 +  ".serif.",
   1.407 +  ".sans-serif.",
   1.408 +  ".monospace.",
   1.409 +  ".cursive.",
   1.410 +  ".fantasy."
   1.411 +};
   1.412 +
   1.413 +// whether no native theme service exists;
   1.414 +// if this gets set to true, we'll stop asking for it.
   1.415 +static bool sNoTheme = false;
   1.416 +
   1.417 +// Set to true when LookAndFeelChanged needs to be called.  This is used
   1.418 +// because the look and feel is a service, so there's no need to notify it from
   1.419 +// more than one prescontext.
   1.420 +static bool sLookAndFeelChanged;
   1.421 +
   1.422 +// Set to true when ThemeChanged needs to be called on mTheme.  This is used
   1.423 +// because mTheme is a service, so there's no need to notify it from more than
   1.424 +// one prescontext.
   1.425 +static bool sThemeChanged;
   1.426 +
   1.427 +const nsPresContext::LangGroupFontPrefs*
   1.428 +nsPresContext::GetFontPrefsForLang(nsIAtom *aLanguage) const
   1.429 +{
   1.430 +  // Get language group for aLanguage:
   1.431 +
   1.432 +  nsresult rv = NS_OK;
   1.433 +  nsIAtom *langGroupAtom = nullptr;
   1.434 +  if (!aLanguage) {
   1.435 +    aLanguage = mLanguage;
   1.436 +  }
   1.437 +  if (aLanguage && mLangService) {
   1.438 +    langGroupAtom = mLangService->GetLanguageGroup(aLanguage, &rv);
   1.439 +  }
   1.440 +  if (NS_FAILED(rv) || !langGroupAtom) {
   1.441 +    langGroupAtom = nsGkAtoms::x_western; // Assume x-western is safe...
   1.442 +  }
   1.443 +
   1.444 +  // Look for cached prefs for this lang group.
   1.445 +  // Most documents will only use one (or very few) language groups. Rather
   1.446 +  // than have the overhead of a hash lookup, we simply look along what will
   1.447 +  // typically be a very short (usually of length 1) linked list. There are 31
   1.448 +  // language groups, so in the worst case scenario we'll need to traverse 31
   1.449 +  // link items.
   1.450 +
   1.451 +  LangGroupFontPrefs *prefs =
   1.452 +    const_cast<LangGroupFontPrefs*>(&mLangGroupFontPrefs);
   1.453 +  if (prefs->mLangGroup) { // if initialized
   1.454 +    DebugOnly<uint32_t> count = 0;
   1.455 +    for (;;) {
   1.456 +      NS_ASSERTION(++count < 35, "Lang group count exceeded!!!");
   1.457 +      if (prefs->mLangGroup == langGroupAtom) {
   1.458 +        return prefs;
   1.459 +      }
   1.460 +      if (!prefs->mNext) {
   1.461 +        break;
   1.462 +      }
   1.463 +      prefs = prefs->mNext;
   1.464 +    }
   1.465 +
   1.466 +    // nothing cached, so go on and fetch the prefs for this lang group:
   1.467 +    prefs = prefs->mNext = new LangGroupFontPrefs;
   1.468 +  }
   1.469 +
   1.470 +  prefs->mLangGroup = langGroupAtom;
   1.471 +
   1.472 +  /* Fetch the font prefs to be used -- see bug 61883 for details.
   1.473 +     Not all prefs are needed upfront. Some are fallback prefs intended
   1.474 +     for the GFX font sub-system...
   1.475 +
   1.476 +  1) unit : assumed to be the same for all language groups -------------
   1.477 +  font.size.unit = px | pt    XXX could be folded in the size... bug 90440
   1.478 +
   1.479 +  2) attributes for generic fonts --------------------------------------
   1.480 +  font.default.[langGroup] = serif | sans-serif - fallback generic font
   1.481 +  font.name.[generic].[langGroup] = current user' selected font on the pref dialog
   1.482 +  font.name-list.[generic].[langGroup] = fontname1, fontname2, ... [factory pre-built list]
   1.483 +  font.size.[generic].[langGroup] = integer - settable by the user
   1.484 +  font.size-adjust.[generic].[langGroup] = "float" - settable by the user
   1.485 +  font.minimum-size.[langGroup] = integer - settable by the user
   1.486 +  */
   1.487 +
   1.488 +  nsAutoCString langGroup;
   1.489 +  langGroupAtom->ToUTF8String(langGroup);
   1.490 +
   1.491 +  prefs->mDefaultVariableFont.size = CSSPixelsToAppUnits(16);
   1.492 +  prefs->mDefaultFixedFont.size = CSSPixelsToAppUnits(13);
   1.493 +
   1.494 +  nsAutoCString pref;
   1.495 +
   1.496 +  // get the current applicable font-size unit
   1.497 +  enum {eUnit_unknown = -1, eUnit_px, eUnit_pt};
   1.498 +  int32_t unit = eUnit_px;
   1.499 +
   1.500 +  nsAdoptingCString cvalue =
   1.501 +    Preferences::GetCString("font.size.unit");
   1.502 +
   1.503 +  if (!cvalue.IsEmpty()) {
   1.504 +    if (cvalue.Equals("px")) {
   1.505 +      unit = eUnit_px;
   1.506 +    }
   1.507 +    else if (cvalue.Equals("pt")) {
   1.508 +      unit = eUnit_pt;
   1.509 +    }
   1.510 +    else {
   1.511 +      // XXX should really send this warning to the user (Error Console?).
   1.512 +      // And just default to unit = eUnit_px?
   1.513 +      NS_WARNING("unexpected font-size unit -- expected: 'px' or 'pt'");
   1.514 +      unit = eUnit_unknown;
   1.515 +    }
   1.516 +  }
   1.517 +
   1.518 +  // get font.minimum-size.[langGroup]
   1.519 +
   1.520 +  MAKE_FONT_PREF_KEY(pref, "font.minimum-size.", langGroup);
   1.521 +
   1.522 +  int32_t size = Preferences::GetInt(pref.get());
   1.523 +  if (unit == eUnit_px) {
   1.524 +    prefs->mMinimumFontSize = CSSPixelsToAppUnits(size);
   1.525 +  }
   1.526 +  else if (unit == eUnit_pt) {
   1.527 +    prefs->mMinimumFontSize = CSSPointsToAppUnits(size);
   1.528 +  }
   1.529 +
   1.530 +  nsFont* fontTypes[] = {
   1.531 +    &prefs->mDefaultVariableFont,
   1.532 +    &prefs->mDefaultFixedFont,
   1.533 +    &prefs->mDefaultSerifFont,
   1.534 +    &prefs->mDefaultSansSerifFont,
   1.535 +    &prefs->mDefaultMonospaceFont,
   1.536 +    &prefs->mDefaultCursiveFont,
   1.537 +    &prefs->mDefaultFantasyFont
   1.538 +  };
   1.539 +  static_assert(MOZ_ARRAY_LENGTH(fontTypes) == eDefaultFont_COUNT,
   1.540 +                "FontTypes array count is not correct");
   1.541 +
   1.542 +  // Get attributes specific to each generic font. We do not get the user's
   1.543 +  // generic-font-name-to-specific-family-name preferences because its the
   1.544 +  // generic name that should be fed into the cascade. It is up to the GFX
   1.545 +  // code to look up the font prefs to convert generic names to specific
   1.546 +  // family names as necessary.
   1.547 +  nsAutoCString generic_dot_langGroup;
   1.548 +  for (uint32_t eType = 0; eType < ArrayLength(fontTypes); ++eType) {
   1.549 +    generic_dot_langGroup.Assign(kGenericFont[eType]);
   1.550 +    generic_dot_langGroup.Append(langGroup);
   1.551 +
   1.552 +    nsFont* font = fontTypes[eType];
   1.553 +
   1.554 +    // set the default variable font (the other fonts are seen as 'generic' fonts
   1.555 +    // in GFX and will be queried there when hunting for alternative fonts)
   1.556 +    if (eType == eDefaultFont_Variable) {
   1.557 +      MAKE_FONT_PREF_KEY(pref, "font.name.variable.", langGroup);
   1.558 +
   1.559 +      nsAdoptingString value = Preferences::GetString(pref.get());
   1.560 +      if (!value.IsEmpty()) {
   1.561 +        prefs->mDefaultVariableFont.name.Assign(value);
   1.562 +      }
   1.563 +      else {
   1.564 +        MAKE_FONT_PREF_KEY(pref, "font.default.", langGroup);
   1.565 +        value = Preferences::GetString(pref.get());
   1.566 +        if (!value.IsEmpty()) {
   1.567 +          prefs->mDefaultVariableFont.name.Assign(value);
   1.568 +        }
   1.569 +      }
   1.570 +    }
   1.571 +    else {
   1.572 +      if (eType == eDefaultFont_Monospace) {
   1.573 +        // This takes care of the confusion whereby people often expect "monospace"
   1.574 +        // to have the same default font-size as "-moz-fixed" (this tentative
   1.575 +        // size may be overwritten with the specific value for "monospace" when
   1.576 +        // "font.size.monospace.[langGroup]" is read -- see below)
   1.577 +        prefs->mDefaultMonospaceFont.size = prefs->mDefaultFixedFont.size;
   1.578 +      }
   1.579 +      else if (eType != eDefaultFont_Fixed) {
   1.580 +        // all the other generic fonts are initialized with the size of the
   1.581 +        // variable font, but their specific size can supersede later -- see below
   1.582 +        font->size = prefs->mDefaultVariableFont.size;
   1.583 +      }
   1.584 +    }
   1.585 +
   1.586 +    // Bug 84398: for spec purists, a different font-size only applies to the
   1.587 +    // .variable. and .fixed. fonts and the other fonts should get |font-size-adjust|.
   1.588 +    // The problem is that only GfxWin has the support for |font-size-adjust|. So for
   1.589 +    // parity, we enable the ability to set a different font-size on all platforms.
   1.590 +
   1.591 +    // get font.size.[generic].[langGroup]
   1.592 +    // size=0 means 'Auto', i.e., generic fonts retain the size of the variable font
   1.593 +    MAKE_FONT_PREF_KEY(pref, "font.size", generic_dot_langGroup);
   1.594 +    size = Preferences::GetInt(pref.get());
   1.595 +    if (size > 0) {
   1.596 +      if (unit == eUnit_px) {
   1.597 +        font->size = CSSPixelsToAppUnits(size);
   1.598 +      }
   1.599 +      else if (unit == eUnit_pt) {
   1.600 +        font->size = CSSPointsToAppUnits(size);
   1.601 +      }
   1.602 +    }
   1.603 +
   1.604 +    // get font.size-adjust.[generic].[langGroup]
   1.605 +    // XXX only applicable on GFX ports that handle |font-size-adjust|
   1.606 +    MAKE_FONT_PREF_KEY(pref, "font.size-adjust", generic_dot_langGroup);
   1.607 +    cvalue = Preferences::GetCString(pref.get());
   1.608 +    if (!cvalue.IsEmpty()) {
   1.609 +      font->sizeAdjust = (float)atof(cvalue.get());
   1.610 +    }
   1.611 +
   1.612 +#ifdef DEBUG_rbs
   1.613 +    printf("%s Family-list:%s size:%d sizeAdjust:%.2f\n",
   1.614 +           generic_dot_langGroup.get(),
   1.615 +           NS_ConvertUTF16toUTF8(font->name).get(), font->size,
   1.616 +           font->sizeAdjust);
   1.617 +#endif
   1.618 +  }
   1.619 +
   1.620 +  return prefs;
   1.621 +}
   1.622 +
   1.623 +void
   1.624 +nsPresContext::GetDocumentColorPreferences()
   1.625 +{
   1.626 +  // Make sure the preferences are initialized.  In the normal run,
   1.627 +  // they would already be, because gfxPlatform would have been created,
   1.628 +  // but in some reference tests, that is not the case.
   1.629 +  gfxPrefs::GetSingleton();
   1.630 +
   1.631 +  int32_t useAccessibilityTheme = 0;
   1.632 +  bool usePrefColors = true;
   1.633 +  bool isChromeDocShell = false;
   1.634 +
   1.635 +  nsIDocument* doc = mDocument->GetDisplayDocument();
   1.636 +  if (doc && doc->GetDocShell()) {
   1.637 +    isChromeDocShell = nsIDocShellTreeItem::typeChrome ==
   1.638 +                       doc->GetDocShell()->ItemType();
   1.639 +  } else {
   1.640 +    nsCOMPtr<nsIDocShellTreeItem> docShell(mContainer);
   1.641 +    if (docShell) {
   1.642 +      isChromeDocShell = nsIDocShellTreeItem::typeChrome == docShell->ItemType();
   1.643 +    }
   1.644 +  }
   1.645 +
   1.646 +  mIsChromeOriginImage = mDocument->IsBeingUsedAsImage() &&
   1.647 +                         IsChromeURI(mDocument->GetDocumentURI());
   1.648 +
   1.649 +  if (isChromeDocShell || mIsChromeOriginImage) {
   1.650 +    usePrefColors = false;
   1.651 +  } else {
   1.652 +    useAccessibilityTheme =
   1.653 +      LookAndFeel::GetInt(LookAndFeel::eIntID_UseAccessibilityTheme, 0);
   1.654 +    usePrefColors = !useAccessibilityTheme;
   1.655 +  }
   1.656 +  if (usePrefColors) {
   1.657 +    usePrefColors =
   1.658 +      !Preferences::GetBool("browser.display.use_system_colors", false);
   1.659 +  }
   1.660 +
   1.661 +  if (usePrefColors) {
   1.662 +    nsAdoptingString colorStr =
   1.663 +      Preferences::GetString("browser.display.foreground_color");
   1.664 +
   1.665 +    if (!colorStr.IsEmpty()) {
   1.666 +      mDefaultColor = MakeColorPref(colorStr);
   1.667 +    }
   1.668 +
   1.669 +    colorStr = Preferences::GetString("browser.display.background_color");
   1.670 +
   1.671 +    if (!colorStr.IsEmpty()) {
   1.672 +      mBackgroundColor = MakeColorPref(colorStr);
   1.673 +    }
   1.674 +  }
   1.675 +  else {
   1.676 +    mDefaultColor =
   1.677 +      LookAndFeel::GetColor(LookAndFeel::eColorID_WindowForeground,
   1.678 +                            NS_RGB(0x00, 0x00, 0x00));
   1.679 +    mBackgroundColor =
   1.680 +      LookAndFeel::GetColor(LookAndFeel::eColorID_WindowBackground,
   1.681 +                            NS_RGB(0xFF, 0xFF, 0xFF));
   1.682 +  }
   1.683 +
   1.684 +  // Wherever we got the default background color from, ensure it is
   1.685 +  // opaque.
   1.686 +  mBackgroundColor = NS_ComposeColors(NS_RGB(0xFF, 0xFF, 0xFF),
   1.687 +                                      mBackgroundColor);
   1.688 +
   1.689 +  mUseDocumentColors = !useAccessibilityTheme &&
   1.690 +    Preferences::GetBool("browser.display.use_document_colors",
   1.691 +                         mUseDocumentColors);
   1.692 +}
   1.693 +
   1.694 +void
   1.695 +nsPresContext::GetUserPreferences()
   1.696 +{
   1.697 +  if (!GetPresShell()) {
   1.698 +    // No presshell means nothing to do here.  We'll do this when we
   1.699 +    // get a presshell.
   1.700 +    return;
   1.701 +  }
   1.702 +
   1.703 +  mAutoQualityMinFontSizePixelsPref =
   1.704 +    Preferences::GetInt("browser.display.auto_quality_min_font_size");
   1.705 +
   1.706 +  // * document colors
   1.707 +  GetDocumentColorPreferences();
   1.708 +
   1.709 +  mSendAfterPaintToContent =
   1.710 +    Preferences::GetBool("dom.send_after_paint_to_content",
   1.711 +                         mSendAfterPaintToContent);
   1.712 +
   1.713 +  // * link colors
   1.714 +  mUnderlineLinks =
   1.715 +    Preferences::GetBool("browser.underline_anchors", mUnderlineLinks);
   1.716 +
   1.717 +  nsAdoptingString colorStr = Preferences::GetString("browser.anchor_color");
   1.718 +
   1.719 +  if (!colorStr.IsEmpty()) {
   1.720 +    mLinkColor = MakeColorPref(colorStr);
   1.721 +  }
   1.722 +
   1.723 +  colorStr = Preferences::GetString("browser.active_color");
   1.724 +
   1.725 +  if (!colorStr.IsEmpty()) {
   1.726 +    mActiveLinkColor = MakeColorPref(colorStr);
   1.727 +  }
   1.728 +
   1.729 +  colorStr = Preferences::GetString("browser.visited_color");
   1.730 +
   1.731 +  if (!colorStr.IsEmpty()) {
   1.732 +    mVisitedLinkColor = MakeColorPref(colorStr);
   1.733 +  }
   1.734 +
   1.735 +  mUseFocusColors =
   1.736 +    Preferences::GetBool("browser.display.use_focus_colors", mUseFocusColors);
   1.737 +
   1.738 +  mFocusTextColor = mDefaultColor;
   1.739 +  mFocusBackgroundColor = mBackgroundColor;
   1.740 +
   1.741 +  colorStr = Preferences::GetString("browser.display.focus_text_color");
   1.742 +
   1.743 +  if (!colorStr.IsEmpty()) {
   1.744 +    mFocusTextColor = MakeColorPref(colorStr);
   1.745 +  }
   1.746 +
   1.747 +  colorStr = Preferences::GetString("browser.display.focus_background_color");
   1.748 +
   1.749 +  if (!colorStr.IsEmpty()) {
   1.750 +    mFocusBackgroundColor = MakeColorPref(colorStr);
   1.751 +  }
   1.752 +
   1.753 +  mFocusRingWidth =
   1.754 +    Preferences::GetInt("browser.display.focus_ring_width", mFocusRingWidth);
   1.755 +
   1.756 +  mFocusRingOnAnything =
   1.757 +    Preferences::GetBool("browser.display.focus_ring_on_anything",
   1.758 +                         mFocusRingOnAnything);
   1.759 +
   1.760 +  mFocusRingStyle =
   1.761 +    Preferences::GetInt("browser.display.focus_ring_style", mFocusRingStyle);
   1.762 +
   1.763 +  mBodyTextColor = mDefaultColor;
   1.764 +
   1.765 +  // * use fonts?
   1.766 +  mUseDocumentFonts =
   1.767 +    Preferences::GetInt("browser.display.use_document_fonts") != 0;
   1.768 +
   1.769 +  mMaxFonts =
   1.770 +    Preferences::GetInt("browser.display.max_font_count", -1);
   1.771 +
   1.772 +  mMaxFontAttempts =
   1.773 +    Preferences::GetInt("browser.display.max_font_attempts", -1);
   1.774 +
   1.775 +  mPrefScrollbarSide = Preferences::GetInt("layout.scrollbar.side");
   1.776 +
   1.777 +  ResetCachedFontPrefs();
   1.778 +
   1.779 +  // * image animation
   1.780 +  const nsAdoptingCString& animatePref =
   1.781 +    Preferences::GetCString("image.animation_mode");
   1.782 +  if (animatePref.Equals("normal"))
   1.783 +    mImageAnimationModePref = imgIContainer::kNormalAnimMode;
   1.784 +  else if (animatePref.Equals("none"))
   1.785 +    mImageAnimationModePref = imgIContainer::kDontAnimMode;
   1.786 +  else if (animatePref.Equals("once"))
   1.787 +    mImageAnimationModePref = imgIContainer::kLoopOnceAnimMode;
   1.788 +  else // dynamic change to invalid value should act like it does initially
   1.789 +    mImageAnimationModePref = imgIContainer::kNormalAnimMode;
   1.790 +
   1.791 +  uint32_t bidiOptions = GetBidi();
   1.792 +
   1.793 +  int32_t prefInt =
   1.794 +    Preferences::GetInt(IBMBIDI_TEXTDIRECTION_STR,
   1.795 +                        GET_BIDI_OPTION_DIRECTION(bidiOptions));
   1.796 +  SET_BIDI_OPTION_DIRECTION(bidiOptions, prefInt);
   1.797 +  mPrefBidiDirection = prefInt;
   1.798 +
   1.799 +  prefInt =
   1.800 +    Preferences::GetInt(IBMBIDI_TEXTTYPE_STR,
   1.801 +                        GET_BIDI_OPTION_TEXTTYPE(bidiOptions));
   1.802 +  SET_BIDI_OPTION_TEXTTYPE(bidiOptions, prefInt);
   1.803 +
   1.804 +  prefInt =
   1.805 +    Preferences::GetInt(IBMBIDI_NUMERAL_STR,
   1.806 +                        GET_BIDI_OPTION_NUMERAL(bidiOptions));
   1.807 +  SET_BIDI_OPTION_NUMERAL(bidiOptions, prefInt);
   1.808 +
   1.809 +  prefInt =
   1.810 +    Preferences::GetInt(IBMBIDI_SUPPORTMODE_STR,
   1.811 +                        GET_BIDI_OPTION_SUPPORT(bidiOptions));
   1.812 +  SET_BIDI_OPTION_SUPPORT(bidiOptions, prefInt);
   1.813 +
   1.814 +  // We don't need to force reflow: either we are initializing a new
   1.815 +  // prescontext or we are being called from UpdateAfterPreferencesChanged()
   1.816 +  // which triggers a reflow anyway.
   1.817 +  SetBidi(bidiOptions, false);
   1.818 +}
   1.819 +
   1.820 +void
   1.821 +nsPresContext::InvalidateThebesLayers()
   1.822 +{
   1.823 +  if (!mShell)
   1.824 +    return;
   1.825 +  nsIFrame* rootFrame = mShell->FrameManager()->GetRootFrame();
   1.826 +  if (rootFrame) {
   1.827 +    // FrameLayerBuilder caches invalidation-related values that depend on the
   1.828 +    // appunits-per-dev-pixel ratio, so ensure that all ThebesLayer drawing
   1.829 +    // is completely flushed.
   1.830 +    rootFrame->InvalidateFrameSubtree();
   1.831 +  }
   1.832 +}
   1.833 +
   1.834 +void
   1.835 +nsPresContext::AppUnitsPerDevPixelChanged()
   1.836 +{
   1.837 +  InvalidateThebesLayers();
   1.838 +
   1.839 +  if (mDeviceContext) {
   1.840 +    mDeviceContext->FlushFontCache();
   1.841 +  }
   1.842 +
   1.843 +  if (HasCachedStyleData()) {
   1.844 +    // All cached style data must be recomputed.
   1.845 +    MediaFeatureValuesChanged(eAlwaysRebuildStyle, NS_STYLE_HINT_REFLOW);
   1.846 +  }
   1.847 +
   1.848 +  mCurAppUnitsPerDevPixel = AppUnitsPerDevPixel();
   1.849 +}
   1.850 +
   1.851 +void
   1.852 +nsPresContext::PreferenceChanged(const char* aPrefName)
   1.853 +{
   1.854 +  nsDependentCString prefName(aPrefName);
   1.855 +  if (prefName.EqualsLiteral("layout.css.dpi") ||
   1.856 +      prefName.EqualsLiteral("layout.css.devPixelsPerPx")) {
   1.857 +    int32_t oldAppUnitsPerDevPixel = AppUnitsPerDevPixel();
   1.858 +    if (mDeviceContext->CheckDPIChange() && mShell) {
   1.859 +      nsCOMPtr<nsIPresShell> shell = mShell;
   1.860 +      // Re-fetch the view manager's window dimensions in case there's a deferred
   1.861 +      // resize which hasn't affected our mVisibleArea yet
   1.862 +      nscoord oldWidthAppUnits, oldHeightAppUnits;
   1.863 +      nsRefPtr<nsViewManager> vm = shell->GetViewManager();
   1.864 +      if (!vm) {
   1.865 +        return;
   1.866 +      }
   1.867 +      vm->GetWindowDimensions(&oldWidthAppUnits, &oldHeightAppUnits);
   1.868 +      float oldWidthDevPixels = oldWidthAppUnits/oldAppUnitsPerDevPixel;
   1.869 +      float oldHeightDevPixels = oldHeightAppUnits/oldAppUnitsPerDevPixel;
   1.870 +
   1.871 +      nscoord width = NSToCoordRound(oldWidthDevPixels*AppUnitsPerDevPixel());
   1.872 +      nscoord height = NSToCoordRound(oldHeightDevPixels*AppUnitsPerDevPixel());
   1.873 +      vm->SetWindowDimensions(width, height);
   1.874 +
   1.875 +      AppUnitsPerDevPixelChanged();
   1.876 +    }
   1.877 +    return;
   1.878 +  }
   1.879 +  if (StringBeginsWith(prefName, NS_LITERAL_CSTRING("font."))) {
   1.880 +    // Changes to font family preferences don't change anything in the
   1.881 +    // computed style data, so the style system won't generate a reflow
   1.882 +    // hint for us.  We need to do that manually.
   1.883 +
   1.884 +    // FIXME We could probably also handle changes to
   1.885 +    // browser.display.auto_quality_min_font_size here, but that
   1.886 +    // probably also requires clearing the text run cache, so don't
   1.887 +    // bother (yet, anyway).
   1.888 +    mPrefChangePendingNeedsReflow = true;
   1.889 +  }
   1.890 +  if (StringBeginsWith(prefName, NS_LITERAL_CSTRING("bidi."))) {
   1.891 +    // Changes to bidi prefs need to trigger a reflow (see bug 443629)
   1.892 +    mPrefChangePendingNeedsReflow = true;
   1.893 +
   1.894 +    // Changes to bidi.numeral also needs to empty the text run cache.
   1.895 +    // This is handled in gfxTextRunWordCache.cpp.
   1.896 +  }
   1.897 +  if (StringBeginsWith(prefName, NS_LITERAL_CSTRING("gfx.font_rendering."))) {
   1.898 +    // Changes to font_rendering prefs need to trigger a reflow
   1.899 +    mPrefChangePendingNeedsReflow = true;
   1.900 +  }
   1.901 +  // we use a zero-delay timer to coalesce multiple pref updates
   1.902 +  if (!mPrefChangedTimer)
   1.903 +  {
   1.904 +    mPrefChangedTimer = do_CreateInstance("@mozilla.org/timer;1");
   1.905 +    if (!mPrefChangedTimer)
   1.906 +      return;
   1.907 +    mPrefChangedTimer->InitWithFuncCallback(nsPresContext::PrefChangedUpdateTimerCallback, (void*)this, 0, nsITimer::TYPE_ONE_SHOT);
   1.908 +  }
   1.909 +  if (prefName.EqualsLiteral("nglayout.debug.paint_flashing") ||
   1.910 +      prefName.EqualsLiteral("nglayout.debug.paint_flashing_chrome")) {
   1.911 +    mPaintFlashingInitialized = false;
   1.912 +    return;
   1.913 +  }
   1.914 +}
   1.915 +
   1.916 +void
   1.917 +nsPresContext::UpdateAfterPreferencesChanged()
   1.918 +{
   1.919 +  mPrefChangedTimer = nullptr;
   1.920 +
   1.921 +  nsCOMPtr<nsIDocShellTreeItem> docShell(mContainer);
   1.922 +  if (docShell && nsIDocShellTreeItem::typeChrome == docShell->ItemType()) {
   1.923 +    return;
   1.924 +  }
   1.925 +
   1.926 +  // Initialize our state from the user preferences
   1.927 +  GetUserPreferences();
   1.928 +
   1.929 +  // update the presShell: tell it to set the preference style rules up
   1.930 +  if (mShell) {
   1.931 +    mShell->SetPreferenceStyleRules(true);
   1.932 +  }
   1.933 +
   1.934 +  InvalidateThebesLayers();
   1.935 +  mDeviceContext->FlushFontCache();
   1.936 +
   1.937 +  nsChangeHint hint = nsChangeHint(0);
   1.938 +
   1.939 +  if (mPrefChangePendingNeedsReflow) {
   1.940 +    NS_UpdateHint(hint, NS_STYLE_HINT_REFLOW);
   1.941 +  }
   1.942 +
   1.943 +  RebuildAllStyleData(hint);
   1.944 +}
   1.945 +
   1.946 +nsresult
   1.947 +nsPresContext::Init(nsDeviceContext* aDeviceContext)
   1.948 +{
   1.949 +  NS_ASSERTION(!mInitialized, "attempt to reinit pres context");
   1.950 +  NS_ENSURE_ARG(aDeviceContext);
   1.951 +
   1.952 +  mDeviceContext = aDeviceContext;
   1.953 +
   1.954 +  if (mDeviceContext->SetPixelScale(mFullZoom))
   1.955 +    mDeviceContext->FlushFontCache();
   1.956 +  mCurAppUnitsPerDevPixel = AppUnitsPerDevPixel();
   1.957 +
   1.958 +  mEventManager = new mozilla::EventStateManager();
   1.959 +
   1.960 +  mTransitionManager = new nsTransitionManager(this);
   1.961 +
   1.962 +  mAnimationManager = new nsAnimationManager(this);
   1.963 +
   1.964 +  // FIXME: Why is mozilla:: needed?
   1.965 +  mRestyleManager = new mozilla::RestyleManager(this);
   1.966 +
   1.967 +  if (mDocument->GetDisplayDocument()) {
   1.968 +    NS_ASSERTION(mDocument->GetDisplayDocument()->GetShell() &&
   1.969 +                 mDocument->GetDisplayDocument()->GetShell()->GetPresContext(),
   1.970 +                 "Why are we being initialized?");
   1.971 +    mRefreshDriver = mDocument->GetDisplayDocument()->GetShell()->
   1.972 +      GetPresContext()->RefreshDriver();
   1.973 +  } else {
   1.974 +    nsIDocument* parent = mDocument->GetParentDocument();
   1.975 +    // Unfortunately, sometimes |parent| here has no presshell because
   1.976 +    // printing screws up things.  Assert that in other cases it does,
   1.977 +    // but whenever the shell is null just fall back on using our own
   1.978 +    // refresh driver.
   1.979 +    NS_ASSERTION(!parent || mDocument->IsStaticDocument() || parent->GetShell(),
   1.980 +                 "How did we end up with a presshell if our parent doesn't "
   1.981 +                 "have one?");
   1.982 +    if (parent && parent->GetShell()) {
   1.983 +      NS_ASSERTION(parent->GetShell()->GetPresContext(),
   1.984 +                   "How did we get a presshell?");
   1.985 +
   1.986 +      // We don't have our container set yet at this point
   1.987 +      nsCOMPtr<nsIDocShellTreeItem> ourItem = mDocument->GetDocShell();
   1.988 +      if (ourItem) {
   1.989 +        nsCOMPtr<nsIDocShellTreeItem> parentItem;
   1.990 +        ourItem->GetSameTypeParent(getter_AddRefs(parentItem));
   1.991 +        if (parentItem) {
   1.992 +          Element* containingElement =
   1.993 +            parent->FindContentForSubDocument(mDocument);
   1.994 +          if (!containingElement->IsXUL() ||
   1.995 +              !containingElement->
   1.996 +                HasAttr(kNameSpaceID_None,
   1.997 +                        nsGkAtoms::forceOwnRefreshDriver)) {
   1.998 +            mRefreshDriver = parent->GetShell()->GetPresContext()->RefreshDriver();
   1.999 +          }
  1.1000 +        }
  1.1001 +      }
  1.1002 +    }
  1.1003 +
  1.1004 +    if (!mRefreshDriver) {
  1.1005 +      mRefreshDriver = new nsRefreshDriver(this);
  1.1006 +    }
  1.1007 +  }
  1.1008 +
  1.1009 +  // Initialise refresh tick counters for OMTA
  1.1010 +  mLastStyleUpdateForAllAnimations =
  1.1011 +    mLastUpdateThrottledAnimationStyle =
  1.1012 +    mLastUpdateThrottledTransitionStyle = mRefreshDriver->MostRecentRefresh();
  1.1013 +
  1.1014 +  mLangService = do_GetService(NS_LANGUAGEATOMSERVICE_CONTRACTID);
  1.1015 +
  1.1016 +  // Register callbacks so we're notified when the preferences change
  1.1017 +  Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
  1.1018 +                                "font.",
  1.1019 +                                this);
  1.1020 +  Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
  1.1021 +                                "browser.display.",
  1.1022 +                                this);
  1.1023 +  Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
  1.1024 +                                "browser.underline_anchors",
  1.1025 +                                this);
  1.1026 +  Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
  1.1027 +                                "browser.anchor_color",
  1.1028 +                                this);
  1.1029 +  Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
  1.1030 +                                "browser.active_color",
  1.1031 +                                this);
  1.1032 +  Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
  1.1033 +                                "browser.visited_color",
  1.1034 +                                this);
  1.1035 +  Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
  1.1036 +                                "image.animation_mode",
  1.1037 +                                this);
  1.1038 +  Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
  1.1039 +                                "bidi.",
  1.1040 +                                this);
  1.1041 +  Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
  1.1042 +                                "dom.send_after_paint_to_content",
  1.1043 +                                this);
  1.1044 +  Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
  1.1045 +                                "gfx.font_rendering.",
  1.1046 +                                this);
  1.1047 +  Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
  1.1048 +                                "layout.css.dpi",
  1.1049 +                                this);
  1.1050 +  Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
  1.1051 +                                "layout.css.devPixelsPerPx",
  1.1052 +                                this);
  1.1053 +  Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
  1.1054 +                                "nglayout.debug.paint_flashing",
  1.1055 +                                this);
  1.1056 +  Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
  1.1057 +                                "nglayout.debug.paint_flashing_chrome",
  1.1058 +                                this);
  1.1059 +
  1.1060 +  nsresult rv = mEventManager->Init();
  1.1061 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1062 +
  1.1063 +  mEventManager->SetPresContext(this);
  1.1064 +
  1.1065 +#ifdef DEBUG
  1.1066 +  mInitialized = true;
  1.1067 +#endif
  1.1068 +
  1.1069 +  mBorderWidthTable[NS_STYLE_BORDER_WIDTH_THIN] = CSSPixelsToAppUnits(1);
  1.1070 +  mBorderWidthTable[NS_STYLE_BORDER_WIDTH_MEDIUM] = CSSPixelsToAppUnits(3);
  1.1071 +  mBorderWidthTable[NS_STYLE_BORDER_WIDTH_THICK] = CSSPixelsToAppUnits(5);
  1.1072 +
  1.1073 +  return NS_OK;
  1.1074 +}
  1.1075 +
  1.1076 +// Note: We don't hold a reference on the shell; it has a reference to
  1.1077 +// us
  1.1078 +void
  1.1079 +nsPresContext::SetShell(nsIPresShell* aShell)
  1.1080 +{
  1.1081 +  if (mUserFontSet) {
  1.1082 +    // Clear out user font set if we have one
  1.1083 +    mUserFontSet->Destroy();
  1.1084 +    NS_RELEASE(mUserFontSet);
  1.1085 +  }
  1.1086 +
  1.1087 +  if (mShell) {
  1.1088 +    // Remove ourselves as the charset observer from the shell's doc, because
  1.1089 +    // this shell may be going away for good.
  1.1090 +    nsIDocument *doc = mShell->GetDocument();
  1.1091 +    if (doc) {
  1.1092 +      doc->RemoveCharSetObserver(this);
  1.1093 +    }
  1.1094 +  }
  1.1095 +
  1.1096 +  mShell = aShell;
  1.1097 +
  1.1098 +  if (mShell) {
  1.1099 +    nsIDocument *doc = mShell->GetDocument();
  1.1100 +    NS_ASSERTION(doc, "expect document here");
  1.1101 +    if (doc) {
  1.1102 +      // Have to update PresContext's mDocument before calling any other methods.
  1.1103 +      mDocument = doc;
  1.1104 +    }
  1.1105 +    // Initialize our state from the user preferences, now that we
  1.1106 +    // have a presshell, and hence a document.
  1.1107 +    GetUserPreferences();
  1.1108 +
  1.1109 +    if (doc) {
  1.1110 +      nsIURI *docURI = doc->GetDocumentURI();
  1.1111 +
  1.1112 +      if (IsDynamic() && docURI) {
  1.1113 +        bool isChrome = false;
  1.1114 +        bool isRes = false;
  1.1115 +        docURI->SchemeIs("chrome", &isChrome);
  1.1116 +        docURI->SchemeIs("resource", &isRes);
  1.1117 +
  1.1118 +        if (!isChrome && !isRes)
  1.1119 +          mImageAnimationMode = mImageAnimationModePref;
  1.1120 +        else
  1.1121 +          mImageAnimationMode = imgIContainer::kNormalAnimMode;
  1.1122 +      }
  1.1123 +
  1.1124 +      if (mLangService) {
  1.1125 +        doc->AddCharSetObserver(this);
  1.1126 +        UpdateCharSet(doc->GetDocumentCharacterSet());
  1.1127 +      }
  1.1128 +    }
  1.1129 +  } else {
  1.1130 +    if (mTransitionManager) {
  1.1131 +      mTransitionManager->Disconnect();
  1.1132 +      mTransitionManager = nullptr;
  1.1133 +    }
  1.1134 +    if (mAnimationManager) {
  1.1135 +      mAnimationManager->Disconnect();
  1.1136 +      mAnimationManager = nullptr;
  1.1137 +    }
  1.1138 +    if (mRestyleManager) {
  1.1139 +      mRestyleManager->Disconnect();
  1.1140 +      mRestyleManager = nullptr;
  1.1141 +    }
  1.1142 +
  1.1143 +    if (IsRoot()) {
  1.1144 +      // Have to cancel our plugin geometry timer, because the
  1.1145 +      // callback for that depends on a non-null presshell.
  1.1146 +      static_cast<nsRootPresContext*>(this)->CancelApplyPluginGeometryTimer();
  1.1147 +    }
  1.1148 +  }
  1.1149 +}
  1.1150 +
  1.1151 +void
  1.1152 +nsPresContext::DoChangeCharSet(const nsCString& aCharSet)
  1.1153 +{
  1.1154 +  UpdateCharSet(aCharSet);
  1.1155 +  mDeviceContext->FlushFontCache();
  1.1156 +  RebuildAllStyleData(NS_STYLE_HINT_REFLOW);
  1.1157 +}
  1.1158 +
  1.1159 +void
  1.1160 +nsPresContext::UpdateCharSet(const nsCString& aCharSet)
  1.1161 +{
  1.1162 +  if (mLangService) {
  1.1163 +    mLanguage = mLangService->LookupCharSet(aCharSet.get());
  1.1164 +    // this will be a language group (or script) code rather than a true language code
  1.1165 +
  1.1166 +    // bug 39570: moved from nsLanguageAtomService::LookupCharSet()
  1.1167 +    if (mLanguage == nsGkAtoms::Unicode) {
  1.1168 +      mLanguage = mLangService->GetLocaleLanguage();
  1.1169 +    }
  1.1170 +    ResetCachedFontPrefs();
  1.1171 +  }
  1.1172 +
  1.1173 +  switch (GET_BIDI_OPTION_TEXTTYPE(GetBidi())) {
  1.1174 +
  1.1175 +    case IBMBIDI_TEXTTYPE_LOGICAL:
  1.1176 +      SetVisualMode(false);
  1.1177 +      break;
  1.1178 +
  1.1179 +    case IBMBIDI_TEXTTYPE_VISUAL:
  1.1180 +      SetVisualMode(true);
  1.1181 +      break;
  1.1182 +
  1.1183 +    case IBMBIDI_TEXTTYPE_CHARSET:
  1.1184 +    default:
  1.1185 +      SetVisualMode(IsVisualCharset(aCharSet));
  1.1186 +  }
  1.1187 +}
  1.1188 +
  1.1189 +NS_IMETHODIMP
  1.1190 +nsPresContext::Observe(nsISupports* aSubject,
  1.1191 +                        const char* aTopic,
  1.1192 +                        const char16_t* aData)
  1.1193 +{
  1.1194 +  if (!nsCRT::strcmp(aTopic, "charset")) {
  1.1195 +    nsRefPtr<CharSetChangingRunnable> runnable =
  1.1196 +      new CharSetChangingRunnable(this, NS_LossyConvertUTF16toASCII(aData));
  1.1197 +    return NS_DispatchToCurrentThread(runnable);
  1.1198 +  }
  1.1199 +
  1.1200 +  NS_WARNING("unrecognized topic in nsPresContext::Observe");
  1.1201 +  return NS_ERROR_FAILURE;
  1.1202 +}
  1.1203 +
  1.1204 +nsPresContext*
  1.1205 +nsPresContext::GetParentPresContext()
  1.1206 +{
  1.1207 +  nsIPresShell* shell = GetPresShell();
  1.1208 +  if (shell) {
  1.1209 +    nsViewManager* viewManager = shell->GetViewManager();
  1.1210 +    if (viewManager) {
  1.1211 +      nsView* view = viewManager->GetRootView();
  1.1212 +      if (view) {
  1.1213 +        view = view->GetParent(); // anonymous inner view
  1.1214 +        if (view) {
  1.1215 +          view = view->GetParent(); // subdocumentframe's view
  1.1216 +          if (view) {
  1.1217 +            nsIFrame* f = view->GetFrame();
  1.1218 +            if (f) {
  1.1219 +              return f->PresContext();
  1.1220 +            }
  1.1221 +          }
  1.1222 +        }
  1.1223 +      }
  1.1224 +    }
  1.1225 +  }
  1.1226 +  return nullptr;
  1.1227 +}
  1.1228 +
  1.1229 +nsPresContext*
  1.1230 +nsPresContext::GetToplevelContentDocumentPresContext()
  1.1231 +{
  1.1232 +  if (IsChrome())
  1.1233 +    return nullptr;
  1.1234 +  nsPresContext* pc = this;
  1.1235 +  for (;;) {
  1.1236 +    nsPresContext* parent = pc->GetParentPresContext();
  1.1237 +    if (!parent || parent->IsChrome())
  1.1238 +      return pc;
  1.1239 +    pc = parent;
  1.1240 +  }
  1.1241 +}
  1.1242 +
  1.1243 +nsIWidget*
  1.1244 +nsPresContext::GetNearestWidget(nsPoint* aOffset)
  1.1245 +{
  1.1246 +  NS_ENSURE_TRUE(mShell, nullptr);
  1.1247 +  nsIFrame* frame = mShell->GetRootFrame();
  1.1248 +  NS_ENSURE_TRUE(frame, nullptr);
  1.1249 +  return frame->GetView()->GetNearestWidget(aOffset);
  1.1250 +}
  1.1251 +
  1.1252 +nsIWidget*
  1.1253 +nsPresContext::GetRootWidget()
  1.1254 +{
  1.1255 +  NS_ENSURE_TRUE(mShell, nullptr);
  1.1256 +  nsViewManager* vm = mShell->GetViewManager();
  1.1257 +  if (!vm) {
  1.1258 +    return nullptr;
  1.1259 +  }
  1.1260 +  nsCOMPtr<nsIWidget> widget;
  1.1261 +  vm->GetRootWidget(getter_AddRefs(widget));
  1.1262 +  return widget.get();
  1.1263 +}
  1.1264 +
  1.1265 +// We may want to replace this with something faster, maybe caching the root prescontext
  1.1266 +nsRootPresContext*
  1.1267 +nsPresContext::GetRootPresContext()
  1.1268 +{
  1.1269 +  nsPresContext* pc = this;
  1.1270 +  for (;;) {
  1.1271 +    nsPresContext* parent = pc->GetParentPresContext();
  1.1272 +    if (!parent)
  1.1273 +      break;
  1.1274 +    pc = parent;
  1.1275 +  }
  1.1276 +  return pc->IsRoot() ? static_cast<nsRootPresContext*>(pc) : nullptr;
  1.1277 +}
  1.1278 +
  1.1279 +nsRootPresContext*
  1.1280 +nsPresContext::GetDisplayRootPresContext()
  1.1281 +{
  1.1282 +  nsPresContext* pc = this;
  1.1283 +  for (;;) {
  1.1284 +    nsPresContext* parent = pc->GetParentPresContext();
  1.1285 +    if (!parent) {
  1.1286 +      // Not sure if this is always strictly the parent, but it works for GetRootPresContext
  1.1287 +      // where the current pres context has no frames.
  1.1288 +      nsIDocument *doc = pc->Document();
  1.1289 +      if (doc) {
  1.1290 +        doc = doc->GetParentDocument();
  1.1291 +        if (doc) {
  1.1292 +          nsIPresShell* shell = doc->GetShell();
  1.1293 +          if (shell) {
  1.1294 +            parent = shell->GetPresContext();
  1.1295 +          }
  1.1296 +        }
  1.1297 +      }
  1.1298 +    }
  1.1299 +    if (!parent || parent == pc)
  1.1300 +      break;
  1.1301 +    pc = parent;
  1.1302 +  }
  1.1303 +  return pc->IsRoot() ? static_cast<nsRootPresContext*>(pc) : nullptr;
  1.1304 +}
  1.1305 +
  1.1306 +void
  1.1307 +nsPresContext::CompatibilityModeChanged()
  1.1308 +{
  1.1309 +  if (!mShell)
  1.1310 +    return;
  1.1311 +
  1.1312 +  // enable/disable the QuirkSheet
  1.1313 +  mShell->StyleSet()->
  1.1314 +    EnableQuirkStyleSheet(CompatibilityMode() == eCompatibility_NavQuirks);
  1.1315 +}
  1.1316 +
  1.1317 +// Helper function for setting Anim Mode on image
  1.1318 +static void SetImgAnimModeOnImgReq(imgIRequest* aImgReq, uint16_t aMode)
  1.1319 +{
  1.1320 +  if (aImgReq) {
  1.1321 +    nsCOMPtr<imgIContainer> imgCon;
  1.1322 +    aImgReq->GetImage(getter_AddRefs(imgCon));
  1.1323 +    if (imgCon) {
  1.1324 +      imgCon->SetAnimationMode(aMode);
  1.1325 +    }
  1.1326 +  }
  1.1327 +}
  1.1328 +
  1.1329 +// IMPORTANT: Assumption is that all images for a Presentation
  1.1330 +// have the same Animation Mode (pavlov said this was OK)
  1.1331 +//
  1.1332 +// Walks content and set the animation mode
  1.1333 +// this is a way to turn on/off image animations
  1.1334 +void nsPresContext::SetImgAnimations(nsIContent *aParent, uint16_t aMode)
  1.1335 +{
  1.1336 +  nsCOMPtr<nsIImageLoadingContent> imgContent(do_QueryInterface(aParent));
  1.1337 +  if (imgContent) {
  1.1338 +    nsCOMPtr<imgIRequest> imgReq;
  1.1339 +    imgContent->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
  1.1340 +                           getter_AddRefs(imgReq));
  1.1341 +    SetImgAnimModeOnImgReq(imgReq, aMode);
  1.1342 +  }
  1.1343 +
  1.1344 +  uint32_t count = aParent->GetChildCount();
  1.1345 +  for (uint32_t i = 0; i < count; ++i) {
  1.1346 +    SetImgAnimations(aParent->GetChildAt(i), aMode);
  1.1347 +  }
  1.1348 +}
  1.1349 +
  1.1350 +void
  1.1351 +nsPresContext::SetSMILAnimations(nsIDocument *aDoc, uint16_t aNewMode,
  1.1352 +                                 uint16_t aOldMode)
  1.1353 +{
  1.1354 +  if (aDoc->HasAnimationController()) {
  1.1355 +    nsSMILAnimationController* controller = aDoc->GetAnimationController();
  1.1356 +    switch (aNewMode)
  1.1357 +    {
  1.1358 +      case imgIContainer::kNormalAnimMode:
  1.1359 +      case imgIContainer::kLoopOnceAnimMode:
  1.1360 +        if (aOldMode == imgIContainer::kDontAnimMode)
  1.1361 +          controller->Resume(nsSMILTimeContainer::PAUSE_USERPREF);
  1.1362 +        break;
  1.1363 +
  1.1364 +      case imgIContainer::kDontAnimMode:
  1.1365 +        if (aOldMode != imgIContainer::kDontAnimMode)
  1.1366 +          controller->Pause(nsSMILTimeContainer::PAUSE_USERPREF);
  1.1367 +        break;
  1.1368 +    }
  1.1369 +  }
  1.1370 +}
  1.1371 +
  1.1372 +void
  1.1373 +nsPresContext::SetImageAnimationModeInternal(uint16_t aMode)
  1.1374 +{
  1.1375 +  NS_ASSERTION(aMode == imgIContainer::kNormalAnimMode ||
  1.1376 +               aMode == imgIContainer::kDontAnimMode ||
  1.1377 +               aMode == imgIContainer::kLoopOnceAnimMode, "Wrong Animation Mode is being set!");
  1.1378 +
  1.1379 +  // Image animation mode cannot be changed when rendering to a printer.
  1.1380 +  if (!IsDynamic())
  1.1381 +    return;
  1.1382 +
  1.1383 +  // Now walk the content tree and set the animation mode
  1.1384 +  // on all the images.
  1.1385 +  if (mShell != nullptr) {
  1.1386 +    nsIDocument *doc = mShell->GetDocument();
  1.1387 +    if (doc) {
  1.1388 +      doc->StyleImageLoader()->SetAnimationMode(aMode);
  1.1389 +
  1.1390 +      Element *rootElement = doc->GetRootElement();
  1.1391 +      if (rootElement) {
  1.1392 +        SetImgAnimations(rootElement, aMode);
  1.1393 +      }
  1.1394 +      SetSMILAnimations(doc, aMode, mImageAnimationMode);
  1.1395 +    }
  1.1396 +  }
  1.1397 +
  1.1398 +  mImageAnimationMode = aMode;
  1.1399 +}
  1.1400 +
  1.1401 +void
  1.1402 +nsPresContext::SetImageAnimationModeExternal(uint16_t aMode)
  1.1403 +{
  1.1404 +  SetImageAnimationModeInternal(aMode);
  1.1405 +}
  1.1406 +
  1.1407 +const nsFont*
  1.1408 +nsPresContext::GetDefaultFont(uint8_t aFontID, nsIAtom *aLanguage) const
  1.1409 +{
  1.1410 +  const LangGroupFontPrefs *prefs = GetFontPrefsForLang(aLanguage);
  1.1411 +
  1.1412 +  const nsFont *font;
  1.1413 +  switch (aFontID) {
  1.1414 +    // Special (our default variable width font and fixed width font)
  1.1415 +    case kPresContext_DefaultVariableFont_ID:
  1.1416 +      font = &prefs->mDefaultVariableFont;
  1.1417 +      break;
  1.1418 +    case kPresContext_DefaultFixedFont_ID:
  1.1419 +      font = &prefs->mDefaultFixedFont;
  1.1420 +      break;
  1.1421 +    // CSS
  1.1422 +    case kGenericFont_serif:
  1.1423 +      font = &prefs->mDefaultSerifFont;
  1.1424 +      break;
  1.1425 +    case kGenericFont_sans_serif:
  1.1426 +      font = &prefs->mDefaultSansSerifFont;
  1.1427 +      break;
  1.1428 +    case kGenericFont_monospace:
  1.1429 +      font = &prefs->mDefaultMonospaceFont;
  1.1430 +      break;
  1.1431 +    case kGenericFont_cursive:
  1.1432 +      font = &prefs->mDefaultCursiveFont;
  1.1433 +      break;
  1.1434 +    case kGenericFont_fantasy:
  1.1435 +      font = &prefs->mDefaultFantasyFont;
  1.1436 +      break;
  1.1437 +    default:
  1.1438 +      font = nullptr;
  1.1439 +      NS_ERROR("invalid arg");
  1.1440 +      break;
  1.1441 +  }
  1.1442 +  return font;
  1.1443 +}
  1.1444 +
  1.1445 +PRBool
  1.1446 +nsPresContext::FontUseCountReached(const nsFont &font) {
  1.1447 +  if (mMaxFonts < 0) {
  1.1448 +    return PR_FALSE;
  1.1449 +  }
  1.1450 +
  1.1451 +  for (PRUint32 i = 0; i < mFontsUsed.Length(); i++) {
  1.1452 +    if (mFontsUsed[i].name.Equals(font.name,
  1.1453 +                                  nsCaseInsensitiveStringComparator())
  1.1454 +        // XXX: Style is sometimes filled with garbage??
  1.1455 +        /*&& mFontsUsed[i].style == font.style*/) {
  1.1456 +      // seen it before: OK
  1.1457 +      return PR_FALSE;
  1.1458 +    }
  1.1459 +  }
  1.1460 +
  1.1461 +  if (mFontsUsed.Length() >= (unsigned)mMaxFonts) {
  1.1462 +    return PR_TRUE;
  1.1463 +  }
  1.1464 +
  1.1465 +  return PR_FALSE;
  1.1466 +}
  1.1467 +
  1.1468 +PRBool
  1.1469 +nsPresContext::FontAttemptCountReached(const nsFont &font) {
  1.1470 +  if (mMaxFontAttempts < 0) {
  1.1471 +    return PR_FALSE;
  1.1472 +  }
  1.1473 +
  1.1474 +  for (PRUint32 i = 0; i < mFontsTried.Length(); i++) {
  1.1475 +    if (mFontsTried[i].name.Equals(font.name,
  1.1476 +                                  nsCaseInsensitiveStringComparator())
  1.1477 +        // XXX: Style is sometimes filled with garbage??
  1.1478 +        /*&& mFontsTried[i].style == font.style*/) {
  1.1479 +      // seen it before: OK
  1.1480 +      return PR_FALSE;
  1.1481 +    }
  1.1482 +  }
  1.1483 +
  1.1484 +  if (mFontsTried.Length() >= (unsigned)mMaxFontAttempts) {
  1.1485 +    return PR_TRUE;
  1.1486 +  }
  1.1487 +
  1.1488 +  return PR_FALSE;
  1.1489 +}
  1.1490 +
  1.1491 +void
  1.1492 +nsPresContext::AddFontUse(const nsFont &font) {
  1.1493 +  if (mMaxFonts < 0) {
  1.1494 +    return;
  1.1495 +  }
  1.1496 +
  1.1497 +  for (PRUint32 i = 0; i < mFontsUsed.Length(); i++) {
  1.1498 +    if (mFontsUsed[i].name.Equals(font.name,
  1.1499 +                                  nsCaseInsensitiveStringComparator())
  1.1500 +        // XXX: Style is sometimes filled with garbage??
  1.1501 +        /*&& mFontsUsed[i].style == font.style*/) {
  1.1502 +      // seen it before: OK
  1.1503 +      return;
  1.1504 +    }
  1.1505 +  }
  1.1506 +
  1.1507 +  if (mFontsUsed.Length() >= (unsigned)mMaxFonts) {
  1.1508 +    return;
  1.1509 +  }
  1.1510 +   
  1.1511 +  mFontsUsed.AppendElement(font);
  1.1512 +  return;
  1.1513 +}
  1.1514 +
  1.1515 +void
  1.1516 +nsPresContext::AddFontAttempt(const nsFont &font) {
  1.1517 +  if (mMaxFontAttempts < 0) {
  1.1518 +    return;
  1.1519 +  }
  1.1520 +
  1.1521 +  for (PRUint32 i = 0; i < mFontsTried.Length(); i++) {
  1.1522 +    if (mFontsTried[i].name.Equals(font.name,
  1.1523 +                                  nsCaseInsensitiveStringComparator())
  1.1524 +        // XXX: Style is sometimes filled with garbage??
  1.1525 +        /*&& mFontsTried[i].style == font.style*/) {
  1.1526 +      // seen it before: OK
  1.1527 +      return;
  1.1528 +    }
  1.1529 +  }
  1.1530 +
  1.1531 +  if (mFontsTried.Length() >= (unsigned)mMaxFontAttempts) {
  1.1532 +    return;
  1.1533 +  }
  1.1534 +   
  1.1535 +  mFontsTried.AppendElement(font);
  1.1536 +  return;
  1.1537 +}
  1.1538 +
  1.1539 +void
  1.1540 +nsPresContext::SetFullZoom(float aZoom)
  1.1541 +{
  1.1542 +  if (!mShell || mFullZoom == aZoom) {
  1.1543 +    return;
  1.1544 +  }
  1.1545 +
  1.1546 +  // Re-fetch the view manager's window dimensions in case there's a deferred
  1.1547 +  // resize which hasn't affected our mVisibleArea yet
  1.1548 +  nscoord oldWidthAppUnits, oldHeightAppUnits;
  1.1549 +  mShell->GetViewManager()->GetWindowDimensions(&oldWidthAppUnits, &oldHeightAppUnits);
  1.1550 +  float oldWidthDevPixels = oldWidthAppUnits / float(mCurAppUnitsPerDevPixel);
  1.1551 +  float oldHeightDevPixels = oldHeightAppUnits / float(mCurAppUnitsPerDevPixel);
  1.1552 +  mDeviceContext->SetPixelScale(aZoom);
  1.1553 +
  1.1554 +  NS_ASSERTION(!mSupressResizeReflow, "two zooms happening at the same time? impossible!");
  1.1555 +  mSupressResizeReflow = true;
  1.1556 +
  1.1557 +  mFullZoom = aZoom;
  1.1558 +  mShell->GetViewManager()->
  1.1559 +    SetWindowDimensions(NSToCoordRound(oldWidthDevPixels * AppUnitsPerDevPixel()),
  1.1560 +                        NSToCoordRound(oldHeightDevPixels * AppUnitsPerDevPixel()));
  1.1561 +
  1.1562 +  AppUnitsPerDevPixelChanged();
  1.1563 +
  1.1564 +  mSupressResizeReflow = false;
  1.1565 +}
  1.1566 +
  1.1567 +float
  1.1568 +nsPresContext::ScreenWidthInchesForFontInflation(bool* aChanged)
  1.1569 +{
  1.1570 +  if (aChanged) {
  1.1571 +    *aChanged = false;
  1.1572 +  }
  1.1573 +
  1.1574 +  nsDeviceContext *dx = DeviceContext();
  1.1575 +  nsRect clientRect;
  1.1576 +  dx->GetClientRect(clientRect); // FIXME: GetClientRect looks expensive
  1.1577 +  float deviceWidthInches =
  1.1578 +    float(clientRect.width) / float(dx->AppUnitsPerPhysicalInch());
  1.1579 +
  1.1580 +  if (mLastFontInflationScreenWidth == -1.0) {
  1.1581 +    mLastFontInflationScreenWidth = deviceWidthInches;
  1.1582 +  }
  1.1583 +
  1.1584 +  if (deviceWidthInches != mLastFontInflationScreenWidth && aChanged) {
  1.1585 +    *aChanged = true;
  1.1586 +    mLastFontInflationScreenWidth = deviceWidthInches;
  1.1587 +  }
  1.1588 +
  1.1589 +  return deviceWidthInches;
  1.1590 +}
  1.1591 +
  1.1592 +void
  1.1593 +nsPresContext::SetContainer(nsIDocShell* aDocShell)
  1.1594 +{
  1.1595 +  if (aDocShell) {
  1.1596 +    mContainer = static_cast<nsDocShell*>(aDocShell)->asWeakPtr();
  1.1597 +  } else {
  1.1598 +    mContainer = WeakPtr<nsDocShell>();
  1.1599 +  }
  1.1600 +  UpdateIsChrome();
  1.1601 +  if (mContainer) {
  1.1602 +    GetDocumentColorPreferences();
  1.1603 +  }
  1.1604 +}
  1.1605 +
  1.1606 +nsISupports*
  1.1607 +nsPresContext::GetContainerWeakInternal() const
  1.1608 +{
  1.1609 +  return static_cast<nsIDocShell*>(mContainer);
  1.1610 +}
  1.1611 +
  1.1612 +nsISupports*
  1.1613 +nsPresContext::GetContainerWeakExternal() const
  1.1614 +{
  1.1615 +  return GetContainerWeakInternal();
  1.1616 +}
  1.1617 +
  1.1618 +nsIDocShell*
  1.1619 +nsPresContext::GetDocShell() const
  1.1620 +{
  1.1621 +  return mContainer;
  1.1622 +}
  1.1623 +
  1.1624 +/* virtual */ void
  1.1625 +nsPresContext::Detach()
  1.1626 +{
  1.1627 +  SetContainer(nullptr);
  1.1628 +  SetLinkHandler(nullptr);
  1.1629 +  if (mShell) {
  1.1630 +    mShell->CancelInvalidatePresShellIfHidden();
  1.1631 +  }
  1.1632 +}
  1.1633 +
  1.1634 +bool
  1.1635 +nsPresContext::ThrottledTransitionStyleIsUpToDate() const
  1.1636 +{
  1.1637 +  return
  1.1638 +    mLastUpdateThrottledTransitionStyle == mRefreshDriver->MostRecentRefresh();
  1.1639 +}
  1.1640 +
  1.1641 +void
  1.1642 +nsPresContext::TickLastUpdateThrottledTransitionStyle()
  1.1643 +{
  1.1644 +  mLastUpdateThrottledTransitionStyle = mRefreshDriver->MostRecentRefresh();
  1.1645 +}
  1.1646 +
  1.1647 +bool
  1.1648 +nsPresContext::ThrottledAnimationStyleIsUpToDate() const
  1.1649 +{
  1.1650 +  return
  1.1651 +    mLastUpdateThrottledAnimationStyle == mRefreshDriver->MostRecentRefresh();
  1.1652 +}
  1.1653 +
  1.1654 +void
  1.1655 +nsPresContext::TickLastUpdateThrottledAnimationStyle()
  1.1656 +{
  1.1657 +  mLastUpdateThrottledAnimationStyle = mRefreshDriver->MostRecentRefresh();
  1.1658 +}
  1.1659 +
  1.1660 +bool
  1.1661 +nsPresContext::StyleUpdateForAllAnimationsIsUpToDate()
  1.1662 +{
  1.1663 +  return mLastStyleUpdateForAllAnimations == mRefreshDriver->MostRecentRefresh();
  1.1664 +}
  1.1665 +
  1.1666 +void
  1.1667 +nsPresContext::TickLastStyleUpdateForAllAnimations()
  1.1668 +{
  1.1669 +  mLastStyleUpdateForAllAnimations = mRefreshDriver->MostRecentRefresh();
  1.1670 +}
  1.1671 +
  1.1672 +bool
  1.1673 +nsPresContext::BidiEnabledExternal() const
  1.1674 +{
  1.1675 +  return BidiEnabledInternal();
  1.1676 +}
  1.1677 +
  1.1678 +bool
  1.1679 +nsPresContext::BidiEnabledInternal() const
  1.1680 +{
  1.1681 +  return Document()->GetBidiEnabled();
  1.1682 +}
  1.1683 +
  1.1684 +void
  1.1685 +nsPresContext::SetBidiEnabled() const
  1.1686 +{
  1.1687 +  if (mShell) {
  1.1688 +    nsIDocument *doc = mShell->GetDocument();
  1.1689 +    if (doc) {
  1.1690 +      doc->SetBidiEnabled();
  1.1691 +    }
  1.1692 +  }
  1.1693 +}
  1.1694 +
  1.1695 +void
  1.1696 +nsPresContext::SetBidi(uint32_t aSource, bool aForceRestyle)
  1.1697 +{
  1.1698 +  // Don't do all this stuff unless the options have changed.
  1.1699 +  if (aSource == GetBidi()) {
  1.1700 +    return;
  1.1701 +  }
  1.1702 +
  1.1703 +  NS_ASSERTION(!(aForceRestyle && (GetBidi() == 0)),
  1.1704 +               "ForceReflow on new prescontext");
  1.1705 +
  1.1706 +  Document()->SetBidiOptions(aSource);
  1.1707 +  if (IBMBIDI_TEXTDIRECTION_RTL == GET_BIDI_OPTION_DIRECTION(aSource)
  1.1708 +      || IBMBIDI_NUMERAL_HINDI == GET_BIDI_OPTION_NUMERAL(aSource)) {
  1.1709 +    SetBidiEnabled();
  1.1710 +  }
  1.1711 +  if (IBMBIDI_TEXTTYPE_VISUAL == GET_BIDI_OPTION_TEXTTYPE(aSource)) {
  1.1712 +    SetVisualMode(true);
  1.1713 +  }
  1.1714 +  else if (IBMBIDI_TEXTTYPE_LOGICAL == GET_BIDI_OPTION_TEXTTYPE(aSource)) {
  1.1715 +    SetVisualMode(false);
  1.1716 +  }
  1.1717 +  else {
  1.1718 +    nsIDocument* doc = mShell->GetDocument();
  1.1719 +    if (doc) {
  1.1720 +      SetVisualMode(IsVisualCharset(doc->GetDocumentCharacterSet()));
  1.1721 +    }
  1.1722 +  }
  1.1723 +  if (aForceRestyle && mShell) {
  1.1724 +    // Reconstruct the root document element's frame and its children,
  1.1725 +    // because we need to trigger frame reconstruction for direction change.
  1.1726 +    RebuildUserFontSet();
  1.1727 +    mShell->ReconstructFrames();
  1.1728 +  }
  1.1729 +}
  1.1730 +
  1.1731 +uint32_t
  1.1732 +nsPresContext::GetBidi() const
  1.1733 +{
  1.1734 +  return Document()->GetBidiOptions();
  1.1735 +}
  1.1736 +
  1.1737 +bool
  1.1738 +nsPresContext::IsTopLevelWindowInactive()
  1.1739 +{
  1.1740 +  nsCOMPtr<nsIDocShellTreeItem> treeItem(mContainer);
  1.1741 +  if (!treeItem)
  1.1742 +    return false;
  1.1743 +
  1.1744 +  nsCOMPtr<nsIDocShellTreeItem> rootItem;
  1.1745 +  treeItem->GetRootTreeItem(getter_AddRefs(rootItem));
  1.1746 +  nsCOMPtr<nsPIDOMWindow> domWindow(do_GetInterface(rootItem));
  1.1747 +
  1.1748 +  return domWindow && !domWindow->IsActive();
  1.1749 +}
  1.1750 +
  1.1751 +nsITheme*
  1.1752 +nsPresContext::GetTheme()
  1.1753 +{
  1.1754 +  if (!sNoTheme && !mTheme) {
  1.1755 +    mTheme = do_GetService("@mozilla.org/chrome/chrome-native-theme;1");
  1.1756 +    if (!mTheme)
  1.1757 +      sNoTheme = true;
  1.1758 +  }
  1.1759 +
  1.1760 +  return mTheme;
  1.1761 +}
  1.1762 +
  1.1763 +void
  1.1764 +nsPresContext::ThemeChanged()
  1.1765 +{
  1.1766 +  if (!mPendingThemeChanged) {
  1.1767 +    sLookAndFeelChanged = true;
  1.1768 +    sThemeChanged = true;
  1.1769 +
  1.1770 +    nsCOMPtr<nsIRunnable> ev =
  1.1771 +      NS_NewRunnableMethod(this, &nsPresContext::ThemeChangedInternal);
  1.1772 +    if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) {
  1.1773 +      mPendingThemeChanged = true;
  1.1774 +    }
  1.1775 +  }
  1.1776 +}
  1.1777 +
  1.1778 +void
  1.1779 +nsPresContext::ThemeChangedInternal()
  1.1780 +{
  1.1781 +  mPendingThemeChanged = false;
  1.1782 +
  1.1783 +  // Tell the theme that it changed, so it can flush any handles to stale theme
  1.1784 +  // data.
  1.1785 +  if (mTheme && sThemeChanged) {
  1.1786 +    mTheme->ThemeChanged();
  1.1787 +    sThemeChanged = false;
  1.1788 +  }
  1.1789 +
  1.1790 +  // Clear all cached LookAndFeel colors.
  1.1791 +  if (sLookAndFeelChanged) {
  1.1792 +    LookAndFeel::Refresh();
  1.1793 +    sLookAndFeelChanged = false;
  1.1794 +  }
  1.1795 +
  1.1796 +  // This will force the system metrics to be generated the next time they're used
  1.1797 +  nsCSSRuleProcessor::FreeSystemMetrics();
  1.1798 +
  1.1799 +  // Changes to system metrics can change media queries on them.
  1.1800 +  // Changes in theme can change system colors (whose changes are
  1.1801 +  // properly reflected in computed style data), system fonts (whose
  1.1802 +  // changes are not), and -moz-appearance (whose changes likewise are
  1.1803 +  // not), so we need to reflow.
  1.1804 +  MediaFeatureValuesChanged(eAlwaysRebuildStyle, NS_STYLE_HINT_REFLOW);
  1.1805 +}
  1.1806 +
  1.1807 +void
  1.1808 +nsPresContext::SysColorChanged()
  1.1809 +{
  1.1810 +  if (!mPendingSysColorChanged) {
  1.1811 +    sLookAndFeelChanged = true;
  1.1812 +    nsCOMPtr<nsIRunnable> ev =
  1.1813 +      NS_NewRunnableMethod(this, &nsPresContext::SysColorChangedInternal);
  1.1814 +    if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) {
  1.1815 +      mPendingSysColorChanged = true;
  1.1816 +    }
  1.1817 +  }
  1.1818 +}
  1.1819 +
  1.1820 +void
  1.1821 +nsPresContext::SysColorChangedInternal()
  1.1822 +{
  1.1823 +  mPendingSysColorChanged = false;
  1.1824 +
  1.1825 +  if (sLookAndFeelChanged) {
  1.1826 +     // Don't use the cached values for the system colors
  1.1827 +    LookAndFeel::Refresh();
  1.1828 +    sLookAndFeelChanged = false;
  1.1829 +  }
  1.1830 +
  1.1831 +  // Reset default background and foreground colors for the document since
  1.1832 +  // they may be using system colors
  1.1833 +  GetDocumentColorPreferences();
  1.1834 +
  1.1835 +  // The system color values are computed to colors in the style data,
  1.1836 +  // so normal style data comparison is sufficient here.
  1.1837 +  RebuildAllStyleData(nsChangeHint(0));
  1.1838 +}
  1.1839 +
  1.1840 +void
  1.1841 +nsPresContext::UIResolutionChanged()
  1.1842 +{
  1.1843 +  if (!mPendingUIResolutionChanged) {
  1.1844 +    nsCOMPtr<nsIRunnable> ev =
  1.1845 +      NS_NewRunnableMethod(this, &nsPresContext::UIResolutionChangedInternal);
  1.1846 +    if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) {
  1.1847 +      mPendingUIResolutionChanged = true;
  1.1848 +    }
  1.1849 +  }
  1.1850 +}
  1.1851 +
  1.1852 +/*static*/ bool
  1.1853 +nsPresContext::UIResolutionChangedSubdocumentCallback(nsIDocument* aDocument,
  1.1854 +                                                      void* aData)
  1.1855 +{
  1.1856 +  nsIPresShell* shell = aDocument->GetShell();
  1.1857 +  if (shell) {
  1.1858 +    nsPresContext* pc = shell->GetPresContext();
  1.1859 +    if (pc) {
  1.1860 +      pc->UIResolutionChangedInternal();
  1.1861 +    }
  1.1862 +  }
  1.1863 +  return true;
  1.1864 +}
  1.1865 +
  1.1866 +void
  1.1867 +nsPresContext::UIResolutionChangedInternal()
  1.1868 +{
  1.1869 +  mPendingUIResolutionChanged = false;
  1.1870 +
  1.1871 +  mDeviceContext->CheckDPIChange();
  1.1872 +  if (mCurAppUnitsPerDevPixel != AppUnitsPerDevPixel()) {
  1.1873 +    AppUnitsPerDevPixelChanged();
  1.1874 +  }
  1.1875 +
  1.1876 +  mDocument->EnumerateSubDocuments(UIResolutionChangedSubdocumentCallback,
  1.1877 +                                   nullptr);
  1.1878 +}
  1.1879 +
  1.1880 +void
  1.1881 +nsPresContext::EmulateMedium(const nsAString& aMediaType)
  1.1882 +{
  1.1883 +  nsIAtom* previousMedium = Medium();
  1.1884 +  mIsEmulatingMedia = true;
  1.1885 +
  1.1886 +  nsAutoString mediaType;
  1.1887 +  nsContentUtils::ASCIIToLower(aMediaType, mediaType);
  1.1888 +
  1.1889 +  mMediaEmulated = do_GetAtom(mediaType);
  1.1890 +  if (mMediaEmulated != previousMedium && mShell) {
  1.1891 +    MediaFeatureValuesChanged(eRebuildStyleIfNeeded, nsChangeHint(0));
  1.1892 +  }
  1.1893 +}
  1.1894 +
  1.1895 +void nsPresContext::StopEmulatingMedium()
  1.1896 +{
  1.1897 +  nsIAtom* previousMedium = Medium();
  1.1898 +  mIsEmulatingMedia = false;
  1.1899 +  if (Medium() != previousMedium) {
  1.1900 +    MediaFeatureValuesChanged(eRebuildStyleIfNeeded, nsChangeHint(0));
  1.1901 +  }
  1.1902 +}
  1.1903 +
  1.1904 +void
  1.1905 +nsPresContext::RebuildAllStyleData(nsChangeHint aExtraHint)
  1.1906 +{
  1.1907 +  if (!mShell) {
  1.1908 +    // We must have been torn down. Nothing to do here.
  1.1909 +    return;
  1.1910 +  }
  1.1911 +
  1.1912 +  mUsesRootEMUnits = false;
  1.1913 +  mUsesViewportUnits = false;
  1.1914 +  RebuildUserFontSet();
  1.1915 +
  1.1916 +  RestyleManager()->RebuildAllStyleData(aExtraHint);
  1.1917 +}
  1.1918 +
  1.1919 +void
  1.1920 +nsPresContext::PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint)
  1.1921 +{
  1.1922 +  if (!mShell) {
  1.1923 +    // We must have been torn down. Nothing to do here.
  1.1924 +    return;
  1.1925 +  }
  1.1926 +  RestyleManager()->PostRebuildAllStyleDataEvent(aExtraHint);
  1.1927 +}
  1.1928 +
  1.1929 +void
  1.1930 +nsPresContext::MediaFeatureValuesChanged(StyleRebuildType aShouldRebuild,
  1.1931 +                                         nsChangeHint aChangeHint)
  1.1932 +{
  1.1933 +  NS_ASSERTION(aShouldRebuild == eAlwaysRebuildStyle || aChangeHint == 0,
  1.1934 +               "If you don't know if we need a rebuild, how can you provide a hint?");
  1.1935 +
  1.1936 +  mPendingMediaFeatureValuesChanged = false;
  1.1937 +
  1.1938 +  // MediumFeaturesChanged updates the applied rules, so it always gets called.
  1.1939 +  bool mediaFeaturesDidChange = mShell ? mShell->StyleSet()->MediumFeaturesChanged(this)
  1.1940 +                                       : false;
  1.1941 +
  1.1942 +  if (aShouldRebuild == eAlwaysRebuildStyle ||
  1.1943 +      mediaFeaturesDidChange ||
  1.1944 +      (mUsesViewportUnits && mPendingViewportChange)) {
  1.1945 +    RebuildAllStyleData(aChangeHint);
  1.1946 +  }
  1.1947 +
  1.1948 +  mPendingViewportChange = false;
  1.1949 +
  1.1950 +  if (!nsContentUtils::IsSafeToRunScript()) {
  1.1951 +    NS_ABORT_IF_FALSE(mDocument->IsBeingUsedAsImage(),
  1.1952 +                      "How did we get here?  Are we failing to notify "
  1.1953 +                      "listeners that we should notify?");
  1.1954 +    return;
  1.1955 +  }
  1.1956 +
  1.1957 +  // Media query list listeners should be notified from a queued task
  1.1958 +  // (in HTML5 terms), although we also want to notify them on certain
  1.1959 +  // flushes.  (We're already running off an event.)
  1.1960 +  //
  1.1961 +  // Note that we do this after the new style from media queries in
  1.1962 +  // style sheets has been computed.
  1.1963 +
  1.1964 +  if (!PR_CLIST_IS_EMPTY(&mDOMMediaQueryLists)) {
  1.1965 +    // We build a list of all the notifications we're going to send
  1.1966 +    // before we send any of them.  (The spec says the notifications
  1.1967 +    // should be a queued task, so any removals that happen during the
  1.1968 +    // notifications shouldn't affect what gets notified.)  Furthermore,
  1.1969 +    // we hold strong pointers to everything we're going to make
  1.1970 +    // notification calls to, since each notification involves calling
  1.1971 +    // arbitrary script that might otherwise destroy these objects, or,
  1.1972 +    // for that matter, |this|.
  1.1973 +    //
  1.1974 +    // Note that we intentionally send the notifications to media query
  1.1975 +    // list in the order they were created and, for each list, to the
  1.1976 +    // listeners in the order added.
  1.1977 +    MediaQueryList::NotifyList notifyList;
  1.1978 +    for (PRCList *l = PR_LIST_HEAD(&mDOMMediaQueryLists);
  1.1979 +         l != &mDOMMediaQueryLists; l = PR_NEXT_LINK(l)) {
  1.1980 +      MediaQueryList *mql = static_cast<MediaQueryList*>(l);
  1.1981 +      mql->MediumFeaturesChanged(notifyList);
  1.1982 +    }
  1.1983 +
  1.1984 +    if (!notifyList.IsEmpty()) {
  1.1985 +      nsPIDOMWindow *win = mDocument->GetInnerWindow();
  1.1986 +      nsCOMPtr<EventTarget> et = do_QueryInterface(win);
  1.1987 +      nsCxPusher pusher;
  1.1988 +
  1.1989 +      for (uint32_t i = 0, i_end = notifyList.Length(); i != i_end; ++i) {
  1.1990 +        if (pusher.RePush(et)) {
  1.1991 +          nsAutoMicroTask mt;
  1.1992 +          MediaQueryList::HandleChangeData &d = notifyList[i];
  1.1993 +          ErrorResult result;
  1.1994 +          d.callback->Call(*d.mql, result);
  1.1995 +        }
  1.1996 +      }
  1.1997 +    }
  1.1998 +
  1.1999 +    // NOTE:  When |notifyList| goes out of scope, our destructor could run.
  1.2000 +  }
  1.2001 +}
  1.2002 +
  1.2003 +void
  1.2004 +nsPresContext::PostMediaFeatureValuesChangedEvent()
  1.2005 +{
  1.2006 +  // FIXME: We should probably replace this event with use of
  1.2007 +  // nsRefreshDriver::AddStyleFlushObserver (except the pres shell would
  1.2008 +  // need to track whether it's been added).
  1.2009 +  if (!mPendingMediaFeatureValuesChanged) {
  1.2010 +    nsCOMPtr<nsIRunnable> ev =
  1.2011 +      NS_NewRunnableMethod(this, &nsPresContext::HandleMediaFeatureValuesChangedEvent);
  1.2012 +    if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) {
  1.2013 +      mPendingMediaFeatureValuesChanged = true;
  1.2014 +      mDocument->SetNeedStyleFlush();
  1.2015 +    }
  1.2016 +  }
  1.2017 +}
  1.2018 +
  1.2019 +void
  1.2020 +nsPresContext::HandleMediaFeatureValuesChangedEvent()
  1.2021 +{
  1.2022 +  // Null-check mShell in case the shell has been destroyed (and the
  1.2023 +  // event is the only thing holding the pres context alive).
  1.2024 +  if (mPendingMediaFeatureValuesChanged && mShell) {
  1.2025 +    MediaFeatureValuesChanged(eRebuildStyleIfNeeded);
  1.2026 +  }
  1.2027 +}
  1.2028 +
  1.2029 +already_AddRefed<MediaQueryList>
  1.2030 +nsPresContext::MatchMedia(const nsAString& aMediaQueryList)
  1.2031 +{
  1.2032 +  nsRefPtr<MediaQueryList> result = new MediaQueryList(this, aMediaQueryList);
  1.2033 +
  1.2034 +  // Insert the new item at the end of the linked list.
  1.2035 +  PR_INSERT_BEFORE(result, &mDOMMediaQueryLists);
  1.2036 +
  1.2037 +  return result.forget();
  1.2038 +}
  1.2039 +
  1.2040 +nsCompatibility
  1.2041 +nsPresContext::CompatibilityMode() const
  1.2042 +{
  1.2043 +  return Document()->GetCompatibilityMode();
  1.2044 +}
  1.2045 +
  1.2046 +void
  1.2047 +nsPresContext::SetPaginatedScrolling(bool aPaginated)
  1.2048 +{
  1.2049 +  if (mType == eContext_PrintPreview || mType == eContext_PageLayout)
  1.2050 +    mCanPaginatedScroll = aPaginated;
  1.2051 +}
  1.2052 +
  1.2053 +void
  1.2054 +nsPresContext::SetPrintSettings(nsIPrintSettings *aPrintSettings)
  1.2055 +{
  1.2056 +  if (mMedium == nsGkAtoms::print)
  1.2057 +    mPrintSettings = aPrintSettings;
  1.2058 +}
  1.2059 +
  1.2060 +bool
  1.2061 +nsPresContext::EnsureVisible()
  1.2062 +{
  1.2063 +  nsCOMPtr<nsIDocShell> docShell(mContainer);
  1.2064 +  if (docShell) {
  1.2065 +    nsCOMPtr<nsIContentViewer> cv;
  1.2066 +    docShell->GetContentViewer(getter_AddRefs(cv));
  1.2067 +    // Make sure this is the content viewer we belong with
  1.2068 +    if (cv) {
  1.2069 +      nsRefPtr<nsPresContext> currentPresContext;
  1.2070 +      cv->GetPresContext(getter_AddRefs(currentPresContext));
  1.2071 +      if (currentPresContext == this) {
  1.2072 +        // OK, this is us.  We want to call Show() on the content viewer.
  1.2073 +        nsresult result = cv->Show();
  1.2074 +        if (NS_SUCCEEDED(result)) {
  1.2075 +          return true;
  1.2076 +        }
  1.2077 +      }
  1.2078 +    }
  1.2079 +  }
  1.2080 +  return false;
  1.2081 +}
  1.2082 +
  1.2083 +#ifdef MOZ_REFLOW_PERF
  1.2084 +void
  1.2085 +nsPresContext::CountReflows(const char * aName, nsIFrame * aFrame)
  1.2086 +{
  1.2087 +  if (mShell) {
  1.2088 +    mShell->CountReflows(aName, aFrame);
  1.2089 +  }
  1.2090 +}
  1.2091 +#endif
  1.2092 +
  1.2093 +void
  1.2094 +nsPresContext::UpdateIsChrome()
  1.2095 +{
  1.2096 +  mIsChrome = mContainer &&
  1.2097 +              nsIDocShellTreeItem::typeChrome == mContainer->ItemType();
  1.2098 +}
  1.2099 +
  1.2100 +/* virtual */ bool
  1.2101 +nsPresContext::HasAuthorSpecifiedRules(nsIFrame *aFrame, uint32_t ruleTypeMask) const
  1.2102 +{
  1.2103 +  return
  1.2104 +    nsRuleNode::HasAuthorSpecifiedRules(aFrame->StyleContext(),
  1.2105 +                                        ruleTypeMask,
  1.2106 +                                        UseDocumentColors());
  1.2107 +}
  1.2108 +
  1.2109 +gfxUserFontSet*
  1.2110 +nsPresContext::GetUserFontSetInternal()
  1.2111 +{
  1.2112 +  // We want to initialize the user font set lazily the first time the
  1.2113 +  // user asks for it, rather than building it too early and forcing
  1.2114 +  // rule cascade creation.  Thus we try to enforce the invariant that
  1.2115 +  // we *never* build the user font set until the first call to
  1.2116 +  // GetUserFontSet.  However, once it's been requested, we can't wait
  1.2117 +  // for somebody to call GetUserFontSet in order to rebuild it (see
  1.2118 +  // comments below in RebuildUserFontSet for why).
  1.2119 +#ifdef DEBUG
  1.2120 +  bool userFontSetGottenBefore = mGetUserFontSetCalled;
  1.2121 +#endif
  1.2122 +  // Set mGetUserFontSetCalled up front, so that FlushUserFontSet will actually
  1.2123 +  // flush.
  1.2124 +  mGetUserFontSetCalled = true;
  1.2125 +  if (mUserFontSetDirty) {
  1.2126 +    // If this assertion fails, and there have actually been changes to
  1.2127 +    // @font-face rules, then we will call StyleChangeReflow in
  1.2128 +    // FlushUserFontSet.  If we're in the middle of reflow,
  1.2129 +    // that's a bad thing to do, and the caller was responsible for
  1.2130 +    // flushing first.  If we're not (e.g., in frame construction), it's
  1.2131 +    // ok.
  1.2132 +    NS_ASSERTION(!userFontSetGottenBefore || !mShell->IsReflowLocked(),
  1.2133 +                 "FlushUserFontSet should have been called first");
  1.2134 +    FlushUserFontSet();
  1.2135 +  }
  1.2136 +
  1.2137 +  return mUserFontSet;
  1.2138 +}
  1.2139 +
  1.2140 +gfxUserFontSet*
  1.2141 +nsPresContext::GetUserFontSetExternal()
  1.2142 +{
  1.2143 +  return GetUserFontSetInternal();
  1.2144 +}
  1.2145 +
  1.2146 +void
  1.2147 +nsPresContext::FlushUserFontSet()
  1.2148 +{
  1.2149 +  if (!mShell) {
  1.2150 +    return; // we've been torn down
  1.2151 +  }
  1.2152 +
  1.2153 +  if (!mGetUserFontSetCalled) {
  1.2154 +    return; // No one cares about this font set yet, but we want to be careful
  1.2155 +            // to not unset our mUserFontSetDirty bit, so when someone really
  1.2156 +            // does we'll create it.
  1.2157 +  }
  1.2158 +
  1.2159 +  if (mUserFontSetDirty) {
  1.2160 +    if (gfxPlatform::GetPlatform()->DownloadableFontsEnabled()) {
  1.2161 +      nsTArray<nsFontFaceRuleContainer> rules;
  1.2162 +      if (!mShell->StyleSet()->AppendFontFaceRules(this, rules)) {
  1.2163 +        if (mUserFontSet) {
  1.2164 +          mUserFontSet->Destroy();
  1.2165 +          NS_RELEASE(mUserFontSet);
  1.2166 +        }
  1.2167 +        return;
  1.2168 +      }
  1.2169 +
  1.2170 +      bool changed = false;
  1.2171 +
  1.2172 +      if (rules.Length() == 0) {
  1.2173 +        if (mUserFontSet) {
  1.2174 +          mUserFontSet->Destroy();
  1.2175 +          NS_RELEASE(mUserFontSet);
  1.2176 +          changed = true;
  1.2177 +        }
  1.2178 +      } else {
  1.2179 +        if (!mUserFontSet) {
  1.2180 +          mUserFontSet = new nsUserFontSet(this);
  1.2181 +          NS_ADDREF(mUserFontSet);
  1.2182 +        }
  1.2183 +        changed = mUserFontSet->UpdateRules(rules);
  1.2184 +      }
  1.2185 +
  1.2186 +      // We need to enqueue a style change reflow (for later) to
  1.2187 +      // reflect that we're modifying @font-face rules.  (However,
  1.2188 +      // without a reflow, nothing will happen to start any downloads
  1.2189 +      // that are needed.)
  1.2190 +      if (changed) {
  1.2191 +        UserFontSetUpdated();
  1.2192 +      }
  1.2193 +    }
  1.2194 +
  1.2195 +    mUserFontSetDirty = false;
  1.2196 +  }
  1.2197 +}
  1.2198 +
  1.2199 +void
  1.2200 +nsPresContext::RebuildUserFontSet()
  1.2201 +{
  1.2202 +  if (!mGetUserFontSetCalled) {
  1.2203 +    // We want to lazily build the user font set the first time it's
  1.2204 +    // requested (so we don't force creation of rule cascades too
  1.2205 +    // early), so don't do anything now.
  1.2206 +    return;
  1.2207 +  }
  1.2208 +
  1.2209 +  mUserFontSetDirty = true;
  1.2210 +  mDocument->SetNeedStyleFlush();
  1.2211 +
  1.2212 +  // Somebody has already asked for the user font set, so we need to
  1.2213 +  // post an event to rebuild it.  Setting the user font set to be dirty
  1.2214 +  // and lazily rebuilding it isn't sufficient, since it is only the act
  1.2215 +  // of rebuilding it that will trigger the style change reflow that
  1.2216 +  // calls GetUserFontSet.  (This reflow causes rebuilding of text runs,
  1.2217 +  // which starts font loads, whose completion causes another style
  1.2218 +  // change reflow).
  1.2219 +  if (!mPostedFlushUserFontSet) {
  1.2220 +    nsCOMPtr<nsIRunnable> ev =
  1.2221 +      NS_NewRunnableMethod(this, &nsPresContext::HandleRebuildUserFontSet);
  1.2222 +    if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) {
  1.2223 +      mPostedFlushUserFontSet = true;
  1.2224 +    }
  1.2225 +  }
  1.2226 +}
  1.2227 +
  1.2228 +void
  1.2229 +nsPresContext::UserFontSetUpdated()
  1.2230 +{
  1.2231 +  if (!mShell)
  1.2232 +    return;
  1.2233 +
  1.2234 +  // Changes to the set of available fonts can cause updates to layout by:
  1.2235 +  //
  1.2236 +  //   1. Changing the font used for text, which changes anything that
  1.2237 +  //      depends on text measurement, including line breaking and
  1.2238 +  //      intrinsic widths, and any other parts of layout that depend on
  1.2239 +  //      font metrics.  This requires a style change reflow to update.
  1.2240 +  //
  1.2241 +  //   2. Changing the value of the 'ex' and 'ch' units in style data,
  1.2242 +  //      which also depend on font metrics.  Updating this information
  1.2243 +  //      requires rebuilding the rule tree from the top, avoiding the
  1.2244 +  //      reuse of cached data even when no style rules have changed.
  1.2245 +
  1.2246 +  PostRebuildAllStyleDataEvent(NS_STYLE_HINT_REFLOW);
  1.2247 +}
  1.2248 +
  1.2249 +void
  1.2250 +nsPresContext::EnsureSafeToHandOutCSSRules()
  1.2251 +{
  1.2252 +  nsCSSStyleSheet::EnsureUniqueInnerResult res =
  1.2253 +    mShell->StyleSet()->EnsureUniqueInnerOnCSSSheets();
  1.2254 +  if (res == nsCSSStyleSheet::eUniqueInner_AlreadyUnique) {
  1.2255 +    // Nothing to do.
  1.2256 +    return;
  1.2257 +  }
  1.2258 +
  1.2259 +  MOZ_ASSERT(res == nsCSSStyleSheet::eUniqueInner_ClonedInner);
  1.2260 +  RebuildAllStyleData(nsChangeHint(0));
  1.2261 +}
  1.2262 +
  1.2263 +void
  1.2264 +nsPresContext::FireDOMPaintEvent(nsInvalidateRequestList* aList)
  1.2265 +{
  1.2266 +  nsPIDOMWindow* ourWindow = mDocument->GetWindow();
  1.2267 +  if (!ourWindow)
  1.2268 +    return;
  1.2269 +
  1.2270 +  nsCOMPtr<EventTarget> dispatchTarget = do_QueryInterface(ourWindow);
  1.2271 +  nsCOMPtr<EventTarget> eventTarget = dispatchTarget;
  1.2272 +  if (!IsChrome() && !mSendAfterPaintToContent) {
  1.2273 +    // Don't tell the window about this event, it should not know that
  1.2274 +    // something happened in a subdocument. Tell only the chrome event handler.
  1.2275 +    // (Events sent to the window get propagated to the chrome event handler
  1.2276 +    // automatically.)
  1.2277 +    dispatchTarget = do_QueryInterface(ourWindow->GetParentTarget());
  1.2278 +    if (!dispatchTarget) {
  1.2279 +      return;
  1.2280 +    }
  1.2281 +  }
  1.2282 +  // Events sent to the window get propagated to the chrome event handler
  1.2283 +  // automatically.
  1.2284 +  nsCOMPtr<nsIDOMEvent> event;
  1.2285 +  // This will empty our list in case dispatching the event causes more damage
  1.2286 +  // (hopefully it won't, or we're likely to get an infinite loop! At least
  1.2287 +  // it won't be blocking app execution though).
  1.2288 +  NS_NewDOMNotifyPaintEvent(getter_AddRefs(event), eventTarget, this, nullptr,
  1.2289 +                            NS_AFTERPAINT, aList);
  1.2290 +  if (!event) {
  1.2291 +    return;
  1.2292 +  }
  1.2293 +
  1.2294 +  // Even if we're not telling the window about the event (so eventTarget is
  1.2295 +  // the chrome event handler, not the window), the window is still
  1.2296 +  // logically the event target.
  1.2297 +  event->SetTarget(eventTarget);
  1.2298 +  event->SetTrusted(true);
  1.2299 +  EventDispatcher::DispatchDOMEvent(dispatchTarget, nullptr, event, this,
  1.2300 +                                    nullptr);
  1.2301 +}
  1.2302 +
  1.2303 +static bool
  1.2304 +MayHavePaintEventListenerSubdocumentCallback(nsIDocument* aDocument, void* aData)
  1.2305 +{
  1.2306 +  bool *result = static_cast<bool*>(aData);
  1.2307 +  nsIPresShell* shell = aDocument->GetShell();
  1.2308 +  if (shell) {
  1.2309 +    nsPresContext* pc = shell->GetPresContext();
  1.2310 +    if (pc) {
  1.2311 +      *result = pc->MayHavePaintEventListenerInSubDocument();
  1.2312 +
  1.2313 +      // If we found a paint event listener, then we can stop enumerating
  1.2314 +      // sub documents.
  1.2315 +      return !*result;
  1.2316 +    }
  1.2317 +  }
  1.2318 +  return true;
  1.2319 +}
  1.2320 +
  1.2321 +static bool
  1.2322 +MayHavePaintEventListener(nsPIDOMWindow* aInnerWindow)
  1.2323 +{
  1.2324 +  if (!aInnerWindow)
  1.2325 +    return false;
  1.2326 +  if (aInnerWindow->HasPaintEventListeners())
  1.2327 +    return true;
  1.2328 +
  1.2329 +  EventTarget* parentTarget = aInnerWindow->GetParentTarget();
  1.2330 +  if (!parentTarget)
  1.2331 +    return false;
  1.2332 +
  1.2333 +  EventListenerManager* manager = nullptr;
  1.2334 +  if ((manager = parentTarget->GetExistingListenerManager()) &&
  1.2335 +      manager->MayHavePaintEventListener()) {
  1.2336 +    return true;
  1.2337 +  }
  1.2338 +
  1.2339 +  nsCOMPtr<nsINode> node;
  1.2340 +  if (parentTarget != aInnerWindow->GetChromeEventHandler()) {
  1.2341 +    nsCOMPtr<nsIInProcessContentFrameMessageManager> mm =
  1.2342 +      do_QueryInterface(parentTarget);
  1.2343 +    if (mm) {
  1.2344 +      node = mm->GetOwnerContent();
  1.2345 +    }
  1.2346 +  }
  1.2347 +
  1.2348 +  if (!node) {
  1.2349 +    node = do_QueryInterface(parentTarget);
  1.2350 +  }
  1.2351 +  if (node)
  1.2352 +    return MayHavePaintEventListener(node->OwnerDoc()->GetInnerWindow());
  1.2353 +
  1.2354 +  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(parentTarget);
  1.2355 +  if (window)
  1.2356 +    return MayHavePaintEventListener(window);
  1.2357 +
  1.2358 +  nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(parentTarget);
  1.2359 +  EventTarget* tabChildGlobal;
  1.2360 +  return root &&
  1.2361 +         (tabChildGlobal = root->GetParentTarget()) &&
  1.2362 +         (manager = tabChildGlobal->GetExistingListenerManager()) &&
  1.2363 +         manager->MayHavePaintEventListener();
  1.2364 +}
  1.2365 +
  1.2366 +bool
  1.2367 +nsPresContext::MayHavePaintEventListener()
  1.2368 +{
  1.2369 +  return ::MayHavePaintEventListener(mDocument->GetInnerWindow());
  1.2370 +}
  1.2371 +
  1.2372 +bool
  1.2373 +nsPresContext::MayHavePaintEventListenerInSubDocument()
  1.2374 +{
  1.2375 +  if (MayHavePaintEventListener()) {
  1.2376 +    return true;
  1.2377 +  }
  1.2378 +
  1.2379 +  bool result = false;
  1.2380 +  mDocument->EnumerateSubDocuments(MayHavePaintEventListenerSubdocumentCallback, &result);
  1.2381 +  return result;
  1.2382 +}
  1.2383 +
  1.2384 +void
  1.2385 +nsPresContext::NotifyInvalidation(uint32_t aFlags)
  1.2386 +{
  1.2387 +  nsIFrame* rootFrame = PresShell()->FrameManager()->GetRootFrame();
  1.2388 +  NotifyInvalidation(rootFrame->GetVisualOverflowRect(), aFlags);
  1.2389 +  mAllInvalidated = true;
  1.2390 +}
  1.2391 +
  1.2392 +void
  1.2393 +nsPresContext::NotifyInvalidation(const nsIntRect& aRect, uint32_t aFlags)
  1.2394 +{
  1.2395 +  nsRect rect(DevPixelsToAppUnits(aRect.x),
  1.2396 +              DevPixelsToAppUnits(aRect.y),
  1.2397 +              DevPixelsToAppUnits(aRect.width),
  1.2398 +              DevPixelsToAppUnits(aRect.height));
  1.2399 +  NotifyInvalidation(rect, aFlags);
  1.2400 +}
  1.2401 +
  1.2402 +void
  1.2403 +nsPresContext::NotifyInvalidation(const nsRect& aRect, uint32_t aFlags)
  1.2404 +{
  1.2405 +  MOZ_ASSERT(GetContainerWeak(), "Invalidation in detached pres context");
  1.2406 +
  1.2407 +  // If there is no paint event listener, then we don't need to fire
  1.2408 +  // the asynchronous event. We don't even need to record invalidation.
  1.2409 +  // MayHavePaintEventListener is pretty cheap and we could make it
  1.2410 +  // even cheaper by providing a more efficient
  1.2411 +  // nsPIDOMWindow::GetListenerManager.
  1.2412 +
  1.2413 +  if (mAllInvalidated) {
  1.2414 +    return;
  1.2415 +  }
  1.2416 +
  1.2417 +  nsPresContext* pc;
  1.2418 +  for (pc = this; pc; pc = pc->GetParentPresContext()) {
  1.2419 +    if (pc->mFireAfterPaintEvents)
  1.2420 +      break;
  1.2421 +    pc->mFireAfterPaintEvents = true;
  1.2422 +  }
  1.2423 +  if (!pc) {
  1.2424 +    nsRootPresContext* rpc = GetRootPresContext();
  1.2425 +    if (rpc) {
  1.2426 +      rpc->EnsureEventualDidPaintEvent();
  1.2427 +    }
  1.2428 +  }
  1.2429 +
  1.2430 +  nsInvalidateRequestList::Request* request =
  1.2431 +    mInvalidateRequestsSinceLastPaint.mRequests.AppendElement();
  1.2432 +  if (!request)
  1.2433 +    return;
  1.2434 +
  1.2435 +  request->mRect = aRect;
  1.2436 +  request->mFlags = aFlags;
  1.2437 +}
  1.2438 +
  1.2439 +/* static */ void
  1.2440 +nsPresContext::NotifySubDocInvalidation(ContainerLayer* aContainer,
  1.2441 +                                        const nsIntRegion& aRegion)
  1.2442 +{
  1.2443 +  ContainerLayerPresContext *data =
  1.2444 +    static_cast<ContainerLayerPresContext*>(
  1.2445 +      aContainer->GetUserData(&gNotifySubDocInvalidationData));
  1.2446 +  if (!data) {
  1.2447 +    return;
  1.2448 +  }
  1.2449 +
  1.2450 +  nsIntPoint topLeft = aContainer->GetVisibleRegion().GetBounds().TopLeft();
  1.2451 +
  1.2452 +  nsIntRegionRectIterator iter(aRegion);
  1.2453 +  while (const nsIntRect* r = iter.Next()) {
  1.2454 +    nsIntRect rect = *r;
  1.2455 +    //PresContext coordinate space is relative to the start of our visible
  1.2456 +    // region. Is this really true? This feels like the wrong way to get the right
  1.2457 +    // answer.
  1.2458 +    rect.MoveBy(-topLeft);
  1.2459 +    data->mPresContext->NotifyInvalidation(rect, 0);
  1.2460 +  }
  1.2461 +}
  1.2462 +
  1.2463 +void
  1.2464 +nsPresContext::SetNotifySubDocInvalidationData(ContainerLayer* aContainer)
  1.2465 +{
  1.2466 +  ContainerLayerPresContext* pres = new ContainerLayerPresContext;
  1.2467 +  pres->mPresContext = this;
  1.2468 +  aContainer->SetUserData(&gNotifySubDocInvalidationData, pres);
  1.2469 +}
  1.2470 +
  1.2471 +/* static */ void
  1.2472 +nsPresContext::ClearNotifySubDocInvalidationData(ContainerLayer* aContainer)
  1.2473 +{
  1.2474 +  aContainer->SetUserData(&gNotifySubDocInvalidationData, nullptr);
  1.2475 +}
  1.2476 +
  1.2477 +struct NotifyDidPaintSubdocumentCallbackClosure {
  1.2478 +  uint32_t mFlags;
  1.2479 +  bool mNeedsAnotherDidPaintNotification;
  1.2480 +};
  1.2481 +static bool
  1.2482 +NotifyDidPaintSubdocumentCallback(nsIDocument* aDocument, void* aData)
  1.2483 +{
  1.2484 +  NotifyDidPaintSubdocumentCallbackClosure* closure =
  1.2485 +    static_cast<NotifyDidPaintSubdocumentCallbackClosure*>(aData);
  1.2486 +  nsIPresShell* shell = aDocument->GetShell();
  1.2487 +  if (shell) {
  1.2488 +    nsPresContext* pc = shell->GetPresContext();
  1.2489 +    if (pc) {
  1.2490 +      pc->NotifyDidPaintForSubtree(closure->mFlags);
  1.2491 +      if (pc->IsDOMPaintEventPending()) {
  1.2492 +        closure->mNeedsAnotherDidPaintNotification = true;
  1.2493 +      }
  1.2494 +    }
  1.2495 +  }
  1.2496 +  return true;
  1.2497 +}
  1.2498 +
  1.2499 +class DelayedFireDOMPaintEvent : public nsRunnable {
  1.2500 +public:
  1.2501 +  DelayedFireDOMPaintEvent(nsPresContext* aPresContext,
  1.2502 +                           nsInvalidateRequestList* aList)
  1.2503 +    : mPresContext(aPresContext)
  1.2504 +  {
  1.2505 +    MOZ_ASSERT(mPresContext->GetContainerWeak(),
  1.2506 +               "DOMPaintEvent requested for a detached pres context");
  1.2507 +    mList.TakeFrom(aList);
  1.2508 +  }
  1.2509 +  NS_IMETHOD Run() MOZ_OVERRIDE
  1.2510 +  {
  1.2511 +    // The pres context might have been detached during the delay -
  1.2512 +    // that's fine, just don't fire the event.
  1.2513 +    if (mPresContext->GetContainerWeak()) {
  1.2514 +      mPresContext->FireDOMPaintEvent(&mList);
  1.2515 +    }
  1.2516 +    return NS_OK;
  1.2517 +  }
  1.2518 +
  1.2519 +  nsRefPtr<nsPresContext> mPresContext;
  1.2520 +  nsInvalidateRequestList mList;
  1.2521 +};
  1.2522 +
  1.2523 +void
  1.2524 +nsPresContext::NotifyDidPaintForSubtree(uint32_t aFlags)
  1.2525 +{
  1.2526 +  if (IsRoot()) {
  1.2527 +    static_cast<nsRootPresContext*>(this)->CancelDidPaintTimer();
  1.2528 +
  1.2529 +    if (!mFireAfterPaintEvents) {
  1.2530 +      return;
  1.2531 +    }
  1.2532 +  }
  1.2533 +  // Non-root prescontexts fire MozAfterPaint to all their descendants
  1.2534 +  // unconditionally, even if no invalidations have been collected. This is
  1.2535 +  // because we don't want to eat the cost of collecting invalidations for
  1.2536 +  // every subdocument (which would require putting every subdocument in its
  1.2537 +  // own layer).
  1.2538 +
  1.2539 +  if (aFlags & nsIPresShell::PAINT_LAYERS) {
  1.2540 +    mUndeliveredInvalidateRequestsBeforeLastPaint.TakeFrom(
  1.2541 +        &mInvalidateRequestsSinceLastPaint);
  1.2542 +    mAllInvalidated = false;
  1.2543 +  }
  1.2544 +  if (aFlags & nsIPresShell::PAINT_COMPOSITE) {
  1.2545 +    nsCOMPtr<nsIRunnable> ev =
  1.2546 +      new DelayedFireDOMPaintEvent(this, &mUndeliveredInvalidateRequestsBeforeLastPaint);
  1.2547 +    nsContentUtils::AddScriptRunner(ev);
  1.2548 +  }
  1.2549 +
  1.2550 +  NotifyDidPaintSubdocumentCallbackClosure closure = { aFlags, false };
  1.2551 +  mDocument->EnumerateSubDocuments(NotifyDidPaintSubdocumentCallback, &closure);
  1.2552 +
  1.2553 +  if (!closure.mNeedsAnotherDidPaintNotification &&
  1.2554 +      mInvalidateRequestsSinceLastPaint.IsEmpty() &&
  1.2555 +      mUndeliveredInvalidateRequestsBeforeLastPaint.IsEmpty()) {
  1.2556 +    // Nothing more to do for the moment.
  1.2557 +    mFireAfterPaintEvents = false;
  1.2558 +  } else {
  1.2559 +    if (IsRoot()) {
  1.2560 +      static_cast<nsRootPresContext*>(this)->EnsureEventualDidPaintEvent();
  1.2561 +    }
  1.2562 +  }
  1.2563 +}
  1.2564 +
  1.2565 +bool
  1.2566 +nsPresContext::HasCachedStyleData()
  1.2567 +{
  1.2568 +  return mShell && mShell->StyleSet()->HasCachedStyleData();
  1.2569 +}
  1.2570 +
  1.2571 +static bool sGotInterruptEnv = false;
  1.2572 +enum InterruptMode {
  1.2573 +  ModeRandom,
  1.2574 +  ModeCounter,
  1.2575 +  ModeEvent
  1.2576 +};
  1.2577 +// Controlled by the GECKO_REFLOW_INTERRUPT_MODE env var; allowed values are
  1.2578 +// "random" (except on Windows) or "counter".  If neither is used, the mode is
  1.2579 +// ModeEvent.
  1.2580 +static InterruptMode sInterruptMode = ModeEvent;
  1.2581 +#ifndef XP_WIN
  1.2582 +// Used for the "random" mode.  Controlled by the GECKO_REFLOW_INTERRUPT_SEED
  1.2583 +// env var.
  1.2584 +static uint32_t sInterruptSeed = 1;
  1.2585 +#endif
  1.2586 +// Used for the "counter" mode.  This is the number of unskipped interrupt
  1.2587 +// checks that have to happen before we interrupt.  Controlled by the
  1.2588 +// GECKO_REFLOW_INTERRUPT_FREQUENCY env var.
  1.2589 +static uint32_t sInterruptMaxCounter = 10;
  1.2590 +// Used for the "counter" mode.  This counts up to sInterruptMaxCounter and is
  1.2591 +// then reset to 0.
  1.2592 +static uint32_t sInterruptCounter;
  1.2593 +// Number of interrupt checks to skip before really trying to interrupt.
  1.2594 +// Controlled by the GECKO_REFLOW_INTERRUPT_CHECKS_TO_SKIP env var.
  1.2595 +static uint32_t sInterruptChecksToSkip = 200;
  1.2596 +// Number of milliseconds that a reflow should be allowed to run for before we
  1.2597 +// actually allow interruption.  Controlled by the
  1.2598 +// GECKO_REFLOW_MIN_NOINTERRUPT_DURATION env var.  Can't be initialized here,
  1.2599 +// because TimeDuration/TimeStamp is not safe to use in static constructors..
  1.2600 +static TimeDuration sInterruptTimeout;
  1.2601 +
  1.2602 +static void GetInterruptEnv()
  1.2603 +{
  1.2604 +  char *ev = PR_GetEnv("GECKO_REFLOW_INTERRUPT_MODE");
  1.2605 +  if (ev) {
  1.2606 +#ifndef XP_WIN
  1.2607 +    if (PL_strcasecmp(ev, "random") == 0) {
  1.2608 +      ev = PR_GetEnv("GECKO_REFLOW_INTERRUPT_SEED");
  1.2609 +      if (ev) {
  1.2610 +        sInterruptSeed = atoi(ev);
  1.2611 +      }
  1.2612 +      srandom(sInterruptSeed);
  1.2613 +      sInterruptMode = ModeRandom;
  1.2614 +    } else
  1.2615 +#endif
  1.2616 +      if (PL_strcasecmp(ev, "counter") == 0) {
  1.2617 +      ev = PR_GetEnv("GECKO_REFLOW_INTERRUPT_FREQUENCY");
  1.2618 +      if (ev) {
  1.2619 +        sInterruptMaxCounter = atoi(ev);
  1.2620 +      }
  1.2621 +      sInterruptCounter = 0;
  1.2622 +      sInterruptMode = ModeCounter;
  1.2623 +    }
  1.2624 +  }
  1.2625 +  ev = PR_GetEnv("GECKO_REFLOW_INTERRUPT_CHECKS_TO_SKIP");
  1.2626 +  if (ev) {
  1.2627 +    sInterruptChecksToSkip = atoi(ev);
  1.2628 +  }
  1.2629 +
  1.2630 +  ev = PR_GetEnv("GECKO_REFLOW_MIN_NOINTERRUPT_DURATION");
  1.2631 +  int duration_ms = ev ? atoi(ev) : 100;
  1.2632 +  sInterruptTimeout = TimeDuration::FromMilliseconds(duration_ms);
  1.2633 +}
  1.2634 +
  1.2635 +bool
  1.2636 +nsPresContext::HavePendingInputEvent()
  1.2637 +{
  1.2638 +  switch (sInterruptMode) {
  1.2639 +#ifndef XP_WIN
  1.2640 +    case ModeRandom:
  1.2641 +      return (random() & 1);
  1.2642 +#endif
  1.2643 +    case ModeCounter:
  1.2644 +      if (sInterruptCounter < sInterruptMaxCounter) {
  1.2645 +        ++sInterruptCounter;
  1.2646 +        return false;
  1.2647 +      }
  1.2648 +      sInterruptCounter = 0;
  1.2649 +      return true;
  1.2650 +    default:
  1.2651 +    case ModeEvent: {
  1.2652 +      nsIFrame* f = PresShell()->GetRootFrame();
  1.2653 +      if (f) {
  1.2654 +        nsIWidget* w = f->GetNearestWidget();
  1.2655 +        if (w) {
  1.2656 +          return w->HasPendingInputEvent();
  1.2657 +        }
  1.2658 +      }
  1.2659 +      return false;
  1.2660 +    }
  1.2661 +  }
  1.2662 +}
  1.2663 +
  1.2664 +void
  1.2665 +nsPresContext::ReflowStarted(bool aInterruptible)
  1.2666 +{
  1.2667 +#ifdef NOISY_INTERRUPTIBLE_REFLOW
  1.2668 +  if (!aInterruptible) {
  1.2669 +    printf("STARTING NONINTERRUPTIBLE REFLOW\n");
  1.2670 +  }
  1.2671 +#endif
  1.2672 +  // We don't support interrupting in paginated contexts, since page
  1.2673 +  // sequences only handle initial reflow
  1.2674 +  mInterruptsEnabled = aInterruptible && !IsPaginated() &&
  1.2675 +                       nsLayoutUtils::InterruptibleReflowEnabled();
  1.2676 +
  1.2677 +  // Don't set mHasPendingInterrupt based on HavePendingInputEvent() here.  If
  1.2678 +  // we ever change that, then we need to update the code in
  1.2679 +  // PresShell::DoReflow to only add the just-reflown root to dirty roots if
  1.2680 +  // it's actually dirty.  Otherwise we can end up adding a root that has no
  1.2681 +  // interruptible descendants, just because we detected an interrupt at reflow
  1.2682 +  // start.
  1.2683 +  mHasPendingInterrupt = false;
  1.2684 +
  1.2685 +  mInterruptChecksToSkip = sInterruptChecksToSkip;
  1.2686 +
  1.2687 +  if (mInterruptsEnabled) {
  1.2688 +    mReflowStartTime = TimeStamp::Now();
  1.2689 +  }
  1.2690 +}
  1.2691 +
  1.2692 +bool
  1.2693 +nsPresContext::CheckForInterrupt(nsIFrame* aFrame)
  1.2694 +{
  1.2695 +  if (mHasPendingInterrupt) {
  1.2696 +    mShell->FrameNeedsToContinueReflow(aFrame);
  1.2697 +    return true;
  1.2698 +  }
  1.2699 +
  1.2700 +  if (!sGotInterruptEnv) {
  1.2701 +    sGotInterruptEnv = true;
  1.2702 +    GetInterruptEnv();
  1.2703 +  }
  1.2704 +
  1.2705 +  if (!mInterruptsEnabled) {
  1.2706 +    return false;
  1.2707 +  }
  1.2708 +
  1.2709 +  if (mInterruptChecksToSkip > 0) {
  1.2710 +    --mInterruptChecksToSkip;
  1.2711 +    return false;
  1.2712 +  }
  1.2713 +  mInterruptChecksToSkip = sInterruptChecksToSkip;
  1.2714 +
  1.2715 +  // Don't interrupt if it's been less than sInterruptTimeout since we started
  1.2716 +  // the reflow.
  1.2717 +  mHasPendingInterrupt =
  1.2718 +    TimeStamp::Now() - mReflowStartTime > sInterruptTimeout &&
  1.2719 +    HavePendingInputEvent() &&
  1.2720 +    !IsChrome();
  1.2721 +  if (mHasPendingInterrupt) {
  1.2722 +#ifdef NOISY_INTERRUPTIBLE_REFLOW
  1.2723 +    printf("*** DETECTED pending interrupt (time=%lld)\n", PR_Now());
  1.2724 +#endif /* NOISY_INTERRUPTIBLE_REFLOW */
  1.2725 +    mShell->FrameNeedsToContinueReflow(aFrame);
  1.2726 +  }
  1.2727 +  return mHasPendingInterrupt;
  1.2728 +}
  1.2729 +
  1.2730 +nsIFrame*
  1.2731 +nsPresContext::GetPrimaryFrameFor(nsIContent* aContent)
  1.2732 +{
  1.2733 +  NS_PRECONDITION(aContent, "Don't do that");
  1.2734 +  if (GetPresShell() &&
  1.2735 +      GetPresShell()->GetDocument() == aContent->GetCurrentDoc()) {
  1.2736 +    return aContent->GetPrimaryFrame();
  1.2737 +  }
  1.2738 +  return nullptr;
  1.2739 +}
  1.2740 +
  1.2741 +
  1.2742 +size_t
  1.2743 +nsPresContext::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
  1.2744 +{
  1.2745 +  return mPropertyTable.SizeOfExcludingThis(aMallocSizeOf);
  1.2746 +         mLangGroupFontPrefs.SizeOfExcludingThis(aMallocSizeOf);
  1.2747 +
  1.2748 +  // Measurement of other members may be added later if DMD finds it is
  1.2749 +  // worthwhile.
  1.2750 +}
  1.2751 +
  1.2752 +bool
  1.2753 +nsPresContext::IsRootContentDocument()
  1.2754 +{
  1.2755 +  // We are a root content document if: we are not a resource doc, we are
  1.2756 +  // not chrome, and we either have no parent or our parent is chrome.
  1.2757 +  if (mDocument->IsResourceDoc()) {
  1.2758 +    return false;
  1.2759 +  }
  1.2760 +  if (IsChrome()) {
  1.2761 +    return false;
  1.2762 +  }
  1.2763 +  // We may not have a root frame, so use views.
  1.2764 +  nsView* view = PresShell()->GetViewManager()->GetRootView();
  1.2765 +  if (!view) {
  1.2766 +    return false;
  1.2767 +  }
  1.2768 +  view = view->GetParent(); // anonymous inner view
  1.2769 +  if (!view) {
  1.2770 +    return true;
  1.2771 +  }
  1.2772 +  view = view->GetParent(); // subdocumentframe's view
  1.2773 +  if (!view) {
  1.2774 +    return true;
  1.2775 +  }
  1.2776 +
  1.2777 +  nsIFrame* f = view->GetFrame();
  1.2778 +  return (f && f->PresContext()->IsChrome());
  1.2779 +}
  1.2780 +
  1.2781 +bool
  1.2782 +nsPresContext::IsCrossProcessRootContentDocument()
  1.2783 +{
  1.2784 +  if (!IsRootContentDocument()) {
  1.2785 +    return false;
  1.2786 +  }
  1.2787 +
  1.2788 +  if (XRE_GetProcessType() == GeckoProcessType_Default) {
  1.2789 +    return true;
  1.2790 +  }
  1.2791 +
  1.2792 +  TabChild* tabChild = TabChild::GetFrom(mShell);
  1.2793 +  return (tabChild && tabChild->IsRootContentDocument());
  1.2794 +}
  1.2795 +
  1.2796 +bool nsPresContext::GetPaintFlashing() const
  1.2797 +{
  1.2798 +  if (!mPaintFlashingInitialized) {
  1.2799 +    bool pref = Preferences::GetBool("nglayout.debug.paint_flashing");
  1.2800 +    if (!pref && IsChrome()) {
  1.2801 +      pref = Preferences::GetBool("nglayout.debug.paint_flashing_chrome");
  1.2802 +    }
  1.2803 +    mPaintFlashing = pref;
  1.2804 +    mPaintFlashingInitialized = true;
  1.2805 +  }
  1.2806 +  return mPaintFlashing;
  1.2807 +}
  1.2808 +
  1.2809 +int32_t
  1.2810 +nsPresContext::AppUnitsPerDevPixel() const
  1.2811 +{
  1.2812 +  return mDeviceContext->AppUnitsPerDevPixel();
  1.2813 +}
  1.2814 +
  1.2815 +nscoord
  1.2816 +nsPresContext::GfxUnitsToAppUnits(gfxFloat aGfxUnits) const
  1.2817 +{
  1.2818 +  return mDeviceContext->GfxUnitsToAppUnits(aGfxUnits);
  1.2819 +}
  1.2820 +
  1.2821 +gfxFloat
  1.2822 +nsPresContext::AppUnitsToGfxUnits(nscoord aAppUnits) const
  1.2823 +{
  1.2824 +  return mDeviceContext->AppUnitsToGfxUnits(aAppUnits);
  1.2825 +}
  1.2826 +
  1.2827 +bool
  1.2828 +nsPresContext::IsDeviceSizePageSize()
  1.2829 +{
  1.2830 +  bool isDeviceSizePageSize = false;
  1.2831 +  nsCOMPtr<nsIDocShell> docShell(mContainer);
  1.2832 +  if (docShell) {
  1.2833 +    isDeviceSizePageSize = docShell->GetDeviceSizeIsPageSize();
  1.2834 +  }
  1.2835 +  return isDeviceSizePageSize;
  1.2836 +}
  1.2837 +
  1.2838 +nsRootPresContext::nsRootPresContext(nsIDocument* aDocument,
  1.2839 +                                     nsPresContextType aType)
  1.2840 +  : nsPresContext(aDocument, aType),
  1.2841 +    mDOMGeneration(0)
  1.2842 +{
  1.2843 +}
  1.2844 +
  1.2845 +nsRootPresContext::~nsRootPresContext()
  1.2846 +{
  1.2847 +  NS_ASSERTION(mRegisteredPlugins.Count() == 0,
  1.2848 +               "All plugins should have been unregistered");
  1.2849 +  CancelDidPaintTimer();
  1.2850 +  CancelApplyPluginGeometryTimer();
  1.2851 +}
  1.2852 +
  1.2853 +/* virtual */ void
  1.2854 +nsRootPresContext::Detach()
  1.2855 +{
  1.2856 +  CancelDidPaintTimer();
  1.2857 +  // XXXmats maybe also CancelApplyPluginGeometryTimer(); ?
  1.2858 +  nsPresContext::Detach();
  1.2859 +}
  1.2860 +
  1.2861 +void
  1.2862 +nsRootPresContext::RegisterPluginForGeometryUpdates(nsIContent* aPlugin)
  1.2863 +{
  1.2864 +  mRegisteredPlugins.PutEntry(aPlugin);
  1.2865 +}
  1.2866 +
  1.2867 +void
  1.2868 +nsRootPresContext::UnregisterPluginForGeometryUpdates(nsIContent* aPlugin)
  1.2869 +{
  1.2870 +  mRegisteredPlugins.RemoveEntry(aPlugin);
  1.2871 +}
  1.2872 +
  1.2873 +static PLDHashOperator
  1.2874 +SetPluginHidden(nsRefPtrHashKey<nsIContent>* aEntry, void* userArg)
  1.2875 +{
  1.2876 +  nsIFrame* root = static_cast<nsIFrame*>(userArg);
  1.2877 +  nsObjectFrame* f = static_cast<nsObjectFrame*>(aEntry->GetKey()->GetPrimaryFrame());
  1.2878 +  if (!f) {
  1.2879 +    NS_WARNING("Null frame in SetPluginHidden");
  1.2880 +    return PL_DHASH_NEXT;
  1.2881 +  }
  1.2882 +  if (!nsLayoutUtils::IsAncestorFrameCrossDoc(root, f)) {
  1.2883 +    // f is not managed by this frame so we should ignore it.
  1.2884 +    return PL_DHASH_NEXT;
  1.2885 +  }
  1.2886 +  f->SetEmptyWidgetConfiguration();
  1.2887 +  return PL_DHASH_NEXT;
  1.2888 +}
  1.2889 +
  1.2890 +void
  1.2891 +nsRootPresContext::ComputePluginGeometryUpdates(nsIFrame* aFrame,
  1.2892 +                                                nsDisplayListBuilder* aBuilder,
  1.2893 +                                                nsDisplayList* aList)
  1.2894 +{
  1.2895 +  if (mRegisteredPlugins.Count() == 0) {
  1.2896 +    return;
  1.2897 +  }
  1.2898 +
  1.2899 +  // Initially make the next state for each plugin descendant of aFrame be
  1.2900 +  // "hidden". Plugins that are visible will have their next state set to
  1.2901 +  // unhidden by nsDisplayPlugin::ComputeVisibility.
  1.2902 +  mRegisteredPlugins.EnumerateEntries(SetPluginHidden, aFrame);
  1.2903 +
  1.2904 +  nsIFrame* rootFrame = FrameManager()->GetRootFrame();
  1.2905 +
  1.2906 +  if (rootFrame && aBuilder->ContainsPluginItem()) {
  1.2907 +    aBuilder->SetForPluginGeometry();
  1.2908 +    aBuilder->SetAccurateVisibleRegions();
  1.2909 +    // Merging and flattening has already been done and we should not do it
  1.2910 +    // again. nsDisplayScroll(Info)Layer doesn't support trying to flatten
  1.2911 +    // again.
  1.2912 +    aBuilder->SetAllowMergingAndFlattening(false);
  1.2913 +    nsRegion region = rootFrame->GetVisualOverflowRectRelativeToSelf();
  1.2914 +    // nsDisplayPlugin::ComputeVisibility will automatically set a non-hidden
  1.2915 +    // widget configuration for the plugin, if it's visible.
  1.2916 +    aList->ComputeVisibilityForRoot(aBuilder, &region);
  1.2917 +  }
  1.2918 +
  1.2919 +#ifdef XP_MACOSX
  1.2920 +  // We control painting of Mac plugins, so just apply geometry updates now.
  1.2921 +  // This is not happening during a paint event.
  1.2922 +  ApplyPluginGeometryUpdates();
  1.2923 +#else
  1.2924 +  InitApplyPluginGeometryTimer();
  1.2925 +#endif
  1.2926 +}
  1.2927 +
  1.2928 +static void
  1.2929 +ApplyPluginGeometryUpdatesCallback(nsITimer *aTimer, void *aClosure)
  1.2930 +{
  1.2931 +  static_cast<nsRootPresContext*>(aClosure)->ApplyPluginGeometryUpdates();
  1.2932 +}
  1.2933 +
  1.2934 +void
  1.2935 +nsRootPresContext::InitApplyPluginGeometryTimer()
  1.2936 +{
  1.2937 +  if (mApplyPluginGeometryTimer) {
  1.2938 +    return;
  1.2939 +  }
  1.2940 +
  1.2941 +  // We'll apply the plugin geometry updates during the next compositing paint in this
  1.2942 +  // presContext (either from nsPresShell::WillPaintWindow or from
  1.2943 +  // nsPresShell::DidPaintWindow, depending on the platform).  But paints might
  1.2944 +  // get optimized away if the old plugin geometry covers the invalid region,
  1.2945 +  // so set a backup timer to do this too.  We want to make sure this
  1.2946 +  // won't fire before our normal paint notifications, if those would
  1.2947 +  // update the geometry, so set it for double the refresh driver interval.
  1.2948 +  mApplyPluginGeometryTimer = do_CreateInstance("@mozilla.org/timer;1");
  1.2949 +  if (mApplyPluginGeometryTimer) {
  1.2950 +    mApplyPluginGeometryTimer->
  1.2951 +      InitWithFuncCallback(ApplyPluginGeometryUpdatesCallback, this,
  1.2952 +                           nsRefreshDriver::DefaultInterval() * 2,
  1.2953 +                           nsITimer::TYPE_ONE_SHOT);
  1.2954 +  }
  1.2955 +}
  1.2956 +
  1.2957 +void
  1.2958 +nsRootPresContext::CancelApplyPluginGeometryTimer()
  1.2959 +{
  1.2960 +  if (mApplyPluginGeometryTimer) {
  1.2961 +    mApplyPluginGeometryTimer->Cancel();
  1.2962 +    mApplyPluginGeometryTimer = nullptr;
  1.2963 +  }
  1.2964 +}
  1.2965 +
  1.2966 +static bool
  1.2967 +HasOverlap(const nsIntPoint& aOffset1, const nsTArray<nsIntRect>& aClipRects1,
  1.2968 +           const nsIntPoint& aOffset2, const nsTArray<nsIntRect>& aClipRects2)
  1.2969 +{
  1.2970 +  nsIntPoint offsetDelta = aOffset1 - aOffset2;
  1.2971 +  for (uint32_t i = 0; i < aClipRects1.Length(); ++i) {
  1.2972 +    for (uint32_t j = 0; j < aClipRects2.Length(); ++j) {
  1.2973 +      if ((aClipRects1[i] + offsetDelta).Intersects(aClipRects2[j]))
  1.2974 +        return true;
  1.2975 +    }
  1.2976 +  }
  1.2977 +  return false;
  1.2978 +}
  1.2979 +
  1.2980 +/**
  1.2981 + * Given a list of plugin windows to move to new locations, sort the list
  1.2982 + * so that for each window move, the window moves to a location that
  1.2983 + * does not intersect other windows. This minimizes flicker and repainting.
  1.2984 + * It's not always possible to do this perfectly, since in general
  1.2985 + * we might have cycles. But we do our best.
  1.2986 + * We need to take into account that windows are clipped to particular
  1.2987 + * regions and the clip regions change as the windows are moved.
  1.2988 + */
  1.2989 +static void
  1.2990 +SortConfigurations(nsTArray<nsIWidget::Configuration>* aConfigurations)
  1.2991 +{
  1.2992 +  if (aConfigurations->Length() > 10) {
  1.2993 +    // Give up, we don't want to get bogged down here
  1.2994 +    return;
  1.2995 +  }
  1.2996 +
  1.2997 +  nsTArray<nsIWidget::Configuration> pluginsToMove;
  1.2998 +  pluginsToMove.SwapElements(*aConfigurations);
  1.2999 +
  1.3000 +  // Our algorithm is quite naive. At each step we try to identify
  1.3001 +  // a window that can be moved to its new location that won't overlap
  1.3002 +  // any other windows at the new location. If there is no such
  1.3003 +  // window, we just move the last window in the list anyway.
  1.3004 +  while (!pluginsToMove.IsEmpty()) {
  1.3005 +    // Find a window whose destination does not overlap any other window
  1.3006 +    uint32_t i;
  1.3007 +    for (i = 0; i + 1 < pluginsToMove.Length(); ++i) {
  1.3008 +      nsIWidget::Configuration* config = &pluginsToMove[i];
  1.3009 +      bool foundOverlap = false;
  1.3010 +      for (uint32_t j = 0; j < pluginsToMove.Length(); ++j) {
  1.3011 +        if (i == j)
  1.3012 +          continue;
  1.3013 +        nsIntRect bounds;
  1.3014 +        pluginsToMove[j].mChild->GetBounds(bounds);
  1.3015 +        nsAutoTArray<nsIntRect,1> clipRects;
  1.3016 +        pluginsToMove[j].mChild->GetWindowClipRegion(&clipRects);
  1.3017 +        if (HasOverlap(bounds.TopLeft(), clipRects,
  1.3018 +                       config->mBounds.TopLeft(),
  1.3019 +                       config->mClipRegion)) {
  1.3020 +          foundOverlap = true;
  1.3021 +          break;
  1.3022 +        }
  1.3023 +      }
  1.3024 +      if (!foundOverlap)
  1.3025 +        break;
  1.3026 +    }
  1.3027 +    // Note that we always move the last plugin in pluginsToMove, if we
  1.3028 +    // can't find any other plugin to move
  1.3029 +    aConfigurations->AppendElement(pluginsToMove[i]);
  1.3030 +    pluginsToMove.RemoveElementAt(i);
  1.3031 +  }
  1.3032 +}
  1.3033 +
  1.3034 +static PLDHashOperator
  1.3035 +PluginDidSetGeometryEnumerator(nsRefPtrHashKey<nsIContent>* aEntry, void* userArg)
  1.3036 +{
  1.3037 +  nsObjectFrame* f = static_cast<nsObjectFrame*>(aEntry->GetKey()->GetPrimaryFrame());
  1.3038 +  if (!f) {
  1.3039 +    NS_WARNING("Null frame in PluginDidSetGeometryEnumerator");
  1.3040 +    return PL_DHASH_NEXT;
  1.3041 +  }
  1.3042 +  f->DidSetWidgetGeometry();
  1.3043 +  return PL_DHASH_NEXT;
  1.3044 +}
  1.3045 +
  1.3046 +struct PluginGetGeometryUpdateClosure {
  1.3047 +  nsTArray<nsIWidget::Configuration> mConfigurations;
  1.3048 +};
  1.3049 +static PLDHashOperator
  1.3050 +PluginGetGeometryUpdate(nsRefPtrHashKey<nsIContent>* aEntry, void* userArg)
  1.3051 +{
  1.3052 +  PluginGetGeometryUpdateClosure* closure =
  1.3053 +    static_cast<PluginGetGeometryUpdateClosure*>(userArg);
  1.3054 +  nsObjectFrame* f = static_cast<nsObjectFrame*>(aEntry->GetKey()->GetPrimaryFrame());
  1.3055 +  if (!f) {
  1.3056 +    NS_WARNING("Null frame in GetPluginGeometryUpdate");
  1.3057 +    return PL_DHASH_NEXT;
  1.3058 +  }
  1.3059 +  f->GetWidgetConfiguration(&closure->mConfigurations);
  1.3060 +  return PL_DHASH_NEXT;
  1.3061 +}
  1.3062 +
  1.3063 +void
  1.3064 +nsRootPresContext::ApplyPluginGeometryUpdates()
  1.3065 +{
  1.3066 +  CancelApplyPluginGeometryTimer();
  1.3067 +
  1.3068 +  PluginGetGeometryUpdateClosure closure;
  1.3069 +  mRegisteredPlugins.EnumerateEntries(PluginGetGeometryUpdate, &closure);
  1.3070 +  // Walk mRegisteredPlugins and ask each plugin for its configuration
  1.3071 +  if (!closure.mConfigurations.IsEmpty()) {
  1.3072 +    nsIWidget* widget = closure.mConfigurations[0].mChild->GetParent();
  1.3073 +    NS_ASSERTION(widget, "Plugins must have a parent window");
  1.3074 +    SortConfigurations(&closure.mConfigurations);
  1.3075 +    widget->ConfigureChildren(closure.mConfigurations);
  1.3076 +  }
  1.3077 +  mRegisteredPlugins.EnumerateEntries(PluginDidSetGeometryEnumerator, nullptr);
  1.3078 +}
  1.3079 +
  1.3080 +static void
  1.3081 +NotifyDidPaintForSubtreeCallback(nsITimer *aTimer, void *aClosure)
  1.3082 +{
  1.3083 +  nsPresContext* presContext = (nsPresContext*)aClosure;
  1.3084 +  nsAutoScriptBlocker blockScripts;
  1.3085 +  // This is a fallback if we don't get paint events for some reason
  1.3086 +  // so we'll just pretend both layer painting and compositing happened.
  1.3087 +  presContext->NotifyDidPaintForSubtree(
  1.3088 +      nsIPresShell::PAINT_LAYERS | nsIPresShell::PAINT_COMPOSITE);
  1.3089 +}
  1.3090 +
  1.3091 +void
  1.3092 +nsRootPresContext::EnsureEventualDidPaintEvent()
  1.3093 +{
  1.3094 +  if (mNotifyDidPaintTimer)
  1.3095 +    return;
  1.3096 +  mNotifyDidPaintTimer = do_CreateInstance("@mozilla.org/timer;1");
  1.3097 +  if (!mNotifyDidPaintTimer)
  1.3098 +    return;
  1.3099 +  mNotifyDidPaintTimer->InitWithFuncCallback(NotifyDidPaintForSubtreeCallback,
  1.3100 +                                             (void*)this, 100, nsITimer::TYPE_ONE_SHOT);
  1.3101 +}
  1.3102 +
  1.3103 +void
  1.3104 +nsRootPresContext::AddWillPaintObserver(nsIRunnable* aRunnable)
  1.3105 +{
  1.3106 +  if (!mWillPaintFallbackEvent.IsPending()) {
  1.3107 +    mWillPaintFallbackEvent = new RunWillPaintObservers(this);
  1.3108 +    NS_DispatchToMainThread(mWillPaintFallbackEvent.get());
  1.3109 +  }
  1.3110 +  mWillPaintObservers.AppendElement(aRunnable);
  1.3111 +}
  1.3112 +
  1.3113 +/**
  1.3114 + * Run all runnables that need to get called before the next paint.
  1.3115 + */
  1.3116 +void
  1.3117 +nsRootPresContext::FlushWillPaintObservers()
  1.3118 +{
  1.3119 +  mWillPaintFallbackEvent = nullptr;
  1.3120 +  nsTArray<nsCOMPtr<nsIRunnable> > observers;
  1.3121 +  observers.SwapElements(mWillPaintObservers);
  1.3122 +  for (uint32_t i = 0; i < observers.Length(); ++i) {
  1.3123 +    observers[i]->Run();
  1.3124 +  }
  1.3125 +}
  1.3126 +
  1.3127 +size_t
  1.3128 +nsRootPresContext::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
  1.3129 +{
  1.3130 +  return nsPresContext::SizeOfExcludingThis(aMallocSizeOf);
  1.3131 +
  1.3132 +  // Measurement of the following members may be added later if DMD finds it is
  1.3133 +  // worthwhile:
  1.3134 +  // - mNotifyDidPaintTimer
  1.3135 +  // - mRegisteredPlugins
  1.3136 +  // - mWillPaintObservers
  1.3137 +  // - mWillPaintFallbackEvent
  1.3138 +}

mercurial