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, ®ion); 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 +}