Changeset 201676 in webkit


Ignore:
Timestamp:
Jun 3, 2016 7:00:50 PM (8 years ago)
Author:
mmaxfield@apple.com
Message:

Text not visible while external font downloading
https://bugs.webkit.org/show_bug.cgi?id=25207
<rdar://problem/15167413>

Reviewed by Dean Jackson.

Source/WebCore:

I already laid the groundwork for this when implementing the CSS Font Loading API.
We only have to create a timer and correctly respond to it timing out (by setting
state).

This patch also adds a new internal setting which puts us in a mode where font
loads never complete and the timeout occurs immediately. This is so we can test
the fallback behavior.

Test: fast/text/web-font-load-fallback-during-loading.html

  • css/CSSFontFace.cpp:

(WebCore::CSSFontFace::CSSFontFace):
(WebCore::CSSFontFace::fontLoadEventOccurred):
(WebCore::CSSFontFace::timeoutFired):
(WebCore::CSSFontFace::setStatus):
(WebCore::CSSFontFace::fontLoaded):
(WebCore::CSSFontFace::webFontsShouldAlwaysFallBack):
(WebCore::CSSFontFace::pump):
(WebCore::CSSFontFace::font):

  • css/CSSFontFace.h:
  • css/CSSFontFaceSource.cpp:

(WebCore::CSSFontFaceSource::fontLoaded):

  • css/FontFace.cpp:

(WebCore::FontFace::fontStateChanged):

  • page/Settings.cpp:

(WebCore::Settings::Settings):
(WebCore::Settings::setWebFontsAlwaysFallBack):

  • page/Settings.h:

(WebCore::Settings::webFontsAlwaysFallBack):

  • testing/InternalSettings.cpp:

(WebCore::InternalSettings::Backup::Backup):
(WebCore::InternalSettings::Backup::restoreTo):
(WebCore::InternalSettings::setWebFontsAlwaysFallBack):

  • testing/InternalSettings.h:
  • testing/InternalSettings.idl:

LayoutTests:

  • fast/text/web-font-load-fallback-during-loading-no-multiple-expected.txt: Added.
  • fast/text/web-font-load-fallback-during-loading-no-multiple.html: Added.
  • fast/text/web-font-load-fallback-during-loading-expected.html: Added.
  • fast/text/web-font-load-fallback-during-loading.html: Added.
