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 17namespace blink { 18 19RemoteFontFaceSource::RemoteFontFaceSource(FontResource* font, PassRefPtrWillBeRawPtr<FontLoader> fontLoader) 20 : m_font(font) 21 , m_fontLoader(fontLoader) 22{ 23 m_font->addClient(this); 24} 25 26RemoteFontFaceSource::~RemoteFontFaceSource() 27{ 28 m_font->removeClient(this); 29 pruneTable(); 30} 31 32void 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 45bool RemoteFontFaceSource::isLoading() const 46{ 47 return !m_font->stillNeedsLoad() && !m_font->isLoaded(); 48} 49 50bool RemoteFontFaceSource::isLoaded() const 51{ 52 return m_font->isLoaded(); 53} 54 55bool RemoteFontFaceSource::isValid() const 56{ 57 return !m_font->errorOccurred(); 58} 59 60void 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 68void 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 79void 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 90PassRefPtr<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 107PassRefPtr<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 120void 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 129bool RemoteFontFaceSource::ensureFontData() 130{ 131 return m_font->ensureCustomFontData(); 132} 133 134void RemoteFontFaceSource::trace(Visitor* visitor) 135{ 136 visitor->trace(m_fontLoader); 137 CSSFontFaceSource::trace(visitor); 138} 139 140void RemoteFontFaceSource::FontLoadHistograms::loadStarted() 141{ 142 if (!m_loadStartTime) 143 m_loadStartTime = currentTimeMS(); 144} 145 146void RemoteFontFaceSource::FontLoadHistograms::fallbackFontPainted() 147{ 148 if (!m_fallbackPaintTime) 149 m_fallbackPaintTime = currentTimeMS(); 150} 151 152void 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 161void 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 enum { CORSFail, CORSSuccess, CORSEnumMax }; 175 int corsValue = font->isCORSFailed() ? CORSFail : CORSSuccess; 176 blink::Platform::current()->histogramEnumeration("WebFont.CORSSuccess", corsValue, CORSEnumMax); 177 } 178} 179 180const char* RemoteFontFaceSource::FontLoadHistograms::histogramName(const FontResource* font) 181{ 182 if (font->errorOccurred()) 183 return "WebFont.DownloadTime.LoadError"; 184 185 unsigned size = font->encodedSize(); 186 if (size < 10 * 1024) 187 return "WebFont.DownloadTime.0.Under10KB"; 188 if (size < 50 * 1024) 189 return "WebFont.DownloadTime.1.10KBTo50KB"; 190 if (size < 100 * 1024) 191 return "WebFont.DownloadTime.2.50KBTo100KB"; 192 if (size < 1024 * 1024) 193 return "WebFont.DownloadTime.3.100KBTo1MB"; 194 return "WebFont.DownloadTime.4.Over1MB"; 195} 196 197} // namespace blink 198