LCOV - code coverage report
Current view: directory - layout/base - nsPresContext.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 1196 3 0.3 %
Date: 2012-06-02 Functions: 118 2 1.7 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is mozilla.org code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   L. David Baron <dbaron@dbaron.org>, Mozilla Corporation
      24                 :  *   Ehsan Akhgari <ehsan.akhgari@gmail.com>
      25                 :  *
      26                 :  * Alternatively, the contents of this file may be used under the terms of
      27                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      28                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      30                 :  * of those above. If you wish to allow use of your version of this file only
      31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      32                 :  * use your version of this file under the terms of the MPL, indicate your
      33                 :  * decision by deleting the provisions above and replace them with the notice
      34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      35                 :  * the provisions above, a recipient may use your version of this file under
      36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      37                 :  *
      38                 :  * ***** END LICENSE BLOCK ***** */
      39                 : 
      40                 : /* a presentation of a document, part 1 */
      41                 : 
      42                 : #include "nsCOMPtr.h"
      43                 : #include "nsPresContext.h"
      44                 : #include "nsIPresShell.h"
      45                 : #include "nsILinkHandler.h"
      46                 : #include "nsIDocShellTreeItem.h"
      47                 : #include "nsIDocShell.h"
      48                 : #include "nsIContentViewer.h"
      49                 : #include "nsPIDOMWindow.h"
      50                 : #include "nsStyleSet.h"
      51                 : #include "nsImageLoader.h"
      52                 : #include "nsIContent.h"
      53                 : #include "nsIFrame.h"
      54                 : #include "nsIURL.h"
      55                 : #include "nsIDocument.h"
      56                 : #include "nsStyleContext.h"
      57                 : #include "mozilla/LookAndFeel.h"
      58                 : #include "nsIComponentManager.h"
      59                 : #include "nsIURIContentListener.h"
      60                 : #include "nsIInterfaceRequestor.h"
      61                 : #include "nsIInterfaceRequestorUtils.h"
      62                 : #include "nsIServiceManager.h"
      63                 : #include "nsIDOMElement.h"
      64                 : #include "nsContentPolicyUtils.h"
      65                 : #include "nsIDOMWindow.h"
      66                 : #include "nsXPIDLString.h"
      67                 : #include "nsIWeakReferenceUtils.h"
      68                 : #include "nsCSSRendering.h"
      69                 : #include "prprf.h"
      70                 : #include "nsIDOMDocument.h"
      71                 : #include "nsAutoPtr.h"
      72                 : #include "nsEventStateManager.h"
      73                 : #include "nsThreadUtils.h"
      74                 : #include "nsFrameManager.h"
      75                 : #include "nsLayoutUtils.h"
      76                 : #include "nsIViewManager.h"
      77                 : #include "nsCSSFrameConstructor.h"
      78                 : #include "nsCSSRuleProcessor.h"
      79                 : #include "nsStyleChangeList.h"
      80                 : #include "nsRuleNode.h"
      81                 : #include "nsEventDispatcher.h"
      82                 : #include "gfxUserFontSet.h"
      83                 : #include "gfxPlatform.h"
      84                 : #include "nsCSSRules.h"
      85                 : #include "nsFontFaceLoader.h"
      86                 : #include "nsEventListenerManager.h"
      87                 : #include "nsStyleStructInlines.h"
      88                 : #include "nsIAppShell.h"
      89                 : #include "prenv.h"
      90                 : #include "nsIPrivateDOMEvent.h"
      91                 : #include "nsIDOMEventTarget.h"
      92                 : #include "nsObjectFrame.h"
      93                 : #include "nsTransitionManager.h"
      94                 : #include "nsAnimationManager.h"
      95                 : #include "mozilla/dom/Element.h"
      96                 : #include "nsIFrameMessageManager.h"
      97                 : #include "FrameLayerBuilder.h"
      98                 : #include "nsDOMMediaQueryList.h"
      99                 : #include "nsSMILAnimationController.h"
     100                 : 
     101                 : #ifdef IBMBIDI
     102                 : #include "nsBidiPresUtils.h"
     103                 : #endif // IBMBIDI
     104                 : 
     105                 : #include "nsContentUtils.h"
     106                 : #include "nsPIWindowRoot.h"
     107                 : #include "mozilla/Preferences.h"
     108                 : 
     109                 : // Needed for Start/Stop of Image Animation
     110                 : #include "imgIContainer.h"
     111                 : #include "nsIImageLoadingContent.h"
     112                 : 
     113                 : //needed for resetting of image service color
     114                 : #include "nsLayoutCID.h"
     115                 : 
     116                 : #include "nsCSSParser.h"
     117                 : 
     118                 : using namespace mozilla;
     119                 : using namespace mozilla::dom;
     120                 : 
     121                 : namespace {
     122                 : 
     123                 : class CharSetChangingRunnable : public nsRunnable
     124               0 : {
     125                 : public:
     126               0 :   CharSetChangingRunnable(nsPresContext* aPresContext,
     127                 :                           const nsCString& aCharSet)
     128                 :     : mPresContext(aPresContext),
     129               0 :       mCharSet(aCharSet)
     130                 :   {
     131               0 :   }
     132                 : 
     133               0 :   NS_IMETHOD Run()
     134                 :   {
     135               0 :     mPresContext->DoChangeCharSet(mCharSet);
     136               0 :     return NS_OK;
     137                 :   }
     138                 : 
     139                 : private:
     140                 :   nsRefPtr<nsPresContext> mPresContext;
     141                 :   nsCString mCharSet;
     142                 : };
     143                 : 
     144                 : } // anonymous namespace
     145                 : 
     146                 : static nscolor
     147               0 : MakeColorPref(const nsString& aColor)
     148                 : {
     149                 :   nscolor color;
     150               0 :   nsCSSParser parser;
     151                 :   nsresult rv =
     152               0 :     parser.ParseColorString(aColor, nsnull, 0, &color);
     153               0 :   if (NS_FAILED(rv)) {
     154                 :     // Any better choices?
     155               0 :     color = NS_RGB(0, 0, 0);
     156                 :   }
     157               0 :   return color;
     158                 : }
     159                 : 
     160                 : int
     161               0 : nsPresContext::PrefChangedCallback(const char* aPrefName, void* instance_data)
     162                 : {
     163               0 :   nsPresContext*  presContext = (nsPresContext*)instance_data;
     164                 : 
     165               0 :   NS_ASSERTION(nsnull != presContext, "bad instance data");
     166               0 :   if (nsnull != presContext) {
     167               0 :     presContext->PreferenceChanged(aPrefName);
     168                 :   }
     169               0 :   return 0;  // PREF_OK
     170                 : }
     171                 : 
     172                 : 
     173                 : void
     174               0 : nsPresContext::PrefChangedUpdateTimerCallback(nsITimer *aTimer, void *aClosure)
     175                 : {
     176               0 :   nsPresContext*  presContext = (nsPresContext*)aClosure;
     177               0 :   NS_ASSERTION(presContext != nsnull, "bad instance data");
     178               0 :   if (presContext)
     179               0 :     presContext->UpdateAfterPreferencesChanged();
     180               0 : }
     181                 : 
     182                 : #ifdef IBMBIDI
     183                 : static bool
     184               0 : IsVisualCharset(const nsCString& aCharset)
     185                 : {
     186               0 :   if (aCharset.LowerCaseEqualsLiteral("ibm864")             // Arabic//ahmed
     187               0 :       || aCharset.LowerCaseEqualsLiteral("ibm862")          // Hebrew
     188               0 :       || aCharset.LowerCaseEqualsLiteral("iso-8859-8") ) {  // Hebrew
     189               0 :     return true; // visual text type
     190                 :   }
     191                 :   else {
     192               0 :     return false; // logical text type
     193                 :   }
     194                 : }
     195                 : #endif // IBMBIDI
     196                 : 
     197                 : 
     198                 : static PLDHashOperator
     199               0 : destroy_loads(const void * aKey, nsRefPtr<nsImageLoader>& aData, void* closure)
     200                 : {
     201               0 :   aData->Destroy();
     202               0 :   return PL_DHASH_NEXT;
     203                 : }
     204                 : 
     205                 : #include "nsContentCID.h"
     206                 : 
     207                 :   // NOTE! nsPresContext::operator new() zeroes out all members, so don't
     208                 :   // bother initializing members to 0.
     209                 : 
     210               0 : nsPresContext::nsPresContext(nsIDocument* aDocument, nsPresContextType aType)
     211                 :   : mType(aType), mDocument(aDocument), mMinFontSize(0),
     212                 :     mTextZoom(1.0), mFullZoom(1.0), mPageSize(-1, -1), mPPScale(1.0f),
     213                 :     mViewportStyleOverflow(NS_STYLE_OVERFLOW_AUTO, NS_STYLE_OVERFLOW_AUTO),
     214               0 :     mImageAnimationModePref(imgIContainer::kNormalAnimMode)
     215                 : {
     216                 :   // NOTE! nsPresContext::operator new() zeroes out all members, so don't
     217                 :   // bother initializing members to 0.
     218                 : 
     219               0 :   mDoScaledTwips = true;
     220                 : 
     221               0 :   SetBackgroundImageDraw(true);         // always draw the background
     222               0 :   SetBackgroundColorDraw(true);
     223                 : 
     224               0 :   mBackgroundColor = NS_RGB(0xFF, 0xFF, 0xFF);
     225                 :   
     226               0 :   mUseDocumentColors = true;
     227               0 :   mUseDocumentFonts = true;
     228                 : 
     229                 :   // the minimum font-size is unconstrained by default
     230                 : 
     231               0 :   mLinkColor = NS_RGB(0x00, 0x00, 0xEE);
     232               0 :   mActiveLinkColor = NS_RGB(0xEE, 0x00, 0x00);
     233               0 :   mVisitedLinkColor = NS_RGB(0x55, 0x1A, 0x8B);
     234               0 :   mUnderlineLinks = true;
     235               0 :   mSendAfterPaintToContent = false;
     236                 : 
     237               0 :   mFocusTextColor = mDefaultColor;
     238               0 :   mFocusBackgroundColor = mBackgroundColor;
     239               0 :   mFocusRingWidth = 1;
     240                 : 
     241               0 :   mBodyTextColor = mDefaultColor;
     242                 : 
     243               0 :   if (aType == eContext_Galley) {
     244               0 :     mMedium = nsGkAtoms::screen;
     245                 :   } else {
     246               0 :     mMedium = nsGkAtoms::print;
     247               0 :     mPaginated = true;
     248                 :   }
     249                 : 
     250               0 :   if (!IsDynamic()) {
     251               0 :     mImageAnimationMode = imgIContainer::kDontAnimMode;
     252               0 :     mNeverAnimate = true;
     253                 :   } else {
     254               0 :     mImageAnimationMode = imgIContainer::kNormalAnimMode;
     255               0 :     mNeverAnimate = false;
     256                 :   }
     257               0 :   NS_ASSERTION(mDocument, "Null document");
     258               0 :   mUserFontSet = nsnull;
     259               0 :   mUserFontSetDirty = true;
     260                 : 
     261               0 :   PR_INIT_CLIST(&mDOMMediaQueryLists);
     262               0 : }
     263                 : 
     264               0 : nsPresContext::~nsPresContext()
     265                 : {
     266               0 :   NS_PRECONDITION(!mShell, "Presshell forgot to clear our mShell pointer");
     267               0 :   SetShell(nsnull);
     268                 : 
     269               0 :   NS_ABORT_IF_FALSE(PR_CLIST_IS_EMPTY(&mDOMMediaQueryLists),
     270                 :                     "must not have media query lists left");
     271                 : 
     272                 :   // Disconnect the refresh driver *after* the transition manager, which
     273                 :   // needs it.
     274               0 :   if (mRefreshDriver && mRefreshDriver->PresContext() == this) {
     275               0 :     mRefreshDriver->Disconnect();
     276                 :   }
     277                 : 
     278               0 :   if (mEventManager) {
     279                 :     // unclear if these are needed, but can't hurt
     280               0 :     mEventManager->NotifyDestroyPresContext(this);
     281               0 :     mEventManager->SetPresContext(nsnull);
     282                 : 
     283               0 :     NS_RELEASE(mEventManager);
     284                 :   }
     285                 : 
     286               0 :   if (mPrefChangedTimer)
     287                 :   {
     288               0 :     mPrefChangedTimer->Cancel();
     289               0 :     mPrefChangedTimer = nsnull;
     290                 :   }
     291                 : 
     292                 :   // Unregister preference callbacks
     293                 :   Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
     294                 :                                   "font.",
     295               0 :                                   this);
     296                 :   Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
     297                 :                                   "browser.display.",
     298               0 :                                   this);
     299                 :   Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
     300                 :                                   "browser.underline_anchors",
     301               0 :                                   this);
     302                 :   Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
     303                 :                                   "browser.anchor_color",
     304               0 :                                   this);
     305                 :   Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
     306                 :                                   "browser.active_color",
     307               0 :                                   this);
     308                 :   Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
     309                 :                                   "browser.visited_color",
     310               0 :                                   this);
     311                 :   Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
     312                 :                                   "image.animation_mode",
     313               0 :                                   this);
     314                 : #ifdef IBMBIDI
     315                 :   Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
     316                 :                                   "bidi.",
     317               0 :                                   this);
     318                 : #endif // IBMBIDI
     319                 :   Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
     320                 :                                   "dom.send_after_paint_to_content",
     321               0 :                                   this);
     322                 :   Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
     323                 :                                   "gfx.font_rendering.",
     324               0 :                                   this);
     325                 :   Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
     326                 :                                   "layout.css.dpi",
     327               0 :                                   this);
     328                 :   Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
     329                 :                                   "layout.css.devPixelsPerPx",
     330               0 :                                   this);
     331                 : 
     332               0 :   NS_IF_RELEASE(mDeviceContext);
     333               0 :   NS_IF_RELEASE(mLanguage);
     334               0 : }
     335                 : 
     336            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsPresContext)
     337                 : 
     338               0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsPresContext)
     339               0 :    NS_INTERFACE_MAP_ENTRY(nsISupports)
     340               0 :    NS_INTERFACE_MAP_ENTRY(nsIObserver)
     341               0 : NS_INTERFACE_MAP_END
     342                 : 
     343               0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsPresContext)
     344               0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsPresContext)
     345                 : 
     346                 : static PLDHashOperator
     347               0 : TraverseImageLoader(const void * aKey, nsRefPtr<nsImageLoader>& aData,
     348                 :                     void* aClosure)
     349                 : {
     350                 :   nsCycleCollectionTraversalCallback *cb =
     351               0 :     static_cast<nsCycleCollectionTraversalCallback*>(aClosure);
     352                 : 
     353               0 :   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "mImageLoaders[i] item");
     354               0 :   cb->NoteXPCOMChild(aData);
     355                 : 
     356               0 :   return PL_DHASH_NEXT;
     357                 : }
     358                 : 
     359               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsPresContext)
     360               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDocument);
     361                 :   // NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mDeviceContext); // not xpcom
     362               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mEventManager, nsIObserver);
     363                 :   // NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mLanguage); // an atom
     364                 : 
     365               0 :   for (PRUint32 i = 0; i < IMAGE_LOAD_TYPE_COUNT; ++i)
     366               0 :     tmp->mImageLoaders[i].Enumerate(TraverseImageLoader, &cb);
     367                 : 
     368                 :   // We own only the items in mDOMMediaQueryLists that have listeners;
     369                 :   // this reference is managed by their AddListener and RemoveListener
     370                 :   // methods.
     371               0 :   for (PRCList *l = PR_LIST_HEAD(&tmp->mDOMMediaQueryLists);
     372                 :        l != &tmp->mDOMMediaQueryLists; l = PR_NEXT_LINK(l)) {
     373               0 :     nsDOMMediaQueryList *mql = static_cast<nsDOMMediaQueryList*>(l);
     374               0 :     if (mql->HasListeners()) {
     375               0 :       NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mDOMMediaQueryLists item");
     376               0 :       cb.NoteXPCOMChild(mql);
     377                 :     }
     378                 :   }
     379                 : 
     380                 :   // NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mTheme); // a service
     381                 :   // NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mLangService); // a service
     382               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mPrintSettings);
     383               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mPrefChangedTimer);
     384               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     385                 : 
     386               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsPresContext)
     387               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDocument);
     388               0 :   NS_RELEASE(tmp->mDeviceContext); // worth bothering?
     389               0 :   if (tmp->mEventManager) {
     390                 :     // unclear if these are needed, but can't hurt
     391               0 :     tmp->mEventManager->NotifyDestroyPresContext(tmp);
     392               0 :     tmp->mEventManager->SetPresContext(nsnull);
     393                 : 
     394               0 :     NS_RELEASE(tmp->mEventManager);
     395                 :   }
     396                 : 
     397                 :   // We own only the items in mDOMMediaQueryLists that have listeners;
     398                 :   // this reference is managed by their AddListener and RemoveListener
     399                 :   // methods.
     400               0 :   for (PRCList *l = PR_LIST_HEAD(&tmp->mDOMMediaQueryLists);
     401                 :        l != &tmp->mDOMMediaQueryLists; ) {
     402               0 :     PRCList *next = PR_NEXT_LINK(l);
     403               0 :     nsDOMMediaQueryList *mql = static_cast<nsDOMMediaQueryList*>(l);
     404               0 :     mql->RemoveAllListeners();
     405               0 :     l = next;
     406                 :   }
     407                 : 
     408                 :   // NS_RELEASE(tmp->mLanguage); // an atom
     409                 : 
     410                 :   // NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mTheme); // a service
     411                 :   // NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mLangService); // a service
     412               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mPrintSettings);
     413               0 :   if (tmp->mPrefChangedTimer)
     414                 :   {
     415               0 :     tmp->mPrefChangedTimer->Cancel();
     416               0 :     tmp->mPrefChangedTimer = nsnull;
     417                 :   }
     418               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     419                 : 
     420                 : 
     421                 : #define MAKE_FONT_PREF_KEY(_pref, _s0, _s1) \
     422                 :  _pref.Assign(_s0); \
     423                 :  _pref.Append(_s1);
     424                 : 
     425                 : static const char* const kGenericFont[] = {
     426                 :   ".variable.",
     427                 :   ".fixed.",
     428                 :   ".serif.", 
     429                 :   ".sans-serif.", 
     430                 :   ".monospace.",
     431                 :   ".cursive.",
     432                 :   ".fantasy."
     433                 : };
     434                 : 
     435                 : // whether no native theme service exists;
     436                 : // if this gets set to true, we'll stop asking for it.
     437                 : static bool sNoTheme = false;
     438                 : 
     439                 : // Set to true when LookAndFeelChanged needs to be called.  This is used
     440                 : // because the look and feel is a service, so there's no need to notify it from
     441                 : // more than one prescontext.
     442                 : static bool sLookAndFeelChanged;
     443                 : 
     444                 : // Set to true when ThemeChanged needs to be called on mTheme.  This is used
     445                 : // because mTheme is a service, so there's no need to notify it from more than
     446                 : // one prescontext.
     447                 : static bool sThemeChanged;
     448                 : 
     449                 : const nsPresContext::LangGroupFontPrefs*
     450               0 : nsPresContext::GetFontPrefsForLang(nsIAtom *aLanguage) const
     451                 : {
     452                 :   // Get language group for aLanguage:
     453                 : 
     454                 :   nsresult rv;
     455               0 :   nsIAtom *langGroupAtom = nsnull;
     456               0 :   if (!aLanguage) {
     457               0 :     aLanguage = mLanguage;
     458                 :   }
     459               0 :   if (aLanguage && mLangService) {
     460               0 :     langGroupAtom = mLangService->GetLanguageGroup(aLanguage, &rv);
     461                 :   }
     462               0 :   if (NS_FAILED(rv) || !langGroupAtom) {
     463               0 :     langGroupAtom = nsGkAtoms::x_western; // Assume x-western is safe...
     464                 :   }
     465                 : 
     466                 :   // Look for cached prefs for this lang group.
     467                 :   // Most documents will only use one (or very few) language groups. Rather
     468                 :   // than have the overhead of a hash lookup, we simply look along what will
     469                 :   // typically be a very short (usually of length 1) linked list. There are 31
     470                 :   // language groups, so in the worst case scenario we'll need to traverse 31
     471                 :   // link items.
     472                 : 
     473                 :   LangGroupFontPrefs *prefs =
     474               0 :     const_cast<LangGroupFontPrefs*>(&mLangGroupFontPrefs);
     475               0 :   if (prefs->mLangGroup) { // if initialized
     476               0 :     DebugOnly<PRUint32> count = 0;
     477               0 :     for (;;) {
     478               0 :       NS_ASSERTION(++count < 35, "Lang group count exceeded!!!");
     479               0 :       if (prefs->mLangGroup == langGroupAtom) {
     480               0 :         return prefs;
     481                 :       }
     482               0 :       if (!prefs->mNext) {
     483                 :         break;
     484                 :       }
     485               0 :       prefs = prefs->mNext;
     486                 :     }
     487                 : 
     488                 :     // nothing cached, so go on and fetch the prefs for this lang group:
     489               0 :     prefs = prefs->mNext = new LangGroupFontPrefs;
     490                 :   }
     491                 : 
     492               0 :   prefs->mLangGroup = langGroupAtom;
     493                 : 
     494                 :   /* Fetch the font prefs to be used -- see bug 61883 for details.
     495                 :      Not all prefs are needed upfront. Some are fallback prefs intended
     496                 :      for the GFX font sub-system...
     497                 : 
     498                 :   1) unit : assumed to be the same for all language groups -------------
     499                 :   font.size.unit = px | pt    XXX could be folded in the size... bug 90440
     500                 : 
     501                 :   2) attributes for generic fonts --------------------------------------
     502                 :   font.default.[langGroup] = serif | sans-serif - fallback generic font
     503                 :   font.name.[generic].[langGroup] = current user' selected font on the pref dialog
     504                 :   font.name-list.[generic].[langGroup] = fontname1, fontname2, ... [factory pre-built list]
     505                 :   font.size.[generic].[langGroup] = integer - settable by the user
     506                 :   font.size-adjust.[generic].[langGroup] = "float" - settable by the user
     507                 :   font.minimum-size.[langGroup] = integer - settable by the user
     508                 :   */
     509                 : 
     510               0 :   nsCAutoString langGroup;
     511               0 :   langGroupAtom->ToUTF8String(langGroup);
     512                 : 
     513               0 :   prefs->mDefaultVariableFont.size = CSSPixelsToAppUnits(16);
     514               0 :   prefs->mDefaultFixedFont.size = CSSPixelsToAppUnits(13);
     515                 : 
     516               0 :   nsCAutoString pref;
     517                 : 
     518                 :   // get the current applicable font-size unit
     519                 :   enum {eUnit_unknown = -1, eUnit_px, eUnit_pt};
     520               0 :   PRInt32 unit = eUnit_px;
     521                 : 
     522                 :   nsAdoptingCString cvalue =
     523               0 :     Preferences::GetCString("font.size.unit");
     524                 : 
     525               0 :   if (!cvalue.IsEmpty()) {
     526               0 :     if (cvalue.Equals("px")) {
     527               0 :       unit = eUnit_px;
     528                 :     }
     529               0 :     else if (cvalue.Equals("pt")) {
     530               0 :       unit = eUnit_pt;
     531                 :     }
     532                 :     else {
     533                 :       // XXX should really send this warning to the user (Error Console?).
     534                 :       // And just default to unit = eUnit_px?
     535               0 :       NS_WARNING("unexpected font-size unit -- expected: 'px' or 'pt'");
     536               0 :       unit = eUnit_unknown;
     537                 :     }
     538                 :   }
     539                 : 
     540                 :   // get font.minimum-size.[langGroup]
     541                 : 
     542               0 :   MAKE_FONT_PREF_KEY(pref, "font.minimum-size.", langGroup);
     543                 : 
     544               0 :   PRInt32 size = Preferences::GetInt(pref.get());
     545               0 :   if (unit == eUnit_px) {
     546               0 :     prefs->mMinimumFontSize = CSSPixelsToAppUnits(size);
     547                 :   }
     548               0 :   else if (unit == eUnit_pt) {
     549               0 :     prefs->mMinimumFontSize = CSSPointsToAppUnits(size);
     550                 :   }
     551                 : 
     552                 :   nsFont* fontTypes[] = {
     553                 :     &prefs->mDefaultVariableFont,
     554                 :     &prefs->mDefaultFixedFont,
     555                 :     &prefs->mDefaultSerifFont,
     556                 :     &prefs->mDefaultSansSerifFont,
     557                 :     &prefs->mDefaultMonospaceFont,
     558                 :     &prefs->mDefaultCursiveFont,
     559                 :     &prefs->mDefaultFantasyFont
     560               0 :   };
     561                 :   PR_STATIC_ASSERT(NS_ARRAY_LENGTH(fontTypes) == eDefaultFont_COUNT);
     562                 : 
     563                 :   // Get attributes specific to each generic font. We do not get the user's
     564                 :   // generic-font-name-to-specific-family-name preferences because its the
     565                 :   // generic name that should be fed into the cascade. It is up to the GFX
     566                 :   // code to look up the font prefs to convert generic names to specific
     567                 :   // family names as necessary.
     568               0 :   nsCAutoString generic_dot_langGroup;
     569               0 :   for (PRUint32 eType = 0; eType < ArrayLength(fontTypes); ++eType) {
     570               0 :     generic_dot_langGroup.Assign(kGenericFont[eType]);
     571               0 :     generic_dot_langGroup.Append(langGroup);
     572                 : 
     573               0 :     nsFont* font = fontTypes[eType];
     574                 : 
     575                 :     // set the default variable font (the other fonts are seen as 'generic' fonts
     576                 :     // in GFX and will be queried there when hunting for alternative fonts)
     577               0 :     if (eType == eDefaultFont_Variable) {
     578               0 :       MAKE_FONT_PREF_KEY(pref, "font.name.variable.", langGroup);
     579                 : 
     580               0 :       nsAdoptingString value = Preferences::GetString(pref.get());
     581               0 :       if (!value.IsEmpty()) {
     582               0 :         prefs->mDefaultVariableFont.name.Assign(value);
     583                 :       }
     584                 :       else {
     585               0 :         MAKE_FONT_PREF_KEY(pref, "font.default.", langGroup);
     586               0 :         value = Preferences::GetString(pref.get());
     587               0 :         if (!value.IsEmpty()) {
     588               0 :           prefs->mDefaultVariableFont.name.Assign(value);
     589                 :         }
     590                 :       } 
     591                 :     }
     592                 :     else {
     593               0 :       if (eType == eDefaultFont_Monospace) {
     594                 :         // This takes care of the confusion whereby people often expect "monospace" 
     595                 :         // to have the same default font-size as "-moz-fixed" (this tentative
     596                 :         // size may be overwritten with the specific value for "monospace" when
     597                 :         // "font.size.monospace.[langGroup]" is read -- see below)
     598               0 :         prefs->mDefaultMonospaceFont.size = prefs->mDefaultFixedFont.size;
     599                 :       }
     600               0 :       else if (eType != eDefaultFont_Fixed) {
     601                 :         // all the other generic fonts are initialized with the size of the
     602                 :         // variable font, but their specific size can supersede later -- see below
     603               0 :         font->size = prefs->mDefaultVariableFont.size;
     604                 :       }
     605                 :     }
     606                 : 
     607                 :     // Bug 84398: for spec purists, a different font-size only applies to the
     608                 :     // .variable. and .fixed. fonts and the other fonts should get |font-size-adjust|.
     609                 :     // The problem is that only GfxWin has the support for |font-size-adjust|. So for
     610                 :     // parity, we enable the ability to set a different font-size on all platforms.
     611                 : 
     612                 :     // get font.size.[generic].[langGroup]
     613                 :     // size=0 means 'Auto', i.e., generic fonts retain the size of the variable font
     614               0 :     MAKE_FONT_PREF_KEY(pref, "font.size", generic_dot_langGroup);
     615               0 :     size = Preferences::GetInt(pref.get());
     616               0 :     if (size > 0) {
     617               0 :       if (unit == eUnit_px) {
     618               0 :         font->size = CSSPixelsToAppUnits(size);
     619                 :       }
     620               0 :       else if (unit == eUnit_pt) {
     621               0 :         font->size = CSSPointsToAppUnits(size);
     622                 :       }
     623                 :     }
     624                 : 
     625                 :     // get font.size-adjust.[generic].[langGroup]
     626                 :     // XXX only applicable on GFX ports that handle |font-size-adjust|
     627               0 :     MAKE_FONT_PREF_KEY(pref, "font.size-adjust", generic_dot_langGroup);
     628               0 :     cvalue = Preferences::GetCString(pref.get());
     629               0 :     if (!cvalue.IsEmpty()) {
     630               0 :       font->sizeAdjust = (float)atof(cvalue.get());
     631                 :     }
     632                 : 
     633                 : #ifdef DEBUG_rbs
     634                 :     printf("%s Family-list:%s size:%d sizeAdjust:%.2f\n",
     635                 :            generic_dot_langGroup.get(),
     636                 :            NS_ConvertUTF16toUTF8(font->name).get(), font->size,
     637                 :            font->sizeAdjust);
     638                 : #endif
     639                 :   }
     640                 : 
     641               0 :   return prefs;
     642                 : }
     643                 : 
     644                 : void
     645               0 : nsPresContext::GetDocumentColorPreferences()
     646                 : {
     647               0 :   PRInt32 useAccessibilityTheme = 0;
     648               0 :   bool usePrefColors = true;
     649               0 :   nsCOMPtr<nsIDocShellTreeItem> docShell(do_QueryReferent(mContainer));
     650               0 :   if (docShell) {
     651                 :     PRInt32 docShellType;
     652               0 :     docShell->GetItemType(&docShellType);
     653               0 :     if (nsIDocShellTreeItem::typeChrome == docShellType) {
     654               0 :       usePrefColors = false;
     655                 :     }
     656                 :     else {
     657                 :       useAccessibilityTheme =
     658               0 :         LookAndFeel::GetInt(LookAndFeel::eIntID_UseAccessibilityTheme, 0);
     659               0 :       usePrefColors = !useAccessibilityTheme;
     660                 :     }
     661                 : 
     662                 :   }
     663               0 :   if (usePrefColors) {
     664                 :     usePrefColors =
     665               0 :       !Preferences::GetBool("browser.display.use_system_colors", false);
     666                 :   }
     667                 : 
     668               0 :   if (usePrefColors) {
     669                 :     nsAdoptingString colorStr =
     670               0 :       Preferences::GetString("browser.display.foreground_color");
     671                 : 
     672               0 :     if (!colorStr.IsEmpty()) {
     673               0 :       mDefaultColor = MakeColorPref(colorStr);
     674                 :     }
     675                 : 
     676               0 :     colorStr = Preferences::GetString("browser.display.background_color");
     677                 : 
     678               0 :     if (!colorStr.IsEmpty()) {
     679               0 :       mBackgroundColor = MakeColorPref(colorStr);
     680                 :     }
     681                 :   }
     682                 :   else {
     683                 :     mDefaultColor =
     684                 :       LookAndFeel::GetColor(LookAndFeel::eColorID_WindowForeground,
     685               0 :                             NS_RGB(0x00, 0x00, 0x00));
     686                 :     mBackgroundColor =
     687                 :       LookAndFeel::GetColor(LookAndFeel::eColorID_WindowBackground,
     688               0 :                             NS_RGB(0xFF, 0xFF, 0xFF));
     689                 :   }
     690                 : 
     691                 :   // Wherever we got the default background color from, ensure it is
     692                 :   // opaque.
     693                 :   mBackgroundColor = NS_ComposeColors(NS_RGB(0xFF, 0xFF, 0xFF),
     694               0 :                                       mBackgroundColor);
     695                 : 
     696                 :   mUseDocumentColors = !useAccessibilityTheme &&
     697                 :     Preferences::GetBool("browser.display.use_document_colors",
     698               0 :                          mUseDocumentColors);
     699               0 : }
     700                 : 
     701                 : void
     702               0 : nsPresContext::GetUserPreferences()
     703                 : {
     704               0 :   if (!GetPresShell()) {
     705                 :     // No presshell means nothing to do here.  We'll do this when we
     706                 :     // get a presshell.
     707               0 :     return;
     708                 :   }
     709                 : 
     710                 :   mAutoQualityMinFontSizePixelsPref =
     711               0 :     Preferences::GetInt("browser.display.auto_quality_min_font_size");
     712                 : 
     713                 :   // * document colors
     714               0 :   GetDocumentColorPreferences();
     715                 : 
     716                 :   mSendAfterPaintToContent =
     717                 :     Preferences::GetBool("dom.send_after_paint_to_content",
     718               0 :                          mSendAfterPaintToContent);
     719                 : 
     720                 :   // * link colors
     721                 :   mUnderlineLinks =
     722               0 :     Preferences::GetBool("browser.underline_anchors", mUnderlineLinks);
     723                 : 
     724               0 :   nsAdoptingString colorStr = Preferences::GetString("browser.anchor_color");
     725                 : 
     726               0 :   if (!colorStr.IsEmpty()) {
     727               0 :     mLinkColor = MakeColorPref(colorStr);
     728                 :   }
     729                 : 
     730               0 :   colorStr = Preferences::GetString("browser.active_color");
     731                 : 
     732               0 :   if (!colorStr.IsEmpty()) {
     733               0 :     mActiveLinkColor = MakeColorPref(colorStr);
     734                 :   }
     735                 : 
     736               0 :   colorStr = Preferences::GetString("browser.visited_color");
     737                 : 
     738               0 :   if (!colorStr.IsEmpty()) {
     739               0 :     mVisitedLinkColor = MakeColorPref(colorStr);
     740                 :   }
     741                 : 
     742                 :   mUseFocusColors =
     743               0 :     Preferences::GetBool("browser.display.use_focus_colors", mUseFocusColors);
     744                 : 
     745               0 :   mFocusTextColor = mDefaultColor;
     746               0 :   mFocusBackgroundColor = mBackgroundColor;
     747                 : 
     748               0 :   colorStr = Preferences::GetString("browser.display.focus_text_color");
     749                 : 
     750               0 :   if (!colorStr.IsEmpty()) {
     751               0 :     mFocusTextColor = MakeColorPref(colorStr);
     752                 :   }
     753                 : 
     754               0 :   colorStr = Preferences::GetString("browser.display.focus_background_color");
     755                 : 
     756               0 :   if (!colorStr.IsEmpty()) {
     757               0 :     mFocusBackgroundColor = MakeColorPref(colorStr);
     758                 :   }
     759                 : 
     760                 :   mFocusRingWidth =
     761               0 :     Preferences::GetInt("browser.display.focus_ring_width", mFocusRingWidth);
     762                 : 
     763                 :   mFocusRingOnAnything =
     764                 :     Preferences::GetBool("browser.display.focus_ring_on_anything",
     765               0 :                          mFocusRingOnAnything);
     766                 : 
     767                 :   mFocusRingStyle =
     768               0 :     Preferences::GetInt("browser.display.focus_ring_style", mFocusRingStyle);
     769                 : 
     770               0 :   mBodyTextColor = mDefaultColor;
     771                 :   
     772                 :   // * use fonts?
     773                 :   mUseDocumentFonts =
     774               0 :     Preferences::GetInt("browser.display.use_document_fonts") != 0;
     775                 : 
     776                 :   // * replace backslashes with Yen signs? (bug 245770)
     777                 :   mEnableJapaneseTransform =
     778               0 :     Preferences::GetBool("layout.enable_japanese_specific_transform");
     779                 : 
     780               0 :   mPrefScrollbarSide = Preferences::GetInt("layout.scrollbar.side");
     781                 : 
     782               0 :   ResetCachedFontPrefs();
     783                 : 
     784                 :   // * image animation
     785                 :   const nsAdoptingCString& animatePref =
     786               0 :     Preferences::GetCString("image.animation_mode");
     787               0 :   if (animatePref.Equals("normal"))
     788               0 :     mImageAnimationModePref = imgIContainer::kNormalAnimMode;
     789               0 :   else if (animatePref.Equals("none"))
     790               0 :     mImageAnimationModePref = imgIContainer::kDontAnimMode;
     791               0 :   else if (animatePref.Equals("once"))
     792               0 :     mImageAnimationModePref = imgIContainer::kLoopOnceAnimMode;
     793                 :   else // dynamic change to invalid value should act like it does initially
     794               0 :     mImageAnimationModePref = imgIContainer::kNormalAnimMode;
     795                 : 
     796               0 :   PRUint32 bidiOptions = GetBidi();
     797                 : 
     798                 :   PRInt32 prefInt =
     799                 :     Preferences::GetInt(IBMBIDI_TEXTDIRECTION_STR,
     800               0 :                         GET_BIDI_OPTION_DIRECTION(bidiOptions));
     801               0 :   SET_BIDI_OPTION_DIRECTION(bidiOptions, prefInt);
     802               0 :   mPrefBidiDirection = prefInt;
     803                 : 
     804                 :   prefInt =
     805                 :     Preferences::GetInt(IBMBIDI_TEXTTYPE_STR,
     806               0 :                         GET_BIDI_OPTION_TEXTTYPE(bidiOptions));
     807               0 :   SET_BIDI_OPTION_TEXTTYPE(bidiOptions, prefInt);
     808                 : 
     809                 :   prefInt =
     810                 :     Preferences::GetInt(IBMBIDI_NUMERAL_STR,
     811               0 :                         GET_BIDI_OPTION_NUMERAL(bidiOptions));
     812               0 :   SET_BIDI_OPTION_NUMERAL(bidiOptions, prefInt);
     813                 : 
     814                 :   prefInt =
     815                 :     Preferences::GetInt(IBMBIDI_SUPPORTMODE_STR,
     816               0 :                         GET_BIDI_OPTION_SUPPORT(bidiOptions));
     817               0 :   SET_BIDI_OPTION_SUPPORT(bidiOptions, prefInt);
     818                 : 
     819                 :   // We don't need to force reflow: either we are initializing a new
     820                 :   // prescontext or we are being called from UpdateAfterPreferencesChanged()
     821                 :   // which triggers a reflow anyway.
     822               0 :   SetBidi(bidiOptions, false);
     823                 : }
     824                 : 
     825                 : void
     826               0 : nsPresContext::InvalidateThebesLayers()
     827                 : {
     828               0 :   if (!mShell)
     829               0 :     return;
     830               0 :   nsIFrame* rootFrame = mShell->FrameManager()->GetRootFrame();
     831               0 :   if (rootFrame) {
     832                 :     // FrameLayerBuilder caches invalidation-related values that depend on the
     833                 :     // appunits-per-dev-pixel ratio, so ensure that all ThebesLayer drawing
     834                 :     // is completely flushed.
     835               0 :     FrameLayerBuilder::InvalidateThebesLayersInSubtree(rootFrame);
     836                 :   }
     837                 : }
     838                 : 
     839                 : void
     840               0 : nsPresContext::AppUnitsPerDevPixelChanged()
     841                 : {
     842               0 :   InvalidateThebesLayers();
     843                 : 
     844               0 :   mDeviceContext->FlushFontCache();
     845                 : 
     846                 :   // All cached style data must be recomputed.
     847               0 :   if (HasCachedStyleData()) {
     848               0 :     MediaFeatureValuesChanged(true);
     849               0 :     RebuildAllStyleData(NS_STYLE_HINT_REFLOW);
     850                 :   }
     851               0 : }
     852                 : 
     853                 : void
     854               0 : nsPresContext::PreferenceChanged(const char* aPrefName)
     855                 : {
     856               0 :   nsDependentCString prefName(aPrefName);
     857               0 :   if (prefName.EqualsLiteral("layout.css.dpi") ||
     858               0 :       prefName.EqualsLiteral("layout.css.devPixelsPerPx")) {
     859               0 :     PRInt32 oldAppUnitsPerDevPixel = AppUnitsPerDevPixel();
     860               0 :     if (mDeviceContext->CheckDPIChange() && mShell) {
     861                 :       // Re-fetch the view manager's window dimensions in case there's a deferred
     862                 :       // resize which hasn't affected our mVisibleArea yet
     863                 :       nscoord oldWidthAppUnits, oldHeightAppUnits;
     864               0 :       nsIViewManager* vm = mShell->GetViewManager();
     865               0 :       vm->GetWindowDimensions(&oldWidthAppUnits, &oldHeightAppUnits);
     866               0 :       float oldWidthDevPixels = oldWidthAppUnits/oldAppUnitsPerDevPixel;
     867               0 :       float oldHeightDevPixels = oldHeightAppUnits/oldAppUnitsPerDevPixel;
     868                 : 
     869               0 :       nscoord width = NSToCoordRound(oldWidthDevPixels*AppUnitsPerDevPixel());
     870               0 :       nscoord height = NSToCoordRound(oldHeightDevPixels*AppUnitsPerDevPixel());
     871               0 :       vm->SetWindowDimensions(width, height);
     872                 : 
     873               0 :       AppUnitsPerDevPixelChanged();
     874                 :     }
     875                 :     return;
     876                 :   }
     877               0 :   if (StringBeginsWith(prefName, NS_LITERAL_CSTRING("font."))) {
     878                 :     // Changes to font family preferences don't change anything in the
     879                 :     // computed style data, so the style system won't generate a reflow
     880                 :     // hint for us.  We need to do that manually.
     881                 : 
     882                 :     // FIXME We could probably also handle changes to
     883                 :     // browser.display.auto_quality_min_font_size here, but that
     884                 :     // probably also requires clearing the text run cache, so don't
     885                 :     // bother (yet, anyway).
     886               0 :     mPrefChangePendingNeedsReflow = true;
     887                 :   }
     888               0 :   if (StringBeginsWith(prefName, NS_LITERAL_CSTRING("bidi."))) {
     889                 :     // Changes to bidi prefs need to trigger a reflow (see bug 443629)
     890               0 :     mPrefChangePendingNeedsReflow = true;
     891                 : 
     892                 :     // Changes to bidi.numeral also needs to empty the text run cache.
     893                 :     // This is handled in gfxTextRunWordCache.cpp.
     894                 :   }
     895               0 :   if (StringBeginsWith(prefName, NS_LITERAL_CSTRING("gfx.font_rendering."))) {
     896                 :     // Changes to font_rendering prefs need to trigger a reflow
     897               0 :     mPrefChangePendingNeedsReflow = true;
     898                 :   }
     899                 :   // we use a zero-delay timer to coalesce multiple pref updates
     900               0 :   if (!mPrefChangedTimer)
     901                 :   {
     902               0 :     mPrefChangedTimer = do_CreateInstance("@mozilla.org/timer;1");
     903               0 :     if (!mPrefChangedTimer)
     904                 :       return;
     905               0 :     mPrefChangedTimer->InitWithFuncCallback(nsPresContext::PrefChangedUpdateTimerCallback, (void*)this, 0, nsITimer::TYPE_ONE_SHOT);
     906                 :   }
     907                 : }
     908                 : 
     909                 : void
     910               0 : nsPresContext::UpdateAfterPreferencesChanged()
     911                 : {
     912               0 :   mPrefChangedTimer = nsnull;
     913                 : 
     914               0 :   nsCOMPtr<nsIDocShellTreeItem> docShell(do_QueryReferent(mContainer));
     915               0 :   if (docShell) {
     916                 :     PRInt32 docShellType;
     917               0 :     docShell->GetItemType(&docShellType);
     918               0 :     if (nsIDocShellTreeItem::typeChrome == docShellType)
     919                 :       return;
     920                 :   }
     921                 : 
     922                 :   // Initialize our state from the user preferences
     923               0 :   GetUserPreferences();
     924                 : 
     925                 :   // update the presShell: tell it to set the preference style rules up
     926               0 :   if (mShell) {
     927               0 :     mShell->SetPreferenceStyleRules(true);
     928                 :   }
     929                 : 
     930               0 :   InvalidateThebesLayers();
     931               0 :   mDeviceContext->FlushFontCache();
     932                 : 
     933               0 :   nsChangeHint hint = nsChangeHint(0);
     934                 : 
     935               0 :   if (mPrefChangePendingNeedsReflow) {
     936               0 :     NS_UpdateHint(hint, NS_STYLE_HINT_REFLOW);
     937                 :   }
     938                 : 
     939               0 :   RebuildAllStyleData(hint);
     940                 : }
     941                 : 
     942                 : nsresult
     943               0 : nsPresContext::Init(nsDeviceContext* aDeviceContext)
     944                 : {
     945               0 :   NS_ASSERTION(!mInitialized, "attempt to reinit pres context");
     946               0 :   NS_ENSURE_ARG(aDeviceContext);
     947                 : 
     948               0 :   mDeviceContext = aDeviceContext;
     949               0 :   NS_ADDREF(mDeviceContext);
     950                 : 
     951               0 :   if (mDeviceContext->SetPixelScale(mFullZoom))
     952               0 :     mDeviceContext->FlushFontCache();
     953               0 :   mCurAppUnitsPerDevPixel = AppUnitsPerDevPixel();
     954                 : 
     955               0 :   for (PRUint32 i = 0; i < IMAGE_LOAD_TYPE_COUNT; ++i)
     956               0 :     if (!mImageLoaders[i].Init())
     957               0 :       return NS_ERROR_OUT_OF_MEMORY;
     958                 : 
     959               0 :   mEventManager = new nsEventStateManager();
     960               0 :   NS_ADDREF(mEventManager);
     961                 : 
     962               0 :   mTransitionManager = new nsTransitionManager(this);
     963                 : 
     964               0 :   mAnimationManager = new nsAnimationManager(this);
     965                 : 
     966               0 :   if (mDocument->GetDisplayDocument()) {
     967               0 :     NS_ASSERTION(mDocument->GetDisplayDocument()->GetShell() &&
     968                 :                  mDocument->GetDisplayDocument()->GetShell()->GetPresContext(),
     969                 :                  "Why are we being initialized?");
     970                 :     mRefreshDriver = mDocument->GetDisplayDocument()->GetShell()->
     971               0 :       GetPresContext()->RefreshDriver();
     972                 :   } else {
     973               0 :     nsIDocument* parent = mDocument->GetParentDocument();
     974                 :     // Unfortunately, sometimes |parent| here has no presshell because
     975                 :     // printing screws up things.  Assert that in other cases it does,
     976                 :     // but whenever the shell is null just fall back on using our own
     977                 :     // refresh driver.
     978               0 :     NS_ASSERTION(!parent || mDocument->IsStaticDocument() || parent->GetShell(),
     979                 :                  "How did we end up with a presshell if our parent doesn't "
     980                 :                  "have one?");
     981               0 :     if (parent && parent->GetShell()) {
     982               0 :       NS_ASSERTION(parent->GetShell()->GetPresContext(),
     983                 :                    "How did we get a presshell?");
     984                 : 
     985                 :       // We don't have our container set yet at this point
     986               0 :       nsCOMPtr<nsISupports> ourContainer = mDocument->GetContainer();
     987                 : 
     988               0 :       nsCOMPtr<nsIDocShellTreeItem> ourItem = do_QueryInterface(ourContainer);
     989               0 :       if (ourItem) {
     990               0 :         nsCOMPtr<nsIDocShellTreeItem> parentItem;
     991               0 :         ourItem->GetSameTypeParent(getter_AddRefs(parentItem));
     992               0 :         if (parentItem) {
     993               0 :           mRefreshDriver = parent->GetShell()->GetPresContext()->RefreshDriver();
     994                 :         }
     995                 :       }
     996                 :     }
     997                 : 
     998               0 :     if (!mRefreshDriver) {
     999               0 :       mRefreshDriver = new nsRefreshDriver(this);
    1000                 :     }
    1001                 :   }
    1002                 : 
    1003               0 :   mLangService = do_GetService(NS_LANGUAGEATOMSERVICE_CONTRACTID);
    1004                 : 
    1005                 :   // Register callbacks so we're notified when the preferences change
    1006                 :   Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
    1007                 :                                 "font.",
    1008               0 :                                 this);
    1009                 :   Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
    1010                 :                                 "browser.display.",
    1011               0 :                                 this);
    1012                 :   Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
    1013                 :                                 "browser.underline_anchors",
    1014               0 :                                 this);
    1015                 :   Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
    1016                 :                                 "browser.anchor_color",
    1017               0 :                                 this);
    1018                 :   Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
    1019                 :                                 "browser.active_color",
    1020               0 :                                 this);
    1021                 :   Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
    1022                 :                                 "browser.visited_color",
    1023               0 :                                 this);
    1024                 :   Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
    1025                 :                                 "image.animation_mode",
    1026               0 :                                 this);
    1027                 : #ifdef IBMBIDI
    1028                 :   Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
    1029                 :                                 "bidi.",
    1030               0 :                                 this);
    1031                 : #endif
    1032                 :   Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
    1033                 :                                 "dom.send_after_paint_to_content",
    1034               0 :                                 this);
    1035                 :   Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
    1036                 :                                 "gfx.font_rendering.",
    1037               0 :                                 this);
    1038                 :   Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
    1039                 :                                 "layout.css.dpi",
    1040               0 :                                 this);
    1041                 :   Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
    1042                 :                                 "layout.css.devPixelsPerPx",
    1043               0 :                                 this);
    1044                 : 
    1045               0 :   nsresult rv = mEventManager->Init();
    1046               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1047                 : 
    1048               0 :   mEventManager->SetPresContext(this);
    1049                 : 
    1050                 : #ifdef DEBUG
    1051               0 :   mInitialized = true;
    1052                 : #endif
    1053                 : 
    1054               0 :   mBorderWidthTable[NS_STYLE_BORDER_WIDTH_THIN] = CSSPixelsToAppUnits(1);
    1055               0 :   mBorderWidthTable[NS_STYLE_BORDER_WIDTH_MEDIUM] = CSSPixelsToAppUnits(3);
    1056               0 :   mBorderWidthTable[NS_STYLE_BORDER_WIDTH_THICK] = CSSPixelsToAppUnits(5);
    1057                 : 
    1058               0 :   return NS_OK;
    1059                 : }
    1060                 : 
    1061                 : // Note: We don't hold a reference on the shell; it has a reference to
    1062                 : // us
    1063                 : void
    1064               0 : nsPresContext::SetShell(nsIPresShell* aShell)
    1065                 : {
    1066               0 :   if (mUserFontSet) {
    1067                 :     // Clear out user font set if we have one
    1068               0 :     mUserFontSet->Destroy();
    1069               0 :     NS_RELEASE(mUserFontSet);
    1070                 :   }
    1071                 : 
    1072               0 :   if (mShell) {
    1073                 :     // Remove ourselves as the charset observer from the shell's doc, because
    1074                 :     // this shell may be going away for good.
    1075               0 :     nsIDocument *doc = mShell->GetDocument();
    1076               0 :     if (doc) {
    1077               0 :       doc->RemoveCharSetObserver(this);
    1078                 :     }
    1079                 :   }    
    1080                 : 
    1081               0 :   mShell = aShell;
    1082                 : 
    1083               0 :   if (mShell) {
    1084               0 :     nsIDocument *doc = mShell->GetDocument();
    1085               0 :     NS_ASSERTION(doc, "expect document here");
    1086               0 :     if (doc) {
    1087                 :       // Have to update PresContext's mDocument before calling any other methods.
    1088               0 :       mDocument = doc;
    1089                 :     }
    1090                 :     // Initialize our state from the user preferences, now that we
    1091                 :     // have a presshell, and hence a document.
    1092               0 :     GetUserPreferences();
    1093                 : 
    1094               0 :     if (doc) {
    1095               0 :       nsIURI *docURI = doc->GetDocumentURI();
    1096                 : 
    1097               0 :       if (IsDynamic() && docURI) {
    1098               0 :         bool isChrome = false;
    1099               0 :         bool isRes = false;
    1100               0 :         docURI->SchemeIs("chrome", &isChrome);
    1101               0 :         docURI->SchemeIs("resource", &isRes);
    1102                 : 
    1103               0 :         if (!isChrome && !isRes)
    1104               0 :           mImageAnimationMode = mImageAnimationModePref;
    1105                 :         else
    1106               0 :           mImageAnimationMode = imgIContainer::kNormalAnimMode;
    1107                 :       }
    1108                 : 
    1109               0 :       if (mLangService) {
    1110               0 :         doc->AddCharSetObserver(this);
    1111               0 :         UpdateCharSet(doc->GetDocumentCharacterSet());
    1112                 :       }
    1113                 :     }
    1114                 :   } else {
    1115               0 :     if (mTransitionManager) {
    1116               0 :       mTransitionManager->Disconnect();
    1117               0 :       mTransitionManager = nsnull;
    1118                 :     }
    1119               0 :     if (mAnimationManager) {
    1120               0 :       mAnimationManager->Disconnect();
    1121               0 :       mAnimationManager = nsnull;
    1122                 :     }
    1123                 : 
    1124               0 :     if (IsRoot()) {
    1125                 :       // Have to cancel our plugin geometry timer, because the
    1126                 :       // callback for that depends on a non-null presshell.
    1127               0 :       static_cast<nsRootPresContext*>(this)->CancelUpdatePluginGeometryTimer();
    1128                 :     }
    1129                 :   }
    1130               0 : }
    1131                 : 
    1132                 : void
    1133               0 : nsPresContext::DestroyImageLoaders()
    1134                 : {
    1135                 :   // Destroy image loaders. This is important to do when frames are being
    1136                 :   // destroyed because imageloaders can have pointers to frames and we don't
    1137                 :   // want those pointers to outlive the destruction of the frame arena.
    1138               0 :   for (PRUint32 i = 0; i < IMAGE_LOAD_TYPE_COUNT; ++i) {
    1139               0 :     mImageLoaders[i].Enumerate(destroy_loads, nsnull);
    1140               0 :     mImageLoaders[i].Clear();
    1141                 :   }
    1142               0 : }
    1143                 : 
    1144                 : void
    1145               0 : nsPresContext::DoChangeCharSet(const nsCString& aCharSet)
    1146                 : {
    1147               0 :   UpdateCharSet(aCharSet);
    1148               0 :   mDeviceContext->FlushFontCache();
    1149               0 :   RebuildAllStyleData(NS_STYLE_HINT_REFLOW);
    1150               0 : }
    1151                 : 
    1152                 : void
    1153               0 : nsPresContext::UpdateCharSet(const nsCString& aCharSet)
    1154                 : {
    1155               0 :   if (mLangService) {
    1156               0 :     NS_IF_RELEASE(mLanguage);
    1157               0 :     mLanguage = mLangService->LookupCharSet(aCharSet.get()).get();  // addrefs
    1158                 :     // this will be a language group (or script) code rather than a true language code
    1159                 : 
    1160                 :     // bug 39570: moved from nsLanguageAtomService::LookupCharSet()
    1161               0 :     if (mLanguage == nsGkAtoms::Unicode) {
    1162               0 :       NS_RELEASE(mLanguage);
    1163               0 :       NS_IF_ADDREF(mLanguage = mLangService->GetLocaleLanguage()); 
    1164                 :     }
    1165               0 :     ResetCachedFontPrefs();
    1166                 :   }
    1167                 : #ifdef IBMBIDI
    1168                 :   //ahmed
    1169                 : 
    1170               0 :   switch (GET_BIDI_OPTION_TEXTTYPE(GetBidi())) {
    1171                 : 
    1172                 :     case IBMBIDI_TEXTTYPE_LOGICAL:
    1173               0 :       SetVisualMode(false);
    1174               0 :       break;
    1175                 : 
    1176                 :     case IBMBIDI_TEXTTYPE_VISUAL:
    1177               0 :       SetVisualMode(true);
    1178               0 :       break;
    1179                 : 
    1180                 :     case IBMBIDI_TEXTTYPE_CHARSET:
    1181                 :     default:
    1182               0 :       SetVisualMode(IsVisualCharset(aCharSet));
    1183                 :   }
    1184                 : #endif // IBMBIDI
    1185               0 : }
    1186                 : 
    1187                 : NS_IMETHODIMP
    1188               0 : nsPresContext::Observe(nsISupports* aSubject, 
    1189                 :                         const char* aTopic,
    1190                 :                         const PRUnichar* aData)
    1191                 : {
    1192               0 :   if (!nsCRT::strcmp(aTopic, "charset")) {
    1193                 :     nsRefPtr<CharSetChangingRunnable> runnable =
    1194               0 :       new CharSetChangingRunnable(this, NS_LossyConvertUTF16toASCII(aData));
    1195               0 :     return NS_DispatchToCurrentThread(runnable);
    1196                 :   }
    1197                 : 
    1198               0 :   NS_WARNING("unrecognized topic in nsPresContext::Observe");
    1199               0 :   return NS_ERROR_FAILURE;
    1200                 : }
    1201                 : 
    1202                 : static nsPresContext*
    1203               0 : GetParentPresContext(nsPresContext* aPresContext)
    1204                 : {
    1205               0 :   nsIPresShell* shell = aPresContext->GetPresShell();
    1206               0 :   if (shell) {
    1207               0 :     nsIFrame* rootFrame = shell->FrameManager()->GetRootFrame();
    1208               0 :     if (rootFrame) {
    1209               0 :       nsIFrame* f = nsLayoutUtils::GetCrossDocParentFrame(rootFrame);
    1210               0 :       if (f)
    1211               0 :         return f->PresContext();
    1212                 :     }
    1213                 :   }
    1214               0 :   return nsnull;
    1215                 : }
    1216                 : 
    1217                 : // We may want to replace this with something faster, maybe caching the root prescontext
    1218                 : nsRootPresContext*
    1219               0 : nsPresContext::GetRootPresContext()
    1220                 : {
    1221               0 :   nsPresContext* pc = this;
    1222               0 :   for (;;) {
    1223               0 :     nsPresContext* parent = GetParentPresContext(pc);
    1224               0 :     if (!parent)
    1225                 :       break;
    1226               0 :     pc = parent;
    1227                 :   }
    1228               0 :   return pc->IsRoot() ? static_cast<nsRootPresContext*>(pc) : nsnull;
    1229                 : }
    1230                 : 
    1231                 : void
    1232               0 : nsPresContext::CompatibilityModeChanged()
    1233                 : {
    1234               0 :   if (!mShell)
    1235               0 :     return;
    1236                 : 
    1237                 :   // enable/disable the QuirkSheet
    1238                 :   mShell->StyleSet()->
    1239               0 :     EnableQuirkStyleSheet(CompatibilityMode() == eCompatibility_NavQuirks);
    1240                 : }
    1241                 : 
    1242                 : // Helper function for setting Anim Mode on image
    1243               0 : static void SetImgAnimModeOnImgReq(imgIRequest* aImgReq, PRUint16 aMode)
    1244                 : {
    1245               0 :   if (aImgReq) {
    1246               0 :     nsCOMPtr<imgIContainer> imgCon;
    1247               0 :     aImgReq->GetImage(getter_AddRefs(imgCon));
    1248               0 :     if (imgCon) {
    1249               0 :       imgCon->SetAnimationMode(aMode);
    1250                 :     }
    1251                 :   }
    1252               0 : }
    1253                 : 
    1254                 :  // Enumeration call back for HashTable
    1255                 : static PLDHashOperator
    1256               0 : set_animation_mode(const void * aKey, nsRefPtr<nsImageLoader>& aData, void* closure)
    1257                 : {
    1258               0 :   for (nsImageLoader *loader = aData; loader;
    1259                 :        loader = loader->GetNextLoader()) {
    1260               0 :     imgIRequest* imgReq = loader->GetRequest();
    1261               0 :     SetImgAnimModeOnImgReq(imgReq, (PRUint16)NS_PTR_TO_INT32(closure));
    1262                 :   }
    1263               0 :   return PL_DHASH_NEXT;
    1264                 : }
    1265                 : 
    1266                 : // IMPORTANT: Assumption is that all images for a Presentation 
    1267                 : // have the same Animation Mode (pavlov said this was OK)
    1268                 : //
    1269                 : // Walks content and set the animation mode
    1270                 : // this is a way to turn on/off image animations
    1271               0 : void nsPresContext::SetImgAnimations(nsIContent *aParent, PRUint16 aMode)
    1272                 : {
    1273               0 :   nsCOMPtr<nsIImageLoadingContent> imgContent(do_QueryInterface(aParent));
    1274               0 :   if (imgContent) {
    1275               0 :     nsCOMPtr<imgIRequest> imgReq;
    1276               0 :     imgContent->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
    1277               0 :                            getter_AddRefs(imgReq));
    1278               0 :     SetImgAnimModeOnImgReq(imgReq, aMode);
    1279                 :   }
    1280                 :   
    1281               0 :   PRUint32 count = aParent->GetChildCount();
    1282               0 :   for (PRUint32 i = 0; i < count; ++i) {
    1283               0 :     SetImgAnimations(aParent->GetChildAt(i), aMode);
    1284                 :   }
    1285               0 : }
    1286                 : 
    1287                 : void
    1288               0 : nsPresContext::SetSMILAnimations(nsIDocument *aDoc, PRUint16 aNewMode,
    1289                 :                                  PRUint16 aOldMode)
    1290                 : {
    1291               0 :   if (aDoc->HasAnimationController()) {
    1292               0 :     nsSMILAnimationController* controller = aDoc->GetAnimationController();
    1293               0 :     switch (aNewMode)
    1294                 :     {
    1295                 :       case imgIContainer::kNormalAnimMode:
    1296                 :       case imgIContainer::kLoopOnceAnimMode:
    1297               0 :         if (aOldMode == imgIContainer::kDontAnimMode)
    1298               0 :           controller->Resume(nsSMILTimeContainer::PAUSE_USERPREF);
    1299               0 :         break;
    1300                 : 
    1301                 :       case imgIContainer::kDontAnimMode:
    1302               0 :         if (aOldMode != imgIContainer::kDontAnimMode)
    1303               0 :           controller->Pause(nsSMILTimeContainer::PAUSE_USERPREF);
    1304               0 :         break;
    1305                 :     }
    1306                 :   }
    1307               0 : }
    1308                 : 
    1309                 : void
    1310               0 : nsPresContext::SetImageAnimationModeInternal(PRUint16 aMode)
    1311                 : {
    1312               0 :   NS_ASSERTION(aMode == imgIContainer::kNormalAnimMode ||
    1313                 :                aMode == imgIContainer::kDontAnimMode ||
    1314                 :                aMode == imgIContainer::kLoopOnceAnimMode, "Wrong Animation Mode is being set!");
    1315                 : 
    1316                 :   // Image animation mode cannot be changed when rendering to a printer.
    1317               0 :   if (!IsDynamic())
    1318               0 :     return;
    1319                 : 
    1320                 :   // Set the mode on the image loaders.
    1321               0 :   for (PRUint32 i = 0; i < IMAGE_LOAD_TYPE_COUNT; ++i)
    1322               0 :     mImageLoaders[i].Enumerate(set_animation_mode, NS_INT32_TO_PTR(aMode));
    1323                 : 
    1324                 :   // Now walk the content tree and set the animation mode 
    1325                 :   // on all the images.
    1326               0 :   if (mShell != nsnull) {
    1327               0 :     nsIDocument *doc = mShell->GetDocument();
    1328               0 :     if (doc) {
    1329               0 :       Element *rootElement = doc->GetRootElement();
    1330               0 :       if (rootElement) {
    1331               0 :         SetImgAnimations(rootElement, aMode);
    1332                 :       }
    1333               0 :       SetSMILAnimations(doc, aMode, mImageAnimationMode);
    1334                 :     }
    1335                 :   }
    1336                 : 
    1337               0 :   mImageAnimationMode = aMode;
    1338                 : }
    1339                 : 
    1340                 : void
    1341               0 : nsPresContext::SetImageAnimationModeExternal(PRUint16 aMode)
    1342                 : {
    1343               0 :   SetImageAnimationModeInternal(aMode);
    1344               0 : }
    1345                 : 
    1346                 : const nsFont*
    1347               0 : nsPresContext::GetDefaultFont(PRUint8 aFontID, nsIAtom *aLanguage) const
    1348                 : {
    1349               0 :   const LangGroupFontPrefs *prefs = GetFontPrefsForLang(aLanguage);
    1350                 : 
    1351                 :   const nsFont *font;
    1352               0 :   switch (aFontID) {
    1353                 :     // Special (our default variable width font and fixed width font)
    1354                 :     case kPresContext_DefaultVariableFont_ID:
    1355               0 :       font = &prefs->mDefaultVariableFont;
    1356               0 :       break;
    1357                 :     case kPresContext_DefaultFixedFont_ID:
    1358               0 :       font = &prefs->mDefaultFixedFont;
    1359               0 :       break;
    1360                 :     // CSS
    1361                 :     case kGenericFont_serif:
    1362               0 :       font = &prefs->mDefaultSerifFont;
    1363               0 :       break;
    1364                 :     case kGenericFont_sans_serif:
    1365               0 :       font = &prefs->mDefaultSansSerifFont;
    1366               0 :       break;
    1367                 :     case kGenericFont_monospace:
    1368               0 :       font = &prefs->mDefaultMonospaceFont;
    1369               0 :       break;
    1370                 :     case kGenericFont_cursive:
    1371               0 :       font = &prefs->mDefaultCursiveFont;
    1372               0 :       break;
    1373                 :     case kGenericFont_fantasy: 
    1374               0 :       font = &prefs->mDefaultFantasyFont;
    1375               0 :       break;
    1376                 :     default:
    1377               0 :       font = nsnull;
    1378               0 :       NS_ERROR("invalid arg");
    1379               0 :       break;
    1380                 :   }
    1381               0 :   return font;
    1382                 : }
    1383                 : 
    1384                 : void
    1385               0 : nsPresContext::SetFullZoom(float aZoom)
    1386                 : {
    1387               0 :   if (!mShell || mFullZoom == aZoom) {
    1388               0 :     return;
    1389                 :   }
    1390                 : 
    1391                 :   // Re-fetch the view manager's window dimensions in case there's a deferred
    1392                 :   // resize which hasn't affected our mVisibleArea yet
    1393                 :   nscoord oldWidthAppUnits, oldHeightAppUnits;
    1394               0 :   mShell->GetViewManager()->GetWindowDimensions(&oldWidthAppUnits, &oldHeightAppUnits);
    1395               0 :   float oldWidthDevPixels = oldWidthAppUnits / float(mCurAppUnitsPerDevPixel);
    1396               0 :   float oldHeightDevPixels = oldHeightAppUnits / float(mCurAppUnitsPerDevPixel);
    1397               0 :   mDeviceContext->SetPixelScale(aZoom);
    1398                 : 
    1399               0 :   NS_ASSERTION(!mSupressResizeReflow, "two zooms happening at the same time? impossible!");
    1400               0 :   mSupressResizeReflow = true;
    1401                 : 
    1402               0 :   mFullZoom = aZoom;
    1403               0 :   mShell->GetViewManager()->
    1404               0 :     SetWindowDimensions(NSToCoordRound(oldWidthDevPixels * AppUnitsPerDevPixel()),
    1405               0 :                         NSToCoordRound(oldHeightDevPixels * AppUnitsPerDevPixel()));
    1406                 : 
    1407               0 :   AppUnitsPerDevPixelChanged();
    1408                 : 
    1409               0 :   mSupressResizeReflow = false;
    1410                 : 
    1411               0 :   mCurAppUnitsPerDevPixel = AppUnitsPerDevPixel();
    1412                 : }
    1413                 : 
    1414                 : void
    1415               0 : nsPresContext::SetImageLoaders(nsIFrame* aTargetFrame,
    1416                 :                                ImageLoadType aType,
    1417                 :                                nsImageLoader* aImageLoaders)
    1418                 : {
    1419               0 :   NS_ASSERTION(mShell || !aImageLoaders,
    1420                 :                "Shouldn't add new image loader after the shell is gone");
    1421                 : 
    1422               0 :   nsRefPtr<nsImageLoader> oldLoaders;
    1423               0 :   mImageLoaders[aType].Get(aTargetFrame, getter_AddRefs(oldLoaders));
    1424                 : 
    1425               0 :   if (aImageLoaders) {
    1426               0 :     mImageLoaders[aType].Put(aTargetFrame, aImageLoaders);
    1427               0 :   } else if (oldLoaders) {
    1428               0 :     mImageLoaders[aType].Remove(aTargetFrame);
    1429                 :   }
    1430                 : 
    1431               0 :   if (oldLoaders)
    1432               0 :     oldLoaders->Destroy();
    1433               0 : }
    1434                 : 
    1435                 : void
    1436               0 : nsPresContext::SetupBackgroundImageLoaders(nsIFrame* aFrame,
    1437                 :                                      const nsStyleBackground* aStyleBackground)
    1438                 : {
    1439               0 :   nsRefPtr<nsImageLoader> loaders;
    1440               0 :   NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, aStyleBackground) {
    1441               0 :     if (aStyleBackground->mLayers[i].mImage.GetType() == eStyleImageType_Image) {
    1442               0 :       PRUint32 actions = nsImageLoader::ACTION_REDRAW_ON_DECODE;
    1443               0 :       imgIRequest *image = aStyleBackground->mLayers[i].mImage.GetImageData();
    1444               0 :       loaders = nsImageLoader::Create(aFrame, image, actions, loaders);
    1445                 :     }
    1446                 :   }
    1447               0 :   SetImageLoaders(aFrame, BACKGROUND_IMAGE, loaders);
    1448               0 : }
    1449                 : 
    1450                 : void
    1451               0 : nsPresContext::SetupBorderImageLoaders(nsIFrame* aFrame,
    1452                 :                                        const nsStyleBorder* aStyleBorder)
    1453                 : {
    1454                 :   // We get called the first time we try to draw a border-image, and
    1455                 :   // also when the border image changes (including when it changes from
    1456                 :   // non-null to null).
    1457               0 :   imgIRequest *borderImage = aStyleBorder->GetBorderImage();
    1458               0 :   if (!borderImage) {
    1459               0 :     SetImageLoaders(aFrame, BORDER_IMAGE, nsnull);
    1460               0 :     return;
    1461                 :   }
    1462                 : 
    1463               0 :   PRUint32 actions = nsImageLoader::ACTION_REDRAW_ON_LOAD;
    1464               0 :   if (aStyleBorder->ImageBorderDiffers())
    1465               0 :     actions |= nsImageLoader::ACTION_REFLOW_ON_LOAD;
    1466                 :   nsRefPtr<nsImageLoader> loader =
    1467               0 :     nsImageLoader::Create(aFrame, borderImage, actions, nsnull);
    1468               0 :   SetImageLoaders(aFrame, BORDER_IMAGE, loader);
    1469                 : }
    1470                 : 
    1471                 : void
    1472               0 : nsPresContext::StopImagesFor(nsIFrame* aTargetFrame)
    1473                 : {
    1474               0 :   for (PRUint32 i = 0; i < IMAGE_LOAD_TYPE_COUNT; ++i)
    1475               0 :     SetImageLoaders(aTargetFrame, ImageLoadType(i), nsnull);
    1476               0 : }
    1477                 : 
    1478                 : void
    1479               0 : nsPresContext::SetContainer(nsISupports* aHandler)
    1480                 : {
    1481               0 :   mContainer = do_GetWeakReference(aHandler);
    1482               0 :   InvalidateIsChromeCache();
    1483               0 :   if (mContainer) {
    1484               0 :     GetDocumentColorPreferences();
    1485                 :   }
    1486               0 : }
    1487                 : 
    1488                 : already_AddRefed<nsISupports>
    1489               0 : nsPresContext::GetContainerInternal() const
    1490                 : {
    1491               0 :   nsISupports *result = nsnull;
    1492               0 :   if (mContainer)
    1493               0 :     CallQueryReferent(mContainer.get(), &result);
    1494                 : 
    1495               0 :   return result;
    1496                 : }
    1497                 : 
    1498                 : already_AddRefed<nsISupports>
    1499               0 : nsPresContext::GetContainerExternal() const
    1500                 : {
    1501               0 :   return GetContainerInternal();
    1502                 : }
    1503                 : 
    1504                 : #ifdef IBMBIDI
    1505                 : void
    1506               0 : nsPresContext::SetBidiEnabled() const
    1507                 : {
    1508               0 :   if (mShell) {
    1509               0 :     nsIDocument *doc = mShell->GetDocument();
    1510               0 :     if (doc) {
    1511               0 :       doc->SetBidiEnabled();
    1512                 :     }
    1513                 :   }
    1514               0 : }
    1515                 : 
    1516                 : void
    1517               0 : nsPresContext::SetBidi(PRUint32 aSource, bool aForceRestyle)
    1518                 : {
    1519                 :   // Don't do all this stuff unless the options have changed.
    1520               0 :   if (aSource == GetBidi()) {
    1521               0 :     return;
    1522                 :   }
    1523                 : 
    1524               0 :   NS_ASSERTION(!(aForceRestyle && (GetBidi() == 0)), 
    1525                 :                "ForceReflow on new prescontext");
    1526                 : 
    1527               0 :   Document()->SetBidiOptions(aSource);
    1528               0 :   if (IBMBIDI_TEXTDIRECTION_RTL == GET_BIDI_OPTION_DIRECTION(aSource)
    1529                 :       || IBMBIDI_NUMERAL_HINDI == GET_BIDI_OPTION_NUMERAL(aSource)) {
    1530               0 :     SetBidiEnabled();
    1531                 :   }
    1532               0 :   if (IBMBIDI_TEXTTYPE_VISUAL == GET_BIDI_OPTION_TEXTTYPE(aSource)) {
    1533               0 :     SetVisualMode(true);
    1534                 :   }
    1535               0 :   else if (IBMBIDI_TEXTTYPE_LOGICAL == GET_BIDI_OPTION_TEXTTYPE(aSource)) {
    1536               0 :     SetVisualMode(false);
    1537                 :   }
    1538                 :   else {
    1539               0 :     nsIDocument* doc = mShell->GetDocument();
    1540               0 :     if (doc) {
    1541               0 :       SetVisualMode(IsVisualCharset(doc->GetDocumentCharacterSet()));
    1542                 :     }
    1543                 :   }
    1544               0 :   if (aForceRestyle && mShell) {
    1545                 :     // Reconstruct the root document element's frame and its children,
    1546                 :     // because we need to trigger frame reconstruction for direction change.
    1547               0 :     RebuildUserFontSet();
    1548               0 :     mShell->ReconstructFrames();
    1549                 :   }
    1550                 : }
    1551                 : 
    1552                 : PRUint32
    1553               0 : nsPresContext::GetBidi() const
    1554                 : {
    1555               0 :   return Document()->GetBidiOptions();
    1556                 : }
    1557                 : 
    1558                 : #endif //IBMBIDI
    1559                 : 
    1560                 : bool
    1561               0 : nsPresContext::IsTopLevelWindowInactive()
    1562                 : {
    1563               0 :   nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryReferent(mContainer));
    1564               0 :   if (!treeItem)
    1565               0 :     return false;
    1566                 : 
    1567               0 :   nsCOMPtr<nsIDocShellTreeItem> rootItem;
    1568               0 :   treeItem->GetRootTreeItem(getter_AddRefs(rootItem));
    1569               0 :   nsCOMPtr<nsPIDOMWindow> domWindow(do_GetInterface(rootItem));
    1570                 : 
    1571               0 :   return domWindow && !domWindow->IsActive();
    1572                 : }
    1573                 : 
    1574                 : nsITheme*
    1575               0 : nsPresContext::GetTheme()
    1576                 : {
    1577               0 :   if (!sNoTheme && !mTheme) {
    1578               0 :     mTheme = do_GetService("@mozilla.org/chrome/chrome-native-theme;1");
    1579               0 :     if (!mTheme)
    1580               0 :       sNoTheme = true;
    1581                 :   }
    1582                 : 
    1583               0 :   return mTheme;
    1584                 : }
    1585                 : 
    1586                 : void
    1587               0 : nsPresContext::ThemeChanged()
    1588                 : {
    1589               0 :   if (!mPendingThemeChanged) {
    1590               0 :     sLookAndFeelChanged = true;
    1591               0 :     sThemeChanged = true;
    1592                 : 
    1593                 :     nsCOMPtr<nsIRunnable> ev =
    1594               0 :       NS_NewRunnableMethod(this, &nsPresContext::ThemeChangedInternal);
    1595               0 :     if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) {
    1596               0 :       mPendingThemeChanged = true;
    1597                 :     }
    1598                 :   }    
    1599               0 : }
    1600                 : 
    1601                 : void
    1602               0 : nsPresContext::ThemeChangedInternal()
    1603                 : {
    1604               0 :   mPendingThemeChanged = false;
    1605                 :   
    1606                 :   // Tell the theme that it changed, so it can flush any handles to stale theme
    1607                 :   // data.
    1608               0 :   if (mTheme && sThemeChanged) {
    1609               0 :     mTheme->ThemeChanged();
    1610               0 :     sThemeChanged = false;
    1611                 :   }
    1612                 : 
    1613                 :   // Clear all cached LookAndFeel colors.
    1614               0 :   if (sLookAndFeelChanged) {
    1615               0 :     LookAndFeel::Refresh();
    1616               0 :     sLookAndFeelChanged = false;
    1617                 :   }
    1618                 : 
    1619                 :   // This will force the system metrics to be generated the next time they're used
    1620               0 :   nsCSSRuleProcessor::FreeSystemMetrics();
    1621                 : 
    1622                 :   // Changes to system metrics can change media queries on them.
    1623               0 :   MediaFeatureValuesChanged(true);
    1624                 : 
    1625                 :   // Changes in theme can change system colors (whose changes are
    1626                 :   // properly reflected in computed style data), system fonts (whose
    1627                 :   // changes are not), and -moz-appearance (whose changes likewise are
    1628                 :   // not), so we need to reflow.
    1629               0 :   RebuildAllStyleData(NS_STYLE_HINT_REFLOW);
    1630               0 : }
    1631                 : 
    1632                 : void
    1633               0 : nsPresContext::SysColorChanged()
    1634                 : {
    1635               0 :   if (!mPendingSysColorChanged) {
    1636               0 :     sLookAndFeelChanged = true;
    1637                 :     nsCOMPtr<nsIRunnable> ev =
    1638               0 :       NS_NewRunnableMethod(this, &nsPresContext::SysColorChangedInternal);
    1639               0 :     if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) {
    1640               0 :       mPendingSysColorChanged = true;
    1641                 :     }
    1642                 :   }
    1643               0 : }
    1644                 : 
    1645                 : void
    1646               0 : nsPresContext::SysColorChangedInternal()
    1647                 : {
    1648               0 :   mPendingSysColorChanged = false;
    1649                 :   
    1650               0 :   if (sLookAndFeelChanged) {
    1651                 :      // Don't use the cached values for the system colors
    1652               0 :     LookAndFeel::Refresh();
    1653               0 :     sLookAndFeelChanged = false;
    1654                 :   }
    1655                 :    
    1656                 :   // Reset default background and foreground colors for the document since
    1657                 :   // they may be using system colors
    1658               0 :   GetDocumentColorPreferences();
    1659                 : 
    1660                 :   // The system color values are computed to colors in the style data,
    1661                 :   // so normal style data comparison is sufficient here.
    1662               0 :   RebuildAllStyleData(nsChangeHint(0));
    1663               0 : }
    1664                 : 
    1665                 : void
    1666               0 : nsPresContext::RebuildAllStyleData(nsChangeHint aExtraHint)
    1667                 : {
    1668               0 :   if (!mShell) {
    1669                 :     // We must have been torn down. Nothing to do here.
    1670               0 :     return;
    1671                 :   }
    1672                 : 
    1673               0 :   RebuildUserFontSet();
    1674               0 :   AnimationManager()->KeyframesListIsDirty();
    1675                 : 
    1676               0 :   mShell->FrameConstructor()->RebuildAllStyleData(aExtraHint);
    1677                 : }
    1678                 : 
    1679                 : void
    1680               0 : nsPresContext::PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint)
    1681                 : {
    1682               0 :   if (!mShell) {
    1683                 :     // We must have been torn down. Nothing to do here.
    1684               0 :     return;
    1685                 :   }
    1686               0 :   mShell->FrameConstructor()->PostRebuildAllStyleDataEvent(aExtraHint);
    1687                 : }
    1688                 : 
    1689                 : void
    1690               0 : nsPresContext::MediaFeatureValuesChanged(bool aCallerWillRebuildStyleData)
    1691                 : {
    1692               0 :   mPendingMediaFeatureValuesChanged = false;
    1693               0 :   if (mShell &&
    1694               0 :       mShell->StyleSet()->MediumFeaturesChanged(this) &&
    1695               0 :       !aCallerWillRebuildStyleData) {
    1696               0 :     RebuildAllStyleData(nsChangeHint(0));
    1697                 :   }
    1698                 : 
    1699               0 :   if (!nsContentUtils::IsSafeToRunScript()) {
    1700               0 :     NS_ABORT_IF_FALSE(mDocument->IsBeingUsedAsImage(),
    1701                 :                       "How did we get here?  Are we failing to notify "
    1702                 :                       "listeners that we should notify?");
    1703               0 :     return;
    1704                 :   }
    1705                 : 
    1706                 :   // Media query list listeners should be notified from a queued task
    1707                 :   // (in HTML5 terms), although we also want to notify them on certain
    1708                 :   // flushes.  (We're already running off an event.)
    1709                 :   //
    1710                 :   // Note that we do this after the new style from media queries in
    1711                 :   // style sheets has been computed.
    1712                 : 
    1713               0 :   if (!PR_CLIST_IS_EMPTY(&mDOMMediaQueryLists)) {
    1714                 :     // We build a list of all the notifications we're going to send
    1715                 :     // before we send any of them.  (The spec says the notifications
    1716                 :     // should be a queued task, so any removals that happen during the
    1717                 :     // notifications shouldn't affect what gets notified.)  Furthermore,
    1718                 :     // we hold strong pointers to everything we're going to make
    1719                 :     // notification calls to, since each notification involves calling
    1720                 :     // arbitrary script that might otherwise destroy these objects, or,
    1721                 :     // for that matter, |this|.
    1722                 :     //
    1723                 :     // Note that we intentionally send the notifications to media query
    1724                 :     // list in the order they were created and, for each list, to the
    1725                 :     // listeners in the order added.
    1726               0 :     nsDOMMediaQueryList::NotifyList notifyList;
    1727               0 :     for (PRCList *l = PR_LIST_HEAD(&mDOMMediaQueryLists);
    1728                 :          l != &mDOMMediaQueryLists; l = PR_NEXT_LINK(l)) {
    1729               0 :       nsDOMMediaQueryList *mql = static_cast<nsDOMMediaQueryList*>(l);
    1730               0 :       mql->MediumFeaturesChanged(notifyList);
    1731                 :     }
    1732                 : 
    1733               0 :     if (!notifyList.IsEmpty()) {
    1734               0 :       nsPIDOMWindow *win = mDocument->GetInnerWindow();
    1735               0 :       nsCOMPtr<nsIDOMEventTarget> et = do_QueryInterface(win);
    1736               0 :       nsCxPusher pusher;
    1737                 : 
    1738               0 :       for (PRUint32 i = 0, i_end = notifyList.Length(); i != i_end; ++i) {
    1739               0 :         if (pusher.RePush(et)) {
    1740               0 :           nsDOMMediaQueryList::HandleChangeData &d = notifyList[i];
    1741               0 :           d.listener->HandleChange(d.mql);
    1742                 :         }
    1743                 :       }
    1744                 :     }
    1745                 : 
    1746                 :     // NOTE:  When |notifyList| goes out of scope, our destructor could run.
    1747                 :   }
    1748                 : }
    1749                 : 
    1750                 : void
    1751               0 : nsPresContext::PostMediaFeatureValuesChangedEvent()
    1752                 : {
    1753                 :   // FIXME: We should probably replace this event with use of
    1754                 :   // nsRefreshDriver::AddStyleFlushObserver (except the pres shell would
    1755                 :   // need to track whether it's been added).
    1756               0 :   if (!mPendingMediaFeatureValuesChanged) {
    1757                 :     nsCOMPtr<nsIRunnable> ev =
    1758               0 :       NS_NewRunnableMethod(this, &nsPresContext::HandleMediaFeatureValuesChangedEvent);
    1759               0 :     if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) {
    1760               0 :       mPendingMediaFeatureValuesChanged = true;
    1761               0 :       mDocument->SetNeedStyleFlush();
    1762                 :     }
    1763                 :   }
    1764               0 : }
    1765                 : 
    1766                 : void
    1767               0 : nsPresContext::HandleMediaFeatureValuesChangedEvent()
    1768                 : {
    1769                 :   // Null-check mShell in case the shell has been destroyed (and the
    1770                 :   // event is the only thing holding the pres context alive).
    1771               0 :   if (mPendingMediaFeatureValuesChanged && mShell) {
    1772               0 :     MediaFeatureValuesChanged(false);
    1773                 :   }
    1774               0 : }
    1775                 : 
    1776                 : void
    1777               0 : nsPresContext::MatchMedia(const nsAString& aMediaQueryList,
    1778                 :                           nsIDOMMediaQueryList** aResult)
    1779                 : {
    1780                 :   nsRefPtr<nsDOMMediaQueryList> result =
    1781               0 :     new nsDOMMediaQueryList(this, aMediaQueryList);
    1782                 : 
    1783                 :   // Insert the new item at the end of the linked list.
    1784               0 :   PR_INSERT_BEFORE(result, &mDOMMediaQueryLists);
    1785                 : 
    1786               0 :   result.forget(aResult);
    1787               0 : }
    1788                 : 
    1789                 : void
    1790               0 : nsPresContext::SetPaginatedScrolling(bool aPaginated)
    1791                 : {
    1792               0 :   if (mType == eContext_PrintPreview || mType == eContext_PageLayout)
    1793               0 :     mCanPaginatedScroll = aPaginated;
    1794               0 : }
    1795                 : 
    1796                 : void
    1797               0 : nsPresContext::SetPrintSettings(nsIPrintSettings *aPrintSettings)
    1798                 : {
    1799               0 :   if (mMedium == nsGkAtoms::print)
    1800               0 :     mPrintSettings = aPrintSettings;
    1801               0 : }
    1802                 : 
    1803                 : bool
    1804               0 : nsPresContext::EnsureVisible()
    1805                 : {
    1806               0 :   nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mContainer));
    1807               0 :   if (docShell) {
    1808               0 :     nsCOMPtr<nsIContentViewer> cv;
    1809               0 :     docShell->GetContentViewer(getter_AddRefs(cv));
    1810                 :     // Make sure this is the content viewer we belong with
    1811               0 :     if (cv) {
    1812               0 :       nsRefPtr<nsPresContext> currentPresContext;
    1813               0 :       cv->GetPresContext(getter_AddRefs(currentPresContext));
    1814               0 :       if (currentPresContext == this) {
    1815                 :         // OK, this is us.  We want to call Show() on the content viewer.
    1816               0 :         cv->Show();
    1817               0 :         return true;
    1818                 :       }
    1819                 :     }
    1820                 :   }
    1821               0 :   return false;
    1822                 : }
    1823                 : 
    1824                 : #ifdef MOZ_REFLOW_PERF
    1825                 : void
    1826               0 : nsPresContext::CountReflows(const char * aName, nsIFrame * aFrame)
    1827                 : {
    1828               0 :   if (mShell) {
    1829               0 :     mShell->CountReflows(aName, aFrame);
    1830                 :   }
    1831               0 : }
    1832                 : #endif
    1833                 : 
    1834                 : bool
    1835               0 : nsPresContext::IsChromeSlow() const
    1836                 : {
    1837               0 :   bool isChrome = false;
    1838               0 :   nsCOMPtr<nsISupports> container = GetContainer();
    1839               0 :   if (container) {
    1840                 :     nsresult result;
    1841               0 :     nsCOMPtr<nsIDocShellTreeItem> docShell(do_QueryInterface(container, &result));
    1842               0 :     if (NS_SUCCEEDED(result) && docShell) {
    1843                 :       PRInt32 docShellType;
    1844               0 :       result = docShell->GetItemType(&docShellType);
    1845               0 :       if (NS_SUCCEEDED(result)) {
    1846               0 :         isChrome = nsIDocShellTreeItem::typeChrome == docShellType;
    1847                 :       }
    1848                 :     }
    1849                 :   }
    1850               0 :   mIsChrome = isChrome;
    1851               0 :   mIsChromeIsCached = true;
    1852               0 :   return mIsChrome;
    1853                 : }
    1854                 : 
    1855                 : void
    1856               0 : nsPresContext::InvalidateIsChromeCacheExternal()
    1857                 : {
    1858               0 :   InvalidateIsChromeCacheInternal();
    1859               0 : }
    1860                 : 
    1861                 : /* virtual */ bool
    1862               0 : nsPresContext::HasAuthorSpecifiedRules(nsIFrame *aFrame, PRUint32 ruleTypeMask) const
    1863                 : {
    1864                 :   return
    1865                 :     nsRuleNode::HasAuthorSpecifiedRules(aFrame->GetStyleContext(),
    1866                 :                                         ruleTypeMask,
    1867               0 :                                         UseDocumentColors());
    1868                 : }
    1869                 : 
    1870                 : gfxUserFontSet*
    1871               0 : nsPresContext::GetUserFontSetInternal()
    1872                 : {
    1873                 :   // We want to initialize the user font set lazily the first time the
    1874                 :   // user asks for it, rather than building it too early and forcing
    1875                 :   // rule cascade creation.  Thus we try to enforce the invariant that
    1876                 :   // we *never* build the user font set until the first call to
    1877                 :   // GetUserFontSet.  However, once it's been requested, we can't wait
    1878                 :   // for somebody to call GetUserFontSet in order to rebuild it (see
    1879                 :   // comments below in RebuildUserFontSet for why).
    1880                 : #ifdef DEBUG
    1881               0 :   bool userFontSetGottenBefore = mGetUserFontSetCalled;
    1882                 : #endif
    1883                 :   // Set mGetUserFontSetCalled up front, so that FlushUserFontSet will actually
    1884                 :   // flush.
    1885               0 :   mGetUserFontSetCalled = true;
    1886               0 :   if (mUserFontSetDirty) {
    1887                 :     // If this assertion fails, and there have actually been changes to
    1888                 :     // @font-face rules, then we will call StyleChangeReflow in
    1889                 :     // FlushUserFontSet.  If we're in the middle of reflow,
    1890                 :     // that's a bad thing to do, and the caller was responsible for
    1891                 :     // flushing first.  If we're not (e.g., in frame construction), it's
    1892                 :     // ok.
    1893               0 :     NS_ASSERTION(!userFontSetGottenBefore || !mShell->IsReflowLocked(),
    1894                 :                  "FlushUserFontSet should have been called first");
    1895               0 :     FlushUserFontSet();
    1896                 :   }
    1897                 : 
    1898               0 :   return mUserFontSet;
    1899                 : }
    1900                 : 
    1901                 : gfxUserFontSet*
    1902               0 : nsPresContext::GetUserFontSetExternal()
    1903                 : {
    1904               0 :   return GetUserFontSetInternal();
    1905                 : }
    1906                 : 
    1907                 : void
    1908               0 : nsPresContext::FlushUserFontSet()
    1909                 : {
    1910               0 :   if (!mShell) {
    1911               0 :     return; // we've been torn down
    1912                 :   }
    1913                 : 
    1914               0 :   if (!mGetUserFontSetCalled) {
    1915               0 :     return; // No one cares about this font set yet, but we want to be careful
    1916                 :             // to not unset our mUserFontSetDirty bit, so when someone really
    1917                 :             // does we'll create it.
    1918                 :   }
    1919                 : 
    1920               0 :   if (mUserFontSetDirty) {
    1921               0 :     if (gfxPlatform::GetPlatform()->DownloadableFontsEnabled()) {
    1922               0 :       nsTArray<nsFontFaceRuleContainer> rules;
    1923               0 :       if (!mShell->StyleSet()->AppendFontFaceRules(this, rules)) {
    1924               0 :         if (mUserFontSet) {
    1925               0 :           mUserFontSet->Destroy();
    1926               0 :           NS_RELEASE(mUserFontSet);
    1927                 :         }
    1928                 :         return;
    1929                 :       }
    1930                 : 
    1931               0 :       bool changed = false;
    1932                 : 
    1933               0 :       if (rules.Length() == 0) {
    1934               0 :         if (mUserFontSet) {
    1935               0 :           mUserFontSet->Destroy();
    1936               0 :           NS_RELEASE(mUserFontSet);
    1937               0 :           changed = true;
    1938                 :         }
    1939                 :       } else {
    1940               0 :         if (!mUserFontSet) {
    1941               0 :           mUserFontSet = new nsUserFontSet(this);
    1942               0 :           NS_ADDREF(mUserFontSet);
    1943                 :         }
    1944               0 :         changed = mUserFontSet->UpdateRules(rules);
    1945                 :       }
    1946                 : 
    1947                 :       // We need to enqueue a style change reflow (for later) to
    1948                 :       // reflect that we're modifying @font-face rules.  (However,
    1949                 :       // without a reflow, nothing will happen to start any downloads
    1950                 :       // that are needed.)
    1951               0 :       if (changed) {
    1952               0 :         UserFontSetUpdated();
    1953                 :       }
    1954                 :     }
    1955                 : 
    1956               0 :     mUserFontSetDirty = false;
    1957                 :   }
    1958                 : }
    1959                 : 
    1960                 : void
    1961               0 : nsPresContext::RebuildUserFontSet()
    1962                 : {
    1963               0 :   if (!mGetUserFontSetCalled) {
    1964                 :     // We want to lazily build the user font set the first time it's
    1965                 :     // requested (so we don't force creation of rule cascades too
    1966                 :     // early), so don't do anything now.
    1967               0 :     return;
    1968                 :   }
    1969                 : 
    1970               0 :   mUserFontSetDirty = true;
    1971               0 :   mDocument->SetNeedStyleFlush();
    1972                 : 
    1973                 :   // Somebody has already asked for the user font set, so we need to
    1974                 :   // post an event to rebuild it.  Setting the user font set to be dirty
    1975                 :   // and lazily rebuilding it isn't sufficient, since it is only the act
    1976                 :   // of rebuilding it that will trigger the style change reflow that
    1977                 :   // calls GetUserFontSet.  (This reflow causes rebuilding of text runs,
    1978                 :   // which starts font loads, whose completion causes another style
    1979                 :   // change reflow).
    1980               0 :   if (!mPostedFlushUserFontSet) {
    1981                 :     nsCOMPtr<nsIRunnable> ev =
    1982               0 :       NS_NewRunnableMethod(this, &nsPresContext::HandleRebuildUserFontSet);
    1983               0 :     if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) {
    1984               0 :       mPostedFlushUserFontSet = true;
    1985                 :     }
    1986                 :   }    
    1987                 : }
    1988                 : 
    1989                 : void
    1990               0 : nsPresContext::UserFontSetUpdated()
    1991                 : {
    1992               0 :   if (!mShell)
    1993               0 :     return;
    1994                 : 
    1995                 :   // Changes to the set of available fonts can cause updates to layout by:
    1996                 :   //
    1997                 :   //   1. Changing the font used for text, which changes anything that
    1998                 :   //      depends on text measurement, including line breaking and
    1999                 :   //      intrinsic widths, and any other parts of layout that depend on
    2000                 :   //      font metrics.  This requires a style change reflow to update.
    2001                 :   //
    2002                 :   //   2. Changing the value of the 'ex' and 'ch' units in style data,
    2003                 :   //      which also depend on font metrics.  Updating this information
    2004                 :   //      requires rebuilding the rule tree from the top, avoiding the
    2005                 :   //      reuse of cached data even when no style rules have changed.
    2006                 : 
    2007               0 :   PostRebuildAllStyleDataEvent(NS_STYLE_HINT_REFLOW);
    2008                 : }
    2009                 : 
    2010                 : bool
    2011               0 : nsPresContext::EnsureSafeToHandOutCSSRules()
    2012                 : {
    2013                 :   nsCSSStyleSheet::EnsureUniqueInnerResult res =
    2014               0 :     mShell->StyleSet()->EnsureUniqueInnerOnCSSSheets();
    2015               0 :   if (res == nsCSSStyleSheet::eUniqueInner_AlreadyUnique) {
    2016                 :     // Nothing to do.
    2017               0 :     return true;
    2018                 :   }
    2019               0 :   if (res == nsCSSStyleSheet::eUniqueInner_CloneFailed) {
    2020               0 :     return false;
    2021                 :   }
    2022                 : 
    2023               0 :   NS_ABORT_IF_FALSE(res == nsCSSStyleSheet::eUniqueInner_ClonedInner,
    2024                 :                     "unexpected result");
    2025               0 :   RebuildAllStyleData(nsChangeHint(0));
    2026               0 :   return true;
    2027                 : }
    2028                 : 
    2029                 : void
    2030               0 : nsPresContext::FireDOMPaintEvent()
    2031                 : {
    2032               0 :   nsPIDOMWindow* ourWindow = mDocument->GetWindow();
    2033               0 :   if (!ourWindow)
    2034               0 :     return;
    2035                 : 
    2036               0 :   nsCOMPtr<nsIDOMEventTarget> dispatchTarget = do_QueryInterface(ourWindow);
    2037               0 :   nsCOMPtr<nsIDOMEventTarget> eventTarget = dispatchTarget;
    2038               0 :   if (!IsChrome()) {
    2039               0 :     bool notifyContent = mSendAfterPaintToContent;
    2040                 : 
    2041               0 :     if (notifyContent) {
    2042                 :       // If the pref is set, we still don't post events when they're
    2043                 :       // entirely cross-doc.
    2044               0 :       notifyContent = false;
    2045               0 :       for (PRUint32 i = 0; i < mInvalidateRequests.mRequests.Length(); ++i) {
    2046               0 :         if (!(mInvalidateRequests.mRequests[i].mFlags &
    2047               0 :               nsIFrame::INVALIDATE_CROSS_DOC)) {
    2048               0 :           notifyContent = true;
    2049                 :         }
    2050                 :       }
    2051                 :     }
    2052               0 :     if (!notifyContent) {
    2053                 :       // Don't tell the window about this event, it should not know that
    2054                 :       // something happened in a subdocument. Tell only the chrome event handler.
    2055                 :       // (Events sent to the window get propagated to the chrome event handler
    2056                 :       // automatically.)
    2057               0 :       dispatchTarget = do_QueryInterface(ourWindow->GetParentTarget());
    2058               0 :       if (!dispatchTarget) {
    2059                 :         return;
    2060                 :       }
    2061                 :     }
    2062                 :   }
    2063                 :   // Events sent to the window get propagated to the chrome event handler
    2064                 :   // automatically.
    2065               0 :   nsCOMPtr<nsIDOMEvent> event;
    2066                 :   // This will empty our list in case dispatching the event causes more damage
    2067                 :   // (hopefully it won't, or we're likely to get an infinite loop! At least
    2068                 :   // it won't be blocking app execution though).
    2069               0 :   NS_NewDOMNotifyPaintEvent(getter_AddRefs(event), this, nsnull,
    2070                 :                             NS_AFTERPAINT,
    2071               0 :                             &mInvalidateRequests);
    2072               0 :   nsCOMPtr<nsIPrivateDOMEvent> pEvent = do_QueryInterface(event);
    2073               0 :   if (!pEvent) return;
    2074                 : 
    2075                 :   // Even if we're not telling the window about the event (so eventTarget is
    2076                 :   // the chrome event handler, not the window), the window is still
    2077                 :   // logically the event target.
    2078               0 :   pEvent->SetTarget(eventTarget);
    2079               0 :   pEvent->SetTrusted(true);
    2080               0 :   nsEventDispatcher::DispatchDOMEvent(dispatchTarget, nsnull, event, this, nsnull);
    2081                 : }
    2082                 : 
    2083                 : static bool
    2084               0 : MayHavePaintEventListener(nsPIDOMWindow* aInnerWindow)
    2085                 : {
    2086               0 :   if (!aInnerWindow)
    2087               0 :     return false;
    2088               0 :   if (aInnerWindow->HasPaintEventListeners())
    2089               0 :     return true;
    2090                 : 
    2091               0 :   nsIDOMEventTarget* parentTarget = aInnerWindow->GetParentTarget();
    2092               0 :   if (!parentTarget)
    2093               0 :     return false;
    2094                 : 
    2095               0 :   nsEventListenerManager* manager = nsnull;
    2096               0 :   if ((manager = parentTarget->GetListenerManager(false)) &&
    2097               0 :       manager->MayHavePaintEventListener()) {
    2098               0 :     return true;
    2099                 :   }
    2100                 : 
    2101               0 :   nsCOMPtr<nsINode> node;
    2102               0 :   if (parentTarget != aInnerWindow->GetChromeEventHandler()) {
    2103                 :     nsCOMPtr<nsIInProcessContentFrameMessageManager> mm =
    2104               0 :       do_QueryInterface(parentTarget);
    2105               0 :     if (mm) {
    2106               0 :       node = mm->GetOwnerContent();
    2107                 :     }
    2108                 :   }
    2109                 : 
    2110               0 :   if (!node) {
    2111               0 :     node = do_QueryInterface(parentTarget);
    2112                 :   }
    2113               0 :   if (node)
    2114               0 :     return MayHavePaintEventListener(node->OwnerDoc()->GetInnerWindow());
    2115                 : 
    2116               0 :   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(parentTarget);
    2117               0 :   if (window)
    2118               0 :     return MayHavePaintEventListener(window);
    2119                 : 
    2120               0 :   nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(parentTarget);
    2121                 :   nsIDOMEventTarget* tabChildGlobal;
    2122                 :   return root &&
    2123               0 :          (tabChildGlobal = root->GetParentTarget()) &&
    2124               0 :          (manager = tabChildGlobal->GetListenerManager(false)) &&
    2125               0 :          manager->MayHavePaintEventListener();
    2126                 : }
    2127                 : 
    2128                 : bool
    2129               0 : nsPresContext::MayHavePaintEventListener()
    2130                 : {
    2131               0 :   return ::MayHavePaintEventListener(mDocument->GetInnerWindow());
    2132                 : }
    2133                 : 
    2134                 : void
    2135               0 : nsPresContext::NotifyInvalidation(const nsRect& aRect, PRUint32 aFlags)
    2136                 : {
    2137                 :   // If there is no paint event listener, then we don't need to fire
    2138                 :   // the asynchronous event. We don't even need to record invalidation.
    2139                 :   // MayHavePaintEventListener is pretty cheap and we could make it
    2140                 :   // even cheaper by providing a more efficient
    2141                 :   // nsPIDOMWindow::GetListenerManager.
    2142               0 :   if (aRect.IsEmpty() || !MayHavePaintEventListener())
    2143               0 :     return;
    2144                 : 
    2145                 :   nsPresContext* pc;
    2146               0 :   for (pc = this; pc; pc = GetParentPresContext(pc)) {
    2147               0 :     if (pc->mFireAfterPaintEvents)
    2148               0 :       break;
    2149               0 :     pc->mFireAfterPaintEvents = true;
    2150                 :   }
    2151               0 :   if (!pc) {
    2152               0 :     nsRootPresContext* rpc = GetRootPresContext();
    2153               0 :     if (rpc) {
    2154               0 :       rpc->EnsureEventualDidPaintEvent();
    2155                 :     }
    2156                 :   }
    2157                 : 
    2158                 :   nsInvalidateRequestList::Request* request =
    2159               0 :     mInvalidateRequests.mRequests.AppendElement();
    2160               0 :   if (!request)
    2161               0 :     return;
    2162                 : 
    2163               0 :   request->mRect = aRect;
    2164               0 :   request->mFlags = aFlags;
    2165                 : }
    2166                 : 
    2167                 : static bool
    2168               0 : NotifyDidPaintSubdocumentCallback(nsIDocument* aDocument, void* aData)
    2169                 : {
    2170               0 :   nsIPresShell* shell = aDocument->GetShell();
    2171               0 :   if (shell) {
    2172               0 :     nsPresContext* pc = shell->GetPresContext();
    2173               0 :     if (pc) {
    2174               0 :       pc->NotifyDidPaintForSubtree();
    2175                 :     }
    2176                 :   }
    2177               0 :   return true;
    2178                 : }
    2179                 : 
    2180                 : void
    2181               0 : nsPresContext::NotifyDidPaintForSubtree()
    2182                 : {
    2183               0 :   if (!mFireAfterPaintEvents)
    2184               0 :     return;
    2185               0 :   mFireAfterPaintEvents = false;
    2186                 : 
    2187               0 :   if (IsRoot()) {
    2188               0 :     static_cast<nsRootPresContext*>(this)->CancelDidPaintTimer();
    2189                 :   }
    2190                 : 
    2191               0 :   if (!mInvalidateRequests.mRequests.IsEmpty()) {
    2192                 :     nsCOMPtr<nsIRunnable> ev =
    2193               0 :       NS_NewRunnableMethod(this, &nsPresContext::FireDOMPaintEvent);
    2194               0 :     nsContentUtils::AddScriptRunner(ev);
    2195                 :   }
    2196                 : 
    2197               0 :   mDocument->EnumerateSubDocuments(NotifyDidPaintSubdocumentCallback, nsnull);
    2198                 : }
    2199                 : 
    2200                 : bool
    2201               0 : nsPresContext::HasCachedStyleData()
    2202                 : {
    2203               0 :   return mShell && mShell->StyleSet()->HasCachedStyleData();
    2204                 : }
    2205                 : 
    2206                 : static bool sGotInterruptEnv = false;
    2207                 : enum InterruptMode {
    2208                 :   ModeRandom,
    2209                 :   ModeCounter,
    2210                 :   ModeEvent
    2211                 : };
    2212                 : // Controlled by the GECKO_REFLOW_INTERRUPT_MODE env var; allowed values are
    2213                 : // "random" (except on Windows) or "counter".  If neither is used, the mode is
    2214                 : // ModeEvent.
    2215                 : static InterruptMode sInterruptMode = ModeEvent;
    2216                 : // Used for the "random" mode.  Controlled by the GECKO_REFLOW_INTERRUPT_SEED
    2217                 : // env var.
    2218                 : static PRUint32 sInterruptSeed = 1;
    2219                 : // Used for the "counter" mode.  This is the number of unskipped interrupt
    2220                 : // checks that have to happen before we interrupt.  Controlled by the
    2221                 : // GECKO_REFLOW_INTERRUPT_FREQUENCY env var.
    2222                 : static PRUint32 sInterruptMaxCounter = 10;
    2223                 : // Used for the "counter" mode.  This counts up to sInterruptMaxCounter and is
    2224                 : // then reset to 0.
    2225                 : static PRUint32 sInterruptCounter;
    2226                 : // Number of interrupt checks to skip before really trying to interrupt.
    2227                 : // Controlled by the GECKO_REFLOW_INTERRUPT_CHECKS_TO_SKIP env var.
    2228                 : static PRUint32 sInterruptChecksToSkip = 200;
    2229                 : // Number of milliseconds that a reflow should be allowed to run for before we
    2230                 : // actually allow interruption.  Controlled by the
    2231                 : // GECKO_REFLOW_MIN_NOINTERRUPT_DURATION env var.  Can't be initialized here,
    2232                 : // because TimeDuration/TimeStamp is not safe to use in static constructors..
    2233            1464 : static TimeDuration sInterruptTimeout;
    2234                 : 
    2235               0 : static void GetInterruptEnv()
    2236                 : {
    2237               0 :   char *ev = PR_GetEnv("GECKO_REFLOW_INTERRUPT_MODE");
    2238               0 :   if (ev) {
    2239                 : #ifndef XP_WIN
    2240               0 :     if (PL_strcasecmp(ev, "random") == 0) {
    2241               0 :       ev = PR_GetEnv("GECKO_REFLOW_INTERRUPT_SEED");
    2242               0 :       if (ev) {
    2243               0 :         sInterruptSeed = atoi(ev);
    2244                 :       }
    2245               0 :       srandom(sInterruptSeed);
    2246               0 :       sInterruptMode = ModeRandom;
    2247                 :     } else
    2248                 : #endif
    2249               0 :       if (PL_strcasecmp(ev, "counter") == 0) {
    2250               0 :       ev = PR_GetEnv("GECKO_REFLOW_INTERRUPT_FREQUENCY");
    2251               0 :       if (ev) {
    2252               0 :         sInterruptMaxCounter = atoi(ev);
    2253                 :       }
    2254               0 :       sInterruptCounter = 0;
    2255               0 :       sInterruptMode = ModeCounter;
    2256                 :     }
    2257                 :   }
    2258               0 :   ev = PR_GetEnv("GECKO_REFLOW_INTERRUPT_CHECKS_TO_SKIP");
    2259               0 :   if (ev) {
    2260               0 :     sInterruptChecksToSkip = atoi(ev);
    2261                 :   }
    2262                 : 
    2263               0 :   ev = PR_GetEnv("GECKO_REFLOW_MIN_NOINTERRUPT_DURATION");
    2264               0 :   int duration_ms = ev ? atoi(ev) : 100;
    2265               0 :   sInterruptTimeout = TimeDuration::FromMilliseconds(duration_ms);
    2266               0 : }
    2267                 : 
    2268                 : bool
    2269               0 : nsPresContext::HavePendingInputEvent()
    2270                 : {
    2271               0 :   switch (sInterruptMode) {
    2272                 : #ifndef XP_WIN
    2273                 :     case ModeRandom:
    2274               0 :       return (random() & 1);
    2275                 : #endif
    2276                 :     case ModeCounter:
    2277               0 :       if (sInterruptCounter < sInterruptMaxCounter) {
    2278               0 :         ++sInterruptCounter;
    2279               0 :         return false;
    2280                 :       }
    2281               0 :       sInterruptCounter = 0;
    2282               0 :       return true;
    2283                 :     default:
    2284                 :     case ModeEvent: {
    2285               0 :       nsIFrame* f = PresShell()->GetRootFrame();
    2286               0 :       if (f) {
    2287               0 :         nsIWidget* w = f->GetNearestWidget();
    2288               0 :         if (w) {
    2289               0 :           return w->HasPendingInputEvent();
    2290                 :         }
    2291                 :       }
    2292               0 :       return false;
    2293                 :     }
    2294                 :   }
    2295                 : }
    2296                 : 
    2297                 : void
    2298               0 : nsPresContext::ReflowStarted(bool aInterruptible)
    2299                 : {
    2300                 : #ifdef NOISY_INTERRUPTIBLE_REFLOW
    2301                 :   if (!aInterruptible) {
    2302                 :     printf("STARTING NONINTERRUPTIBLE REFLOW\n");
    2303                 :   }
    2304                 : #endif
    2305                 :   // We don't support interrupting in paginated contexts, since page
    2306                 :   // sequences only handle initial reflow
    2307               0 :   mInterruptsEnabled = aInterruptible && !IsPaginated();
    2308                 : 
    2309                 :   // Don't set mHasPendingInterrupt based on HavePendingInputEvent() here.  If
    2310                 :   // we ever change that, then we need to update the code in
    2311                 :   // PresShell::DoReflow to only add the just-reflown root to dirty roots if
    2312                 :   // it's actually dirty.  Otherwise we can end up adding a root that has no
    2313                 :   // interruptible descendants, just because we detected an interrupt at reflow
    2314                 :   // start.
    2315               0 :   mHasPendingInterrupt = false;
    2316                 : 
    2317               0 :   mInterruptChecksToSkip = sInterruptChecksToSkip;
    2318                 : 
    2319               0 :   if (mInterruptsEnabled) {
    2320               0 :     mReflowStartTime = TimeStamp::Now();
    2321                 :   }
    2322               0 : }
    2323                 : 
    2324                 : bool
    2325               0 : nsPresContext::CheckForInterrupt(nsIFrame* aFrame)
    2326                 : {
    2327               0 :   if (mHasPendingInterrupt) {
    2328               0 :     mShell->FrameNeedsToContinueReflow(aFrame);
    2329               0 :     return true;
    2330                 :   }
    2331                 : 
    2332               0 :   if (!sGotInterruptEnv) {
    2333               0 :     sGotInterruptEnv = true;
    2334               0 :     GetInterruptEnv();
    2335                 :   }
    2336                 : 
    2337               0 :   if (!mInterruptsEnabled) {
    2338               0 :     return false;
    2339                 :   }
    2340                 : 
    2341               0 :   if (mInterruptChecksToSkip > 0) {
    2342               0 :     --mInterruptChecksToSkip;
    2343               0 :     return false;
    2344                 :   }
    2345               0 :   mInterruptChecksToSkip = sInterruptChecksToSkip;
    2346                 : 
    2347                 :   // Don't interrupt if it's been less than sInterruptTimeout since we started
    2348                 :   // the reflow.
    2349                 :   mHasPendingInterrupt =
    2350               0 :     TimeStamp::Now() - mReflowStartTime > sInterruptTimeout &&
    2351               0 :     HavePendingInputEvent() &&
    2352               0 :     !IsChrome();
    2353               0 :   if (mHasPendingInterrupt) {
    2354                 : #ifdef NOISY_INTERRUPTIBLE_REFLOW
    2355                 :     printf("*** DETECTED pending interrupt (time=%lld)\n", PR_Now());
    2356                 : #endif /* NOISY_INTERRUPTIBLE_REFLOW */
    2357               0 :     mShell->FrameNeedsToContinueReflow(aFrame);
    2358                 :   }
    2359               0 :   return mHasPendingInterrupt;
    2360                 : }
    2361                 : 
    2362                 : size_t
    2363               0 : nsPresContext::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const
    2364                 : {
    2365               0 :   return mPropertyTable.SizeOfExcludingThis(aMallocSizeOf);
    2366                 :          mLangGroupFontPrefs.SizeOfExcludingThis(aMallocSizeOf);
    2367                 : 
    2368                 :   // Measurement of other members may be added later if DMD finds it is
    2369                 :   // worthwhile.
    2370                 : }
    2371                 : 
    2372                 : bool
    2373               0 : nsPresContext::IsRootContentDocument()
    2374                 : {
    2375                 :   // We are a root content document if: we are not a resource doc, we are
    2376                 :   // not chrome, and we either have no parent or our parent is chrome.
    2377               0 :   if (mDocument->IsResourceDoc()) {
    2378               0 :     return false;
    2379                 :   }
    2380               0 :   if (IsChrome()) {
    2381               0 :     return false;
    2382                 :   }
    2383                 :   // We may not have a root frame, so use views.
    2384               0 :   nsIView* view = PresShell()->GetViewManager()->GetRootView();
    2385               0 :   if (!view) {
    2386               0 :     return false;
    2387                 :   }
    2388               0 :   view = view->GetParent(); // anonymous inner view
    2389               0 :   if (!view) {
    2390               0 :     return true;
    2391                 :   }
    2392               0 :   view = view->GetParent(); // subdocumentframe's view
    2393               0 :   if (!view) {
    2394               0 :     return true;
    2395                 :   }
    2396                 : 
    2397               0 :   nsIFrame* f = view->GetFrame();
    2398               0 :   return (f && f->PresContext()->IsChrome());
    2399                 : }
    2400                 : 
    2401               0 : nsRootPresContext::nsRootPresContext(nsIDocument* aDocument,
    2402                 :                                      nsPresContextType aType)
    2403                 :   : nsPresContext(aDocument, aType),
    2404                 :     mUpdatePluginGeometryForFrame(nsnull),
    2405                 :     mDOMGeneration(0),
    2406               0 :     mNeedsToUpdatePluginGeometry(false)
    2407                 : {
    2408               0 :   mRegisteredPlugins.Init();
    2409               0 : }
    2410                 : 
    2411               0 : nsRootPresContext::~nsRootPresContext()
    2412                 : {
    2413               0 :   NS_ASSERTION(mRegisteredPlugins.Count() == 0,
    2414                 :                "All plugins should have been unregistered");
    2415               0 :   CancelDidPaintTimer();
    2416               0 :   CancelUpdatePluginGeometryTimer();
    2417               0 : }
    2418                 : 
    2419                 : void
    2420               0 : nsRootPresContext::RegisterPluginForGeometryUpdates(nsObjectFrame* aPlugin)
    2421                 : {
    2422               0 :   mRegisteredPlugins.PutEntry(aPlugin);
    2423               0 : }
    2424                 : 
    2425                 : void
    2426               0 : nsRootPresContext::UnregisterPluginForGeometryUpdates(nsObjectFrame* aPlugin)
    2427                 : {
    2428               0 :   mRegisteredPlugins.RemoveEntry(aPlugin);
    2429               0 : }
    2430                 : 
    2431               0 : struct PluginGeometryClosure {
    2432                 :   nsIFrame* mRootFrame;
    2433                 :   PRInt32   mRootAPD;
    2434                 :   nsIFrame* mChangedSubtree;
    2435                 :   nsRect    mChangedRect;
    2436                 :   nsTHashtable<nsPtrHashKey<nsObjectFrame> > mAffectedPlugins;
    2437                 :   nsRect    mAffectedPluginBounds;
    2438                 :   nsTArray<nsIWidget::Configuration>* mOutputConfigurations;
    2439                 : };
    2440                 : static PLDHashOperator
    2441               0 : PluginBoundsEnumerator(nsPtrHashKey<nsObjectFrame>* aEntry, void* userArg)
    2442                 : {
    2443               0 :   PluginGeometryClosure* closure = static_cast<PluginGeometryClosure*>(userArg);
    2444               0 :   nsObjectFrame* f = aEntry->GetKey();
    2445               0 :   nsRect fBounds = f->GetContentRect() +
    2446               0 :       f->GetParent()->GetOffsetToCrossDoc(closure->mRootFrame);
    2447               0 :   PRInt32 APD = f->PresContext()->AppUnitsPerDevPixel();
    2448               0 :   fBounds = fBounds.ConvertAppUnitsRoundOut(APD, closure->mRootAPD);
    2449                 :   // We're identifying the plugins that may have been affected by changes
    2450                 :   // to the frame subtree rooted at aChangedRoot. Any plugin that overlaps
    2451                 :   // the overflow area of aChangedRoot could have its clip region affected
    2452                 :   // because it might be covered (or uncovered) by changes to the subtree.
    2453                 :   // Plugins in the subtree might have changed position and/or size, and
    2454                 :   // they might not be in aChangedRoot's overflow area (because they're
    2455                 :   // being clipped by an ancestor in the subtree).
    2456               0 :   if (fBounds.Intersects(closure->mChangedRect) ||
    2457               0 :       nsLayoutUtils::IsAncestorFrameCrossDoc(closure->mChangedSubtree, f)) {
    2458                 :     closure->mAffectedPluginBounds.UnionRect(
    2459               0 :         closure->mAffectedPluginBounds, fBounds);
    2460               0 :     closure->mAffectedPlugins.PutEntry(f);
    2461                 :   }
    2462               0 :   return PL_DHASH_NEXT;
    2463                 : }
    2464                 : 
    2465                 : static PLDHashOperator
    2466               0 : PluginHideEnumerator(nsPtrHashKey<nsObjectFrame>* aEntry, void* userArg)
    2467                 : {
    2468               0 :   PluginGeometryClosure* closure = static_cast<PluginGeometryClosure*>(userArg);
    2469               0 :   nsObjectFrame* f = aEntry->GetKey();
    2470               0 :   f->GetEmptyClipConfiguration(closure->mOutputConfigurations);
    2471               0 :   return PL_DHASH_NEXT;
    2472                 : }
    2473                 : 
    2474                 : static void
    2475               0 : RecoverPluginGeometry(nsDisplayListBuilder* aBuilder,
    2476                 :     nsDisplayList* aList, bool aInTransform, PluginGeometryClosure* aClosure)
    2477                 : {
    2478               0 :   for (nsDisplayItem* i = aList->GetBottom(); i; i = i->GetAbove()) {
    2479               0 :     switch (i->GetType()) {
    2480                 :     case nsDisplayItem::TYPE_PLUGIN: {
    2481               0 :       nsDisplayPlugin* displayPlugin = static_cast<nsDisplayPlugin*>(i);
    2482                 :       nsObjectFrame* f = static_cast<nsObjectFrame*>(
    2483               0 :           displayPlugin->GetUnderlyingFrame());
    2484                 :       // Ignore plugins which aren't supposed to be affected by this
    2485                 :       // operation --- their bounds will not have been included in the
    2486                 :       // display list computations so the visible region computed for them
    2487                 :       // would be incorrect
    2488                 :       nsPtrHashKey<nsObjectFrame>* entry =
    2489               0 :         aClosure->mAffectedPlugins.GetEntry(f);
    2490                 :       // Windowed plugins in transforms are always ignored, we don't
    2491                 :       // create configurations for them
    2492               0 :       if (entry && (!aInTransform || f->PaintedByGecko())) {
    2493                 :         displayPlugin->GetWidgetConfiguration(aBuilder,
    2494               0 :                                               aClosure->mOutputConfigurations);
    2495                 :         // we've dealt with this plugin now
    2496               0 :         aClosure->mAffectedPlugins.RawRemoveEntry(entry);
    2497                 :       }
    2498               0 :       break;
    2499                 :     }
    2500                 :     case nsDisplayItem::TYPE_TRANSFORM: {
    2501                 :       nsDisplayList* sublist =
    2502               0 :           static_cast<nsDisplayTransform*>(i)->GetStoredList()->GetList();
    2503               0 :       RecoverPluginGeometry(aBuilder, sublist, true, aClosure);
    2504               0 :       break;
    2505                 :     }
    2506                 :     default: {
    2507               0 :       nsDisplayList* sublist = i->GetList();
    2508               0 :       if (sublist) {
    2509               0 :         RecoverPluginGeometry(aBuilder, sublist, aInTransform, aClosure);
    2510                 :       }
    2511               0 :       break;
    2512                 :     }
    2513                 :     }
    2514                 :   }
    2515               0 : }
    2516                 : 
    2517                 : #ifdef DEBUG
    2518                 : #include <stdio.h>
    2519                 : 
    2520                 : static bool gDumpPluginList = false;
    2521                 : #endif
    2522                 : 
    2523                 : void
    2524               0 : nsRootPresContext::GetPluginGeometryUpdates(nsIFrame* aChangedSubtree,
    2525                 :                                             nsTArray<nsIWidget::Configuration>* aConfigurations)
    2526                 : {
    2527               0 :   if (mRegisteredPlugins.Count() == 0)
    2528               0 :     return;
    2529                 : 
    2530               0 :   PluginGeometryClosure closure;
    2531               0 :   closure.mRootFrame = mShell->FrameManager()->GetRootFrame();
    2532               0 :   closure.mRootAPD = closure.mRootFrame->PresContext()->AppUnitsPerDevPixel();
    2533               0 :   closure.mChangedSubtree = aChangedSubtree;
    2534               0 :   closure.mChangedRect = aChangedSubtree->GetVisualOverflowRect() +
    2535               0 :       aChangedSubtree->GetOffsetToCrossDoc(closure.mRootFrame);
    2536               0 :   PRInt32 subtreeAPD = aChangedSubtree->PresContext()->AppUnitsPerDevPixel();
    2537                 :   closure.mChangedRect =
    2538               0 :     closure.mChangedRect.ConvertAppUnitsRoundOut(subtreeAPD, closure.mRootAPD);
    2539               0 :   closure.mAffectedPlugins.Init();
    2540               0 :   closure.mOutputConfigurations = aConfigurations;
    2541                 :   // Fill in closure.mAffectedPlugins and closure.mAffectedPluginBounds
    2542               0 :   mRegisteredPlugins.EnumerateEntries(PluginBoundsEnumerator, &closure);
    2543                 : 
    2544               0 :   nsRect bounds;
    2545               0 :   if (bounds.IntersectRect(closure.mAffectedPluginBounds,
    2546               0 :                            closure.mRootFrame->GetRect())) {
    2547                 :     nsDisplayListBuilder builder(closure.mRootFrame,
    2548               0 :                 nsDisplayListBuilder::PLUGIN_GEOMETRY, false);
    2549               0 :     builder.SetAccurateVisibleRegions();
    2550               0 :     nsDisplayList list;
    2551                 : 
    2552               0 :     builder.EnterPresShell(closure.mRootFrame, bounds);
    2553                 :     closure.mRootFrame->BuildDisplayListForStackingContext(
    2554               0 :         &builder, bounds, &list);
    2555               0 :     builder.LeavePresShell(closure.mRootFrame, bounds);
    2556                 : 
    2557                 : #ifdef DEBUG
    2558               0 :     if (gDumpPluginList) {
    2559                 :       fprintf(stderr, "Plugins --- before optimization (bounds %d,%d,%d,%d):\n",
    2560               0 :           bounds.x, bounds.y, bounds.width, bounds.height);
    2561               0 :       nsFrame::PrintDisplayList(&builder, list);
    2562                 :     }
    2563                 : #endif
    2564                 : 
    2565               0 :     nsRegion visibleRegion(bounds);
    2566               0 :     list.ComputeVisibilityForRoot(&builder, &visibleRegion);
    2567                 : 
    2568                 : #ifdef DEBUG
    2569               0 :     if (gDumpPluginList) {
    2570               0 :       fprintf(stderr, "Plugins --- after optimization:\n");
    2571               0 :       nsFrame::PrintDisplayList(&builder, list);
    2572                 :     }
    2573                 : #endif
    2574                 : 
    2575               0 :     RecoverPluginGeometry(&builder, &list, false, &closure);
    2576               0 :     list.DeleteAll();
    2577                 :   }
    2578                 : 
    2579                 :   // Plugins that we didn't find in the display list are not visible
    2580               0 :   closure.mAffectedPlugins.EnumerateEntries(PluginHideEnumerator, &closure);
    2581                 : }
    2582                 : 
    2583                 : static bool
    2584               0 : HasOverlap(const nsIntPoint& aOffset1, const nsTArray<nsIntRect>& aClipRects1,
    2585                 :            const nsIntPoint& aOffset2, const nsTArray<nsIntRect>& aClipRects2)
    2586                 : {
    2587               0 :   nsIntPoint offsetDelta = aOffset1 - aOffset2;
    2588               0 :   for (PRUint32 i = 0; i < aClipRects1.Length(); ++i) {
    2589               0 :     for (PRUint32 j = 0; j < aClipRects2.Length(); ++j) {
    2590               0 :       if ((aClipRects1[i] + offsetDelta).Intersects(aClipRects2[j]))
    2591               0 :         return true;
    2592                 :     }
    2593                 :   }
    2594               0 :   return false;
    2595                 : }
    2596                 : 
    2597                 : /**
    2598                 :  * Given a list of plugin windows to move to new locations, sort the list
    2599                 :  * so that for each window move, the window moves to a location that
    2600                 :  * does not intersect other windows. This minimizes flicker and repainting.
    2601                 :  * It's not always possible to do this perfectly, since in general
    2602                 :  * we might have cycles. But we do our best.
    2603                 :  * We need to take into account that windows are clipped to particular
    2604                 :  * regions and the clip regions change as the windows are moved.
    2605                 :  */
    2606                 : static void
    2607               0 : SortConfigurations(nsTArray<nsIWidget::Configuration>* aConfigurations)
    2608                 : {
    2609               0 :   if (aConfigurations->Length() > 10) {
    2610                 :     // Give up, we don't want to get bogged down here
    2611               0 :     return;
    2612                 :   }
    2613                 : 
    2614               0 :   nsTArray<nsIWidget::Configuration> pluginsToMove;
    2615               0 :   pluginsToMove.SwapElements(*aConfigurations);
    2616                 : 
    2617                 :   // Our algorithm is quite naive. At each step we try to identify
    2618                 :   // a window that can be moved to its new location that won't overlap
    2619                 :   // any other windows at the new location. If there is no such
    2620                 :   // window, we just move the last window in the list anyway.
    2621               0 :   while (!pluginsToMove.IsEmpty()) {
    2622                 :     // Find a window whose destination does not overlap any other window
    2623                 :     PRUint32 i;
    2624               0 :     for (i = 0; i + 1 < pluginsToMove.Length(); ++i) {
    2625               0 :       nsIWidget::Configuration* config = &pluginsToMove[i];
    2626               0 :       bool foundOverlap = false;
    2627               0 :       for (PRUint32 j = 0; j < pluginsToMove.Length(); ++j) {
    2628               0 :         if (i == j)
    2629               0 :           continue;
    2630               0 :         nsIntRect bounds;
    2631               0 :         pluginsToMove[j].mChild->GetBounds(bounds);
    2632               0 :         nsAutoTArray<nsIntRect,1> clipRects;
    2633               0 :         pluginsToMove[j].mChild->GetWindowClipRegion(&clipRects);
    2634               0 :         if (HasOverlap(bounds.TopLeft(), clipRects,
    2635                 :                        config->mBounds.TopLeft(),
    2636               0 :                        config->mClipRegion)) {
    2637               0 :           foundOverlap = true;
    2638                 :           break;
    2639                 :         }
    2640                 :       }
    2641               0 :       if (!foundOverlap)
    2642               0 :         break;
    2643                 :     }
    2644                 :     // Note that we always move the last plugin in pluginsToMove, if we
    2645                 :     // can't find any other plugin to move
    2646               0 :     aConfigurations->AppendElement(pluginsToMove[i]);
    2647               0 :     pluginsToMove.RemoveElementAt(i);
    2648                 :   }
    2649                 : }
    2650                 : 
    2651                 : void
    2652               0 : nsRootPresContext::UpdatePluginGeometry()
    2653                 : {
    2654               0 :   if (!mNeedsToUpdatePluginGeometry)
    2655               0 :     return;
    2656               0 :   mNeedsToUpdatePluginGeometry = false;
    2657                 :   // Cancel out mUpdatePluginGeometryTimer so it doesn't do a random
    2658                 :   // update when we don't actually want one.
    2659               0 :   CancelUpdatePluginGeometryTimer();
    2660                 : 
    2661               0 :   nsIFrame* f = mUpdatePluginGeometryForFrame;
    2662               0 :   if (f) {
    2663                 :     mUpdatePluginGeometryForFrame->PresContext()->
    2664               0 :       SetContainsUpdatePluginGeometryFrame(false);
    2665               0 :     mUpdatePluginGeometryForFrame = nsnull;
    2666                 :   } else {
    2667               0 :     f = FrameManager()->GetRootFrame();
    2668                 :   }
    2669                 : 
    2670               0 :   nsTArray<nsIWidget::Configuration> configurations;
    2671               0 :   GetPluginGeometryUpdates(f, &configurations);
    2672               0 :   if (configurations.IsEmpty())
    2673                 :     return;
    2674               0 :   SortConfigurations(&configurations);
    2675               0 :   nsIWidget* widget = FrameManager()->GetRootFrame()->GetNearestWidget();
    2676               0 :   NS_ASSERTION(widget, "Plugins must have a parent window");
    2677               0 :   widget->ConfigureChildren(configurations);
    2678               0 :   DidApplyPluginGeometryUpdates();
    2679                 : }
    2680                 : 
    2681                 : static void
    2682               0 : UpdatePluginGeometryCallback(nsITimer *aTimer, void *aClosure)
    2683                 : {
    2684               0 :   static_cast<nsRootPresContext*>(aClosure)->UpdatePluginGeometry();
    2685               0 : }
    2686                 : 
    2687                 : void
    2688               0 : nsRootPresContext::RequestUpdatePluginGeometry(nsIFrame* aFrame)
    2689                 : {
    2690               0 :   if (mRegisteredPlugins.Count() == 0)
    2691               0 :     return;
    2692                 : 
    2693               0 :   if (!mNeedsToUpdatePluginGeometry) {
    2694                 :     // We'll update the plugin geometry during the next paint in this
    2695                 :     // presContext (either from nsPresShell::WillPaint or from
    2696                 :     // nsPresShell::DidPaint, depending on the platform) or on the next
    2697                 :     // layout flush, whichever comes first.  But we may not have anyone
    2698                 :     // flush layout, and paints might get optimized away if the old
    2699                 :     // plugin geometry covers the whole canvas, so set a backup timer to
    2700                 :     // do this too.  We want to make sure this won't fire before our
    2701                 :     // normal paint notifications, if those would update the geometry,
    2702                 :     // so set it for double the refresh driver interval.
    2703               0 :     mUpdatePluginGeometryTimer = do_CreateInstance("@mozilla.org/timer;1");
    2704               0 :     if (mUpdatePluginGeometryTimer) {
    2705               0 :       mUpdatePluginGeometryTimer->
    2706                 :         InitWithFuncCallback(UpdatePluginGeometryCallback, this,
    2707               0 :                              nsRefreshDriver::DefaultInterval() * 2,
    2708               0 :                              nsITimer::TYPE_ONE_SHOT);
    2709                 :     }
    2710               0 :     mNeedsToUpdatePluginGeometry = true;
    2711               0 :     mUpdatePluginGeometryForFrame = aFrame;
    2712                 :     mUpdatePluginGeometryForFrame->PresContext()->
    2713               0 :       SetContainsUpdatePluginGeometryFrame(true);
    2714                 :   } else {
    2715               0 :     if (!mUpdatePluginGeometryForFrame ||
    2716                 :         aFrame == mUpdatePluginGeometryForFrame)
    2717               0 :       return;
    2718                 :     mUpdatePluginGeometryForFrame->PresContext()->
    2719               0 :       SetContainsUpdatePluginGeometryFrame(false);
    2720               0 :     mUpdatePluginGeometryForFrame = nsnull;
    2721                 :   }
    2722                 : }
    2723                 : 
    2724                 : static PLDHashOperator
    2725               0 : PluginDidSetGeometryEnumerator(nsPtrHashKey<nsObjectFrame>* aEntry, void* userArg)
    2726                 : {
    2727               0 :   nsObjectFrame* f = aEntry->GetKey();
    2728               0 :   f->DidSetWidgetGeometry();
    2729               0 :   return PL_DHASH_NEXT;
    2730                 : }
    2731                 : 
    2732                 : void
    2733               0 : nsRootPresContext::DidApplyPluginGeometryUpdates()
    2734                 : {
    2735               0 :   mRegisteredPlugins.EnumerateEntries(PluginDidSetGeometryEnumerator, nsnull);
    2736               0 : }
    2737                 : 
    2738                 : void
    2739               0 : nsRootPresContext::RootForgetUpdatePluginGeometryFrame(nsIFrame* aFrame)
    2740                 : {
    2741               0 :   if (aFrame == mUpdatePluginGeometryForFrame) {
    2742                 :     mUpdatePluginGeometryForFrame->PresContext()->
    2743               0 :       SetContainsUpdatePluginGeometryFrame(false);
    2744               0 :     mUpdatePluginGeometryForFrame = nsnull;
    2745                 :   }
    2746               0 : }
    2747                 : 
    2748                 : void
    2749               0 : nsRootPresContext::RootForgetUpdatePluginGeometryFrameForPresContext(
    2750                 :   nsPresContext* aPresContext)
    2751                 : {
    2752               0 :   if (aPresContext->GetContainsUpdatePluginGeometryFrame()) {
    2753               0 :     aPresContext->SetContainsUpdatePluginGeometryFrame(false);
    2754               0 :     mUpdatePluginGeometryForFrame = nsnull;
    2755                 :   }
    2756               0 : }
    2757                 : 
    2758                 : static void
    2759               0 : NotifyDidPaintForSubtreeCallback(nsITimer *aTimer, void *aClosure)
    2760                 : {
    2761               0 :   nsPresContext* presContext = (nsPresContext*)aClosure;
    2762               0 :   nsAutoScriptBlocker blockScripts;
    2763               0 :   presContext->NotifyDidPaintForSubtree();
    2764               0 : }
    2765                 : 
    2766                 : void
    2767               0 : nsRootPresContext::EnsureEventualDidPaintEvent()
    2768                 : {
    2769               0 :   if (mNotifyDidPaintTimer)
    2770               0 :     return;
    2771               0 :   mNotifyDidPaintTimer = do_CreateInstance("@mozilla.org/timer;1");
    2772               0 :   if (!mNotifyDidPaintTimer)
    2773               0 :     return;
    2774               0 :   mNotifyDidPaintTimer->InitWithFuncCallback(NotifyDidPaintForSubtreeCallback,
    2775               0 :                                              (void*)this, 100, nsITimer::TYPE_ONE_SHOT);
    2776                 : }
    2777                 : 
    2778                 : void
    2779               0 : nsRootPresContext::AddWillPaintObserver(nsIRunnable* aRunnable)
    2780                 : {
    2781               0 :   if (!mWillPaintFallbackEvent.IsPending()) {
    2782               0 :     mWillPaintFallbackEvent = new RunWillPaintObservers(this);
    2783               0 :     NS_DispatchToMainThread(mWillPaintFallbackEvent.get());
    2784                 :   }
    2785               0 :   mWillPaintObservers.AppendElement(aRunnable);
    2786               0 : }
    2787                 : 
    2788                 : /**
    2789                 :  * Run all runnables that need to get called before the next paint.
    2790                 :  */
    2791                 : void
    2792               0 : nsRootPresContext::FlushWillPaintObservers()
    2793                 : {
    2794               0 :   mWillPaintFallbackEvent = nsnull;
    2795               0 :   nsTArray<nsCOMPtr<nsIRunnable> > observers;
    2796               0 :   observers.SwapElements(mWillPaintObservers);
    2797               0 :   for (PRUint32 i = 0; i < observers.Length(); ++i) {
    2798               0 :     observers[i]->Run();
    2799                 :   }
    2800               0 : }
    2801                 : 
    2802                 : size_t
    2803               0 : nsRootPresContext::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const
    2804                 : {
    2805               0 :   return nsPresContext::SizeOfExcludingThis(aMallocSizeOf);
    2806                 : 
    2807                 :   // Measurement of the following members may be added later if DMD finds it is
    2808                 :   // worthwhile:
    2809                 :   // - mNotifyDidPaintTimer
    2810                 :   // - mRegisteredPlugins
    2811                 :   // - mWillPaintObservers
    2812                 :   // - mWillPaintFallbackEvent
    2813                 :   //
    2814                 :   // The following member are not measured:
    2815                 :   // - mUpdatePluginGeometryForFrame, because it is non-owning
    2816            4392 : }
    2817                 : 

Generated by: LCOV version 1.7