Location:
trunk
Files:
4 added
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r201674 r201676  
     12016-06-03  Myles C. Maxfield  <mmaxfield@apple.com>
     2
     3        Text not visible while external font downloading
     4        https://bugs.webkit.org/show_bug.cgi?id=25207
     5        <rdar://problem/15167413>
     6
     7        Reviewed by Dean Jackson.
     8
     9        * fast/text/web-font-load-fallback-during-loading-no-multiple-expected.txt: Added.
     10        * fast/text/web-font-load-fallback-during-loading-no-multiple.html: Added.
     11        * fast/text/web-font-load-fallback-during-loading-expected.html: Added.
     12        * fast/text/web-font-load-fallback-during-loading.html: Added.
     13
    1142016-06-03  Benjamin Poulain  <bpoulain@apple.com>
    215
  • trunk/Source/WebCore/ChangeLog

    r201675 r201676  
     12016-06-03  Myles C. Maxfield  <mmaxfield@apple.com>
     2
     3        Text not visible while external font downloading
     4        https://bugs.webkit.org/show_bug.cgi?id=25207
     5        <rdar://problem/15167413>
     6
     7        Reviewed by Dean Jackson.
     8
     9        I already laid the groundwork for this when implementing the CSS Font Loading API.
     10        We only have to create a timer and correctly respond to it timing out (by setting
     11        state).
     12
     13        This patch also adds a new internal setting which puts us in a mode where font
     14        loads never complete and the timeout occurs immediately. This is so we can test
     15        the fallback behavior.
     16
     17        Test: fast/text/web-font-load-fallback-during-loading.html
     18
     19        * css/CSSFontFace.cpp:
     20        (WebCore::CSSFontFace::CSSFontFace):
     21        (WebCore::CSSFontFace::fontLoadEventOccurred):
     22        (WebCore::CSSFontFace::timeoutFired):
     23        (WebCore::CSSFontFace::setStatus):
     24        (WebCore::CSSFontFace::fontLoaded):
     25        (WebCore::CSSFontFace::webFontsShouldAlwaysFallBack):
     26        (WebCore::CSSFontFace::pump):
     27        (WebCore::CSSFontFace::font):
     28        * css/CSSFontFace.h:
     29        * css/CSSFontFaceSource.cpp:
     30        (WebCore::CSSFontFaceSource::fontLoaded):
     31        * css/FontFace.cpp:
     32        (WebCore::FontFace::fontStateChanged):
     33        * page/Settings.cpp:
     34        (WebCore::Settings::Settings):
     35        (WebCore::Settings::setWebFontsAlwaysFallBack):
     36        * page/Settings.h:
     37        (WebCore::Settings::webFontsAlwaysFallBack):
     38        * testing/InternalSettings.cpp:
     39        (WebCore::InternalSettings::Backup::Backup):
     40        (WebCore::InternalSettings::Backup::restoreTo):
     41        (WebCore::InternalSettings::setWebFontsAlwaysFallBack):
     42        * testing/InternalSettings.h:
     43        * testing/InternalSettings.idl:
     44
    1452016-06-03  Chris Dumez  <cdumez@apple.com>
    246
  • trunk/Source/WebCore/css/CSSFontFace.cpp

    r201570 r201676  
    9090
    9191CSSFontFace::CSSFontFace(CSSFontSelector* fontSelector, StyleRuleFontFace* cssConnection, FontFace* wrapper, bool isLocalFallback)
    92     : m_fontSelector(fontSelector)
     92    : m_timeoutTimer(*this, &CSSFontFace::timeoutFired)
     93    , m_fontSelector(fontSelector)
    9394    , m_cssConnection(cssConnection)
    9495    , m_wrapper(wrapper ? wrapper->createWeakPtr() : WeakPtr<FontFace>())
     
    336337}
    337338
    338 bool CSSFontFace::allSourcesFailed() const
    339 {
    340     for (auto& source : m_sources) {
    341         if (source->status() != CSSFontFaceSource::Status::Failure)
    342             return false;
    343     }
    344     return true;
    345 }
    346 
    347 void CSSFontFace::addClient(Client& client)
    348 {
    349     m_clients.add(&client);
    350 }
    351 
    352 void CSSFontFace::removeClient(Client& client)
    353 {
    354     ASSERT(m_clients.contains(&client));
    355     m_clients.remove(&client);
    356 }
    357 
    358 Ref<FontFace> CSSFontFace::wrapper()
    359 {
    360     if (m_wrapper)
    361         return Ref<FontFace>(*m_wrapper.get());
    362 
    363     Ref<FontFace> wrapper = FontFace::create(*this);
    364     switch (m_status) {
    365     case Status::Pending:
    366         break;
    367     case Status::Loading:
    368         wrapper->fontStateChanged(*this, Status::Pending, Status::Loading);
    369         break;
    370     case Status::TimedOut:
    371         wrapper->fontStateChanged(*this, Status::Pending, Status::Loading);
    372         wrapper->fontStateChanged(*this, Status::Loading, Status::TimedOut);
    373         break;
    374     case Status::Success:
    375         wrapper->fontStateChanged(*this, Status::Pending, Status::Loading);
    376         wrapper->fontStateChanged(*this, Status::Pending, Status::Success);
    377         break;
    378     case Status::Failure:
    379         wrapper->fontStateChanged(*this, Status::Pending, Status::Loading);
    380         wrapper->fontStateChanged(*this, Status::Pending, Status::Failure);
    381         break;
    382     }
    383     m_wrapper = wrapper->createWeakPtr();
    384     return wrapper;
    385 }
    386 
    387 void CSSFontFace::adoptSource(std::unique_ptr<CSSFontFaceSource>&& source)
    388 {
    389     m_sources.append(WTFMove(source));
    390 
    391     // We should never add sources in the middle of loading.
    392     ASSERT(!m_sourcesPopulated);
    393 }
    394 
    395 void CSSFontFace::setStatus(Status newStatus)
    396 {
    397     switch (newStatus) {
    398     case Status::Pending:
    399         ASSERT_NOT_REACHED();
    400         break;
    401     case Status::Loading:
    402         ASSERT(m_status == Status::Pending);
    403         break;
    404     case Status::TimedOut:
    405         ASSERT(m_status == Status::Loading);
    406         break;
    407     case Status::Success:
    408         ASSERT(m_status == Status::Loading || m_status == Status::TimedOut);
    409         break;
    410     case Status::Failure:
    411         ASSERT(m_status == Status::Loading || m_status == Status::TimedOut);
    412         break;
    413     }
    414 
    415     iterateClients(m_clients, [&](Client& client) {
    416         client.fontStateChanged(*this, m_status, newStatus);
    417     });
    418 
    419     m_status = newStatus;
    420 }
    421 
    422 void CSSFontFace::fontLoaded(CSSFontFaceSource&)
     339void CSSFontFace::fontLoadEventOccurred()
    423340{
    424341    Ref<CSSFontFace> protectedThis(*this);
     
    436353        client.fontLoaded(*this);
    437354    });
     355}
     356
     357void CSSFontFace::timeoutFired()
     358{
     359    setStatus(Status::TimedOut);
     360
     361    fontLoadEventOccurred();
     362}
     363
     364bool CSSFontFace::allSourcesFailed() const
     365{
     366    for (auto& source : m_sources) {
     367        if (source->status() != CSSFontFaceSource::Status::Failure)
     368            return false;
     369    }
     370    return true;
     371}
     372
     373void CSSFontFace::addClient(Client& client)
     374{
     375    m_clients.add(&client);
     376}
     377
     378void CSSFontFace::removeClient(Client& client)
     379{
     380    ASSERT(m_clients.contains(&client));
     381    m_clients.remove(&client);
     382}
     383
     384Ref<FontFace> CSSFontFace::wrapper()
     385{
     386    if (m_wrapper)
     387        return Ref<FontFace>(*m_wrapper.get());
     388
     389    Ref<FontFace> wrapper = FontFace::create(*this);
     390    switch (m_status) {
     391    case Status::Pending:
     392        break;
     393    case Status::Loading:
     394        wrapper->fontStateChanged(*this, Status::Pending, Status::Loading);
     395        break;
     396    case Status::TimedOut:
     397        wrapper->fontStateChanged(*this, Status::Pending, Status::Loading);
     398        wrapper->fontStateChanged(*this, Status::Loading, Status::TimedOut);
     399        break;
     400    case Status::Success:
     401        wrapper->fontStateChanged(*this, Status::Pending, Status::Loading);
     402        wrapper->fontStateChanged(*this, Status::Pending, Status::Success);
     403        break;
     404    case Status::Failure:
     405        wrapper->fontStateChanged(*this, Status::Pending, Status::Loading);
     406        wrapper->fontStateChanged(*this, Status::Pending, Status::Failure);
     407        break;
     408    }
     409    m_wrapper = wrapper->createWeakPtr();
     410    return wrapper;
     411}
     412
     413void CSSFontFace::adoptSource(std::unique_ptr<CSSFontFaceSource>&& source)
     414{
     415    m_sources.append(WTFMove(source));
     416
     417    // We should never add sources in the middle of loading.
     418    ASSERT(!m_sourcesPopulated);
     419}
     420
     421void CSSFontFace::setStatus(Status newStatus)
     422{
     423    switch (newStatus) {
     424    case Status::Pending:
     425        ASSERT_NOT_REACHED();
     426        break;
     427    case Status::Loading:
     428        ASSERT(m_status == Status::Pending);
     429        break;
     430    case Status::TimedOut:
     431        ASSERT(m_status == Status::Loading);
     432        break;
     433    case Status::Success:
     434        ASSERT(m_status == Status::Loading || m_status == Status::TimedOut);
     435        break;
     436    case Status::Failure:
     437        ASSERT(m_status == Status::Loading || m_status == Status::TimedOut);
     438        break;
     439    }
     440
     441    if (newStatus == Status::Loading)
     442        m_timeoutTimer.startOneShot(webFontsShouldAlwaysFallBack() ? 0 : 3);
     443    else if (newStatus == Status::Success || newStatus == Status::Failure)
     444        m_timeoutTimer.stop();
     445
     446    iterateClients(m_clients, [&](Client& client) {
     447        client.fontStateChanged(*this, m_status, newStatus);
     448    });
     449
     450    m_status = newStatus;
     451}
     452
     453void CSSFontFace::fontLoaded(CSSFontFaceSource&)
     454{
     455    ASSERT(!webFontsShouldAlwaysFallBack());
     456
     457    fontLoadEventOccurred();
     458}
     459
     460bool CSSFontFace::webFontsShouldAlwaysFallBack() const
     461{
     462    return m_fontSelector && m_fontSelector->document() && m_fontSelector->document()->settings() && m_fontSelector->document()->settings()->webFontsAlwaysFallBack();
    438463}
    439464
     
    457482            break;
    458483        case CSSFontFaceSource::Status::Loading:
    459             ASSERT(m_status == Status::Pending || m_status == Status::Loading);
     484            ASSERT(m_status == Status::Pending || m_status == Status::Loading || m_status == Status::TimedOut);
    460485            if (m_status == Status::Pending)
    461486                setStatus(Status::Loading);
     
    496521    // our own state, though.
    497522    size_t startIndex = pump();
     523    bool fontIsLoading = false;
    498524    for (size_t i = startIndex; i < m_sources.size(); ++i) {
    499525        auto& source = m_sources[i];
    500526        if (source->status() == CSSFontFaceSource::Status::Pending) {
    501527            ASSERT(m_fontSelector);
     528            if (fontIsLoading)
     529                continue;
    502530            source->load(*m_fontSelector);
    503531        }
     
    508536            break;
    509537        case CSSFontFaceSource::Status::Loading:
     538            ASSERT(!fontIsLoading);
     539            fontIsLoading = true;
     540            if (status() == Status::TimedOut)
     541                continue;
    510542            return Font::create(FontCache::singleton().lastResortFallbackFont(fontDescription)->platformData(), true, true);
    511543        case CSSFontFaceSource::Status::Success:
  • trunk/Source/WebCore/css/CSSFontFace.h

    r201570 r201676  
    2929#include "FontFeatureSettings.h"
    3030#include "TextFlags.h"
     31#include "Timer.h"
    3132#include <memory>
    3233#include <wtf/Forward.h>
     
    136137    Ref<FontFace> wrapper();
    137138
     139    bool webFontsShouldAlwaysFallBack() const;
     140
    138141#if ENABLE(SVG_FONTS)
    139142    bool hasSVGFontFaceSource() const;
     
    147150    void notifyClientsOfFontPropertyChange();
    148151
     152    void fontLoadEventOccurred();
     153    void timeoutFired();
     154
    149155    RefPtr<CSSValueList> m_families;
    150156    FontTraitsMask m_traitsMask { static_cast<FontTraitsMask>(FontStyleNormalMask | FontWeight400Mask) };
     
    152158    FontFeatureSettings m_featureSettings;
    153159    FontVariantSettings m_variantSettings;
     160    Timer m_timeoutTimer;
    154161    Vector<std::unique_ptr<CSSFontFaceSource>> m_sources;
    155162    RefPtr<CSSFontSelector> m_fontSelector;
  • trunk/Source/WebCore/css/CSSFontFaceSource.cpp

    r201596 r201676  
    6666        break;
    6767    }
     68
    6869    m_status = newStatus;
    6970}
     
    114115    }
    115116
     117    if (m_face.webFontsShouldAlwaysFallBack())
     118        return;
     119
    116120    if (m_font->errorOccurred())
    117121        setStatus(Status::Failure);
    118122    else
    119123        setStatus(Status::Success);
     124
    120125    m_face.fontLoaded(*this);
    121126}
  • trunk/Source/WebCore/css/FontFace.cpp

    r201421 r201676  
    368368        ref();
    369369        break;
     370    case CSSFontFace::Status::TimedOut:
     371        break;
    370372    case CSSFontFace::Status::Success:
    371373        if (m_promise)
     
    373375        deref();
    374376        return;
    375     case CSSFontFace::Status::TimedOut:
    376377    case CSSFontFace::Status::Failure:
    377378        if (m_promise)
  • trunk/Source/WebCore/page/Settings.cpp

    r201404 r201676  
    210210    , m_hiddenPageCSSAnimationSuspensionEnabled(false)
    211211    , m_fontFallbackPrefersPictographs(false)
     212    , m_webFontsAlwaysFallBack(false)
    212213    , m_forcePendingWebGLPolicy(false)
    213214{
     
    697698}
    698699
     700void Settings::setWebFontsAlwaysFallBack(bool enable)
     701{
     702    if (m_webFontsAlwaysFallBack == enable)
     703        return;
     704
     705    m_webFontsAlwaysFallBack = enable;
     706}
     707
    699708void Settings::setLowPowerVideoAudioBufferSizeEnabled(bool flag)
    700709{
  • trunk/Source/WebCore/page/Settings.h

    r201404 r201676  
    243243    bool fontFallbackPrefersPictographs() const { return m_fontFallbackPrefersPictographs; }
    244244
     245    WEBCORE_EXPORT void setWebFontsAlwaysFallBack(bool);
     246    bool webFontsAlwaysFallBack() const { return m_webFontsAlwaysFallBack; }
     247
    245248    static bool lowPowerVideoAudioBufferSizeEnabled() { return gLowPowerVideoAudioBufferSizeEnabled; }
    246249    WEBCORE_EXPORT static void setLowPowerVideoAudioBufferSizeEnabled(bool);
     
    340343    bool m_hiddenPageCSSAnimationSuspensionEnabled : 1;
    341344    bool m_fontFallbackPrefersPictographs : 1;
     345    bool m_webFontsAlwaysFallBack : 1;
    342346
    343347    bool m_forcePendingWebGLPolicy : 1;
  • trunk/Source/WebCore/testing/InternalSettings.cpp

    r201404 r201676  
    9494    , m_shouldConvertPositionStyleOnCopy(settings.shouldConvertPositionStyleOnCopy())
    9595    , m_fontFallbackPrefersPictographs(settings.fontFallbackPrefersPictographs())
     96    , m_webFontsAlwaysFallBack(settings.webFontsAlwaysFallBack())
    9697    , m_backgroundShouldExtendBeyondPage(settings.backgroundShouldExtendBeyondPage())
    9798    , m_storageBlockingPolicy(settings.storageBlockingPolicy())
     
    170171    settings.setShouldConvertPositionStyleOnCopy(m_shouldConvertPositionStyleOnCopy);
    171172    settings.setFontFallbackPrefersPictographs(m_fontFallbackPrefersPictographs);
     173    settings.setWebFontsAlwaysFallBack(m_webFontsAlwaysFallBack);
    172174    settings.setBackgroundShouldExtendBeyondPage(m_backgroundShouldExtendBeyondPage);
    173175    settings.setStorageBlockingPolicy(m_storageBlockingPolicy);
     
    516518}
    517519
     520void InternalSettings::setWebFontsAlwaysFallBack(bool enable, ExceptionCode& ec)
     521{
     522    InternalSettingsGuardForSettings();
     523    settings()->setWebFontsAlwaysFallBack(enable);
     524}
     525
    518526void InternalSettings::setPluginReplacementEnabled(bool enabled)
    519527{
  • trunk/Source/WebCore/testing/InternalSettings.h

    r201404 r201676  
    9494        bool m_shouldConvertPositionStyleOnCopy;
    9595        bool m_fontFallbackPrefersPictographs;
     96        bool m_webFontsAlwaysFallBack;
    9697        bool m_backgroundShouldExtendBeyondPage;
    9798        SecurityOrigin::StorageBlockingPolicy m_storageBlockingPolicy;
     
    151152    void setAutoscrollForDragAndDropEnabled(bool, ExceptionCode&);
    152153    void setFontFallbackPrefersPictographs(bool, ExceptionCode&);
     154    void setWebFontsAlwaysFallBack(bool, ExceptionCode&);
    153155    void setPluginReplacementEnabled(bool);
    154156    void setBackgroundShouldExtendBeyondPage(bool, ExceptionCode&);
  • trunk/Source/WebCore/testing/InternalSettings.idl

    r201187 r201676  
    4141    [RaisesException] void setPictographFontFamily(DOMString family, DOMString script);
    4242    [RaisesException] void setFontFallbackPrefersPictographs(boolean preferPictographs);
     43    [RaisesException] void setWebFontsAlwaysFallBack(boolean enable);
    4344
    4445    [RaisesException] void setTextAutosizingEnabled(boolean enabled);
Note: See TracChangeset for help on using the changeset viewer.