diff options
Diffstat (limited to 'Source/WebCore/css/CSSSegmentedFontFace.cpp')
-rw-r--r-- | Source/WebCore/css/CSSSegmentedFontFace.cpp | 190 |
1 files changed, 69 insertions, 121 deletions
diff --git a/Source/WebCore/css/CSSSegmentedFontFace.cpp b/Source/WebCore/css/CSSSegmentedFontFace.cpp index f32832cc5..621344163 100644 --- a/Source/WebCore/css/CSSSegmentedFontFace.cpp +++ b/Source/WebCore/css/CSSSegmentedFontFace.cpp @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -30,159 +30,107 @@ #include "CSSFontFaceSource.h" #include "CSSFontSelector.h" #include "Document.h" +#include "Font.h" +#include "FontCache.h" #include "FontDescription.h" #include "RuntimeEnabledFeatures.h" -#include "SegmentedFontData.h" -#include "SimpleFontData.h" namespace WebCore { -CSSSegmentedFontFace::CSSSegmentedFontFace(CSSFontSelector* fontSelector) - : m_fontSelector(fontSelector) +CSSSegmentedFontFace::CSSSegmentedFontFace() { } CSSSegmentedFontFace::~CSSSegmentedFontFace() { - pruneTable(); - unsigned size = m_fontFaces.size(); - for (unsigned i = 0; i < size; i++) - m_fontFaces[i]->removedFromSegmentedFontFace(this); + for (auto& face : m_fontFaces) + face->removeClient(*this); } -void CSSSegmentedFontFace::pruneTable() +void CSSSegmentedFontFace::appendFontFace(Ref<CSSFontFace>&& fontFace) { - // Make sure the glyph page tree prunes out all uses of this custom font. - if (m_fontDataTable.isEmpty()) - return; - - m_fontDataTable.clear(); + m_cache.clear(); + fontFace->addClient(*this); + m_fontFaces.append(WTFMove(fontFace)); } -bool CSSSegmentedFontFace::isValid() const +void CSSSegmentedFontFace::fontLoaded(CSSFontFace&) { - // Valid if at least one font face is valid. - unsigned size = m_fontFaces.size(); - for (unsigned i = 0; i < size; i++) { - if (m_fontFaces[i]->isValid()) - return true; - } - return false; + m_cache.clear(); } -void CSSSegmentedFontFace::fontLoaded(CSSFontFace*) -{ - pruneTable(); - -#if ENABLE(FONT_LOAD_EVENTS) - if (RuntimeEnabledFeatures::sharedFeatures().fontLoadEventsEnabled() && !isLoading()) { - Vector<RefPtr<LoadFontCallback>> callbacks; - m_callbacks.swap(callbacks); - for (size_t index = 0; index < callbacks.size(); ++index) { - if (checkFont()) - callbacks[index]->notifyLoaded(); - else - callbacks[index]->notifyError(); - } +class CSSFontAccessor final : public FontAccessor { +public: + static Ref<CSSFontAccessor> create(CSSFontFace& fontFace, const FontDescription& fontDescription, bool syntheticBold, bool syntheticItalic) + { + return adoptRef(*new CSSFontAccessor(fontFace, fontDescription, syntheticBold, syntheticItalic)); } -#endif -} -void CSSSegmentedFontFace::appendFontFace(PassRefPtr<CSSFontFace> fontFace) -{ - pruneTable(); - fontFace->addedToSegmentedFontFace(this); - m_fontFaces.append(fontFace); -} - -static void appendFontDataWithInvalidUnicodeRangeIfLoading(SegmentedFontData* newFontData, PassRefPtr<SimpleFontData> prpFaceFontData, const Vector<CSSFontFace::UnicodeRange>& ranges) -{ - RefPtr<SimpleFontData> faceFontData = prpFaceFontData; - if (faceFontData->isLoading()) { - newFontData->appendRange(FontDataRange(0, 0, faceFontData)); - return; + const Font* font() const final + { + if (!m_result) + m_result = m_fontFace->font(m_fontDescription, m_syntheticBold, m_syntheticItalic); + return m_result.value().get(); } - unsigned numRanges = ranges.size(); - if (!numRanges) { - newFontData->appendRange(FontDataRange(0, 0x7FFFFFFF, faceFontData)); - return; +private: + CSSFontAccessor(CSSFontFace& fontFace, const FontDescription& fontDescription, bool syntheticBold, bool syntheticItalic) + : m_fontFace(fontFace) + , m_fontDescription(fontDescription) + , m_syntheticBold(syntheticBold) + , m_syntheticItalic(syntheticItalic) + { } - for (unsigned j = 0; j < numRanges; ++j) - newFontData->appendRange(FontDataRange(ranges[j].from(), ranges[j].to(), faceFontData)); -} - -PassRefPtr<FontData> CSSSegmentedFontFace::getFontData(const FontDescription& fontDescription) -{ - if (!isValid()) - return 0; - - FontTraitsMask desiredTraitsMask = fontDescription.traitsMask(); - unsigned hashKey = ((fontDescription.computedPixelSize() + 1) << (FontTraitsMaskWidth + FontWidthVariantWidth + 1)) - | ((fontDescription.orientation() == Vertical ? 1 : 0) << (FontTraitsMaskWidth + FontWidthVariantWidth)) - | fontDescription.widthVariant() << FontTraitsMaskWidth - | desiredTraitsMask; - - RefPtr<SegmentedFontData>& fontData = m_fontDataTable.add(hashKey, nullptr).iterator->value; - if (fontData && fontData->numRanges()) - return fontData; // No release, we have a reference to an object in the cache which should retain the ref count it has. - - if (!fontData) - fontData = SegmentedFontData::create(); - - unsigned size = m_fontFaces.size(); - for (unsigned i = 0; i < size; i++) { - if (!m_fontFaces[i]->isValid()) - continue; - FontTraitsMask traitsMask = m_fontFaces[i]->traitsMask(); - bool syntheticBold = !(traitsMask & (FontWeight600Mask | FontWeight700Mask | FontWeight800Mask | FontWeight900Mask)) && (desiredTraitsMask & (FontWeight600Mask | FontWeight700Mask | FontWeight800Mask | FontWeight900Mask)); - bool syntheticItalic = !(traitsMask & FontStyleItalicMask) && (desiredTraitsMask & FontStyleItalicMask); - if (RefPtr<SimpleFontData> faceFontData = m_fontFaces[i]->getFontData(fontDescription, syntheticBold, syntheticItalic)) { - ASSERT(!faceFontData->isSegmented()); - appendFontDataWithInvalidUnicodeRangeIfLoading(fontData.get(), faceFontData.release(), m_fontFaces[i]->ranges()); - } + bool isLoading() const final + { + return m_result && m_result.value() && m_result.value()->isLoading(); } - if (fontData->numRanges()) - return fontData; // No release, we have a reference to an object in the cache which should retain the ref count it has. - return 0; -} + mutable std::optional<RefPtr<Font>> m_result; // Caches nullptr too + mutable Ref<CSSFontFace> m_fontFace; + FontDescription m_fontDescription; + bool m_syntheticBold; + bool m_syntheticItalic; +}; -#if ENABLE(FONT_LOAD_EVENTS) -bool CSSSegmentedFontFace::isLoading() const +static void appendFont(FontRanges& ranges, Ref<FontAccessor>&& fontAccessor, const Vector<CSSFontFace::UnicodeRange>& unicodeRanges) { - unsigned size = m_fontFaces.size(); - for (unsigned i = 0; i < size; i++) { - if (m_fontFaces[i]->loadState() == CSSFontFace::Loading) - return true; + if (unicodeRanges.isEmpty()) { + ranges.appendRange({ 0, 0x7FFFFFFF, WTFMove(fontAccessor) }); + return; } - return false; -} -bool CSSSegmentedFontFace::checkFont() const -{ - unsigned size = m_fontFaces.size(); - for (unsigned i = 0; i < size; i++) { - if (m_fontFaces[i]->loadState() != CSSFontFace::Loaded) - return false; - } - return true; + for (auto& range : unicodeRanges) + ranges.appendRange({ range.from, range.to, fontAccessor.copyRef() }); } -void CSSSegmentedFontFace::loadFont(const FontDescription& fontDescription, PassRefPtr<LoadFontCallback> callback) +FontRanges CSSSegmentedFontFace::fontRanges(const FontDescription& fontDescription) { - getFontData(fontDescription); // Kick off the load. - - if (callback) { - if (isLoading()) - m_callbacks.append(callback); - else if (checkFont()) - callback->notifyLoaded(); - else - callback->notifyError(); + FontTraitsMask desiredTraitsMask = fontDescription.traitsMask(); + + auto addResult = m_cache.add(FontDescriptionKey(fontDescription), FontRanges()); + auto& result = addResult.iterator->value; + + if (addResult.isNewEntry) { + for (auto& face : m_fontFaces) { + if (face->allSourcesFailed()) + continue; + + FontTraitsMask traitsMask = face->traitsMask(); + bool syntheticBold = (fontDescription.fontSynthesis() & FontSynthesisWeight) && !(traitsMask & (FontWeight600Mask | FontWeight700Mask | FontWeight800Mask | FontWeight900Mask)) && (desiredTraitsMask & (FontWeight600Mask | FontWeight700Mask | FontWeight800Mask | FontWeight900Mask)); + bool syntheticItalic = (fontDescription.fontSynthesis() & FontSynthesisStyle) && !(traitsMask & FontStyleItalicMask) && (desiredTraitsMask & FontStyleItalicMask); + + // This doesn't trigger an unnecessary download because every element styled with this family will need font metrics in order to run layout. + // Metrics used for layout come from FontRanges::fontForFirstRange(), which assumes that the first font is non-null. + // We're kicking off this necessary first download now. + auto fontAccessor = CSSFontAccessor::create(face, fontDescription, syntheticBold, syntheticItalic); + if (result.isNull() && !fontAccessor->font()) + continue; + appendFont(result, WTFMove(fontAccessor), face->ranges()); + } } + return result; } -#endif } |