Changeset 200601 in webkit


Ignore:
Timestamp:
May 9, 2016, 5:13:01 PM (9 years ago)
Author:
mmaxfield@apple.com
Message:

Web Font is downloaded even when all the characters in the document are outside its unicode-range
https://bugs.webkit.org/show_bug.cgi?id=42154
<rdar://problem/17779042>

Reviewed by Darin Adler.

Source/WebCore:

Fonts are requested in two stages:

  • For a given font family, all the relevant @font-face rules are consulted. We build up a

mapping of unicode-range -> Font object. This result is cached.

  • Then, when we have the mapping, we look up the character we are trying to render to

find the appropriate Font object.

However, we are not supposed to create any Font objects (because that causes a download to
be triggered) until we consult with the character we're trying to render. Therefore, this
patch swaps out the Font objects with a FontAccessor. This FontAccessor is essentially a
lazily-created Font. When step 2 starts looking up the appropriate character, the
FontAccessor will be asked to start the download.

Test: fast/text/unicode-range-download.html

  • css/CSSFontFace.cpp:

(WebCore::CSSFontFace::removeClient):
as a client from all its CSSFontFaces.

  • css/CSSFontFaceSet.cpp:

(WebCore::CSSFontFaceSet::clear): Clearing the CSSFontFaceSet needs to remove itself as a
client from all its CSSFontFaces.

  • css/CSSSegmentedFontFace.cpp:

(WebCore::CSSFontAccessor::create): The lazy Font object.
(WebCore::CSSFontAccessor::CSSFontAccessor): Ditto.
(WebCore::appendFontWithInvalidUnicodeRangeIfLoading): Appends a FontAccessor.
(WebCore::CSSSegmentedFontFace::fontRanges): Create the FontAccessor and use it instead.

  • platform/graphics/FontCascadeFonts.cpp:

(WebCore::FontCascadeFonts::determinePitch): Use the fontForFirstRange() convenience
function.
(WebCore::glyphPageFromFontRanges): font() may now return nullptr. Update this function to
handle that.

  • platform/graphics/FontRanges.cpp:

(WebCore::FontRanges::Range::font): Trigger the lazy initialization.
(WebCore::TrivialFontAccessor::create): Used in the case where there is only one font in
the Ranges object and it has a full unicode-range.
(WebCore::TrivialFontAccessor::TrivialFontAccessor):
(WebCore::FontRanges::FontRanges): Use TrivialFontAccessor.
(WebCore::FontRanges::glyphDataForCharacter): font() may now return nullptr. Update this
function to handle that. This is where the magic happens: this is where we trigger
downloads only if the character falls within the unicode-range.
(WebCore::FontRanges::fontForFirstRange): Add ASSERT.
(WebCore::FontRanges::isLoading): Update to use the new FontAccessor.

  • platform/graphics/FontRanges.h: Ditto.

(WebCore::FontRanges::Range::Range):
(WebCore::FontRanges::Range::fontAccessor):
(WebCore::FontRanges::appendRange):
(WebCore::FontRanges::Range::font): Deleted.

  • platform/graphics/FontSelector.h: The virtual base class of FontAccessor. This is

necessary because it must be shared between platform code and non-platform code.
(WebCore::FontAccessor::~FontAccessor):

LayoutTests:

  • fast/text/unicode-range-download-expected.txt: Added.
  • fast/text/unicode-range-download.html: Added.
  • fast/text/resources/unicode-range-download-Ahem.otf: Added.
  • fast/text/resources/unicode-range-download-Ahem.ttf: Added.
  • fast/text/resources/unicode-range-download-Ahem.woff: Added.
  • imported/blink/svg/custom/resources/graffiti.svg: Added.

imported/blink/svg/custom/svg-fonts-unloaded-segment.html requires this font.

