Changeset 201551 in webkit
- Timestamp:
- Jun 1, 2016, 7:29:30 AM (9 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 14 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r201549 r201551 1 2016-05-31 Antti Koivisto <antti@apple.com> 2 3 Precache primary font in a secondary thread 4 https://bugs.webkit.org/show_bug.cgi?id=158243 5 6 Reviewed by Andreas Kling. 7 8 We know the font families and descriptions to use on style resolution. The actual fonts are only needed for 9 layout. There is often time to load and cache fonts asynchronously before they are accessed. This can substantially 10 reduce font related workload in the main thread. 11 12 * css/CSSFontFace.cpp: 13 (WebCore::CSSFontFace::font): 14 (WebCore::CSSFontFace::resolveFamilies): 15 (WebCore::CSSFontFace::hasSVGFontFaceSource): 16 * css/CSSFontFace.h: 17 * css/CSSFontFaceSource.cpp: 18 (WebCore::CSSFontFaceSource::font): 19 (WebCore::CSSFontFaceSource::url): 20 (WebCore::CSSFontFaceSource::isSVGFontFaceSource): 21 * css/CSSFontFaceSource.h: 22 * css/CSSFontSelector.cpp: 23 (WebCore::CSSFontSelector::fallbackFontAt): 24 (WebCore::CSSFontSelector::resolveFamilies): 25 26 Add a function for resolving font families of a cascade to their final values. 27 28 * css/CSSFontSelector.h: 29 * css/CSSSegmentedFontFace.cpp: 30 (WebCore::CSSSegmentedFontFace::fontRanges): 31 (WebCore::CSSSegmentedFontFace::resolveFamilies): 32 * css/CSSSegmentedFontFace.h: 33 * platform/graphics/FontCache.cpp: 34 (WebCore::fontPlatformDataCache): 35 (WebCore::precacheTasksInProgress): 36 (WebCore::alternateFamilyName): 37 (WebCore::FontCache::getCachedFontPlatformData): 38 (WebCore::FontCache::invalidate): 39 (WebCore::FontCache::precache): 40 41 Precache fonts by trying to load them asyncronously one by one. On success the font is cached into font platform data cache. 42 43 (WebCore::FontCache::similarFont): 44 * platform/graphics/FontCache.h: 45 * platform/graphics/FontCascade.cpp: 46 (WebCore::pruneSystemFallbackFonts): 47 (WebCore::precachePrimaryFamily): 48 49 When initializing a new font cascade resolve any platform fonts to their actual names using FontSelector, 50 then precache the primary font for the cascade. 51 52 Web fonts are ignored for now. 53 54 (WebCore::retrieveOrAddCachedFonts): 55 * platform/graphics/FontSelector.h: 56 (WebCore::FontSelector::~FontSelector): 57 * platform/graphics/cocoa/FontCacheCoreText.cpp: 58 (WebCore::FontCache::setFontWhitelist): 59 (WebCore::fontWithFamily): 60 (WebCore::autoActivateFont): 61 (WebCore::createFontPlatformDataThreadSafe): 62 63 Factor thread safe part of createFontPlatformData to a function. 64 65 (WebCore::FontCache::createFontPlatformData): 66 67 Do the main thread only hash lookups here then call to createFontPlatformDataThreadSafe. 68 69 (WebCore::fallbackDedupSet): 70 (WebCore::FontCache::systemFallbackForCharacters): 71 (WebCore::FontCache::platformPrecache): 72 73 Try to initialize font asynchronously in a dispatch queue, call completion handler on success or failure. 74 75 (WebCore::FontCache::platformCancelPrecache): 76 77 Cancel ongoing precache operation. 78 79 (WebCore::platformFontLookupWithFamily): Deleted. 80 81 This was inlined to the only client, fontWithFamily. 82 1 83 2016-06-01 Adam Bergkvist <adam.bergkvist@ericsson.com> 2 84 -
trunk/Source/WebCore/css/CSSFontFace.cpp
r201358 r201551 521 521 } 522 522 523 Vector<ResolvedFontFamily> CSSFontFace::resolveFamilies() const 524 { 525 Vector<ResolvedFontFamily> result; 526 for (auto& source : m_sources) { 527 if (source->familyNameOrURI().isEmpty()) 528 continue; 529 if (source->status() == CSSFontFaceSource::Status::Failure) 530 continue; 531 result.append({ source->familyNameOrURI(), source->url() }); 532 } 533 return result; 534 } 535 523 536 #if ENABLE(SVG_FONTS) 524 537 bool CSSFontFace::hasSVGFontFaceSource() const -
trunk/Source/WebCore/css/CSSFontFace.h
r200547 r201551 28 28 #include "CSSFontFaceRule.h" 29 29 #include "FontFeatureSettings.h" 30 #include "FontSelector.h" 30 31 #include "TextFlags.h" 31 32 #include <memory> … … 136 137 Ref<FontFace> wrapper(); 137 138 139 Vector<ResolvedFontFamily> resolveFamilies() const; 140 138 141 #if ENABLE(SVG_FONTS) 139 142 bool hasSVGFontFaceSource() const; -
trunk/Source/WebCore/css/CSSFontFaceSource.cpp
r200921 r201551 189 189 } 190 190 191 Optional<URL> CSSFontFaceSource::url() const 192 { 193 if (!m_font) 194 return Nullopt; 195 return m_font->url(); 196 } 197 191 198 #if ENABLE(SVG_FONTS) 192 199 bool CSSFontFaceSource::isSVGFontFaceSource() const -
trunk/Source/WebCore/css/CSSFontFaceSource.h
r200921 r201551 29 29 #include "CachedFontClient.h" 30 30 #include "CachedResourceHandle.h" 31 #include "URL.h" 31 32 #include <runtime/ArrayBufferView.h> 32 33 #include <wtf/text/AtomicString.h> … … 72 73 #endif 73 74 75 Optional<URL> url() const; 76 74 77 private: 75 78 void fontLoaded(CachedFont&) override; -
trunk/Source/WebCore/css/CSSFontSelector.cpp
r200895 r201551 335 335 } 336 336 337 } 337 Vector<ResolvedFontFamily> CSSFontSelector::resolveFamilies(const Vector<AtomicString>& families, const FontDescription& fontDescription, UChar32 character) 338 { 339 Vector<ResolvedFontFamily> result; 340 341 for (auto& family : families) { 342 if (family.isEmpty()) 343 continue; 344 auto* segmentedFace = m_cssFontFaceSet->getFontFace(fontDescription.traitsMask(), family); 345 if (!segmentedFace) { 346 result.append({ resolveGenericFamily(m_document, fontDescription, family), { } }); 347 continue; 348 } 349 result.appendVector(segmentedFace->resolveFamilies(character)); 350 } 351 352 return result; 353 } 354 355 } -
trunk/Source/WebCore/css/CSSFontSelector.h
r197563 r201551 65 65 RefPtr<Font> fallbackFontAt(const FontDescription&, size_t) override; 66 66 67 Vector<ResolvedFontFamily> resolveFamilies(const Vector<AtomicString>&, const FontDescription&, UChar32) override; 68 67 69 void clearDocument(); 68 70 -
trunk/Source/WebCore/css/CSSSegmentedFontFace.cpp
r200803 r201551 139 139 } 140 140 141 Vector<ResolvedFontFamily> CSSSegmentedFontFace::resolveFamilies(UChar32 character) const 142 { 143 for (auto& face : m_fontFaces) { 144 bool inRange = face->ranges().isEmpty(); 145 for (auto& range : face->ranges()) { 146 if (character >= range.from && character <= range.to) { 147 inRange = true; 148 break; 149 } 150 } 151 if (inRange) 152 return face->resolveFamilies(); 153 } 154 return { }; 141 155 } 156 157 } -
trunk/Source/WebCore/css/CSSSegmentedFontFace.h
r201113 r201551 29 29 #include "CSSFontFace.h" 30 30 #include "FontCache.h" 31 #include "FontSelector.h" 31 32 #include <wtf/HashMap.h> 32 33 #include <wtf/RefCounted.h> … … 58 59 void deref() override { RefCounted<CSSSegmentedFontFace>::deref(); } 59 60 61 Vector<ResolvedFontFamily> resolveFamilies(UChar32 character) const; 62 60 63 private: 61 64 CSSSegmentedFontFace(); -
trunk/Source/WebCore/platform/graphics/FontCache.cpp
r200364 r201551 107 107 , m_fontFaceVariantSettings(fontFaceVariantSettings ? *fontFaceVariantSettings : FontVariantSettings()) 108 108 { } 109 FontPlatformDataCacheKey(const FontPlatformDataCacheKey&) = default; 109 110 110 111 explicit FontPlatformDataCacheKey(HashTableDeletedValueType t) … … 160 161 } 161 162 163 #if PLATFORM(COCOA) && ENABLE(PLATFORM_FONT_LOOKUP) 164 using PrecacheMap = HashMap<FontPlatformDataCacheKey, FontCache::PrecacheTask*, FontPlatformDataCacheKeyHash, WTF::SimpleClassHashTraits<FontPlatformDataCacheKey>>; 165 166 static PrecacheMap& precacheTasksInProgress() 167 { 168 static NeverDestroyed<PrecacheMap> map; 169 return map; 170 } 171 #endif 172 162 173 static AtomicString alternateFamilyName(const AtomicString& familyName) 163 174 { … … 243 254 244 255 FontPlatformDataCacheKey key(familyName, fontDescription, fontFaceFeatures, fontFaceVariantSettings); 256 257 #if PLATFORM(COCOA) && ENABLE(PLATFORM_FONT_LOOKUP) 258 auto* precacheTask = precacheTasksInProgress().get(key); 259 if (precacheTask) 260 platformCancelPrecache(*precacheTask); 261 #endif 245 262 246 263 auto addResult = fontPlatformDataCache().add(key, nullptr); … … 490 507 } 491 508 509 #if PLATFORM(COCOA) && ENABLE(PLATFORM_FONT_LOOKUP) 510 void FontCache::precache(const Vector<AtomicString>& resolvedFamilies, const FontDescription& fontDescription) 511 { 512 if (resolvedFamilies.isEmpty()) 513 return; 514 auto& family = resolvedFamilies.first(); 515 516 FontPlatformDataCacheKey key(family, fontDescription, nullptr, nullptr); 517 518 // Maybe we have it already? 519 auto it = fontPlatformDataCache().find(key); 520 if (it != fontPlatformDataCache().end()) { 521 if (it->value) 522 return; 523 524 // We already know this font isn't available. Try the next. 525 Vector<AtomicString> remainingFamilies; 526 remainingFamilies.appendRange(resolvedFamilies.begin() + 1, resolvedFamilies.end()); 527 precache(remainingFamilies, fontDescription); 528 return; 529 } 530 531 auto taskAdd = precacheTasksInProgress().add(key, nullptr); 532 if (!taskAdd.isNewEntry) 533 return; 534 535 auto& task = platformPrecache(family, fontDescription, [key, resolvedFamilies, fontDescription] (auto platformData, bool wasCanceled) { 536 precacheTasksInProgress().remove(key); 537 538 if (wasCanceled) 539 return; 540 541 if (platformData) { 542 auto r = fontPlatformDataCache().add(key, WTFMove(platformData)); 543 fprintf(stderr, "success %d\n", r.isNewEntry); 544 return; 545 } 546 547 // Didn't find the font. Try the next one. 548 Vector<AtomicString> remainingFamilies; 549 550 auto alternateName = alternateFamilyName(resolvedFamilies.first()); 551 if (!alternateName.isNull()) { 552 remainingFamilies = resolvedFamilies; 553 remainingFamilies.first() = alternateName; 554 } else { 555 fontPlatformDataCache().add(key, nullptr); 556 remainingFamilies.appendRange(resolvedFamilies.begin() + 1, resolvedFamilies.end()); 557 } 558 559 singleton().precache(remainingFamilies, fontDescription); 560 }); 561 562 taskAdd.iterator->value = &task; 563 } 564 #else 565 void FontCache::precache(const Vector<AtomicString>&, const FontDescription&) 566 { 567 } 568 #endif 569 492 570 #if !PLATFORM(COCOA) 493 571 RefPtr<Font> FontCache::similarFont(const FontDescription&, const AtomicString&) -
trunk/Source/WebCore/platform/graphics/FontCache.h
r200237 r201551 194 194 RefPtr<Font> similarFont(const FontDescription&, const AtomicString& family); 195 195 196 void precache(const Vector<AtomicString>& resolvedFamilies, const FontDescription&); 197 196 198 void addClient(FontSelector&); 197 199 void removeClient(FontSelector&); … … 213 215 #endif 214 216 217 struct PrecacheTask; 218 215 219 private: 216 220 FontCache(); … … 227 231 #endif 228 232 std::unique_ptr<FontPlatformData> createFontPlatformData(const FontDescription&, const AtomicString& family, const FontFeatureSettings* fontFaceFeatures, const FontVariantSettings* fontFaceVariantSettings); 233 234 #if PLATFORM(COCOA) && ENABLE(PLATFORM_FONT_LOOKUP) 235 using PrecacheCompletionHandler = std::function<void (std::unique_ptr<FontPlatformData>, bool wasCanceled)>; 236 PrecacheTask& platformPrecache(const AtomicString& family, const FontDescription&, PrecacheCompletionHandler&&); 237 void platformCancelPrecache(PrecacheTask&); 238 #endif 229 239 230 240 Timer m_purgeTimer; -
trunk/Source/WebCore/platform/graphics/FontCascade.cpp
r201333 r201551 262 262 } 263 263 264 static void precachePrimaryFamily(const FontCascadeDescription& fontDescription, FontSelector& fontSelector) 265 { 266 Vector<AtomicString> families; 267 for (unsigned i = 0; i < fontDescription.familyCount(); ++i) 268 families.append(fontDescription.familyAt(i)); 269 270 // Primary family lookup falls back to the standard family. 271 families.append(standardFamily); 272 273 auto resolvedPrimaryFamilies = fontSelector.resolveFamilies(families, fontDescription, ' '); 274 275 Vector<AtomicString> resolvedPrimaryFamilyNames; 276 for (auto& family : resolvedPrimaryFamilies) { 277 // This doesn't handle web fonts for now. 278 if (family.url) 279 break; 280 resolvedPrimaryFamilyNames.append(family.name); 281 } 282 283 // Asynchronously find first available font and precache it so it is likely to be available when needed. 284 FontCache::singleton().precache(resolvedPrimaryFamilyNames, fontDescription); 285 } 286 264 287 static Ref<FontCascadeFonts> retrieveOrAddCachedFonts(const FontCascadeDescription& fontDescription, RefPtr<FontSelector>&& fontSelector) 265 288 { … … 270 293 if (!addResult.isNewEntry && keysMatch(addResult.iterator->value->key, key)) 271 294 return addResult.iterator->value->fonts.get(); 295 296 if (fontSelector) 297 precachePrimaryFamily(fontDescription, *fontSelector); 272 298 273 299 auto& newEntry = addResult.iterator->value; -
trunk/Source/WebCore/platform/graphics/FontSelector.h
r200601 r201551 27 27 28 28 #include "FontRanges.h" 29 #include "URL.h" 29 30 #include <wtf/Forward.h> 30 31 #include <wtf/PassRefPtr.h> … … 45 46 }; 46 47 48 struct ResolvedFontFamily { 49 AtomicString name; 50 Optional<URL> url; 51 }; 52 47 53 class FontSelector : public RefCounted<FontSelector> { 48 54 public: … … 59 65 virtual void unregisterForInvalidationCallbacks(FontSelectorClient&) = 0; 60 66 67 virtual Vector<ResolvedFontFamily> resolveFamilies(const Vector<AtomicString>& families, const FontDescription&, UChar32 character) = 0; 68 61 69 virtual unsigned uniqueId() const = 0; 62 70 virtual unsigned version() const = 0; -
trunk/Source/WebCore/platform/graphics/cocoa/FontCacheCoreText.cpp
r200094 r201551 35 35 #include <wtf/MainThread.h> 36 36 #include <wtf/NeverDestroyed.h> 37 #include <wtf/RunLoop.h> 38 #include <wtf/WorkQueue.h> 37 39 38 40 namespace WebCore { … … 661 663 } 662 664 663 #if ENABLE(PLATFORM_FONT_LOOKUP) 664 static RetainPtr<CTFontRef> platformFontLookupWithFamily(const AtomicString& family, CTFontSymbolicTraits requestedTraits, FontWeight weight, float size) 665 { 666 const auto& whitelist = fontWhitelist(); 667 if (whitelist.size() && !whitelist.contains(family)) 668 return nullptr; 669 670 return adoptCF(CTFontCreateForCSS(family.string().createCFString().get(), toCoreTextFontWeight(weight), requestedTraits, size)); 671 } 672 #endif 673 674 static RetainPtr<CTFontRef> fontWithFamily(const AtomicString& family, CTFontSymbolicTraits desiredTraits, FontWeight weight, const FontFeatureSettings& featureSettings, const FontVariantSettings& variantSettings, const FontFeatureSettings* fontFaceFeatures, const FontVariantSettings* fontFaceVariantSettings, const TextRenderingMode& textRenderingMode, float size) 665 static RetainPtr<CTFontRef> fontWithFamily(const String& family, CTFontSymbolicTraits desiredTraits, FontWeight weight, const FontFeatureSettings& featureSettings, const FontVariantSettings& variantSettings, const FontFeatureSettings* fontFaceFeatures, const FontVariantSettings* fontFaceVariantSettings, const TextRenderingMode& textRenderingMode, float size, bool isWhitelisted) 675 666 { 676 667 if (family.isEmpty()) … … 680 671 if (!foundFont) { 681 672 #if ENABLE(PLATFORM_FONT_LOOKUP) 682 foundFont = platformFontLookupWithFamily(family, desiredTraits, weight, size); 673 if (!isWhitelisted) 674 return nullptr; 675 foundFont = adoptCF(CTFontCreateForCSS(family.createCFString().get(), toCoreTextFontWeight(weight), desiredTraits, size)); 683 676 #else 677 UNUSED_PARAM(isWhitelisted); 684 678 foundFont = platformFontWithFamily(family, desiredTraits, weight, textRenderingMode, size); 685 679 #endif … … 720 714 #endif 721 715 722 std::unique_ptr<FontPlatformData> FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family, const FontFeatureSettings* fontFaceFeatures, const FontVariantSettings* fontFaceVariantSettings) 716 // This is only thread safe with ENABLE(PLATFORM_FONT_LOOKUP) due to fontWithFamily() implementation 717 static std::unique_ptr<FontPlatformData> createFontPlatformDataThreadSafe(const FontDescription& fontDescription, const String& family, const FontFeatureSettings* fontFaceFeatures, const FontVariantSettings* fontFaceVariantSettings, bool isWhitelisted, bool shouldAutoActivateIfNeeded) 723 718 { 724 719 CTFontSymbolicTraits traits = computeTraits(fontDescription); 725 720 float size = fontDescription.computedPixelSize(); 726 721 727 RetainPtr<CTFontRef> font = fontWithFamily(family, traits, fontDescription.weight(), fontDescription.featureSettings(), fontDescription.variantSettings(), fontFaceFeatures, fontFaceVariantSettings, fontDescription.textRenderingMode(), size );722 RetainPtr<CTFontRef> font = fontWithFamily(family, traits, fontDescription.weight(), fontDescription.featureSettings(), fontDescription.variantSettings(), fontFaceFeatures, fontFaceVariantSettings, fontDescription.textRenderingMode(), size, isWhitelisted); 728 723 729 724 #if PLATFORM(MAC) 730 if (!font) { 731 if (!shouldAutoActivateFontIfNeeded(family)) 732 return nullptr; 733 725 if (!font && shouldAutoActivateIfNeeded) { 734 726 // Auto activate the font before looking for it a second time. 735 727 // Ignore the result because we want to use our own algorithm to actually find the font. 736 autoActivateFont(family.string(), size); 737 738 font = fontWithFamily(family, traits, fontDescription.weight(), fontDescription.featureSettings(), fontDescription.variantSettings(), fontFaceFeatures, fontFaceVariantSettings, fontDescription.textRenderingMode(), size); 739 } 728 autoActivateFont(family, size); 729 730 font = fontWithFamily(family, traits, fontDescription.weight(), fontDescription.featureSettings(), fontDescription.variantSettings(), fontFaceFeatures, fontFaceVariantSettings, fontDescription.textRenderingMode(), size, isWhitelisted); 731 } 732 #else 733 UNUSED_PARAM(shouldAutoActivateIfNeeded); 740 734 #endif 741 735 … … 747 741 748 742 return std::make_unique<FontPlatformData>(font.get(), size, syntheticBold, syntheticOblique, fontDescription.orientation(), fontDescription.widthVariant(), fontDescription.textRenderingMode()); 743 } 744 745 std::unique_ptr<FontPlatformData> FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family, const FontFeatureSettings* fontFaceFeatures, const FontVariantSettings* fontFaceVariantSettings) 746 { 747 const auto& whitelist = fontWhitelist(); 748 bool isWhitelisted = whitelist.isEmpty() || whitelist.contains(family); 749 750 bool shouldAutoActivateIfNeeded = false; 751 #if PLATFORM(MAC) 752 shouldAutoActivateIfNeeded = shouldAutoActivateFontIfNeeded(family); 753 #endif 754 755 return createFontPlatformDataThreadSafe(fontDescription, family, fontFaceFeatures, fontFaceVariantSettings, isWhitelisted, shouldAutoActivateIfNeeded); 749 756 } 750 757 … … 797 804 } 798 805 799 } 806 #if ENABLE(PLATFORM_FONT_LOOKUP) 807 struct FontCache::PrecacheTask { 808 String family; 809 FontDescription fontDescription; 810 bool shouldAutoActivateIfNeeded { false }; 811 bool isWhitelisted { true }; 812 PrecacheCompletionHandler completionHandler; 813 814 std::unique_ptr<FontPlatformData> result; 815 std::atomic_bool isCanceled { false }; 816 }; 817 818 FontCache::PrecacheTask& FontCache::platformPrecache(const AtomicString& family, const FontDescription& fontDescription, PrecacheCompletionHandler&& completionHandler) 819 { 820 static WorkQueue& queue = WorkQueue::create("org.webkit.font-precache", WorkQueue::Type::Serial, WorkQueue::QOS::UserInitiated).leakRef(); 821 822 auto task = std::make_unique<PrecacheTask>(); 823 task->family = family; 824 task->fontDescription = fontDescription; 825 const auto& whitelist = fontWhitelist(); 826 task->isWhitelisted = whitelist.isEmpty() || whitelist.contains(family); 827 #if PLATFORM(MAC) 828 task->shouldAutoActivateIfNeeded = shouldAutoActivateFontIfNeeded(family); 829 #endif 830 task->completionHandler = WTFMove(completionHandler); 831 832 auto& resultTask = *task; 833 834 queue.dispatch([task = task.release()] { 835 if (!task->isCanceled) { 836 auto family = task->family.isolatedCopy(); 837 task->result = createFontPlatformDataThreadSafe(task->fontDescription, family, nullptr, nullptr, task->isWhitelisted, task->shouldAutoActivateIfNeeded); 838 } 839 840 RunLoop::main().dispatch([task] { 841 std::unique_ptr<PrecacheTask> deleter(task); 842 task->completionHandler(WTFMove(task->result), task->isCanceled); 843 }); 844 }); 845 846 return resultTask; 847 } 848 849 void FontCache::platformCancelPrecache(FontCache::PrecacheTask& task) 850 { 851 task.isCanceled = true; 852 } 853 #endif 854 855 }
Note:
See TracChangeset
for help on using the changeset viewer.