LCOV - code coverage report
Current view: directory - layout/style - nsFontFaceLoader.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 369 2 0.5 %
Date: 2012-06-02 Functions: 27 2 7.4 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : // vim:cindent:ts=2:et:sw=2:
       3                 : /* ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is Mozilla Foundation code.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * Mozilla Foundation.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 2008
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   John Daggett <jdaggett@mozilla.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                 : /* code for loading in @font-face defined font data */
      41                 : 
      42                 : #ifdef MOZ_LOGGING
      43                 : #define FORCE_PR_LOG /* Allow logging in the release build */
      44                 : #endif /* MOZ_LOGGING */
      45                 : #include "prlog.h"
      46                 : 
      47                 : #include "nsFontFaceLoader.h"
      48                 : 
      49                 : #include "nsError.h"
      50                 : #include "nsIFile.h"
      51                 : #include "nsILocalFile.h"
      52                 : #include "nsIStreamListener.h"
      53                 : #include "nsNetUtil.h"
      54                 : #include "nsIChannelEventSink.h"
      55                 : #include "nsIInterfaceRequestor.h"
      56                 : #include "nsContentUtils.h"
      57                 : #include "mozilla/Preferences.h"
      58                 : 
      59                 : #include "nsPresContext.h"
      60                 : #include "nsIPresShell.h"
      61                 : #include "nsIDocument.h"
      62                 : #include "nsIFrame.h"
      63                 : #include "nsIPrincipal.h"
      64                 : #include "nsIScriptSecurityManager.h"
      65                 : 
      66                 : #include "nsDirectoryServiceUtils.h"
      67                 : #include "nsDirectoryServiceDefs.h"
      68                 : #include "nsIContentPolicy.h"
      69                 : #include "nsContentPolicyUtils.h"
      70                 : #include "nsContentErrors.h"
      71                 : #include "nsCrossSiteListenerProxy.h"
      72                 : #include "nsIContentSecurityPolicy.h"
      73                 : #include "nsIChannelPolicy.h"
      74                 : #include "nsChannelPolicy.h"
      75                 : 
      76                 : #include "nsIConsoleService.h"
      77                 : 
      78                 : #include "nsStyleSet.h"
      79                 : #include "nsPrintfCString.h"
      80                 : 
      81                 : using namespace mozilla;
      82                 : 
      83                 : #ifdef PR_LOGGING
      84            1464 : static PRLogModuleInfo *gFontDownloaderLog = PR_NewLogModule("fontdownloader");
      85                 : #endif /* PR_LOGGING */
      86                 : 
      87                 : #define LOG(args) PR_LOG(gFontDownloaderLog, PR_LOG_DEBUG, args)
      88                 : #define LOG_ENABLED() PR_LOG_TEST(gFontDownloaderLog, PR_LOG_DEBUG)
      89                 : 
      90                 : 
      91               0 : nsFontFaceLoader::nsFontFaceLoader(gfxProxyFontEntry *aProxy, nsIURI *aFontURI,
      92                 :                                    nsUserFontSet *aFontSet, nsIChannel *aChannel)
      93                 :   : mFontEntry(aProxy), mFontURI(aFontURI), mFontSet(aFontSet),
      94               0 :     mChannel(aChannel)
      95                 : {
      96               0 :   mFontFamily = aProxy->Family();
      97               0 : }
      98                 : 
      99               0 : nsFontFaceLoader::~nsFontFaceLoader()
     100                 : {
     101               0 :   if (mLoadTimer) {
     102               0 :     mLoadTimer->Cancel();
     103               0 :     mLoadTimer = nsnull;
     104                 :   }
     105               0 :   if (mFontSet) {
     106               0 :     mFontSet->RemoveLoader(this);
     107                 :   }
     108               0 : }
     109                 : 
     110                 : void
     111               0 : nsFontFaceLoader::StartedLoading(nsIStreamLoader *aStreamLoader)
     112                 : {
     113                 :   PRInt32 loadTimeout =
     114               0 :     Preferences::GetInt("gfx.downloadable_fonts.fallback_delay", 3000);
     115               0 :   if (loadTimeout > 0) {
     116               0 :     mLoadTimer = do_CreateInstance("@mozilla.org/timer;1");
     117               0 :     if (mLoadTimer) {
     118               0 :       mLoadTimer->InitWithFuncCallback(LoadTimerCallback,
     119                 :                                        static_cast<void*>(this),
     120                 :                                        loadTimeout,
     121               0 :                                        nsITimer::TYPE_ONE_SHOT);
     122                 :     }
     123                 :   } else {
     124               0 :     mFontEntry->mLoadingState = gfxProxyFontEntry::LOADING_SLOWLY;
     125                 :   }
     126               0 :   mStreamLoader = aStreamLoader;
     127               0 : }
     128                 : 
     129                 : void
     130               0 : nsFontFaceLoader::LoadTimerCallback(nsITimer *aTimer, void *aClosure)
     131                 : {
     132               0 :   nsFontFaceLoader *loader = static_cast<nsFontFaceLoader*>(aClosure);
     133                 : 
     134               0 :   gfxProxyFontEntry *pe = loader->mFontEntry.get();
     135               0 :   bool updateUserFontSet = true;
     136                 : 
     137                 :   // If the entry is loading, check whether it's >75% done; if so,
     138                 :   // we allow another timeout period before showing a fallback font.
     139               0 :   if (pe->mLoadingState == gfxProxyFontEntry::LOADING_STARTED) {
     140                 :     PRInt32 contentLength;
     141                 :     PRUint32 numBytesRead;
     142               0 :     if (NS_SUCCEEDED(loader->mChannel->GetContentLength(&contentLength)) &&
     143                 :         contentLength > 0 &&
     144               0 :         NS_SUCCEEDED(loader->mStreamLoader->GetNumBytesRead(&numBytesRead)) &&
     145                 :         numBytesRead > 3 * (PRUint32(contentLength) >> 2))
     146                 :     {
     147                 :       // More than 3/4 the data has been downloaded, so allow 50% extra
     148                 :       // time and hope the remainder will arrive before the additional
     149                 :       // time expires.
     150               0 :       pe->mLoadingState = gfxProxyFontEntry::LOADING_ALMOST_DONE;
     151                 :       PRUint32 delay;
     152               0 :       loader->mLoadTimer->GetDelay(&delay);
     153               0 :       loader->mLoadTimer->InitWithFuncCallback(LoadTimerCallback,
     154                 :                                                static_cast<void*>(loader),
     155                 :                                                delay >> 1,
     156               0 :                                                nsITimer::TYPE_ONE_SHOT);
     157               0 :       updateUserFontSet = false;
     158               0 :       LOG(("fontdownloader (%p) 75%% done, resetting timer\n", loader));
     159                 :     }
     160                 :   }
     161                 : 
     162                 :   // If the font is not 75% loaded, or if we've already timed out once
     163                 :   // before, we mark this entry as "loading slowly", so the fallback
     164                 :   // font will be used in the meantime, and tell the context to refresh.
     165               0 :   if (updateUserFontSet) {
     166               0 :     pe->mLoadingState = gfxProxyFontEntry::LOADING_SLOWLY;
     167               0 :     nsPresContext *ctx = loader->mFontSet->GetPresContext();
     168               0 :     NS_ASSERTION(ctx, "fontSet doesn't have a presContext?");
     169                 :     gfxUserFontSet *fontSet;
     170               0 :     if (ctx && (fontSet = ctx->GetUserFontSet()) != nsnull) {
     171               0 :       fontSet->IncrementGeneration();
     172               0 :       ctx->UserFontSetUpdated();
     173               0 :       LOG(("fontdownloader (%p) timeout reflow\n", loader));
     174                 :     }
     175                 :   }
     176               0 : }
     177                 : 
     178               0 : NS_IMPL_ISUPPORTS1(nsFontFaceLoader, nsIStreamLoaderObserver)
     179                 : 
     180                 : NS_IMETHODIMP
     181               0 : nsFontFaceLoader::OnStreamComplete(nsIStreamLoader* aLoader,
     182                 :                                    nsISupports* aContext,
     183                 :                                    nsresult aStatus,
     184                 :                                    PRUint32 aStringLen,
     185                 :                                    const PRUint8* aString)
     186                 : {
     187               0 :   if (!mFontSet) {
     188                 :     // We've been canceled
     189               0 :     return aStatus;
     190                 :   }
     191                 : 
     192               0 :   mFontSet->RemoveLoader(this);
     193                 : 
     194                 : #ifdef PR_LOGGING
     195               0 :   if (LOG_ENABLED()) {
     196               0 :     nsCAutoString fontURI;
     197               0 :     mFontURI->GetSpec(fontURI);
     198               0 :     if (NS_SUCCEEDED(aStatus)) {
     199               0 :       LOG(("fontdownloader (%p) download completed - font uri: (%s)\n", 
     200                 :            this, fontURI.get()));
     201                 :     } else {
     202               0 :       LOG(("fontdownloader (%p) download failed - font uri: (%s) error: %8.8x\n", 
     203                 :            this, fontURI.get(), aStatus));
     204                 :     }
     205                 :   }
     206                 : #endif
     207                 : 
     208               0 :   nsPresContext *ctx = mFontSet->GetPresContext();
     209               0 :   NS_ASSERTION(ctx && !ctx->PresShell()->IsDestroying(),
     210                 :                "We should have been canceled already");
     211                 : 
     212                 :   // whether an error occurred or not, notify the user font set of the completion
     213               0 :   gfxUserFontSet *userFontSet = ctx->GetUserFontSet();
     214               0 :   if (!userFontSet) {
     215               0 :     return aStatus;
     216                 :   }
     217                 : 
     218               0 :   if (NS_SUCCEEDED(aStatus)) {
     219                 :     // for HTTP requests, check whether the request _actually_ succeeded;
     220                 :     // the "request status" in aStatus does not necessarily indicate this,
     221                 :     // because HTTP responses such as 404 (Not Found) will still result in
     222                 :     // a success code and potentially an HTML error page from the server
     223                 :     // as the resulting data. We don't want to use that as a font.
     224               0 :     nsCOMPtr<nsIRequest> request;
     225               0 :     nsCOMPtr<nsIHttpChannel> httpChannel;
     226               0 :     aLoader->GetRequest(getter_AddRefs(request));
     227               0 :     httpChannel = do_QueryInterface(request);
     228               0 :     if (httpChannel) {
     229                 :       bool succeeded;
     230               0 :       nsresult rv = httpChannel->GetRequestSucceeded(&succeeded);
     231               0 :       if (NS_SUCCEEDED(rv) && !succeeded) {
     232               0 :         aStatus = NS_ERROR_NOT_AVAILABLE;
     233                 :       }
     234                 :     }
     235                 :   }
     236                 : 
     237                 :   // The userFontSet is responsible for freeing the downloaded data
     238                 :   // (aString) when finished with it; the pointer is no longer valid
     239                 :   // after OnLoadComplete returns.
     240                 :   // This is called even in the case of a failed download (HTTP 404, etc),
     241                 :   // as there may still be data to be freed (e.g. an error page),
     242                 :   // and we need the fontSet to initiate loading the next source.
     243                 :   bool fontUpdate = userFontSet->OnLoadComplete(mFontEntry,
     244                 :                                                   aString, aStringLen,
     245               0 :                                                   aStatus);
     246                 : 
     247                 :   // when new font loaded, need to reflow
     248               0 :   if (fontUpdate) {
     249                 :     // Update layout for the presence of the new font.  Since this is
     250                 :     // asynchronous, reflows will coalesce.
     251               0 :     ctx->UserFontSetUpdated();
     252               0 :     LOG(("fontdownloader (%p) reflow\n", this));
     253                 :   }
     254                 : 
     255               0 :   return NS_SUCCESS_ADOPTED_DATA;
     256                 : }
     257                 : 
     258                 : void
     259               0 : nsFontFaceLoader::Cancel()
     260                 : {
     261               0 :   mFontEntry->mLoadingState = gfxProxyFontEntry::NOT_LOADING;
     262               0 :   mFontSet = nsnull;
     263               0 :   if (mLoadTimer) {
     264               0 :     mLoadTimer->Cancel();
     265               0 :     mLoadTimer = nsnull;
     266                 :   }
     267               0 :   mChannel->Cancel(NS_BINDING_ABORTED);
     268               0 : }
     269                 : 
     270                 : nsresult
     271               0 : nsFontFaceLoader::CheckLoadAllowed(nsIPrincipal* aSourcePrincipal,
     272                 :                                    nsIURI* aTargetURI,
     273                 :                                    nsISupports* aContext)
     274                 : {
     275                 :   nsresult rv;
     276                 :   
     277               0 :   if (!aSourcePrincipal)
     278               0 :     return NS_OK;
     279                 : 
     280                 :   // check with the security manager
     281               0 :   nsIScriptSecurityManager *secMan = nsContentUtils::GetSecurityManager();
     282                 :   rv = secMan->CheckLoadURIWithPrincipal(aSourcePrincipal, aTargetURI,
     283               0 :                                         nsIScriptSecurityManager::STANDARD);
     284               0 :   if (NS_FAILED(rv)) {
     285               0 :     return rv;
     286                 :   }
     287                 : 
     288                 :   // check content policy
     289               0 :   PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;
     290                 :   rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_FONT,
     291                 :                                  aTargetURI,
     292                 :                                  aSourcePrincipal,
     293                 :                                  aContext,
     294               0 :                                  EmptyCString(), // mime type
     295                 :                                  nsnull,
     296                 :                                  &shouldLoad,
     297                 :                                  nsContentUtils::GetContentPolicy(),
     298               0 :                                  nsContentUtils::GetSecurityManager());
     299                 : 
     300               0 :   if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
     301               0 :     return NS_ERROR_CONTENT_BLOCKED;
     302                 :   }
     303                 : 
     304               0 :   return NS_OK;
     305                 : }
     306                 :   
     307               0 : nsUserFontSet::nsUserFontSet(nsPresContext *aContext)
     308               0 :   : mPresContext(aContext)
     309                 : {
     310               0 :   NS_ASSERTION(mPresContext, "null context passed to nsUserFontSet");
     311               0 :   mLoaders.Init();
     312               0 : }
     313                 : 
     314               0 : nsUserFontSet::~nsUserFontSet()
     315                 : {
     316               0 :   NS_ASSERTION(mLoaders.Count() == 0, "mLoaders should have been emptied");
     317               0 : }
     318                 : 
     319               0 : static PLDHashOperator DestroyIterator(nsPtrHashKey<nsFontFaceLoader>* aKey,
     320                 :                                        void* aUserArg)
     321                 : {
     322               0 :   aKey->GetKey()->Cancel();
     323               0 :   return PL_DHASH_REMOVE;
     324                 : }
     325                 : 
     326                 : void
     327               0 : nsUserFontSet::Destroy()
     328                 : {
     329               0 :   mPresContext = nsnull;
     330               0 :   mLoaders.EnumerateEntries(DestroyIterator, nsnull);
     331               0 : }
     332                 : 
     333                 : void
     334               0 : nsUserFontSet::RemoveLoader(nsFontFaceLoader *aLoader)
     335                 : {
     336               0 :   mLoaders.RemoveEntry(aLoader);
     337               0 : }
     338                 : 
     339                 : nsresult 
     340               0 : nsUserFontSet::StartLoad(gfxProxyFontEntry *aProxy,
     341                 :                          const gfxFontFaceSrc *aFontFaceSrc)
     342                 : {
     343                 :   nsresult rv;
     344                 :   
     345                 :   // check same-site origin
     346               0 :   nsIPresShell *ps = mPresContext->PresShell();
     347               0 :   if (!ps)
     348               0 :     return NS_ERROR_FAILURE;
     349                 :     
     350               0 :   NS_ASSERTION(aFontFaceSrc && !aFontFaceSrc->mIsLocal, 
     351                 :                "bad font face url passed to fontloader");
     352               0 :   NS_ASSERTION(aFontFaceSrc->mURI, "null font uri");
     353               0 :   if (!aFontFaceSrc->mURI)
     354               0 :     return NS_ERROR_FAILURE;
     355                 : 
     356                 :   // use document principal, original principal if flag set
     357                 :   // this enables user stylesheets to load font files via
     358                 :   // @font-face rules
     359               0 :   nsCOMPtr<nsIPrincipal> principal = ps->GetDocument()->NodePrincipal();
     360                 : 
     361               0 :   NS_ASSERTION(aFontFaceSrc->mOriginPrincipal, 
     362                 :                "null origin principal in @font-face rule");
     363               0 :   if (aFontFaceSrc->mUseOriginPrincipal) {
     364               0 :     principal = do_QueryInterface(aFontFaceSrc->mOriginPrincipal);
     365                 :   }
     366                 :   
     367                 :   rv = nsFontFaceLoader::CheckLoadAllowed(principal, aFontFaceSrc->mURI, 
     368               0 :                                           ps->GetDocument());
     369               0 :   if (NS_FAILED(rv)) {
     370               0 :     LogMessage(aProxy, "download not allowed", nsIScriptError::errorFlag, rv);
     371               0 :     return rv;
     372                 :   }
     373                 : 
     374               0 :   nsCOMPtr<nsIStreamLoader> streamLoader;
     375               0 :   nsCOMPtr<nsILoadGroup> loadGroup(ps->GetDocument()->GetDocumentLoadGroup());
     376                 : 
     377               0 :   nsCOMPtr<nsIChannel> channel;
     378                 :   // get Content Security Policy from principal to pass into channel
     379               0 :   nsCOMPtr<nsIChannelPolicy> channelPolicy;
     380               0 :   nsCOMPtr<nsIContentSecurityPolicy> csp;
     381               0 :   rv = principal->GetCsp(getter_AddRefs(csp));
     382               0 :   NS_ENSURE_SUCCESS(rv, rv);
     383               0 :   if (csp) {
     384               0 :     channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
     385               0 :     channelPolicy->SetContentSecurityPolicy(csp);
     386               0 :     channelPolicy->SetLoadType(nsIContentPolicy::TYPE_FONT);
     387                 :   }
     388               0 :   rv = NS_NewChannel(getter_AddRefs(channel),
     389                 :                      aFontFaceSrc->mURI,
     390                 :                      nsnull,
     391                 :                      loadGroup,
     392                 :                      nsnull,
     393                 :                      nsIRequest::LOAD_NORMAL,
     394               0 :                      channelPolicy);
     395                 : 
     396               0 :   NS_ENSURE_SUCCESS(rv, rv);
     397                 : 
     398                 :   nsRefPtr<nsFontFaceLoader> fontLoader =
     399               0 :     new nsFontFaceLoader(aProxy, aFontFaceSrc->mURI, this, channel);
     400                 : 
     401               0 :   if (!fontLoader)
     402               0 :     return NS_ERROR_OUT_OF_MEMORY;
     403                 : 
     404                 : #ifdef PR_LOGGING
     405               0 :   if (LOG_ENABLED()) {
     406               0 :     nsCAutoString fontURI, referrerURI;
     407               0 :     aFontFaceSrc->mURI->GetSpec(fontURI);
     408               0 :     if (aFontFaceSrc->mReferrer)
     409               0 :       aFontFaceSrc->mReferrer->GetSpec(referrerURI);
     410               0 :     LOG(("fontdownloader (%p) download start - font uri: (%s) "
     411                 :          "referrer uri: (%s)\n", 
     412                 :          fontLoader.get(), fontURI.get(), referrerURI.get()));
     413                 :   }
     414                 : #endif  
     415                 : 
     416               0 :   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
     417               0 :   if (httpChannel)
     418               0 :     httpChannel->SetReferrer(aFontFaceSrc->mReferrer);
     419               0 :   rv = NS_NewStreamLoader(getter_AddRefs(streamLoader), fontLoader);
     420               0 :   NS_ENSURE_SUCCESS(rv, rv);
     421                 :   
     422               0 :   bool inherits = false;
     423                 :   rv = NS_URIChainHasFlags(aFontFaceSrc->mURI,
     424                 :                            nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT,
     425               0 :                            &inherits);
     426               0 :   if (NS_SUCCEEDED(rv) && inherits) {
     427                 :     // allow data, javascript, etc URI's
     428               0 :     rv = channel->AsyncOpen(streamLoader, nsnull);
     429                 :   } else {
     430                 :     nsCOMPtr<nsIStreamListener> listener =
     431                 :       new nsCORSListenerProxy(streamLoader, principal, channel, 
     432               0 :                               false, &rv);
     433               0 :     if (NS_FAILED(rv)) {
     434               0 :       fontLoader->DropChannel();  // explicitly need to break ref cycle
     435                 :     }
     436               0 :     NS_ENSURE_TRUE(listener, NS_ERROR_OUT_OF_MEMORY);
     437               0 :     NS_ENSURE_SUCCESS(rv, rv);
     438                 : 
     439               0 :     rv = channel->AsyncOpen(listener, nsnull);
     440                 :   }
     441                 : 
     442               0 :   if (NS_SUCCEEDED(rv)) {
     443               0 :     mLoaders.PutEntry(fontLoader);
     444               0 :     fontLoader->StartedLoading(streamLoader);
     445                 :   }
     446                 : 
     447               0 :   return rv;
     448                 : }
     449                 : 
     450               0 : static PLDHashOperator DetachFontEntries(const nsAString& aKey,
     451                 :                                          nsRefPtr<gfxMixedFontFamily>& aFamily,
     452                 :                                          void* aUserArg)
     453                 : {
     454               0 :   aFamily->DetachFontEntries();
     455               0 :   return PL_DHASH_NEXT;
     456                 : }
     457                 : 
     458                 : bool
     459               0 : nsUserFontSet::UpdateRules(const nsTArray<nsFontFaceRuleContainer>& aRules)
     460                 : {
     461               0 :   bool modified = false;
     462                 : 
     463                 :   // destroy any current loaders, as the entries they refer to
     464                 :   // may be about to get replaced
     465               0 :   if (mLoaders.Count() > 0) {
     466               0 :     modified = true; // trigger reflow so that any necessary downloads
     467                 :                         // will be reinitiated
     468                 :   }
     469               0 :   mLoaders.EnumerateEntries(DestroyIterator, nsnull);
     470                 : 
     471               0 :   nsTArray<FontFaceRuleRecord> oldRules;
     472               0 :   mRules.SwapElements(oldRules);
     473                 : 
     474                 :   // destroy the font family records; we need to re-create them
     475                 :   // because we might end up with faces in a different order,
     476                 :   // even if they're the same font entries as before
     477               0 :   mFontFamilies.Enumerate(DetachFontEntries, nsnull);
     478               0 :   mFontFamilies.Clear();
     479                 : 
     480               0 :   for (PRUint32 i = 0, i_end = aRules.Length(); i < i_end; ++i) {
     481                 :     // insert each rule into our list, migrating old font entries if possible
     482                 :     // rather than creating new ones; set  modified  to true if we detect
     483                 :     // that rule ordering has changed, or if a new entry is created
     484               0 :     InsertRule(aRules[i].mRule, aRules[i].mSheetType, oldRules, modified);
     485                 :   }
     486                 : 
     487                 :   // if any rules are left in the old list, note that the set has changed
     488               0 :   if (oldRules.Length() > 0) {
     489               0 :     modified = true;
     490                 :   }
     491                 : 
     492               0 :   if (modified) {
     493               0 :     IncrementGeneration();
     494                 :   }
     495                 : 
     496               0 :   return modified;
     497                 : }
     498                 : 
     499                 : void
     500               0 : nsUserFontSet::InsertRule(nsCSSFontFaceRule *aRule, PRUint8 aSheetType,
     501                 :                           nsTArray<FontFaceRuleRecord>& aOldRules,
     502                 :                           bool& aFontSetModified)
     503                 : {
     504               0 :   NS_ABORT_IF_FALSE(aRule->GetType() == mozilla::css::Rule::FONT_FACE_RULE,
     505                 :                     "InsertRule passed a non-fontface CSS rule");
     506                 : 
     507                 :   // set up family name
     508               0 :   nsAutoString fontfamily;
     509               0 :   nsCSSValue val;
     510                 :   PRUint32 unit;
     511                 : 
     512               0 :   aRule->GetDesc(eCSSFontDesc_Family, val);
     513               0 :   unit = val.GetUnit();
     514               0 :   if (unit == eCSSUnit_String) {
     515               0 :     val.GetStringValue(fontfamily);
     516                 :   } else {
     517               0 :     NS_ASSERTION(unit == eCSSUnit_Null,
     518                 :                  "@font-face family name has unexpected unit");
     519                 :   }
     520               0 :   if (fontfamily.IsEmpty()) {
     521                 :     // If there is no family name, this rule cannot contribute a
     522                 :     // usable font, so there is no point in processing it further.
     523                 :     return;
     524                 :   }
     525                 : 
     526                 :   // first, we check in oldRules; if the rule exists there, just move it
     527                 :   // to the new rule list, and put the entry into the appropriate family
     528               0 :   for (PRUint32 i = 0; i < aOldRules.Length(); ++i) {
     529               0 :     const FontFaceRuleRecord& ruleRec = aOldRules[i];
     530               0 :     if (ruleRec.mContainer.mRule == aRule &&
     531                 :         ruleRec.mContainer.mSheetType == aSheetType) {
     532               0 :       AddFontFace(fontfamily, ruleRec.mFontEntry);
     533               0 :       mRules.AppendElement(ruleRec);
     534               0 :       aOldRules.RemoveElementAt(i);
     535                 :       // note the set has been modified if an old rule was skipped to find
     536                 :       // this one - something has been dropped, or ordering changed
     537               0 :       if (i > 0) {
     538               0 :         aFontSetModified = true;
     539                 :       }
     540                 :       return;
     541                 :     }
     542                 :   }
     543                 : 
     544                 :   // this is a new rule:
     545                 : 
     546               0 :   PRUint32 weight = NS_STYLE_FONT_WEIGHT_NORMAL;
     547               0 :   PRUint32 stretch = NS_STYLE_FONT_STRETCH_NORMAL;
     548               0 :   PRUint32 italicStyle = FONT_STYLE_NORMAL;
     549               0 :   nsString featureSettings, languageOverride;
     550                 : 
     551                 :   // set up weight
     552               0 :   aRule->GetDesc(eCSSFontDesc_Weight, val);
     553               0 :   unit = val.GetUnit();
     554               0 :   if (unit == eCSSUnit_Integer || unit == eCSSUnit_Enumerated) {
     555               0 :     weight = val.GetIntValue();
     556               0 :   } else if (unit == eCSSUnit_Normal) {
     557               0 :     weight = NS_STYLE_FONT_WEIGHT_NORMAL;
     558                 :   } else {
     559               0 :     NS_ASSERTION(unit == eCSSUnit_Null,
     560                 :                  "@font-face weight has unexpected unit");
     561                 :   }
     562                 : 
     563                 :   // set up stretch
     564               0 :   aRule->GetDesc(eCSSFontDesc_Stretch, val);
     565               0 :   unit = val.GetUnit();
     566               0 :   if (unit == eCSSUnit_Enumerated) {
     567               0 :     stretch = val.GetIntValue();
     568               0 :   } else if (unit == eCSSUnit_Normal) {
     569               0 :     stretch = NS_STYLE_FONT_STRETCH_NORMAL;
     570                 :   } else {
     571               0 :     NS_ASSERTION(unit == eCSSUnit_Null,
     572                 :                  "@font-face stretch has unexpected unit");
     573                 :   }
     574                 : 
     575                 :   // set up font style
     576               0 :   aRule->GetDesc(eCSSFontDesc_Style, val);
     577               0 :   unit = val.GetUnit();
     578               0 :   if (unit == eCSSUnit_Enumerated) {
     579               0 :     italicStyle = val.GetIntValue();
     580               0 :   } else if (unit == eCSSUnit_Normal) {
     581               0 :     italicStyle = FONT_STYLE_NORMAL;
     582                 :   } else {
     583               0 :     NS_ASSERTION(unit == eCSSUnit_Null,
     584                 :                  "@font-face style has unexpected unit");
     585                 :   }
     586                 : 
     587                 :   // set up font features
     588               0 :   aRule->GetDesc(eCSSFontDesc_FontFeatureSettings, val);
     589               0 :   unit = val.GetUnit();
     590               0 :   if (unit == eCSSUnit_Normal) {
     591                 :     // empty feature string
     592               0 :   } else if (unit == eCSSUnit_String) {
     593               0 :     val.GetStringValue(featureSettings);
     594                 :   } else {
     595               0 :     NS_ASSERTION(unit == eCSSUnit_Null,
     596                 :                  "@font-face font-feature-settings has unexpected unit");
     597                 :   }
     598                 : 
     599                 :   // set up font language override
     600               0 :   aRule->GetDesc(eCSSFontDesc_FontLanguageOverride, val);
     601               0 :   unit = val.GetUnit();
     602               0 :   if (unit == eCSSUnit_Normal) {
     603                 :     // empty feature string
     604               0 :   } else if (unit == eCSSUnit_String) {
     605               0 :     val.GetStringValue(languageOverride);
     606                 :   } else {
     607               0 :     NS_ASSERTION(unit == eCSSUnit_Null,
     608                 :                  "@font-face font-language-override has unexpected unit");
     609                 :   }
     610                 : 
     611                 :   // set up src array
     612               0 :   nsTArray<gfxFontFaceSrc> srcArray;
     613                 : 
     614               0 :   aRule->GetDesc(eCSSFontDesc_Src, val);
     615               0 :   unit = val.GetUnit();
     616               0 :   if (unit == eCSSUnit_Array) {
     617               0 :     nsCSSValue::Array *srcArr = val.GetArrayValue();
     618               0 :     size_t numSrc = srcArr->Count();
     619                 :     
     620               0 :     for (size_t i = 0; i < numSrc; i++) {
     621               0 :       val = srcArr->Item(i);
     622               0 :       unit = val.GetUnit();
     623               0 :       gfxFontFaceSrc *face = srcArray.AppendElements(1);
     624               0 :       if (!face)
     625                 :         return;
     626                 : 
     627               0 :       switch (unit) {
     628                 : 
     629                 :       case eCSSUnit_Local_Font:
     630               0 :         val.GetStringValue(face->mLocalName);
     631               0 :         face->mIsLocal = true;
     632               0 :         face->mURI = nsnull;
     633               0 :         face->mFormatFlags = 0;
     634               0 :         break;
     635                 :       case eCSSUnit_URL:
     636               0 :         face->mIsLocal = false;
     637               0 :         face->mURI = val.GetURLValue();
     638               0 :         NS_ASSERTION(face->mURI, "null url in @font-face rule");
     639               0 :         face->mReferrer = val.GetURLStructValue()->mReferrer;
     640               0 :         face->mOriginPrincipal = val.GetURLStructValue()->mOriginPrincipal;
     641               0 :         NS_ASSERTION(face->mOriginPrincipal, "null origin principal in @font-face rule");
     642                 : 
     643                 :         // agent and user stylesheets are treated slightly differently,
     644                 :         // the same-site origin check and access control headers are
     645                 :         // enforced against the sheet principal rather than the document
     646                 :         // principal to allow user stylesheets to include @font-face rules
     647                 :         face->mUseOriginPrincipal = (aSheetType == nsStyleSet::eUserSheet ||
     648               0 :                                      aSheetType == nsStyleSet::eAgentSheet);
     649                 : 
     650               0 :         face->mLocalName.Truncate();
     651               0 :         face->mFormatFlags = 0;
     652               0 :         while (i + 1 < numSrc && (val = srcArr->Item(i+1), 
     653               0 :                  val.GetUnit() == eCSSUnit_Font_Format)) {
     654               0 :           nsDependentString valueString(val.GetStringBufferValue());
     655               0 :           if (valueString.LowerCaseEqualsASCII("woff")) {
     656               0 :             face->mFormatFlags |= FLAG_FORMAT_WOFF;
     657               0 :           } else if (valueString.LowerCaseEqualsASCII("opentype")) {
     658               0 :             face->mFormatFlags |= FLAG_FORMAT_OPENTYPE;
     659               0 :           } else if (valueString.LowerCaseEqualsASCII("truetype")) {
     660               0 :             face->mFormatFlags |= FLAG_FORMAT_TRUETYPE;
     661               0 :           } else if (valueString.LowerCaseEqualsASCII("truetype-aat")) {
     662               0 :             face->mFormatFlags |= FLAG_FORMAT_TRUETYPE_AAT;
     663               0 :           } else if (valueString.LowerCaseEqualsASCII("embedded-opentype")) {
     664               0 :             face->mFormatFlags |= FLAG_FORMAT_EOT;
     665               0 :           } else if (valueString.LowerCaseEqualsASCII("svg")) {
     666               0 :             face->mFormatFlags |= FLAG_FORMAT_SVG;
     667                 :           } else {
     668                 :             // unknown format specified, mark to distinguish from the
     669                 :             // case where no format hints are specified
     670               0 :             face->mFormatFlags |= FLAG_FORMAT_UNKNOWN;
     671                 :           }
     672               0 :           i++;
     673                 :         }
     674               0 :         break;
     675                 :       default:
     676               0 :         NS_ASSERTION(unit == eCSSUnit_Local_Font || unit == eCSSUnit_URL,
     677                 :                      "strange unit type in font-face src array");
     678               0 :         break;
     679                 :       }
     680                 :      }
     681                 :   } else {
     682               0 :     NS_ASSERTION(unit == eCSSUnit_Null, "@font-face src has unexpected unit");
     683                 :   }
     684                 : 
     685               0 :   if (srcArray.Length() > 0) {
     686               0 :     FontFaceRuleRecord ruleRec;
     687               0 :     ruleRec.mContainer.mRule = aRule;
     688               0 :     ruleRec.mContainer.mSheetType = aSheetType;
     689                 :     ruleRec.mFontEntry = AddFontFace(fontfamily, srcArray,
     690                 :                                      weight, stretch, italicStyle,
     691               0 :                                      featureSettings, languageOverride);
     692               0 :     if (ruleRec.mFontEntry) {
     693               0 :       mRules.AppendElement(ruleRec);
     694                 :     }
     695                 :     // this was a new rule and fontEntry, so note that the set was modified
     696               0 :     aFontSetModified = true;
     697                 :   }
     698                 : }
     699                 : 
     700                 : void
     701               0 : nsUserFontSet::ReplaceFontEntry(gfxProxyFontEntry *aProxy,
     702                 :                                 gfxFontEntry *aFontEntry)
     703                 : {
     704               0 :   for (PRUint32 i = 0; i < mRules.Length(); ++i) {
     705               0 :     if (mRules[i].mFontEntry == aProxy) {
     706               0 :       mRules[i].mFontEntry = aFontEntry;
     707               0 :       break;
     708                 :     }
     709                 :   }
     710                 :   gfxMixedFontFamily *family =
     711               0 :     static_cast<gfxMixedFontFamily*>(aProxy->Family());
     712               0 :   if (family) {
     713               0 :     family->ReplaceFontEntry(aProxy, aFontEntry);
     714                 :   }
     715               0 : }
     716                 : 
     717                 : nsCSSFontFaceRule*
     718               0 : nsUserFontSet::FindRuleForEntry(gfxFontEntry *aFontEntry)
     719                 : {
     720               0 :   for (PRUint32 i = 0; i < mRules.Length(); ++i) {
     721               0 :     if (mRules[i].mFontEntry == aFontEntry) {
     722               0 :       return mRules[i].mContainer.mRule;
     723                 :     }
     724                 :   }
     725               0 :   return nsnull;
     726                 : }
     727                 : 
     728                 : nsresult
     729               0 : nsUserFontSet::LogMessage(gfxProxyFontEntry *aProxy,
     730                 :                           const char        *aMessage,
     731                 :                           PRUint32          aFlags,
     732                 :                           nsresult          aStatus)
     733                 : {
     734                 :   nsCOMPtr<nsIConsoleService>
     735               0 :     console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
     736               0 :   if (!console) {
     737               0 :     return NS_ERROR_NOT_AVAILABLE;
     738                 :   }
     739                 : 
     740               0 :   NS_ConvertUTF16toUTF8 familyName(aProxy->FamilyName());
     741               0 :   nsCAutoString fontURI;
     742               0 :   if (aProxy->mSrcIndex == aProxy->mSrcList.Length()) {
     743               0 :     fontURI.AppendLiteral("(end of source list)");
     744                 :   } else {
     745               0 :     if (aProxy->mSrcList[aProxy->mSrcIndex].mURI) {
     746               0 :       aProxy->mSrcList[aProxy->mSrcIndex].mURI->GetSpec(fontURI);
     747                 :     } else {
     748               0 :       fontURI.AppendLiteral("(invalid URI)");
     749                 :     }
     750                 :   }
     751                 : 
     752                 :   char weightKeywordBuf[8]; // plenty to sprintf() a PRUint16
     753                 :   const char *weightKeyword;
     754                 :   const nsAFlatCString& weightKeywordString =
     755               0 :     nsCSSProps::ValueToKeyword(aProxy->Weight(),
     756               0 :                                nsCSSProps::kFontWeightKTable);
     757               0 :   if (weightKeywordString.Length() > 0) {
     758               0 :     weightKeyword = weightKeywordString.get();
     759                 :   } else {
     760               0 :     sprintf(weightKeywordBuf, "%u", aProxy->Weight());
     761               0 :     weightKeyword = weightKeywordBuf;
     762                 :   }
     763                 : 
     764                 :   nsPrintfCString
     765                 :     msg(1024,
     766                 :         "downloadable font: %s "
     767                 :         "(font-family: \"%s\" style:%s weight:%s stretch:%s src index:%d)",
     768                 :         aMessage,
     769                 :         familyName.get(),
     770               0 :         aProxy->IsItalic() ? "italic" : "normal",
     771                 :         weightKeyword,
     772               0 :         nsCSSProps::ValueToKeyword(aProxy->Stretch(),
     773               0 :                                    nsCSSProps::kFontStretchKTable).get(),
     774               0 :         aProxy->mSrcIndex);
     775                 : 
     776               0 :   if (aStatus != 0) {
     777               0 :     msg.Append(": ");
     778               0 :     switch (aStatus) {
     779                 :     case NS_ERROR_DOM_BAD_URI:
     780               0 :       msg.Append("bad URI or cross-site access not allowed");
     781               0 :       break;
     782                 :     case NS_ERROR_CONTENT_BLOCKED:
     783               0 :       msg.Append("content blocked");
     784               0 :       break;
     785                 :     default:
     786               0 :       msg.Append("status=");
     787               0 :       msg.AppendInt(aStatus);
     788               0 :       break;
     789                 :     }
     790                 :   }
     791               0 :   msg.Append("\nsource: ");
     792               0 :   msg.Append(fontURI);
     793                 : 
     794                 : #ifdef PR_LOGGING
     795               0 :   if (PR_LOG_TEST(sUserFontsLog, PR_LOG_DEBUG)) {
     796               0 :     PR_LOG(sUserFontsLog, PR_LOG_DEBUG,
     797                 :            ("userfonts (%p) %s", this, msg.get()));
     798                 :   }
     799                 : #endif
     800                 : 
     801                 :   // try to give the user an indication of where the rule came from
     802               0 :   nsCSSFontFaceRule* rule = FindRuleForEntry(aProxy);
     803               0 :   nsString href;
     804               0 :   nsString text;
     805                 :   nsresult rv;
     806               0 :   if (rule) {
     807               0 :     rv = rule->GetCssText(text);
     808               0 :     NS_ENSURE_SUCCESS(rv, rv);
     809               0 :     nsCOMPtr<nsIDOMCSSStyleSheet> sheet;
     810               0 :     rv = rule->GetParentStyleSheet(getter_AddRefs(sheet));
     811               0 :     NS_ENSURE_SUCCESS(rv, rv);
     812               0 :     rv = sheet->GetHref(href);
     813               0 :     NS_ENSURE_SUCCESS(rv, rv);
     814                 :   }
     815                 : 
     816                 :   nsCOMPtr<nsIScriptError> scriptError =
     817               0 :     do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv);
     818               0 :   NS_ENSURE_SUCCESS(rv, rv);
     819                 : 
     820               0 :   PRUint64 innerWindowID = GetPresContext()->Document()->InnerWindowID();
     821               0 :   rv = scriptError->InitWithWindowID(NS_ConvertUTF8toUTF16(msg).get(),
     822                 :                                      href.get(),   // file
     823                 :                                      text.get(),   // src line
     824                 :                                      0, 0,         // line & column number
     825                 :                                      aFlags,       // flags
     826                 :                                      "CSS Loader", // category (make separate?)
     827               0 :                                      innerWindowID);
     828               0 :   if (NS_SUCCEEDED(rv)) {
     829               0 :     console->LogMessage(scriptError);
     830                 :   }
     831                 : 
     832               0 :   return NS_OK;
     833            4392 : }

Generated by: LCOV version 1.7