Location:
trunk
Files:
6 added
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r200590 r200601  
     12016-05-09  Myles C. Maxfield  <mmaxfield@apple.com>
     2
     3        Web Font is downloaded even when all the characters in the document are outside its unicode-range
     4        https://bugs.webkit.org/show_bug.cgi?id=42154
     5        <rdar://problem/17779042>
     6
     7        Reviewed by Darin Adler.
     8
     9        * fast/text/unicode-range-download-expected.txt: Added.
     10        * fast/text/unicode-range-download.html: Added.
     11        * fast/text/resources/unicode-range-download-Ahem.otf: Added.
     12        * fast/text/resources/unicode-range-download-Ahem.ttf: Added.
     13        * fast/text/resources/unicode-range-download-Ahem.woff: Added.
     14        * imported/blink/svg/custom/resources/graffiti.svg: Added.
     15        imported/blink/svg/custom/svg-fonts-unloaded-segment.html requires this font.
     16
    1172016-05-09  Simon Fraser  <simon.fraser@apple.com>
    218
  • trunk/Source/WebCore/ChangeLog

    r200598 r200601  
     12016-05-09  Myles C. Maxfield  <mmaxfield@apple.com>
     2
     3        Web Font is downloaded even when all the characters in the document are outside its unicode-range
     4        https://bugs.webkit.org/show_bug.cgi?id=42154
     5        <rdar://problem/17779042>
     6
     7        Reviewed by Darin Adler.
     8
     9        Fonts are requested in two stages:
     10        - For a given font family, all the relevant @font-face rules are consulted. We build up a
     11        mapping of unicode-range -> Font object. This result is cached.
     12        - Then, when we have the mapping, we look up the character we are trying to render to
     13        find the appropriate Font object.
     14
     15        However, we are not supposed to create any Font objects (because that causes a download to
     16        be triggered) until we consult with the character we're trying to render. Therefore, this
     17        patch swaps out the Font objects with a FontAccessor. This FontAccessor is essentially a
     18        lazily-created Font. When step 2 starts looking up the appropriate character, the
     19        FontAccessor will be asked to start the download.
     20
     21        Test: fast/text/unicode-range-download.html
     22
     23        * css/CSSFontFace.cpp:
     24        (WebCore::CSSFontFace::removeClient):
     25        as a client from all its CSSFontFaces.
     26        * css/CSSFontFaceSet.cpp:
     27        (WebCore::CSSFontFaceSet::clear): Clearing the CSSFontFaceSet needs to remove itself as a
     28        client from all its CSSFontFaces.
     29        * css/CSSSegmentedFontFace.cpp:
     30        (WebCore::CSSFontAccessor::create): The lazy Font object.
     31        (WebCore::CSSFontAccessor::CSSFontAccessor): Ditto.
     32        (WebCore::appendFontWithInvalidUnicodeRangeIfLoading): Appends a FontAccessor.
     33        (WebCore::CSSSegmentedFontFace::fontRanges): Create the FontAccessor and use it instead.
     34        * platform/graphics/FontCascadeFonts.cpp:
     35        (WebCore::FontCascadeFonts::determinePitch): Use the fontForFirstRange() convenience
     36        function.
     37        (WebCore::glyphPageFromFontRanges): font() may now return nullptr. Update this function to
     38        handle that.
     39        * platform/graphics/FontRanges.cpp:
     40        (WebCore::FontRanges::Range::font): Trigger the lazy initialization.
     41        (WebCore::TrivialFontAccessor::create): Used in the case where there is only one font in
     42        the Ranges object and it has a full unicode-range.
     43        (WebCore::TrivialFontAccessor::TrivialFontAccessor):
     44        (WebCore::FontRanges::FontRanges): Use TrivialFontAccessor.
     45        (WebCore::FontRanges::glyphDataForCharacter): font() may now return nullptr. Update this
     46        function to handle that. This is where the magic happens: this is where we trigger
     47        downloads only if the character falls within the unicode-range.
     48        (WebCore::FontRanges::fontForFirstRange): Add ASSERT.
     49        (WebCore::FontRanges::isLoading): Update to use the new FontAccessor.
     50        * platform/graphics/FontRanges.h: Ditto.
     51        (WebCore::FontRanges::Range::Range):
     52        (WebCore::FontRanges::Range::fontAccessor):
     53        (WebCore::FontRanges::appendRange):
     54        (WebCore::FontRanges::Range::font): Deleted.
     55        * platform/graphics/FontSelector.h: The virtual base class of FontAccessor. This is
     56        necessary because it must be shared between platform code and non-platform code.
     57        (WebCore::FontAccessor::~FontAccessor):
     58
    1592016-05-09  Brady Eidson  <beidson@apple.com>
    260
  • trunk/Source/WebCore/css/CSSFontFaceSet.cpp

    r197804 r200601  
    239239void CSSFontFaceSet::clear()
    240240{
     241    for (auto& face : m_faces)
     242        face->removeClient(*this);
    241243    m_faces.clear();
    242244    m_facesLookupTable.clear();
  • trunk/Source/WebCore/css/CSSSegmentedFontFace.cpp

    r200547 r200601  
    6060}
    6161
    62 static void appendFontWithInvalidUnicodeRangeIfLoading(FontRanges& ranges, Ref<Font>&& font, const Vector<CSSFontFace::UnicodeRange>& unicodeRanges)
     62class CSSFontAccessor final : public FontAccessor {
     63public:
     64    static Ref<CSSFontAccessor> create(CSSFontFace& fontFace, const FontDescription& fontDescription, bool syntheticBold, bool syntheticItalic)
     65    {
     66        return adoptRef(*new CSSFontAccessor(fontFace, fontDescription, syntheticBold, syntheticItalic));
     67    }
     68
     69    const Font* font() const final
     70    {
     71        if (!m_result)
     72            m_result = m_fontFace->font(m_fontDescription, m_syntheticBold, m_syntheticItalic);
     73        return m_result.value().get();
     74    }
     75
     76private:
     77    CSSFontAccessor(CSSFontFace& fontFace, const FontDescription& fontDescription, bool syntheticBold, bool syntheticItalic)
     78        : m_fontFace(fontFace)
     79        , m_fontDescription(fontDescription)
     80        , m_syntheticBold(syntheticBold)
     81        , m_syntheticItalic(syntheticItalic)
     82    {
     83    }
     84
     85    bool isLoading() const final
     86    {
     87        return m_result && m_result.value()->isLoading();
     88    }
     89
     90    mutable Optional<RefPtr<Font>> m_result; // Caches nullptr too
     91    mutable Ref<CSSFontFace> m_fontFace;
     92    FontDescription m_fontDescription;
     93    bool m_syntheticBold;
     94    bool m_syntheticItalic;
     95};
     96
     97static void appendFontWithInvalidUnicodeRangeIfLoading(FontRanges& ranges, Ref<FontAccessor>&& fontAccessor, const Vector<CSSFontFace::UnicodeRange>& unicodeRanges)
    6398{
    64     if (font->isLoading()) {
    65         ranges.appendRange({ 0, 0, WTFMove(font) });
     99    if (fontAccessor->isLoading()) {
     100        ranges.appendRange({ 0, 0, WTFMove(fontAccessor) });
    66101        return;
    67102    }
    68103
    69104    if (unicodeRanges.isEmpty()) {
    70         ranges.appendRange({ 0, 0x7FFFFFFF, WTFMove(font) });
     105        ranges.appendRange({ 0, 0x7FFFFFFF, WTFMove(fontAccessor) });
    71106        return;
    72107    }
    73108
    74109    for (auto& range : unicodeRanges)
    75         ranges.appendRange({ range.from, range.to, font.copyRef() });
     110        ranges.appendRange({ range.from, range.to, fontAccessor.copyRef() });
    76111}
    77112
     
    81116
    82117    auto addResult = m_cache.add(FontDescriptionKey(fontDescription), FontRanges());
    83     auto& fontRanges = addResult.iterator->value;
     118    auto& result = addResult.iterator->value;
    84119
    85120    if (addResult.isNewEntry) {
     
    92127            bool syntheticItalic = (fontDescription.fontSynthesis() & FontSynthesisStyle) && !(traitsMask & FontStyleItalicMask) && (desiredTraitsMask & FontStyleItalicMask);
    93128
    94             if (RefPtr<Font> faceFont = face->font(fontDescription, syntheticBold, syntheticItalic))
    95                 appendFontWithInvalidUnicodeRangeIfLoading(fontRanges, faceFont.releaseNonNull(), face->ranges());
     129            // This doesn't trigger an unnecessary download because every element styled with this family will need font metrics in order to run layout.
     130            // Metrics used for layout come from FontRanges::fontForFirstRange(), which assumes that the first font is non-null.
     131            // We're kicking off this necessary first download now.
     132            auto fontAccessor = CSSFontAccessor::create(face, fontDescription, syntheticBold, syntheticItalic);
     133            if (result.isNull() && !fontAccessor->font())
     134                continue;
     135            appendFontWithInvalidUnicodeRangeIfLoading(result, WTFMove(fontAccessor), face->ranges());
    96136        }
    97137    }
    98     return fontRanges;
     138    return result;
    99139}
    100140
  • trunk/Source/WebCore/platform/graphics/FontCascadeFonts.cpp

    r194496 r200601  
    123123    unsigned numRanges = primaryRanges.size();
    124124    if (numRanges == 1)
    125         m_pitch = primaryRanges.rangeAt(0).font().pitch();
     125        m_pitch = primaryRanges.fontForFirstRange().pitch();
    126126    else
    127127        m_pitch = VariablePitch;
     
    411411        if (range.to()) {
    412412            if (range.from() <= pageRangeFrom && pageRangeTo <= range.to())
    413                 font = &range.font();
     413                font = range.font();
    414414            break;
    415415        }
    416416    }
    417     if (!font)
    418         return nullptr;
    419 
    420     if (font->platformData().orientation() == Vertical)
     417    if (!font || font->platformData().orientation() == Vertical)
    421418        return nullptr;
    422419
  • trunk/Source/WebCore/platform/graphics/FontRanges.cpp

    r186827 r200601  
    2828
    2929#include "Font.h"
     30#include "FontSelector.h"
    3031#include <wtf/Assertions.h>
    3132#include <wtf/text/WTFString.h>
     
    3334namespace WebCore {
    3435
     36const Font* FontRanges::Range::font() const
     37{
     38    return m_fontAccessor->font();
     39}
     40
    3541FontRanges::FontRanges()
    3642{
    3743}
    3844
     45class TrivialFontAccessor final : public FontAccessor {
     46public:
     47    static Ref<TrivialFontAccessor> create(Ref<Font>&& font)
     48    {
     49        return adoptRef(*new TrivialFontAccessor(WTFMove(font)));
     50    }
     51
     52private:
     53    TrivialFontAccessor(RefPtr<Font>&& font)
     54        : m_font(WTFMove(font))
     55    {
     56    }
     57
     58    const Font* font() const final
     59    {
     60        return m_font.get();
     61    }
     62
     63    bool isLoading() const final
     64    {
     65        return m_font->isLoading();
     66    }
     67
     68    RefPtr<Font> m_font;
     69};
     70
    3971FontRanges::FontRanges(RefPtr<Font>&& font)
    4072{
    4173    if (font)
    42         m_ranges.append(Range { 0, 0x7FFFFFFF, font.releaseNonNull() });
     74        m_ranges.append(Range { 0, 0x7FFFFFFF, TrivialFontAccessor::create(font.releaseNonNull()) });
    4375}
    4476
     
    5183    for (auto& range : m_ranges) {
    5284        if (range.from() <= character && character <= range.to()) {
    53             auto glyphData = range.font().glyphDataForCharacter(character);
    54             if (glyphData.glyph)
    55                 return glyphData;
     85            if (auto* font = range.font()) {
     86                auto glyphData = font->glyphDataForCharacter(character);
     87                if (glyphData.glyph)
     88                    return glyphData;
     89            }
    5690        }
    5791    }
     
    66100const Font& FontRanges::fontForFirstRange() const
    67101{
    68     return m_ranges[0].font();
     102    auto* font = m_ranges[0].font();
     103    ASSERT(font);
     104    return *font;
    69105}
    70106
     
    72108{
    73109    for (auto& range : m_ranges) {
    74         if (range.font().isLoading())
     110        if (range.fontAccessor().isLoading())
    75111            return true;
    76112    }
  • trunk/Source/WebCore/platform/graphics/FontRanges.h

    r194496 r200601  
    3333namespace WebCore {
    3434
     35class FontAccessor;
     36
    3537class FontRanges {
    3638public:
    3739    struct Range {
    38         Range(UChar32 from, UChar32 to, Ref<Font>&& font)
     40        Range(UChar32 from, UChar32 to, Ref<FontAccessor>&& fontAccessor)
    3941            : m_from(from)
    4042            , m_to(to)
    41             , m_font(WTFMove(font))
     43            , m_fontAccessor(WTFMove(fontAccessor))
    4244        {
    4345        }
    4446
     47        Range(const Range& range)
     48            : m_from(range.m_from)
     49            , m_to(range.m_to)
     50            , m_fontAccessor(range.m_fontAccessor.copyRef())
     51        {
     52        }
     53
     54        Range(Range&&) = default;
     55        Range& operator=(const Range&) = delete;
     56        Range& operator=(Range&&) = default;
     57
    4558        UChar32 from() const { return m_from; }
    4659        UChar32 to() const { return m_to; }
    47         const Font& font() const { return *m_font; }
     60        const Font* font() const;
     61        const FontAccessor& fontAccessor() const { return m_fontAccessor; }
    4862
    4963    private:
    5064        UChar32 m_from;
    5165        UChar32 m_to;
    52         RefPtr<Font> m_font;
     66        Ref<FontAccessor> m_fontAccessor;
    5367    };
    5468
     
    5771    ~FontRanges();
    5872
     73    FontRanges(const FontRanges&) = default;
     74    FontRanges& operator=(FontRanges&&) = default;
     75
    5976    bool isNull() const { return m_ranges.isEmpty(); }
    6077
    61     void appendRange(const Range& range) { m_ranges.append(range); }
     78    void appendRange(Range&& range) { m_ranges.append(WTFMove(range)); }
    6279    unsigned size() const { return m_ranges.size(); }
    6380    const Range& rangeAt(unsigned i) const { return m_ranges[i]; }
  • trunk/Source/WebCore/platform/graphics/FontSelector.h

    r199722 r200601  
    3737class FontSelectorClient;
    3838
     39class FontAccessor : public RefCounted<FontAccessor> {
     40public:
     41    virtual ~FontAccessor() { }
     42
     43    virtual const Font* font() const = 0;
     44    virtual bool isLoading() const = 0;
     45};
     46
    3947class FontSelector : public RefCounted<FontSelector> {
    4048public:
Note: See TracChangeset for help on using the changeset viewer.