Home | History | Annotate | Download | only in css
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "config.h"
      6 #include "core/css/RemoteFontFaceSource.h"
      7 
      8 #include "core/css/CSSCustomFontData.h"
      9 #include "core/css/CSSFontFace.h"
     10 #include "core/css/FontLoader.h"
     11 #include "platform/fonts/FontCache.h"
     12 #include "platform/fonts/FontDescription.h"
     13 #include "platform/fonts/SimpleFontData.h"
     14 #include "public/platform/Platform.h"
     15 #include "wtf/CurrentTime.h"
     16 
     17 namespace WebCore {
     18 
     19 RemoteFontFaceSource::RemoteFontFaceSource(FontResource* font, PassRefPtrWillBeRawPtr<FontLoader> fontLoader)
     20     : m_font(font)
     21     , m_fontLoader(fontLoader)
     22 {
     23     m_font->addClient(this);
     24 }
     25 
     26 RemoteFontFaceSource::~RemoteFontFaceSource()
     27 {
     28     m_font->removeClient(this);
     29     pruneTable();
     30 }
     31 
     32 void RemoteFontFaceSource::pruneTable()
     33 {
     34     if (m_fontDataTable.isEmpty())
     35         return;
     36 
     37     for (FontDataTable::iterator it = m_fontDataTable.begin(); it != m_fontDataTable.end(); ++it) {
     38         SimpleFontData* fontData = it->value.get();
     39         if (fontData && fontData->customFontData())
     40             fontData->customFontData()->clearFontFaceSource();
     41     }
     42     m_fontDataTable.clear();
     43 }
     44 
     45 bool RemoteFontFaceSource::isLoading() const
     46 {
     47     return !m_font->stillNeedsLoad() && !m_font->isLoaded();
     48 }
     49 
     50 bool RemoteFontFaceSource::isLoaded() const
     51 {
     52     return m_font->isLoaded();
     53 }
     54 
     55 bool RemoteFontFaceSource::isValid() const
     56 {
     57     return !m_font->errorOccurred();
     58 }
     59 
     60 void RemoteFontFaceSource::didStartFontLoad(FontResource*)
     61 {
     62     // We may send duplicated reports when multiple CSSFontFaceSource are
     63     // registered at this FontResource. Associating the same URL to different
     64     // font-family causes the case, but we treat them as indivisual resources.
     65     m_histograms.loadStarted();
     66 }
     67 
     68 void RemoteFontFaceSource::fontLoaded(FontResource*)
     69 {
     70     m_histograms.recordRemoteFont(m_font.get());
     71 
     72     pruneTable();
     73     if (m_face) {
     74         m_fontLoader->fontFaceInvalidated();
     75         m_face->fontLoaded(this);
     76     }
     77 }
     78 
     79 void RemoteFontFaceSource::fontLoadWaitLimitExceeded(FontResource*)
     80 {
     81     pruneTable();
     82     if (m_face) {
     83         m_fontLoader->fontFaceInvalidated();
     84         m_face->fontLoadWaitLimitExceeded(this);
     85     }
     86 
     87     m_histograms.recordFallbackTime(m_font.get());
     88 }
     89 
     90 PassRefPtr<SimpleFontData> RemoteFontFaceSource::createFontData(const FontDescription& fontDescription)
     91 {
     92     if (!isLoaded())
     93         return createLoadingFallbackFontData(fontDescription);
     94 
     95     // Create new FontPlatformData from our CGFontRef, point size and ATSFontRef.
     96     if (!m_font->ensureCustomFontData())
     97         return nullptr;
     98 
     99     m_histograms.recordFallbackTime(m_font.get());
    100 
    101     return SimpleFontData::create(
    102         m_font->platformDataFromCustomData(fontDescription.effectiveFontSize(),
    103             fontDescription.isSyntheticBold(), fontDescription.isSyntheticItalic(),
    104             fontDescription.orientation(), fontDescription.widthVariant()), CustomFontData::create());
    105 }
    106 
    107 PassRefPtr<SimpleFontData> RemoteFontFaceSource::createLoadingFallbackFontData(const FontDescription& fontDescription)
    108 {
    109     // This temporary font is not retained and should not be returned.
    110     FontCachePurgePreventer fontCachePurgePreventer;
    111     SimpleFontData* temporaryFont = FontCache::fontCache()->getNonRetainedLastResortFallbackFont(fontDescription);
    112     if (!temporaryFont) {
    113         ASSERT_NOT_REACHED();
    114         return nullptr;
    115     }
    116     RefPtr<CSSCustomFontData> cssFontData = CSSCustomFontData::create(this, m_font->exceedsFontLoadWaitLimit() ? CSSCustomFontData::VisibleFallback : CSSCustomFontData::InvisibleFallback);
    117     return SimpleFontData::create(temporaryFont->platformData(), cssFontData);
    118 }
    119 
    120 void RemoteFontFaceSource::beginLoadIfNeeded()
    121 {
    122     if (m_font->stillNeedsLoad())
    123         m_fontLoader->addFontToBeginLoading(m_font.get());
    124 
    125     if (m_face)
    126         m_face->didBeginLoad();
    127 }
    128 
    129 bool RemoteFontFaceSource::ensureFontData()
    130 {
    131     return m_font->ensureCustomFontData();
    132 }
    133 
    134 void RemoteFontFaceSource::trace(Visitor* visitor)
    135 {
    136     visitor->trace(m_fontLoader);
    137     CSSFontFaceSource::trace(visitor);
    138 }
    139 
    140 void RemoteFontFaceSource::FontLoadHistograms::loadStarted()
    141 {
    142     if (!m_loadStartTime)
    143         m_loadStartTime = currentTimeMS();
    144 }
    145 
    146 void RemoteFontFaceSource::FontLoadHistograms::fallbackFontPainted()
    147 {
    148     if (!m_fallbackPaintTime)
    149         m_fallbackPaintTime = currentTimeMS();
    150 }
    151 
    152 void RemoteFontFaceSource::FontLoadHistograms::recordFallbackTime(const FontResource* font)
    153 {
    154     if (m_fallbackPaintTime <= 0)
    155         return;
    156     int duration = static_cast<int>(currentTimeMS() - m_fallbackPaintTime);
    157     blink::Platform::current()->histogramCustomCounts("WebFont.BlankTextShownTime", duration, 0, 10000, 50);
    158     m_fallbackPaintTime = -1;
    159 }
    160 
    161 void RemoteFontFaceSource::FontLoadHistograms::recordRemoteFont(const FontResource* font)
    162 {
    163     if (m_loadStartTime > 0 && font && !font->isLoading()) {
    164         int duration = static_cast<int>(currentTimeMS() - m_loadStartTime);
    165         blink::Platform::current()->histogramCustomCounts(histogramName(font), duration, 0, 10000, 50);
    166         m_loadStartTime = -1;
    167 
    168         enum { Miss, Hit, DataUrl, CacheHitEnumMax };
    169         int histogramValue = font->url().protocolIsData() ? DataUrl
    170             : font->response().wasCached() ? Hit
    171             : Miss;
    172         blink::Platform::current()->histogramEnumeration("WebFont.CacheHit", histogramValue, CacheHitEnumMax);
    173     }
    174 }
    175 
    176 const char* RemoteFontFaceSource::FontLoadHistograms::histogramName(const FontResource* font)
    177 {
    178     if (font->errorOccurred())
    179         return "WebFont.DownloadTime.LoadError";
    180 
    181     unsigned size = font->encodedSize();
    182     if (size < 10 * 1024)
    183         return "WebFont.DownloadTime.0.Under10KB";
    184     if (size < 50 * 1024)
    185         return "WebFont.DownloadTime.1.10KBTo50KB";
    186     if (size < 100 * 1024)
    187         return "WebFont.DownloadTime.2.50KBTo100KB";
    188     if (size < 1024 * 1024)
    189         return "WebFont.DownloadTime.3.100KBTo1MB";
    190     return "WebFont.DownloadTime.4.Over1MB";
    191 }
    192 
    193 } // namespace WebCore
    194