LCOV - code coverage report
Current view: directory - layout/base - nsPresContext.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 1194 3 0.3 %
Date: 2012-04-21 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            1396 : 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                 :   nsRefPtr<nsImageLoader> loader =
    1465               0 :     nsImageLoader::Create(aFrame, borderImage, actions, nsnull);
    1466               0 :   SetImageLoaders(aFrame, BORDER_IMAGE, loader);
    1467                 : }
    1468                 : 
    1469                 : void
    1470               0 : nsPresContext::StopImagesFor(nsIFrame* aTargetFrame)
    1471                 : {
    1472               0 :   for (PRUint32 i = 0; i < IMAGE_LOAD_TYPE_COUNT; ++i)
    1473               0 :     SetImageLoaders(aTargetFrame, ImageLoadType(i), nsnull);
    1474               0 : }
    1475                 : 
    1476                 : void
    1477               0 : nsPresContext::SetContainer(nsISupports* aHandler)
    1478                 : {
    1479               0 :   mContainer = do_GetWeakReference(aHandler);
    1480               0 :   InvalidateIsChromeCache();
    1481               0 :   if (mContainer) {
    1482               0 :     GetDocumentColorPreferences();
    1483                 :   }
    1484               0 : }
    1485                 : 
    1486                 : already_AddRefed<nsISupports>
    1487               0 : nsPresContext::GetContainerInternal() const
    1488                 : {
    1489               0 :   nsISupports *result = nsnull;
    1490               0 :   if (mContainer)
    1491               0 :     CallQueryReferent(mContainer.get(), &result);
    1492                 : 
    1493               0 :   return result;
    1494                 : }
    1495                 : 
    1496                 : already_AddRefed<nsISupports>
    1497               0 : nsPresContext::GetContainerExternal() const
    1498                 : {
    1499               0 :   return GetContainerInternal();
    1500                 : }
    1501                 : 
    1502                 : #ifdef IBMBIDI
    1503                 : void
    1504               0 : nsPresContext::SetBidiEnabled() const
    1505                 : {
    1506               0 :   if (mShell) {
    1507               0 :     nsIDocument *doc = mShell->GetDocument();
    1508               0 :     if (doc) {
    1509               0 :       doc->SetBidiEnabled();
    1510                 :     }
    1511                 :   }
    1512               0 : }
    1513                 : 
    1514                 : void
    1515               0 : nsPresContext::SetBidi(PRUint32 aSource, bool aForceRestyle)
    1516                 : {
    1517                 :   // Don't do all this stuff unless the options have changed.
    1518               0 :   if (aSource == GetBidi()) {
    1519               0 :     return;
    1520                 :   }
    1521                 : 
    1522               0 :   NS_ASSERTION(!(aForceRestyle && (GetBidi() == 0)), 
    1523                 :                "ForceReflow on new prescontext");
    1524                 : 
    1525               0 :   Document()->SetBidiOptions(aSource);
    1526               0 :   if (IBMBIDI_TEXTDIRECTION_RTL == GET_BIDI_OPTION_DIRECTION(aSource)
    1527                 :       || IBMBIDI_NUMERAL_HINDI == GET_BIDI_OPTION_NUMERAL(aSource)) {
    1528               0 :     SetBidiEnabled();
    1529                 :   }
    1530               0 :   if (IBMBIDI_TEXTTYPE_VISUAL == GET_BIDI_OPTION_TEXTTYPE(aSource)) {
    1531               0 :     SetVisualMode(true);
    1532                 :   }
    1533               0 :   else if (IBMBIDI_TEXTTYPE_LOGICAL == GET_BIDI_OPTION_TEXTTYPE(aSource)) {
    1534               0 :     SetVisualMode(false);
    1535                 :   }
    1536                 :   else {
    1537               0 :     nsIDocument* doc = mShell->GetDocument();
    1538               0 :     if (doc) {
    1539               0 :       SetVisualMode(IsVisualCharset(doc->GetDocumentCharacterSet()));
    1540                 :     }
    1541                 :   }
    1542               0 :   if (aForceRestyle && mShell) {
    1543                 :     // Reconstruct the root document element's frame and its children,
    1544                 :     // because we need to trigger frame reconstruction for direction change.
    1545               0 :     RebuildUserFontSet();
    1546               0 :     mShell->ReconstructFrames();
    1547                 :   }
    1548                 : }
    1549                 : 
    1550                 : PRUint32
    1551               0 : nsPresContext::GetBidi() const
    1552                 : {
    1553               0 :   return Document()->GetBidiOptions();
    1554                 : }
    1555                 : 
    1556                 : #endif //IBMBIDI
    1557                 : 
    1558                 : bool
    1559               0 : nsPresContext::IsTopLevelWindowInactive()
    1560                 : {
    1561               0 :   nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryReferent(mContainer));
    1562               0 :   if (!treeItem)
    1563               0 :     return false;
    1564                 : 
    1565               0 :   nsCOMPtr<nsIDocShellTreeItem> rootItem;
    1566               0 :   treeItem->GetRootTreeItem(getter_AddRefs(rootItem));
    1567               0 :   nsCOMPtr<nsPIDOMWindow> domWindow(do_GetInterface(rootItem));
    1568                 : 
    1569               0 :   return domWindow && !domWindow->IsActive();
    1570                 : }
    1571                 : 
    1572                 : nsITheme*
    1573               0 : nsPresContext::GetTheme()
    1574                 : {
    1575               0 :   if (!sNoTheme && !mTheme) {
    1576               0 :     mTheme = do_GetService("@mozilla.org/chrome/chrome-native-theme;1");
    1577               0 :     if (!mTheme)
    1578               0 :       sNoTheme = true;
    1579                 :   }
    1580                 : 
    1581               0 :   return mTheme;
    1582                 : }
    1583                 : 
    1584                 : void
    1585               0 : nsPresContext::ThemeChanged()
    1586                 : {
    1587               0 :   if (!mPendingThemeChanged) {
    1588               0 :     sLookAndFeelChanged = true;
    1589               0 :     sThemeChanged = true;
    1590                 : 
    1591                 :     nsCOMPtr<nsIRunnable> ev =
    1592               0 :       NS_NewRunnableMethod(this, &nsPresContext::ThemeChangedInternal);
    1593               0 :     if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) {
    1594               0 :       mPendingThemeChanged = true;
    1595                 :     }
    1596                 :   }    
    1597               0 : }
    1598                 : 
    1599                 : void
    1600               0 : nsPresContext::ThemeChangedInternal()
    1601                 : {
    1602               0 :   mPendingThemeChanged = false;
    1603                 :   
    1604                 :   // Tell the theme that it changed, so it can flush any handles to stale theme
    1605                 :   // data.
    1606               0 :   if (mTheme && sThemeChanged) {
    1607               0 :     mTheme->ThemeChanged();
    1608               0 :     sThemeChanged = false;
    1609                 :   }
    1610                 : 
    1611                 :   // Clear all cached LookAndFeel colors.
    1612               0 :   if (sLookAndFeelChanged) {
    1613               0 :     LookAndFeel::Refresh();
    1614               0 :     sLookAndFeelChanged = false;
    1615                 :   }
    1616                 : 
    1617                 :   // This will force the system metrics to be generated the next time they're used
    1618               0 :   nsCSSRuleProcessor::FreeSystemMetrics();
    1619                 : 
    1620                 :   // Changes to system metrics can change media queries on them.
    1621               0 :   MediaFeatureValuesChanged(true);
    1622                 : 
    1623                 :   // Changes in theme can change system colors (whose changes are
    1624                 :   // properly reflected in computed style data), system fonts (whose
    1625                 :   // changes are not), and -moz-appearance (whose changes likewise are
    1626                 :   // not), so we need to reflow.
    1627               0 :   RebuildAllStyleData(NS_STYLE_HINT_REFLOW);
    1628               0 : }
    1629                 : 
    1630                 : void
    1631               0 : nsPresContext::SysColorChanged()
    1632                 : {
    1633               0 :   if (!mPendingSysColorChanged) {
    1634               0 :     sLookAndFeelChanged = true;
    1635                 :     nsCOMPtr<nsIRunnable> ev =
    1636               0 :       NS_NewRunnableMethod(this, &nsPresContext::SysColorChangedInternal);
    1637               0 :     if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) {
    1638               0 :       mPendingSysColorChanged = true;
    1639                 :     }
    1640                 :   }
    1641               0 : }
    1642                 : 
    1643                 : void
    1644               0 : nsPresContext::SysColorChangedInternal()
    1645                 : {
    1646               0 :   mPendingSysColorChanged = false;
    1647                 :   
    1648               0 :   if (sLookAndFeelChanged) {
    1649                 :      // Don't use the cached values for the system colors
    1650               0 :     LookAndFeel::Refresh();
    1651               0 :     sLookAndFeelChanged = false;
    1652                 :   }
    1653                 :    
    1654                 :   // Reset default background and foreground colors for the document since
    1655                 :   // they may be using system colors
    1656               0 :   GetDocumentColorPreferences();
    1657                 : 
    1658                 :   // The system color values are computed to colors in the style data,
    1659                 :   // so normal style data comparison is sufficient here.
    1660               0 :   RebuildAllStyleData(nsChangeHint(0));
    1661               0 : }
    1662                 : 
    1663                 : void
    1664               0 : nsPresContext::RebuildAllStyleData(nsChangeHint aExtraHint)
    1665                 : {
    1666               0 :   if (!mShell) {
    1667                 :     // We must have been torn down. Nothing to do here.
    1668               0 :     return;
    1669                 :   }
    1670                 : 
    1671               0 :   RebuildUserFontSet();
    1672               0 :   AnimationManager()->KeyframesListIsDirty();
    1673                 : 
    1674               0 :   mShell->FrameConstructor()->RebuildAllStyleData(aExtraHint);
    1675                 : }
    1676                 : 
    1677                 : void
    1678               0 : nsPresContext::PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint)
    1679                 : {
    1680               0 :   if (!mShell) {
    1681                 :     // We must have been torn down. Nothing to do here.
    1682               0 :     return;
    1683                 :   }
    1684               0 :   mShell->FrameConstructor()->PostRebuildAllStyleDataEvent(aExtraHint);
    1685                 : }
    1686                 : 
    1687                 : void
    1688               0 : nsPresContext::MediaFeatureValuesChanged(bool aCallerWillRebuildStyleData)
    1689                 : {
    1690               0 :   mPendingMediaFeatureValuesChanged = false;
    1691               0 :   if (mShell &&
    1692               0 :       mShell->StyleSet()->MediumFeaturesChanged(this) &&
    1693               0 :       !aCallerWillRebuildStyleData) {
    1694               0 :     RebuildAllStyleData(nsChangeHint(0));
    1695                 :   }
    1696                 : 
    1697               0 :   if (!nsContentUtils::IsSafeToRunScript()) {
    1698               0 :     NS_ABORT_IF_FALSE(mDocument->IsBeingUsedAsImage(),
    1699                 :                       "How did we get here?  Are we failing to notify "
    1700                 :                       "listeners that we should notify?");
    1701               0 :     return;
    1702                 :   }
    1703                 : 
    1704                 :   // Media query list listeners should be notified from a queued task
    1705                 :   // (in HTML5 terms), although we also want to notify them on certain
    1706                 :   // flushes.  (We're already running off an event.)
    1707                 :   //
    1708                 :   // Note that we do this after the new style from media queries in
    1709                 :   // style sheets has been computed.
    1710                 : 
    1711               0 :   if (!PR_CLIST_IS_EMPTY(&mDOMMediaQueryLists)) {
    1712                 :     // We build a list of all the notifications we're going to send
    1713                 :     // before we send any of them.  (The spec says the notifications
    1714                 :     // should be a queued task, so any removals that happen during the
    1715                 :     // notifications shouldn't affect what gets notified.)  Furthermore,
    1716                 :     // we hold strong pointers to everything we're going to make
    1717                 :     // notification calls to, since each notification involves calling
    1718                 :     // arbitrary script that might otherwise destroy these objects, or,
    1719                 :     // for that matter, |this|.
    1720                 :     //
    1721                 :     // Note that we intentionally send the notifications to media query
    1722                 :     // list in the order they were created and, for each list, to the
    1723                 :     // listeners in the order added.
    1724               0 :     nsDOMMediaQueryList::NotifyList notifyList;
    1725               0 :     for (PRCList *l = PR_LIST_HEAD(&mDOMMediaQueryLists);
    1726                 :          l != &mDOMMediaQueryLists; l = PR_NEXT_LINK(l)) {
    1727               0 :       nsDOMMediaQueryList *mql = static_cast<nsDOMMediaQueryList*>(l);
    1728               0 :       mql->MediumFeaturesChanged(notifyList);
    1729                 :     }
    1730                 : 
    1731               0 :     if (!notifyList.IsEmpty()) {
    1732               0 :       nsPIDOMWindow *win = mDocument->GetInnerWindow();
    1733               0 :       nsCOMPtr<nsIDOMEventTarget> et = do_QueryInterface(win);
    1734               0 :       nsCxPusher pusher;
    1735                 : 
    1736               0 :       for (PRUint32 i = 0, i_end = notifyList.Length(); i != i_end; ++i) {
    1737               0 :         if (pusher.RePush(et)) {
    1738               0 :           nsDOMMediaQueryList::HandleChangeData &d = notifyList[i];
    1739               0 :           d.listener->HandleChange(d.mql);
    1740                 :         }
    1741                 :       }
    1742                 :     }
    1743                 : 
    1744                 :     // NOTE:  When |notifyList| goes out of scope, our destructor could run.
    1745                 :   }
    1746                 : }
    1747                 : 
    1748                 : void
    1749               0 : nsPresContext::PostMediaFeatureValuesChangedEvent()
    1750                 : {
    1751                 :   // FIXME: We should probably replace this event with use of
    1752                 :   // nsRefreshDriver::AddStyleFlushObserver (except the pres shell would
    1753                 :   // need to track whether it's been added).
    1754               0 :   if (!mPendingMediaFeatureValuesChanged) {
    1755                 :     nsCOMPtr<nsIRunnable> ev =
    1756               0 :       NS_NewRunnableMethod(this, &nsPresContext::HandleMediaFeatureValuesChangedEvent);
    1757               0 :     if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) {
    1758               0 :       mPendingMediaFeatureValuesChanged = true;
    1759               0 :       mDocument->SetNeedStyleFlush();
    1760                 :     }
    1761                 :   }
    1762               0 : }
    1763                 : 
    1764                 : void
    1765               0 : nsPresContext::HandleMediaFeatureValuesChangedEvent()
    1766                 : {
    1767                 :   // Null-check mShell in case the shell has been destroyed (and the
    1768                 :   // event is the only thing holding the pres context alive).
    1769               0 :   if (mPendingMediaFeatureValuesChanged && mShell) {
    1770               0 :     MediaFeatureValuesChanged(false);
    1771                 :   }
    1772               0 : }
    1773                 : 
    1774                 : void
    1775               0 : nsPresContext::MatchMedia(const nsAString& aMediaQueryList,
    1776                 :                           nsIDOMMediaQueryList** aResult)
    1777                 : {
    1778                 :   nsRefPtr<nsDOMMediaQueryList> result =
    1779               0 :     new nsDOMMediaQueryList(this, aMediaQueryList);
    1780                 : 
    1781                 :   // Insert the new item at the end of the linked list.
    1782               0 :   PR_INSERT_BEFORE(result, &mDOMMediaQueryLists);
    1783                 : 
    1784               0 :   result.forget(aResult);
    1785               0 : }
    1786                 : 
    1787                 : void
    1788               0 : nsPresContext::SetPaginatedScrolling(bool aPaginated)
    1789                 : {
    1790               0 :   if (mType == eContext_PrintPreview || mType == eContext_PageLayout)
    1791               0 :     mCanPaginatedScroll = aPaginated;
    1792               0 : }
    1793                 : 
    1794                 : void
    1795               0 : nsPresContext::SetPrintSettings(nsIPrintSettings *aPrintSettings)
    1796                 : {
    1797               0 :   if (mMedium == nsGkAtoms::print)
    1798               0 :     mPrintSettings = aPrintSettings;
    1799               0 : }
    1800                 : 
    1801                 : bool
    1802               0 : nsPresContext::EnsureVisible()
    1803                 : {
    1804               0 :   nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mContainer));
    1805               0 :   if (docShell) {
    1806               0 :     nsCOMPtr<nsIContentViewer> cv;
    1807               0 :     docShell->GetContentViewer(getter_AddRefs(cv));
    1808                 :     // Make sure this is the content viewer we belong with
    1809               0 :     if (cv) {
    1810               0 :       nsRefPtr<nsPresContext> currentPresContext;
    1811               0 :       cv->GetPresContext(getter_AddRefs(currentPresContext));
    1812               0 :       if (currentPresContext == this) {
    1813                 :         // OK, this is us.  We want to call Show() on the content viewer.
    1814               0 :         cv->Show();
    1815               0 :         return true;
    1816                 :       }
    1817                 :     }
    1818                 :   }
    1819               0 :   return false;
    1820                 : }
    1821                 : 
    1822                 : #ifdef MOZ_REFLOW_PERF
    1823                 : void
    1824               0 : nsPresContext::CountReflows(const char * aName, nsIFrame * aFrame)
    1825                 : {
    1826               0 :   if (mShell) {
    1827               0 :     mShell->CountReflows(aName, aFrame);
    1828                 :   }
    1829               0 : }
    1830                 : #endif
    1831                 : 
    1832                 : bool
    1833               0 : nsPresContext::IsChromeSlow() const
    1834                 : {
    1835               0 :   bool isChrome = false;
    1836               0 :   nsCOMPtr<nsISupports> container = GetContainer();
    1837               0 :   if (container) {
    1838                 :     nsresult result;
    1839               0 :     nsCOMPtr<nsIDocShellTreeItem> docShell(do_QueryInterface(container, &result));
    1840               0 :     if (NS_SUCCEEDED(result) && docShell) {
    1841                 :       PRInt32 docShellType;
    1842               0 :       result = docShell->GetItemType(&docShellType);
    1843               0 :       if (NS_SUCCEEDED(result)) {
    1844               0 :         isChrome = nsIDocShellTreeItem::typeChrome == docShellType;
    1845                 :       }
    1846                 :     }
    1847                 :   }
    1848               0 :   mIsChrome = isChrome;
    1849               0 :   mIsChromeIsCached = true;
    1850               0 :   return mIsChrome;
    1851                 : }
    1852                 : 
    1853                 : void
    1854               0 : nsPresContext::InvalidateIsChromeCacheExternal()
    1855                 : {
    1856               0 :   InvalidateIsChromeCacheInternal();
    1857               0 : }
    1858                 : 
    1859                 : /* virtual */ bool
    1860               0 : nsPresContext::HasAuthorSpecifiedRules(nsIFrame *aFrame, PRUint32 ruleTypeMask) const
    1861                 : {
    1862                 :   return
    1863                 :     nsRuleNode::HasAuthorSpecifiedRules(aFrame->GetStyleContext(),
    1864                 :                                         ruleTypeMask,
    1865               0 :                                         UseDocumentColors());
    1866                 : }
    1867                 : 
    1868                 : gfxUserFontSet*
    1869               0 : nsPresContext::GetUserFontSetInternal()
    1870                 : {
    1871                 :   // We want to initialize the user font set lazily the first time the
    1872                 :   // user asks for it, rather than building it too early and forcing
    1873                 :   // rule cascade creation.  Thus we try to enforce the invariant that
    1874                 :   // we *never* build the user font set until the first call to
    1875                 :   // GetUserFontSet.  However, once it's been requested, we can't wait
    1876                 :   // for somebody to call GetUserFontSet in order to rebuild it (see
    1877                 :   // comments below in RebuildUserFontSet for why).
    1878                 : #ifdef DEBUG
    1879               0 :   bool userFontSetGottenBefore = mGetUserFontSetCalled;
    1880                 : #endif
    1881                 :   // Set mGetUserFontSetCalled up front, so that FlushUserFontSet will actually
    1882                 :   // flush.
    1883               0 :   mGetUserFontSetCalled = true;
    1884               0 :   if (mUserFontSetDirty) {
    1885                 :     // If this assertion fails, and there have actually been changes to
    1886                 :     // @font-face rules, then we will call StyleChangeReflow in
    1887                 :     // FlushUserFontSet.  If we're in the middle of reflow,
    1888                 :     // that's a bad thing to do, and the caller was responsible for
    1889                 :     // flushing first.  If we're not (e.g., in frame construction), it's
    1890                 :     // ok.
    1891               0 :     NS_ASSERTION(!userFontSetGottenBefore || !mShell->IsReflowLocked(),
    1892                 :                  "FlushUserFontSet should have been called first");
    1893               0 :     FlushUserFontSet();
    1894                 :   }
    1895                 : 
    1896               0 :   return mUserFontSet;
    1897                 : }
    1898                 : 
    1899                 : gfxUserFontSet*
    1900               0 : nsPresContext::GetUserFontSetExternal()
    1901                 : {
    1902               0 :   return GetUserFontSetInternal();
    1903                 : }
    1904                 : 
    1905                 : void
    1906               0 : nsPresContext::FlushUserFontSet()
    1907                 : {
    1908               0 :   if (!mShell) {
    1909               0 :     return; // we've been torn down
    1910                 :   }
    1911                 : 
    1912               0 :   if (!mGetUserFontSetCalled) {
    1913               0 :     return; // No one cares about this font set yet, but we want to be careful
    1914                 :             // to not unset our mUserFontSetDirty bit, so when someone really
    1915                 :             // does we'll create it.
    1916                 :   }
    1917                 : 
    1918               0 :   if (mUserFontSetDirty) {
    1919               0 :     if (gfxPlatform::GetPlatform()->DownloadableFontsEnabled()) {
    1920               0 :       nsTArray<nsFontFaceRuleContainer> rules;
    1921               0 :       if (!mShell->StyleSet()->AppendFontFaceRules(this, rules)) {
    1922               0 :         if (mUserFontSet) {
    1923               0 :           mUserFontSet->Destroy();
    1924               0 :           NS_RELEASE(mUserFontSet);
    1925                 :         }
    1926                 :         return;
    1927                 :       }
    1928                 : 
    1929               0 :       bool changed = false;
    1930                 : 
    1931               0 :       if (rules.Length() == 0) {
    1932               0 :         if (mUserFontSet) {
    1933               0 :           mUserFontSet->Destroy();
    1934               0 :           NS_RELEASE(mUserFontSet);
    1935               0 :           changed = true;
    1936                 :         }
    1937                 :       } else {
    1938               0 :         if (!mUserFontSet) {
    1939               0 :           mUserFontSet = new nsUserFontSet(this);
    1940               0 :           NS_ADDREF(mUserFontSet);
    1941                 :         }
    1942               0 :         changed = mUserFontSet->UpdateRules(rules);
    1943                 :       }
    1944                 : 
    1945                 :       // We need to enqueue a style change reflow (for later) to
    1946                 :       // reflect that we're modifying @font-face rules.  (However,
    1947                 :       // without a reflow, nothing will happen to start any downloads
    1948                 :       // that are needed.)
    1949               0 :       if (changed) {
    1950               0 :         UserFontSetUpdated();
    1951                 :       }
    1952                 :     }
    1953                 : 
    1954               0 :     mUserFontSetDirty = false;
    1955                 :   }
    1956                 : }
    1957                 : 
    1958                 : void
    1959               0 : nsPresContext::RebuildUserFontSet()
    1960                 : {
    1961               0 :   if (!mGetUserFontSetCalled) {
    1962                 :     // We want to lazily build the user font set the first time it's
    1963                 :     // requested (so we don't force creation of rule cascades too
    1964                 :     // early), so don't do anything now.
    1965               0 :     return;
    1966                 :   }
    1967                 : 
    1968               0 :   mUserFontSetDirty = true;
    1969               0 :   mDocument->SetNeedStyleFlush();
    1970                 : 
    1971                 :   // Somebody has already asked for the user font set, so we need to
    1972                 :   // post an event to rebuild it.  Setting the user font set to be dirty
    1973                 :   // and lazily rebuilding it isn't sufficient, since it is only the act
    1974                 :   // of rebuilding it that will trigger the style change reflow that
    1975                 :   // calls GetUserFontSet.  (This reflow causes rebuilding of text runs,
    1976                 :   // which starts font loads, whose completion causes another style
    1977                 :   // change reflow).
    1978               0 :   if (!mPostedFlushUserFontSet) {
    1979                 :     nsCOMPtr<nsIRunnable> ev =
    1980               0 :       NS_NewRunnableMethod(this, &nsPresContext::HandleRebuildUserFontSet);
    1981               0 :     if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) {
    1982               0 :       mPostedFlushUserFontSet = true;
    1983                 :     }
    1984                 :   }    
    1985                 : }
    1986                 : 
    1987                 : void
    1988               0 : nsPresContext::UserFontSetUpdated()
    1989                 : {
    1990               0 :   if (!mShell)
    1991               0 :     return;
    1992                 : 
    1993                 :   // Changes to the set of available fonts can cause updates to layout by:
    1994                 :   //
    1995                 :   //   1. Changing the font used for text, which changes anything that
    1996                 :   //      depends on text measurement, including line breaking and
    1997                 :   //      intrinsic widths, and any other parts of layout that depend on
    1998                 :   //      font metrics.  This requires a style change reflow to update.
    1999                 :   //
    2000                 :   //   2. Changing the value of the 'ex' and 'ch' units in style data,
    2001                 :   //      which also depend on font metrics.  Updating this information
    2002                 :   //      requires rebuilding the rule tree from the top, avoiding the
    2003                 :   //      reuse of cached data even when no style rules have changed.
    2004                 : 
    2005               0 :   PostRebuildAllStyleDataEvent(NS_STYLE_HINT_REFLOW);
    2006                 : }
    2007                 : 
    2008                 : bool
    2009               0 : nsPresContext::EnsureSafeToHandOutCSSRules()
    2010                 : {
    2011                 :   nsCSSStyleSheet::EnsureUniqueInnerResult res =
    2012               0 :     mShell->StyleSet()->EnsureUniqueInnerOnCSSSheets();
    2013               0 :   if (res == nsCSSStyleSheet::eUniqueInner_AlreadyUnique) {
    2014                 :     // Nothing to do.
    2015               0 :     return true;
    2016                 :   }
    2017               0 :   if (res == nsCSSStyleSheet::eUniqueInner_CloneFailed) {
    2018               0 :     return false;
    2019                 :   }
    2020                 : 
    2021               0 :   NS_ABORT_IF_FALSE(res == nsCSSStyleSheet::eUniqueInner_ClonedInner,
    2022                 :                     "unexpected result");
    2023               0 :   RebuildAllStyleData(nsChangeHint(0));
    2024               0 :   return true;
    2025                 : }
    2026                 : 
    2027                 : void
    2028               0 : nsPresContext::FireDOMPaintEvent()
    2029                 : {
    2030               0 :   nsPIDOMWindow* ourWindow = mDocument->GetWindow();
    2031               0 :   if (!ourWindow)
    2032               0 :     return;
    2033                 : 
    2034               0 :   nsCOMPtr<nsIDOMEventTarget> dispatchTarget = do_QueryInterface(ourWindow);
    2035               0 :   nsCOMPtr<nsIDOMEventTarget> eventTarget = dispatchTarget;
    2036               0 :   if (!IsChrome()) {
    2037               0 :     bool notifyContent = mSendAfterPaintToContent;
    2038                 : 
    2039               0 :     if (notifyContent) {
    2040                 :       // If the pref is set, we still don't post events when they're
    2041                 :       // entirely cross-doc.
    2042               0 :       notifyContent = false;
    2043               0 :       for (PRUint32 i = 0; i < mInvalidateRequests.mRequests.Length(); ++i) {
    2044               0 :         if (!(mInvalidateRequests.mRequests[i].mFlags &
    2045               0 :               nsIFrame::INVALIDATE_CROSS_DOC)) {
    2046               0 :           notifyContent = true;
    2047                 :         }
    2048                 :       }
    2049                 :     }
    2050               0 :     if (!notifyContent) {
    2051                 :       // Don't tell the window about this event, it should not know that
    2052                 :       // something happened in a subdocument. Tell only the chrome event handler.
    2053                 :       // (Events sent to the window get propagated to the chrome event handler
    2054                 :       // automatically.)
    2055               0 :       dispatchTarget = do_QueryInterface(ourWindow->GetParentTarget());
    2056               0 :       if (!dispatchTarget) {
    2057                 :         return;
    2058                 :       }
    2059                 :     }
    2060                 :   }
    2061                 :   // Events sent to the window get propagated to the chrome event handler
    2062                 :   // automatically.
    2063               0 :   nsCOMPtr<nsIDOMEvent> event;
    2064                 :   // This will empty our list in case dispatching the event causes more damage
    2065                 :   // (hopefully it won't, or we're likely to get an infinite loop! At least
    2066                 :   // it won't be blocking app execution though).
    2067               0 :   NS_NewDOMNotifyPaintEvent(getter_AddRefs(event), this, nsnull,
    2068                 :                             NS_AFTERPAINT,
    2069               0 :                             &mInvalidateRequests);
    2070               0 :   nsCOMPtr<nsIPrivateDOMEvent> pEvent = do_QueryInterface(event);
    2071               0 :   if (!pEvent) return;
    2072                 : 
    2073                 :   // Even if we're not telling the window about the event (so eventTarget is
    2074                 :   // the chrome event handler, not the window), the window is still
    2075                 :   // logically the event target.
    2076               0 :   pEvent->SetTarget(eventTarget);
    2077               0 :   pEvent->SetTrusted(true);
    2078               0 :   nsEventDispatcher::DispatchDOMEvent(dispatchTarget, nsnull, event, this, nsnull);
    2079                 : }
    2080                 : 
    2081                 : static bool
    2082               0 : MayHavePaintEventListener(nsPIDOMWindow* aInnerWindow)
    2083                 : {
    2084               0 :   if (!aInnerWindow)
    2085               0 :     return false;
    2086               0 :   if (aInnerWindow->HasPaintEventListeners())
    2087               0 :     return true;
    2088                 : 
    2089               0 :   nsIDOMEventTarget* parentTarget = aInnerWindow->GetParentTarget();
    2090               0 :   if (!parentTarget)
    2091               0 :     return false;
    2092                 : 
    2093               0 :   nsEventListenerManager* manager = nsnull;
    2094               0 :   if ((manager = parentTarget->GetListenerManager(false)) &&
    2095               0 :       manager->MayHavePaintEventListener()) {
    2096               0 :     return true;
    2097                 :   }
    2098                 : 
    2099               0 :   nsCOMPtr<nsINode> node;
    2100               0 :   if (parentTarget != aInnerWindow->GetChromeEventHandler()) {
    2101                 :     nsCOMPtr<nsIInProcessContentFrameMessageManager> mm =
    2102               0 :       do_QueryInterface(parentTarget);
    2103               0 :     if (mm) {
    2104               0 :       node = mm->GetOwnerContent();
    2105                 :     }
    2106                 :   }
    2107                 : 
    2108               0 :   if (!node) {
    2109               0 :     node = do_QueryInterface(parentTarget);
    2110                 :   }
    2111               0 :   if (node)
    2112               0 :     return MayHavePaintEventListener(node->OwnerDoc()->GetInnerWindow());
    2113                 : 
    2114               0 :   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(parentTarget);
    2115               0 :   if (window)
    2116               0 :     return MayHavePaintEventListener(window);
    2117                 : 
    2118               0 :   nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(parentTarget);
    2119                 :   nsIDOMEventTarget* tabChildGlobal;
    2120                 :   return root &&
    2121               0 :          (tabChildGlobal = root->GetParentTarget()) &&
    2122               0 :          (manager = tabChildGlobal->GetListenerManager(false)) &&
    2123               0 :          manager->MayHavePaintEventListener();
    2124                 : }
    2125                 : 
    2126                 : bool
    2127               0 : nsPresContext::MayHavePaintEventListener()
    2128                 : {
    2129               0 :   return ::MayHavePaintEventListener(mDocument->GetInnerWindow());
    2130                 : }
    2131                 : 
    2132                 : void
    2133               0 : nsPresContext::NotifyInvalidation(const nsRect& aRect, PRUint32 aFlags)
    2134                 : {
    2135                 :   // If there is no paint event listener, then we don't need to fire
    2136                 :   // the asynchronous event. We don't even need to record invalidation.
    2137                 :   // MayHavePaintEventListener is pretty cheap and we could make it
    2138                 :   // even cheaper by providing a more efficient
    2139                 :   // nsPIDOMWindow::GetListenerManager.
    2140               0 :   if (aRect.IsEmpty() || !MayHavePaintEventListener())
    2141               0 :     return;
    2142                 : 
    2143                 :   nsPresContext* pc;
    2144               0 :   for (pc = this; pc; pc = GetParentPresContext(pc)) {
    2145               0 :     if (pc->mFireAfterPaintEvents)
    2146               0 :       break;
    2147               0 :     pc->mFireAfterPaintEvents = true;
    2148                 :   }
    2149               0 :   if (!pc) {
    2150               0 :     nsRootPresContext* rpc = GetRootPresContext();
    2151               0 :     if (rpc) {
    2152               0 :       rpc->EnsureEventualDidPaintEvent();
    2153                 :     }
    2154                 :   }
    2155                 : 
    2156                 :   nsInvalidateRequestList::Request* request =
    2157               0 :     mInvalidateRequests.mRequests.AppendElement();
    2158               0 :   if (!request)
    2159               0 :     return;
    2160                 : 
    2161               0 :   request->mRect = aRect;
    2162               0 :   request->mFlags = aFlags;
    2163                 : }
    2164                 : 
    2165                 : static bool
    2166               0 : NotifyDidPaintSubdocumentCallback(nsIDocument* aDocument, void* aData)
    2167                 : {
    2168               0 :   nsIPresShell* shell = aDocument->GetShell();
    2169               0 :   if (shell) {
    2170               0 :     nsPresContext* pc = shell->GetPresContext();
    2171               0 :     if (pc) {
    2172               0 :       pc->NotifyDidPaintForSubtree();
    2173                 :     }
    2174                 :   }
    2175               0 :   return true;
    2176                 : }
    2177                 : 
    2178                 : void
    2179               0 : nsPresContext::NotifyDidPaintForSubtree()
    2180                 : {
    2181               0 :   if (!mFireAfterPaintEvents)
    2182               0 :     return;
    2183               0 :   mFireAfterPaintEvents = false;
    2184                 : 
    2185               0 :   if (IsRoot()) {
    2186               0 :     static_cast<nsRootPresContext*>(this)->CancelDidPaintTimer();
    2187                 :   }
    2188                 : 
    2189               0 :   if (!mInvalidateRequests.mRequests.IsEmpty()) {
    2190                 :     nsCOMPtr<nsIRunnable> ev =
    2191               0 :       NS_NewRunnableMethod(this, &nsPresContext::FireDOMPaintEvent);
    2192               0 :     nsContentUtils::AddScriptRunner(ev);
    2193                 :   }
    2194                 : 
    2195               0 :   mDocument->EnumerateSubDocuments(NotifyDidPaintSubdocumentCallback, nsnull);
    2196                 : }
    2197                 : 
    2198                 : bool
    2199               0 : nsPresContext::HasCachedStyleData()
    2200                 : {
    2201               0 :   return mShell && mShell->StyleSet()->HasCachedStyleData();
    2202                 : }
    2203                 : 
    2204                 : static bool sGotInterruptEnv = false;
    2205                 : enum InterruptMode {
    2206                 :   ModeRandom,
    2207                 :   ModeCounter,
    2208                 :   ModeEvent
    2209                 : };
    2210                 : // Controlled by the GECKO_REFLOW_INTERRUPT_MODE env var; allowed values are
    2211                 : // "random" (except on Windows) or "counter".  If neither is used, the mode is
    2212                 : // ModeEvent.
    2213                 : static InterruptMode sInterruptMode = ModeEvent;
    2214                 : // Used for the "random" mode.  Controlled by the GECKO_REFLOW_INTERRUPT_SEED
    2215                 : // env var.
    2216                 : static PRUint32 sInterruptSeed = 1;
    2217                 : // Used for the "counter" mode.  This is the number of unskipped interrupt
    2218                 : // checks that have to happen before we interrupt.  Controlled by the
    2219                 : // GECKO_REFLOW_INTERRUPT_FREQUENCY env var.
    2220                 : static PRUint32 sInterruptMaxCounter = 10;
    2221                 : // Used for the "counter" mode.  This counts up to sInterruptMaxCounter and is
    2222                 : // then reset to 0.
    2223                 : static PRUint32 sInterruptCounter;
    2224                 : // Number of interrupt checks to skip before really trying to interrupt.
    2225                 : // Controlled by the GECKO_REFLOW_INTERRUPT_CHECKS_TO_SKIP env var.
    2226                 : static PRUint32 sInterruptChecksToSkip = 200;
    2227                 : // Number of milliseconds that a reflow should be allowed to run for before we
    2228                 : // actually allow interruption.  Controlled by the
    2229                 : // GECKO_REFLOW_MIN_NOINTERRUPT_DURATION env var.  Can't be initialized here,
    2230                 : // because TimeDuration/TimeStamp is not safe to use in static constructors..
    2231            1396 : static TimeDuration sInterruptTimeout;
    2232                 : 
    2233               0 : static void GetInterruptEnv()
    2234                 : {
    2235               0 :   char *ev = PR_GetEnv("GECKO_REFLOW_INTERRUPT_MODE");
    2236               0 :   if (ev) {
    2237                 : #ifndef XP_WIN
    2238               0 :     if (PL_strcasecmp(ev, "random") == 0) {
    2239               0 :       ev = PR_GetEnv("GECKO_REFLOW_INTERRUPT_SEED");
    2240               0 :       if (ev) {
    2241               0 :         sInterruptSeed = atoi(ev);
    2242                 :       }
    2243               0 :       srandom(sInterruptSeed);
    2244               0 :       sInterruptMode = ModeRandom;
    2245                 :     } else
    2246                 : #endif
    2247               0 :       if (PL_strcasecmp(ev, "counter") == 0) {
    2248               0 :       ev = PR_GetEnv("GECKO_REFLOW_INTERRUPT_FREQUENCY");
    2249               0 :       if (ev) {
    2250               0 :         sInterruptMaxCounter = atoi(ev);
    2251                 :       }
    2252               0 :       sInterruptCounter = 0;
    2253               0 :       sInterruptMode = ModeCounter;
    2254                 :     }
    2255                 :   }
    2256               0 :   ev = PR_GetEnv("GECKO_REFLOW_INTERRUPT_CHECKS_TO_SKIP");
    2257               0 :   if (ev) {
    2258               0 :     sInterruptChecksToSkip = atoi(ev);
    2259                 :   }
    2260                 : 
    2261               0 :   ev = PR_GetEnv("GECKO_REFLOW_MIN_NOINTERRUPT_DURATION");
    2262               0 :   int duration_ms = ev ? atoi(ev) : 100;
    2263               0 :   sInterruptTimeout = TimeDuration::FromMilliseconds(duration_ms);
    2264               0 : }
    2265                 : 
    2266                 : bool
    2267               0 : nsPresContext::HavePendingInputEvent()
    2268                 : {
    2269               0 :   switch (sInterruptMode) {
    2270                 : #ifndef XP_WIN
    2271                 :     case ModeRandom:
    2272               0 :       return (random() & 1);
    2273                 : #endif
    2274                 :     case ModeCounter:
    2275               0 :       if (sInterruptCounter < sInterruptMaxCounter) {
    2276               0 :         ++sInterruptCounter;
    2277               0 :         return false;
    2278                 :       }
    2279               0 :       sInterruptCounter = 0;
    2280               0 :       return true;
    2281                 :     default:
    2282                 :     case ModeEvent: {
    2283               0 :       nsIFrame* f = PresShell()->GetRootFrame();
    2284               0 :       if (f) {
    2285               0 :         nsIWidget* w = f->GetNearestWidget();
    2286               0 :         if (w) {
    2287               0 :           return w->HasPendingInputEvent();
    2288                 :         }
    2289                 :       }
    2290               0 :       return false;
    2291                 :     }
    2292                 :   }
    2293                 : }
    2294                 : 
    2295                 : void
    2296               0 : nsPresContext::ReflowStarted(bool aInterruptible)
    2297                 : {
    2298                 : #ifdef NOISY_INTERRUPTIBLE_REFLOW
    2299                 :   if (!aInterruptible) {
    2300                 :     printf("STARTING NONINTERRUPTIBLE REFLOW\n");
    2301                 :   }
    2302                 : #endif
    2303                 :   // We don't support interrupting in paginated contexts, since page
    2304                 :   // sequences only handle initial reflow
    2305               0 :   mInterruptsEnabled = aInterruptible && !IsPaginated();
    2306                 : 
    2307                 :   // Don't set mHasPendingInterrupt based on HavePendingInputEvent() here.  If
    2308                 :   // we ever change that, then we need to update the code in
    2309                 :   // PresShell::DoReflow to only add the just-reflown root to dirty roots if
    2310                 :   // it's actually dirty.  Otherwise we can end up adding a root that has no
    2311                 :   // interruptible descendants, just because we detected an interrupt at reflow
    2312                 :   // start.
    2313               0 :   mHasPendingInterrupt = false;
    2314                 : 
    2315               0 :   mInterruptChecksToSkip = sInterruptChecksToSkip;
    2316                 : 
    2317               0 :   if (mInterruptsEnabled) {
    2318               0 :     mReflowStartTime = TimeStamp::Now();
    2319                 :   }
    2320               0 : }
    2321                 : 
    2322                 : bool
    2323               0 : nsPresContext::CheckForInterrupt(nsIFrame* aFrame)
    2324                 : {
    2325               0 :   if (mHasPendingInterrupt) {
    2326               0 :     mShell->FrameNeedsToContinueReflow(aFrame);
    2327               0 :     return true;
    2328                 :   }
    2329                 : 
    2330               0 :   if (!sGotInterruptEnv) {
    2331               0 :     sGotInterruptEnv = true;
    2332               0 :     GetInterruptEnv();
    2333                 :   }
    2334                 : 
    2335               0 :   if (!mInterruptsEnabled) {
    2336               0 :     return false;
    2337                 :   }
    2338                 : 
    2339               0 :   if (mInterruptChecksToSkip > 0) {
    2340               0 :     --mInterruptChecksToSkip;
    2341               0 :     return false;
    2342                 :   }
    2343               0 :   mInterruptChecksToSkip = sInterruptChecksToSkip;
    2344                 : 
    2345                 :   // Don't interrupt if it's been less than sInterruptTimeout since we started
    2346                 :   // the reflow.
    2347                 :   mHasPendingInterrupt =
    2348               0 :     TimeStamp::Now() - mReflowStartTime > sInterruptTimeout &&
    2349               0 :     HavePendingInputEvent() &&
    2350               0 :     !IsChrome();
    2351               0 :   if (mHasPendingInterrupt) {
    2352                 : #ifdef NOISY_INTERRUPTIBLE_REFLOW
    2353                 :     printf("*** DETECTED pending interrupt (time=%lld)\n", PR_Now());
    2354                 : #endif /* NOISY_INTERRUPTIBLE_REFLOW */
    2355               0 :     mShell->FrameNeedsToContinueReflow(aFrame);
    2356                 :   }
    2357               0 :   return mHasPendingInterrupt;
    2358                 : }
    2359                 : 
    2360                 : size_t
    2361               0 : nsPresContext::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const
    2362                 : {
    2363               0 :   return mPropertyTable.SizeOfExcludingThis(aMallocSizeOf);
    2364                 :          mLangGroupFontPrefs.SizeOfExcludingThis(aMallocSizeOf);
    2365                 : 
    2366                 :   // Measurement of other members may be added later if DMD finds it is
    2367                 :   // worthwhile.
    2368                 : }
    2369                 : 
    2370                 : bool
    2371               0 : nsPresContext::IsRootContentDocument()
    2372                 : {
    2373                 :   // We are a root content document if: we are not a resource doc, we are
    2374                 :   // not chrome, and we either have no parent or our parent is chrome.
    2375               0 :   if (mDocument->IsResourceDoc()) {
    2376               0 :     return false;
    2377                 :   }
    2378               0 :   if (IsChrome()) {
    2379               0 :     return false;
    2380                 :   }
    2381                 :   // We may not have a root frame, so use views.
    2382               0 :   nsIView* view = PresShell()->GetViewManager()->GetRootView();
    2383               0 :   if (!view) {
    2384               0 :     return false;
    2385                 :   }
    2386               0 :   view = view->GetParent(); // anonymous inner view
    2387               0 :   if (!view) {
    2388               0 :     return true;
    2389                 :   }
    2390               0 :   view = view->GetParent(); // subdocumentframe's view
    2391               0 :   if (!view) {
    2392               0 :     return true;
    2393                 :   }
    2394                 : 
    2395               0 :   nsIFrame* f = view->GetFrame();
    2396               0 :   return (f && f->PresContext()->IsChrome());
    2397                 : }
    2398                 : 
    2399               0 : nsRootPresContext::nsRootPresContext(nsIDocument* aDocument,
    2400                 :                                      nsPresContextType aType)
    2401                 :   : nsPresContext(aDocument, aType),
    2402                 :     mUpdatePluginGeometryForFrame(nsnull),
    2403                 :     mDOMGeneration(0),
    2404               0 :     mNeedsToUpdatePluginGeometry(false)
    2405                 : {
    2406               0 :   mRegisteredPlugins.Init();
    2407               0 : }
    2408                 : 
    2409               0 : nsRootPresContext::~nsRootPresContext()
    2410                 : {
    2411               0 :   NS_ASSERTION(mRegisteredPlugins.Count() == 0,
    2412                 :                "All plugins should have been unregistered");
    2413               0 :   CancelDidPaintTimer();
    2414               0 :   CancelUpdatePluginGeometryTimer();
    2415               0 : }
    2416                 : 
    2417                 : void
    2418               0 : nsRootPresContext::RegisterPluginForGeometryUpdates(nsObjectFrame* aPlugin)
    2419                 : {
    2420               0 :   mRegisteredPlugins.PutEntry(aPlugin);
    2421               0 : }
    2422                 : 
    2423                 : void
    2424               0 : nsRootPresContext::UnregisterPluginForGeometryUpdates(nsObjectFrame* aPlugin)
    2425                 : {
    2426               0 :   mRegisteredPlugins.RemoveEntry(aPlugin);
    2427               0 : }
    2428                 : 
    2429               0 : struct PluginGeometryClosure {
    2430                 :   nsIFrame* mRootFrame;
    2431                 :   PRInt32   mRootAPD;
    2432                 :   nsIFrame* mChangedSubtree;
    2433                 :   nsRect    mChangedRect;
    2434                 :   nsTHashtable<nsPtrHashKey<nsObjectFrame> > mAffectedPlugins;
    2435                 :   nsRect    mAffectedPluginBounds;
    2436                 :   nsTArray<nsIWidget::Configuration>* mOutputConfigurations;
    2437                 : };
    2438                 : static PLDHashOperator
    2439               0 : PluginBoundsEnumerator(nsPtrHashKey<nsObjectFrame>* aEntry, void* userArg)
    2440                 : {
    2441               0 :   PluginGeometryClosure* closure = static_cast<PluginGeometryClosure*>(userArg);
    2442               0 :   nsObjectFrame* f = aEntry->GetKey();
    2443               0 :   nsRect fBounds = f->GetContentRect() +
    2444               0 :       f->GetParent()->GetOffsetToCrossDoc(closure->mRootFrame);
    2445               0 :   PRInt32 APD = f->PresContext()->AppUnitsPerDevPixel();
    2446               0 :   fBounds = fBounds.ConvertAppUnitsRoundOut(APD, closure->mRootAPD);
    2447                 :   // We're identifying the plugins that may have been affected by changes
    2448                 :   // to the frame subtree rooted at aChangedRoot. Any plugin that overlaps
    2449                 :   // the overflow area of aChangedRoot could have its clip region affected
    2450                 :   // because it might be covered (or uncovered) by changes to the subtree.
    2451                 :   // Plugins in the subtree might have changed position and/or size, and
    2452                 :   // they might not be in aChangedRoot's overflow area (because they're
    2453                 :   // being clipped by an ancestor in the subtree).
    2454               0 :   if (fBounds.Intersects(closure->mChangedRect) ||
    2455               0 :       nsLayoutUtils::IsAncestorFrameCrossDoc(closure->mChangedSubtree, f)) {
    2456                 :     closure->mAffectedPluginBounds.UnionRect(
    2457               0 :         closure->mAffectedPluginBounds, fBounds);
    2458               0 :     closure->mAffectedPlugins.PutEntry(f);
    2459                 :   }
    2460               0 :   return PL_DHASH_NEXT;
    2461                 : }
    2462                 : 
    2463                 : static PLDHashOperator
    2464               0 : PluginHideEnumerator(nsPtrHashKey<nsObjectFrame>* aEntry, void* userArg)
    2465                 : {
    2466               0 :   PluginGeometryClosure* closure = static_cast<PluginGeometryClosure*>(userArg);
    2467               0 :   nsObjectFrame* f = aEntry->GetKey();
    2468               0 :   f->GetEmptyClipConfiguration(closure->mOutputConfigurations);
    2469               0 :   return PL_DHASH_NEXT;
    2470                 : }
    2471                 : 
    2472                 : static void
    2473               0 : RecoverPluginGeometry(nsDisplayListBuilder* aBuilder,
    2474                 :     nsDisplayList* aList, bool aInTransform, PluginGeometryClosure* aClosure)
    2475                 : {
    2476               0 :   for (nsDisplayItem* i = aList->GetBottom(); i; i = i->GetAbove()) {
    2477               0 :     switch (i->GetType()) {
    2478                 :     case nsDisplayItem::TYPE_PLUGIN: {
    2479               0 :       nsDisplayPlugin* displayPlugin = static_cast<nsDisplayPlugin*>(i);
    2480                 :       nsObjectFrame* f = static_cast<nsObjectFrame*>(
    2481               0 :           displayPlugin->GetUnderlyingFrame());
    2482                 :       // Ignore plugins which aren't supposed to be affected by this
    2483                 :       // operation --- their bounds will not have been included in the
    2484                 :       // display list computations so the visible region computed for them
    2485                 :       // would be incorrect
    2486                 :       nsPtrHashKey<nsObjectFrame>* entry =
    2487               0 :         aClosure->mAffectedPlugins.GetEntry(f);
    2488                 :       // Windowed plugins in transforms are always ignored, we don't
    2489                 :       // create configurations for them
    2490               0 :       if (entry && (!aInTransform || f->PaintedByGecko())) {
    2491                 :         displayPlugin->GetWidgetConfiguration(aBuilder,
    2492               0 :                                               aClosure->mOutputConfigurations);
    2493                 :         // we've dealt with this plugin now
    2494               0 :         aClosure->mAffectedPlugins.RawRemoveEntry(entry);
    2495                 :       }
    2496               0 :       break;
    2497                 :     }
    2498                 :     case nsDisplayItem::TYPE_TRANSFORM: {
    2499                 :       nsDisplayList* sublist =
    2500               0 :           static_cast<nsDisplayTransform*>(i)->GetStoredList()->GetList();
    2501               0 :       RecoverPluginGeometry(aBuilder, sublist, true, aClosure);
    2502               0 :       break;
    2503                 :     }
    2504                 :     default: {
    2505               0 :       nsDisplayList* sublist = i->GetList();
    2506               0 :       if (sublist) {
    2507               0 :         RecoverPluginGeometry(aBuilder, sublist, aInTransform, aClosure);
    2508                 :       }
    2509               0 :       break;
    2510                 :     }
    2511                 :     }
    2512                 :   }
    2513               0 : }
    2514                 : 
    2515                 : #ifdef DEBUG
    2516                 : #include <stdio.h>
    2517                 : 
    2518                 : static bool gDumpPluginList = false;
    2519                 : #endif
    2520                 : 
    2521                 : void
    2522               0 : nsRootPresContext::GetPluginGeometryUpdates(nsIFrame* aChangedSubtree,
    2523                 :                                             nsTArray<nsIWidget::Configuration>* aConfigurations)
    2524                 : {
    2525               0 :   if (mRegisteredPlugins.Count() == 0)
    2526               0 :     return;
    2527                 : 
    2528               0 :   PluginGeometryClosure closure;
    2529               0 :   closure.mRootFrame = mShell->FrameManager()->GetRootFrame();
    2530               0 :   closure.mRootAPD = closure.mRootFrame->PresContext()->AppUnitsPerDevPixel();
    2531               0 :   closure.mChangedSubtree = aChangedSubtree;
    2532               0 :   closure.mChangedRect = aChangedSubtree->GetVisualOverflowRect() +
    2533               0 :       aChangedSubtree->GetOffsetToCrossDoc(closure.mRootFrame);
    2534               0 :   PRInt32 subtreeAPD = aChangedSubtree->PresContext()->AppUnitsPerDevPixel();
    2535                 :   closure.mChangedRect =
    2536               0 :     closure.mChangedRect.ConvertAppUnitsRoundOut(subtreeAPD, closure.mRootAPD);
    2537               0 :   closure.mAffectedPlugins.Init();
    2538               0 :   closure.mOutputConfigurations = aConfigurations;
    2539                 :   // Fill in closure.mAffectedPlugins and closure.mAffectedPluginBounds
    2540               0 :   mRegisteredPlugins.EnumerateEntries(PluginBoundsEnumerator, &closure);
    2541                 : 
    2542               0 :   nsRect bounds;
    2543               0 :   if (bounds.IntersectRect(closure.mAffectedPluginBounds,
    2544               0 :                            closure.mRootFrame->GetRect())) {
    2545                 :     nsDisplayListBuilder builder(closure.mRootFrame,
    2546               0 :                 nsDisplayListBuilder::PLUGIN_GEOMETRY, false);
    2547               0 :     builder.SetAccurateVisibleRegions();
    2548               0 :     nsDisplayList list;
    2549                 : 
    2550               0 :     builder.EnterPresShell(closure.mRootFrame, bounds);
    2551                 :     closure.mRootFrame->BuildDisplayListForStackingContext(
    2552               0 :         &builder, bounds, &list);
    2553               0 :     builder.LeavePresShell(closure.mRootFrame, bounds);
    2554                 : 
    2555                 : #ifdef DEBUG
    2556               0 :     if (gDumpPluginList) {
    2557                 :       fprintf(stderr, "Plugins --- before optimization (bounds %d,%d,%d,%d):\n",
    2558               0 :           bounds.x, bounds.y, bounds.width, bounds.height);
    2559               0 :       nsFrame::PrintDisplayList(&builder, list);
    2560                 :     }
    2561                 : #endif
    2562                 : 
    2563               0 :     nsRegion visibleRegion(bounds);
    2564               0 :     list.ComputeVisibilityForRoot(&builder, &visibleRegion);
    2565                 : 
    2566                 : #ifdef DEBUG
    2567               0 :     if (gDumpPluginList) {
    2568               0 :       fprintf(stderr, "Plugins --- after optimization:\n");
    2569               0 :       nsFrame::PrintDisplayList(&builder, list);
    2570                 :     }
    2571                 : #endif
    2572                 : 
    2573               0 :     RecoverPluginGeometry(&builder, &list, false, &closure);
    2574               0 :     list.DeleteAll();
    2575                 :   }
    2576                 : 
    2577                 :   // Plugins that we didn't find in the display list are not visible
    2578               0 :   closure.mAffectedPlugins.EnumerateEntries(PluginHideEnumerator, &closure);
    2579                 : }
    2580                 : 
    2581                 : static bool
    2582               0 : HasOverlap(const nsIntPoint& aOffset1, const nsTArray<nsIntRect>& aClipRects1,
    2583                 :            const nsIntPoint& aOffset2, const nsTArray<nsIntRect>& aClipRects2)
    2584                 : {
    2585               0 :   nsIntPoint offsetDelta = aOffset1 - aOffset2;
    2586               0 :   for (PRUint32 i = 0; i < aClipRects1.Length(); ++i) {
    2587               0 :     for (PRUint32 j = 0; j < aClipRects2.Length(); ++j) {
    2588               0 :       if ((aClipRects1[i] + offsetDelta).Intersects(aClipRects2[j]))
    2589               0 :         return true;
    2590                 :     }
    2591                 :   }
    2592               0 :   return false;
    2593                 : }
    2594                 : 
    2595                 : /**
    2596                 :  * Given a list of plugin windows to move to new locations, sort the list
    2597                 :  * so that for each window move, the window moves to a location that
    2598                 :  * does not intersect other windows. This minimizes flicker and repainting.
    2599                 :  * It's not always possible to do this perfectly, since in general
    2600                 :  * we might have cycles. But we do our best.
    2601                 :  * We need to take into account that windows are clipped to particular
    2602                 :  * regions and the clip regions change as the windows are moved.
    2603                 :  */
    2604                 : static void
    2605               0 : SortConfigurations(nsTArray<nsIWidget::Configuration>* aConfigurations)
    2606                 : {
    2607               0 :   if (aConfigurations->Length() > 10) {
    2608                 :     // Give up, we don't want to get bogged down here
    2609               0 :     return;
    2610                 :   }
    2611                 : 
    2612               0 :   nsTArray<nsIWidget::Configuration> pluginsToMove;
    2613               0 :   pluginsToMove.SwapElements(*aConfigurations);
    2614                 : 
    2615                 :   // Our algorithm is quite naive. At each step we try to identify
    2616                 :   // a window that can be moved to its new location that won't overlap
    2617                 :   // any other windows at the new location. If there is no such
    2618                 :   // window, we just move the last window in the list anyway.
    2619               0 :   while (!pluginsToMove.IsEmpty()) {
    2620                 :     // Find a window whose destination does not overlap any other window
    2621                 :     PRUint32 i;
    2622               0 :     for (i = 0; i + 1 < pluginsToMove.Length(); ++i) {
    2623               0 :       nsIWidget::Configuration* config = &pluginsToMove[i];
    2624               0 :       bool foundOverlap = false;
    2625               0 :       for (PRUint32 j = 0; j < pluginsToMove.Length(); ++j) {
    2626               0 :         if (i == j)
    2627               0 :           continue;
    2628               0 :         nsIntRect bounds;
    2629               0 :         pluginsToMove[j].mChild->GetBounds(bounds);
    2630               0 :         nsAutoTArray<nsIntRect,1> clipRects;
    2631               0 :         pluginsToMove[j].mChild->GetWindowClipRegion(&clipRects);
    2632               0 :         if (HasOverlap(bounds.TopLeft(), clipRects,
    2633                 :                        config->mBounds.TopLeft(),
    2634               0 :                        config->mClipRegion)) {
    2635               0 :           foundOverlap = true;
    2636                 :           break;
    2637                 :         }
    2638                 :       }
    2639               0 :       if (!foundOverlap)
    2640               0 :         break;
    2641                 :     }
    2642                 :     // Note that we always move the last plugin in pluginsToMove, if we
    2643                 :     // can't find any other plugin to move
    2644               0 :     aConfigurations->AppendElement(pluginsToMove[i]);
    2645               0 :     pluginsToMove.RemoveElementAt(i);
    2646                 :   }
    2647                 : }
    2648                 : 
    2649                 : void
    2650               0 : nsRootPresContext::UpdatePluginGeometry()
    2651                 : {
    2652               0 :   if (!mNeedsToUpdatePluginGeometry)
    2653               0 :     return;
    2654               0 :   mNeedsToUpdatePluginGeometry = false;
    2655                 :   // Cancel out mUpdatePluginGeometryTimer so it doesn't do a random
    2656                 :   // update when we don't actually want one.
    2657               0 :   CancelUpdatePluginGeometryTimer();
    2658                 : 
    2659               0 :   nsIFrame* f = mUpdatePluginGeometryForFrame;
    2660               0 :   if (f) {
    2661                 :     mUpdatePluginGeometryForFrame->PresContext()->
    2662               0 :       SetContainsUpdatePluginGeometryFrame(false);
    2663               0 :     mUpdatePluginGeometryForFrame = nsnull;
    2664                 :   } else {
    2665               0 :     f = FrameManager()->GetRootFrame();
    2666                 :   }
    2667                 : 
    2668               0 :   nsTArray<nsIWidget::Configuration> configurations;
    2669               0 :   GetPluginGeometryUpdates(f, &configurations);
    2670               0 :   if (configurations.IsEmpty())
    2671                 :     return;
    2672               0 :   SortConfigurations(&configurations);
    2673               0 :   nsIWidget* widget = FrameManager()->GetRootFrame()->GetNearestWidget();
    2674               0 :   NS_ASSERTION(widget, "Plugins must have a parent window");
    2675               0 :   widget->ConfigureChildren(configurations);
    2676               0 :   DidApplyPluginGeometryUpdates();
    2677                 : }
    2678                 : 
    2679                 : static void
    2680               0 : UpdatePluginGeometryCallback(nsITimer *aTimer, void *aClosure)
    2681                 : {
    2682               0 :   static_cast<nsRootPresContext*>(aClosure)->UpdatePluginGeometry();
    2683               0 : }
    2684                 : 
    2685                 : void
    2686               0 : nsRootPresContext::RequestUpdatePluginGeometry(nsIFrame* aFrame)
    2687                 : {
    2688               0 :   if (mRegisteredPlugins.Count() == 0)
    2689               0 :     return;
    2690                 : 
    2691               0 :   if (!mNeedsToUpdatePluginGeometry) {
    2692                 :     // We'll update the plugin geometry during the next paint in this
    2693                 :     // presContext (either from nsPresShell::WillPaint or from
    2694                 :     // nsPresShell::DidPaint, depending on the platform) or on the next
    2695                 :     // layout flush, whichever comes first.  But we may not have anyone
    2696                 :     // flush layout, and paints might get optimized away if the old
    2697                 :     // plugin geometry covers the whole canvas, so set a backup timer to
    2698                 :     // do this too.  We want to make sure this won't fire before our
    2699                 :     // normal paint notifications, if those would update the geometry,
    2700                 :     // so set it for double the refresh driver interval.
    2701               0 :     mUpdatePluginGeometryTimer = do_CreateInstance("@mozilla.org/timer;1");
    2702               0 :     if (mUpdatePluginGeometryTimer) {
    2703               0 :       mUpdatePluginGeometryTimer->
    2704                 :         InitWithFuncCallback(UpdatePluginGeometryCallback, this,
    2705               0 :                              nsRefreshDriver::DefaultInterval() * 2,
    2706               0 :                              nsITimer::TYPE_ONE_SHOT);
    2707                 :     }
    2708               0 :     mNeedsToUpdatePluginGeometry = true;
    2709               0 :     mUpdatePluginGeometryForFrame = aFrame;
    2710                 :     mUpdatePluginGeometryForFrame->PresContext()->
    2711               0 :       SetContainsUpdatePluginGeometryFrame(true);
    2712                 :   } else {
    2713               0 :     if (!mUpdatePluginGeometryForFrame ||
    2714                 :         aFrame == mUpdatePluginGeometryForFrame)
    2715               0 :       return;
    2716                 :     mUpdatePluginGeometryForFrame->PresContext()->
    2717               0 :       SetContainsUpdatePluginGeometryFrame(false);
    2718               0 :     mUpdatePluginGeometryForFrame = nsnull;
    2719                 :   }
    2720                 : }
    2721                 : 
    2722                 : static PLDHashOperator
    2723               0 : PluginDidSetGeometryEnumerator(nsPtrHashKey<nsObjectFrame>* aEntry, void* userArg)
    2724                 : {
    2725               0 :   nsObjectFrame* f = aEntry->GetKey();
    2726               0 :   f->DidSetWidgetGeometry();
    2727               0 :   return PL_DHASH_NEXT;
    2728                 : }
    2729                 : 
    2730                 : void
    2731               0 : nsRootPresContext::DidApplyPluginGeometryUpdates()
    2732                 : {
    2733               0 :   mRegisteredPlugins.EnumerateEntries(PluginDidSetGeometryEnumerator, nsnull);
    2734               0 : }
    2735                 : 
    2736                 : void
    2737               0 : nsRootPresContext::RootForgetUpdatePluginGeometryFrame(nsIFrame* aFrame)
    2738                 : {
    2739               0 :   if (aFrame == mUpdatePluginGeometryForFrame) {
    2740                 :     mUpdatePluginGeometryForFrame->PresContext()->
    2741               0 :       SetContainsUpdatePluginGeometryFrame(false);
    2742               0 :     mUpdatePluginGeometryForFrame = nsnull;
    2743                 :   }
    2744               0 : }
    2745                 : 
    2746                 : void
    2747               0 : nsRootPresContext::RootForgetUpdatePluginGeometryFrameForPresContext(
    2748                 :   nsPresContext* aPresContext)
    2749                 : {
    2750               0 :   if (aPresContext->GetContainsUpdatePluginGeometryFrame()) {
    2751               0 :     aPresContext->SetContainsUpdatePluginGeometryFrame(false);
    2752               0 :     mUpdatePluginGeometryForFrame = nsnull;
    2753                 :   }
    2754               0 : }
    2755                 : 
    2756                 : static void
    2757               0 : NotifyDidPaintForSubtreeCallback(nsITimer *aTimer, void *aClosure)
    2758                 : {
    2759               0 :   nsPresContext* presContext = (nsPresContext*)aClosure;
    2760               0 :   nsAutoScriptBlocker blockScripts;
    2761               0 :   presContext->NotifyDidPaintForSubtree();
    2762               0 : }
    2763                 : 
    2764                 : void
    2765               0 : nsRootPresContext::EnsureEventualDidPaintEvent()
    2766                 : {
    2767               0 :   if (mNotifyDidPaintTimer)
    2768               0 :     return;
    2769               0 :   mNotifyDidPaintTimer = do_CreateInstance("@mozilla.org/timer;1");
    2770               0 :   if (!mNotifyDidPaintTimer)
    2771               0 :     return;
    2772               0 :   mNotifyDidPaintTimer->InitWithFuncCallback(NotifyDidPaintForSubtreeCallback,
    2773               0 :                                              (void*)this, 100, nsITimer::TYPE_ONE_SHOT);
    2774                 : }
    2775                 : 
    2776                 : void
    2777               0 : nsRootPresContext::AddWillPaintObserver(nsIRunnable* aRunnable)
    2778                 : {
    2779               0 :   if (!mWillPaintFallbackEvent.IsPending()) {
    2780               0 :     mWillPaintFallbackEvent = new RunWillPaintObservers(this);
    2781               0 :     NS_DispatchToMainThread(mWillPaintFallbackEvent.get());
    2782                 :   }
    2783               0 :   mWillPaintObservers.AppendElement(aRunnable);
    2784               0 : }
    2785                 : 
    2786                 : /**
    2787                 :  * Run all runnables that need to get called before the next paint.
    2788                 :  */
    2789                 : void
    2790               0 : nsRootPresContext::FlushWillPaintObservers()
    2791                 : {
    2792               0 :   mWillPaintFallbackEvent = nsnull;
    2793               0 :   nsTArray<nsCOMPtr<nsIRunnable> > observers;
    2794               0 :   observers.SwapElements(mWillPaintObservers);
    2795               0 :   for (PRUint32 i = 0; i < observers.Length(); ++i) {
    2796               0 :     observers[i]->Run();
    2797                 :   }
    2798               0 : }
    2799                 : 
    2800                 : size_t
    2801               0 : nsRootPresContext::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const
    2802                 : {
    2803               0 :   return nsPresContext::SizeOfExcludingThis(aMallocSizeOf);
    2804                 : 
    2805                 :   // Measurement of the following members may be added later if DMD finds it is
    2806                 :   // worthwhile:
    2807                 :   // - mNotifyDidPaintTimer
    2808                 :   // - mRegisteredPlugins
    2809                 :   // - mWillPaintObservers
    2810                 :   // - mWillPaintFallbackEvent
    2811                 :   //
    2812                 :   // The following member are not measured:
    2813                 :   // - mUpdatePluginGeometryForFrame, because it is non-owning
    2814            4188 : }
    2815                 : 

Generated by: LCOV version 1.7