Changeset 244682 in webkit


Ignore:
Timestamp:
Apr 25, 2019 11:33:56 PM (5 years ago)
Author:
mmaxfield@apple.com
Message:

[iOS] Implement idempotent mode for text autosizing
https://bugs.webkit.org/show_bug.cgi?id=197250
<rdar://problem/50211034>

Reviewed by Jon Lee.

Source/WebCore:

Our text autosizing code has this interesting behavior where it is sensitive to the width of the text's container
and the number of lines of text inside the element. Not only is it sensitive to those things, but as those things
change, their values are stored inside the RenderObject itself and then never recomputed. This means that the text
autosizing parameters are sensitive to the entire history of an element. So, a newly created element with the same
style as an existing element can have dramatically different results.

This patch adds a new mode for text autosizing, which isn't sensitive to either of those things, and therefore
maintains the invariant that a newly created element will behave the same as an existing element with the same style.
Instead of using container size, it instead uses the viewport's initial scale. As the viewport's initial scale
changes, new layouts will be triggered, which will cause the autosizing code to use the new value.

Tests: fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-identity.html

fast/text-autosizing/ios/idempotentmode/idempotent-autosizing.html

  • page/FrameViewLayoutContext.cpp:

(WebCore::FrameViewLayoutContext::applyTextSizingIfNeeded):

  • page/Page.cpp:

(WebCore::Page::setInitialScale): WebKit will push the initial scale down into the page.

  • page/Page.h:

(WebCore::Page::initialScale const):

  • page/SettingsBase.h:
  • page/cocoa/SettingsBaseCocoa.mm:

(WebCore::SettingsBase::textAutosizingUsesIdempotentMode):
(WebCore::SettingsBase::defaultTextAutosizingEnabled):

  • rendering/RenderBlockFlow.cpp:

(WebCore::idempotentTextSize): Describe a piecewise-linear curve for the text size to follow. The curve scales
depending on the viewport's initial scale.
(WebCore::RenderBlockFlow::adjustComputedFontSizes):

  • rendering/RenderBlockFlow.h:
  • rendering/RenderElement.cpp:

(WebCore::includeNonFixedHeight): This new mode should consider max-height as well as height when determining if
content overflows.
(WebCore::RenderElement::adjustComputedFontSizesOnBlocks):
(WebCore::RenderElement::resetTextAutosizing):

  • rendering/RenderElement.h:
  • rendering/RenderObject.h:

Source/WebKit:

Push the initial scale down into the page.

  • WebProcess/WebPage/ios/WebPageIOS.mm:

(WebKit::WebPage::dynamicViewportSizeUpdate):
(WebKit::WebPage::viewportConfigurationChanged):

LayoutTests:

Add two simple tests that make sure that fonts get autosized > 1x when the layout viewport is wide,
and that fonts don't get autosized when the layout viewport isn't wide.

We don't want to add tons of tests to test exact values because the curve will likely be tweaked
in the future.

  • fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-expected.txt: Added.
  • fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-identity-expected.txt: Added.
  • fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-identity.html: Added.
  • fast/text-autosizing/ios/idempotentmode/idempotent-autosizing.html: Added.
Location:
trunk
Files:
5 added
19 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r244674 r244682  
     12019-04-25  Myles C. Maxfield  <mmaxfield@apple.com>
     2
     3        [iOS] Implement idempotent mode for text autosizing
     4        https://bugs.webkit.org/show_bug.cgi?id=197250
     5        <rdar://problem/50211034>
     6
     7        Reviewed by Jon Lee.
     8
     9        Add two simple tests that make sure that fonts get autosized > 1x when the layout viewport is wide,
     10        and that fonts don't get autosized when the layout viewport isn't wide.
     11
     12        We don't want to add tons of tests to test exact values because the curve will likely be tweaked
     13        in the future.
     14
     15        * fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-expected.txt: Added.
     16        * fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-identity-expected.txt: Added.
     17        * fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-identity.html: Added.
     18        * fast/text-autosizing/ios/idempotentmode/idempotent-autosizing.html: Added.
     19
    1202019-04-25  Sihui Liu  <sihui_liu@apple.com>
    221
  • trunk/LayoutTests/platform/mac/TestExpectations

    r244674 r244682  
    2323fast/text-autosizing/ios/text-size-adjust-inline-style.html [ Skip ]
    2424fast/text-autosizing [ Pass ]
     25# Tests for idempotent autosizing mode rely on viewport scaling which isn't implemented on Mac.
     26fast/text-autosizing/ios/idempotentmode [ Pass Failure ImageOnlyFailure ]
    2527
    2628fast/attachment/attachment-subtitle-resize.html [ Pass ]
  • trunk/Source/WebCore/ChangeLog

    r244675 r244682  
     12019-04-25  Myles C. Maxfield  <mmaxfield@apple.com>
     2
     3        [iOS] Implement idempotent mode for text autosizing
     4        https://bugs.webkit.org/show_bug.cgi?id=197250
     5        <rdar://problem/50211034>
     6
     7        Reviewed by Jon Lee.
     8
     9        Our text autosizing code has this interesting behavior where it is sensitive to the width of the text's container
     10        and the number of lines of text inside the element. Not only is it sensitive to those things, but as those things
     11        change, their values are stored inside the RenderObject itself and then never recomputed. This means that the text
     12        autosizing parameters are sensitive to the entire history of an element. So, a newly created element with the same
     13        style as an existing element can have dramatically different results.
     14
     15        This patch adds a new mode for text autosizing, which isn't sensitive to either of those things, and therefore
     16        maintains the invariant that a newly created element will behave the same as an existing element with the same style.
     17        Instead of using container size, it instead uses the viewport's initial scale. As the viewport's initial scale
     18        changes, new layouts will be triggered, which will cause the autosizing code to use the new value.
     19
     20        Tests: fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-identity.html
     21               fast/text-autosizing/ios/idempotentmode/idempotent-autosizing.html
     22
     23        * page/FrameViewLayoutContext.cpp:
     24        (WebCore::FrameViewLayoutContext::applyTextSizingIfNeeded):
     25        * page/Page.cpp:
     26        (WebCore::Page::setInitialScale): WebKit will push the initial scale down into the page.
     27        * page/Page.h:
     28        (WebCore::Page::initialScale const):
     29        * page/SettingsBase.h:
     30        * page/cocoa/SettingsBaseCocoa.mm:
     31        (WebCore::SettingsBase::textAutosizingUsesIdempotentMode):
     32        (WebCore::SettingsBase::defaultTextAutosizingEnabled):
     33        * rendering/RenderBlockFlow.cpp:
     34        (WebCore::idempotentTextSize): Describe a piecewise-linear curve for the text size to follow. The curve scales
     35        depending on the viewport's initial scale.
     36        (WebCore::RenderBlockFlow::adjustComputedFontSizes):
     37        * rendering/RenderBlockFlow.h:
     38        * rendering/RenderElement.cpp:
     39        (WebCore::includeNonFixedHeight): This new mode should consider max-height as well as height when determining if
     40        content overflows.
     41        (WebCore::RenderElement::adjustComputedFontSizesOnBlocks):
     42        (WebCore::RenderElement::resetTextAutosizing):
     43        * rendering/RenderElement.h:
     44        * rendering/RenderObject.h:
     45
    1462019-04-25  Simon Fraser  <simon.fraser@apple.com>
    247
  • trunk/Source/WebCore/page/FrameViewLayoutContext.cpp

    r244182 r244682  
    494494    if (!settings.textAutosizingEnabled() || renderView()->printing())
    495495        return;
     496    bool idempotentMode = settings.textAutosizingUsesIdempotentMode();
    496497    auto minimumZoomFontSize = settings.minimumZoomFontSize();
    497     if (!minimumZoomFontSize)
     498    if (!idempotentMode && !minimumZoomFontSize)
    498499        return;
    499500    auto textAutosizingWidth = layoutRoot.page().textAutosizingWidth();
    500501    if (auto overrideWidth = settings.textAutosizingWindowSizeOverride().width())
    501502        textAutosizingWidth = overrideWidth;
    502     if (!textAutosizingWidth)
     503    if (!idempotentMode && !textAutosizingWidth)
    503504        return;
    504505    layoutRoot.adjustComputedFontSizesOnBlocks(minimumZoomFontSize, textAutosizingWidth);
  • trunk/Source/WebCore/page/Page.cpp

    r244517 r244682  
    10781078}
    10791079
     1080void Page::setInitialScale(float initialScale)
     1081{
     1082    m_initialScale = initialScale;
     1083}
     1084
    10801085void Page::setUserInterfaceLayoutDirection(UserInterfaceLayoutDirection userInterfaceLayoutDirection)
    10811086{
  • trunk/Source/WebCore/page/Page.h

    r244182 r244682  
    354354    WEBCORE_EXPORT void setDeviceScaleFactor(float);
    355355
     356    float initialScale() const { return m_initialScale; }
     357    WEBCORE_EXPORT void setInitialScale(float);
     358
    356359    float topContentInset() const { return m_topContentInset; }
    357360    WEBCORE_EXPORT void setTopContentInset(float);
     
    835838    float m_textAutosizingWidth { 0 };
    836839#endif
     840    float m_initialScale { 1.0f };
    837841   
    838842    bool m_suppressScrollbarAnimations { false };
  • trunk/Source/WebCore/page/Settings.yaml

    r244582 r244682  
    441441  initial: defaultMinimumZoomFontSize()
    442442  conditional: TEXT_AUTOSIZING
     443textAutosizingUsesIdempotentMode:
     444  initial: defaultTextAutosizingUsesIdempotentMode()
     445  onChange: setNeedsRecalcStyleInAllFrames
     446  conditional: TEXT_AUTOSIZING
    443447
    444448subpixelAntialiasedLayerTextEnabled:
  • trunk/Source/WebCore/page/SettingsBase.cpp

    r244665 r244682  
    9797    return false;
    9898}
     99
     100bool SettingsBase::defaultTextAutosizingUsesIdempotentMode()
     101{
     102    return false;
     103}
    99104#endif
    100105
  • trunk/Source/WebCore/page/SettingsBase.h

    r242621 r244682  
    114114
    115115    WEBCORE_EXPORT static bool defaultTextAutosizingEnabled();
     116    static bool defaultTextAutosizingUsesIdempotentMode();
    116117    WEBCORE_EXPORT static float defaultMinimumZoomFontSize();
    117118    WEBCORE_EXPORT static bool defaultDownloadableBinaryFontsEnabled();
  • trunk/Source/WebCore/page/cocoa/SettingsBaseCocoa.mm

    r242357 r244682  
    8484bool SettingsBase::defaultTextAutosizingEnabled()
    8585{
    86     return !deviceHasIPadCapability() || [[PAL::getUIApplicationClass() sharedApplication] _isClassic];
     86    return true;
     87}
     88
     89bool SettingsBase::defaultTextAutosizingUsesIdempotentMode()
     90{
     91    return deviceHasIPadCapability() && ![[PAL::getUIApplicationClass() sharedApplication] _isClassic];
    8792}
    8893
  • trunk/Source/WebCore/rendering/RenderBlockFlow.cpp

    r239427 r244682  
    37243724}
    37253725
    3726 void RenderBlockFlow::adjustComputedFontSizes(float size, float visibleWidth)
     3726static inline float idempotentTextSize(float specifiedSize, float pageScale)
     3727{
     3728    // This describes a piecewise curve when the page scale is 2/3.
     3729    FloatPoint points[] = { {0.0f, 0.0f}, {6.0f, 12.0f}, {12.0f, 18.0f} };
     3730
     3731    // When the page scale is 1, the curve should be the identity.
     3732    // Linearly interpolate between the curve above and identity based on the page scale.
     3733    // Beware that depending on the specific values picked in the curve, this interpolation might change the shape of the curve for very small pageScales.
     3734    pageScale = std::min(std::max(pageScale, 0.5f), 1.0f);
     3735    auto scalePoint = [&](FloatPoint point) {
     3736        float fraction = 3.0f - 3.0f * pageScale;
     3737        point.setY(point.x() + (point.y() - point.x()) * fraction);
     3738        return point;
     3739    };
     3740
     3741    if (specifiedSize <= 0)
     3742        return 0;
     3743
     3744    float result = scalePoint(points[WTF_ARRAY_LENGTH(points) - 1]).y();
     3745    for (size_t i = 1; i < WTF_ARRAY_LENGTH(points); ++i) {
     3746        if (points[i].x() < specifiedSize)
     3747            continue;
     3748        auto leftPoint = scalePoint(points[i - 1]);
     3749        auto rightPoint = scalePoint(points[i]);
     3750        float fraction = (specifiedSize - leftPoint.x()) / (rightPoint.x() - leftPoint.x());
     3751        result = leftPoint.y() + fraction * (rightPoint.y() - leftPoint.y());
     3752        break;
     3753    }
     3754
     3755    return std::max(result, specifiedSize);
     3756}
     3757
     3758void RenderBlockFlow::adjustComputedFontSizes(float size, float visibleWidth, float pageScale, bool idempotentMode)
    37273759{
    37283760    LOG(TextAutosizing, "RenderBlockFlow %p adjustComputedFontSizes, size=%f visibleWidth=%f, width()=%f. Bailing: %d", this, size, visibleWidth, width().toFloat(), visibleWidth >= width());
    37293761
    37303762    // Don't do any work if the block is smaller than the visible area.
    3731     if (visibleWidth >= width())
     3763    if (!idempotentMode && visibleWidth >= width())
    37323764        return;
    37333765   
     
    37673799        float specifiedSize = fontDescription.specifiedSize();
    37683800        float scaledSize = roundf(specifiedSize * scale);
    3769         if (scaledSize > 0 && scaledSize < minFontSize) {
     3801        if (idempotentMode || (scaledSize > 0 && scaledSize < minFontSize)) {
    37703802            // Record the width of the block and the line count the first time we resize text and use it from then on for text resizing.
    37713803            // This makes text resizing consistent even if the block's width or line count changes (which can be caused by text resizing itself 5159915).
     
    37753807                m_widthForTextAutosizing = actualWidth;
    37763808
    3777             float lineTextMultiplier = lineCount == ONE_LINE ? oneLineTextMultiplier(text, specifiedSize) : textMultiplier(text, specifiedSize);
    3778             float candidateNewSize = roundf(std::min(minFontSize, specifiedSize * lineTextMultiplier));
     3809            float candidateNewSize;
     3810            if (idempotentMode) {
     3811                float lineTextSize = idempotentTextSize(specifiedSize, pageScale);
     3812                candidateNewSize = roundf(lineTextSize);
     3813            } else {
     3814                float lineTextMultiplier = lineCount == ONE_LINE ? oneLineTextMultiplier(text, specifiedSize) : textMultiplier(text, specifiedSize);
     3815                candidateNewSize = roundf(std::min(minFontSize, specifiedSize * lineTextMultiplier));
     3816            }
     3817
    37793818            if (candidateNewSize > specifiedSize && candidateNewSize != fontDescription.computedSize() && text.textNode() && oldStyle.textSizeAdjust().isAuto())
    37803819                document().textAutoSizing().addTextNode(*text.textNode(), candidateNewSize);
  • trunk/Source/WebCore/rendering/RenderBlockFlow.h

    r239427 r244682  
    605605#if ENABLE(TEXT_AUTOSIZING)
    606606    int lineCountForTextAutosizing();
    607     void adjustComputedFontSizes(float size, float visibleWidth);
     607    void adjustComputedFontSizes(float size, float visibleWidth, float pageScale, bool idempotentMode);
    608608    void resetComputedFontSize()
    609609    {
  • trunk/Source/WebCore/rendering/RenderElement.cpp

    r244037 r244682  
    21242124        return RenderObject::FixedHeight;
    21252125    }
     2126    if (renderer.document().settings().textAutosizingUsesIdempotentMode() && style.maxHeight().type() == Fixed && is<RenderBlock>(renderer) && style.maxHeight().value() <= downcast<RenderBlock>(renderer).layoutOverflowRect().maxY())
     2127        return RenderObject::FixedHeight;
    21262128    return RenderObject::FlexibleHeight;
    21272129}
     
    21322134    if (!document)
    21332135        return;
     2136
     2137    auto pageScale = document->page() ? document->page()->initialScale() : 1.0f;
    21342138
    21352139    Vector<int> depthStack;
    21362140    int currentDepth = 0;
    21372141    int newFixedDepth = 0;
     2142    auto idempotentMode = document->settings().textAutosizingUsesIdempotentMode();
    21382143
    21392144    // We don't apply autosizing to nodes with fixed height normally.
     
    21482153
    21492154        int stackSize = depthStack.size();
    2150         if (is<RenderBlockFlow>(*descendent) && !descendent->isListItem() && (!stackSize || currentDepth - depthStack[stackSize - 1] > TextAutoSizingFixedHeightDepth))
    2151             downcast<RenderBlockFlow>(*descendent).adjustComputedFontSizes(size, visibleWidth);
     2155        if (is<RenderBlockFlow>(*descendent) && !descendent->isListItem() && (idempotentMode || !stackSize || currentDepth - depthStack[stackSize - 1] > TextAutoSizingFixedHeightDepth))
     2156            downcast<RenderBlockFlow>(*descendent).adjustComputedFontSizes(size, visibleWidth, pageScale, idempotentMode);
    21522157        newFixedDepth = 0;
    21532158    }
     
    21702175    int currentDepth = 0;
    21712176    int newFixedDepth = 0;
     2177    auto idempotentMode = document->settings().textAutosizingUsesIdempotentMode();
    21722178
    21732179    for (RenderObject* descendent = traverseNext(this, includeNonFixedHeight, currentDepth, newFixedDepth); descendent; descendent = descendent->traverseNext(this, includeNonFixedHeight, currentDepth, newFixedDepth)) {
     
    21782184
    21792185        int stackSize = depthStack.size();
    2180         if (is<RenderBlockFlow>(*descendent) && !descendent->isListItem() && (!stackSize || currentDepth - depthStack[stackSize - 1] > TextAutoSizingFixedHeightDepth))
     2186        if (is<RenderBlockFlow>(*descendent) && !descendent->isListItem() && (idempotentMode || !stackSize || currentDepth - depthStack[stackSize - 1] > TextAutoSizingFixedHeightDepth))
    21812187            downcast<RenderBlockFlow>(*descendent).resetComputedFontSize();
    21822188        newFixedDepth = 0;
  • trunk/Source/WebCore/rendering/RenderObject.h

    r242561 r244682  
    155155
    156156    typedef BlockContentHeightType (*HeightTypeTraverseNextInclusionFunction)(const RenderObject&);
    157     RenderObject* traverseNext(const RenderObject* stayWithin, HeightTypeTraverseNextInclusionFunction, int& currentDepth,  int& newFixedDepth) const;
     157    RenderObject* traverseNext(const RenderObject* stayWithin, HeightTypeTraverseNextInclusionFunction, int& currentDepth, int& newFixedDepth) const;
    158158#endif
    159159
  • trunk/Source/WebCore/testing/InternalSettings.cpp

    r244582 r244682  
    5959    , m_originalTextAutosizingEnabled(settings.textAutosizingEnabled())
    6060    , m_originalTextAutosizingWindowSizeOverride(settings.textAutosizingWindowSizeOverride())
     61    , m_originalTextAutosizingUsesIdempotentMode(settings.textAutosizingUsesIdempotentMode())
    6162#endif
    6263    , m_originalMediaTypeOverride(settings.mediaTypeOverride())
     
    158159    settings.setTextAutosizingEnabled(m_originalTextAutosizingEnabled);
    159160    settings.setTextAutosizingWindowSizeOverride(m_originalTextAutosizingWindowSizeOverride);
     161    settings.setTextAutosizingUsesIdempotentMode(m_originalTextAutosizingUsesIdempotentMode);
    160162#endif
    161163    settings.setMediaTypeOverride(m_originalMediaTypeOverride);
     
    418420}
    419421
     422ExceptionOr<void> InternalSettings::setTextAutosizingUsesIdempotentMode(bool enabled)
     423{
     424    if (!m_page)
     425        return Exception { InvalidAccessError };
     426#if ENABLE(TEXT_AUTOSIZING)
     427    settings().setTextAutosizingUsesIdempotentMode(enabled);
     428#else
     429    UNUSED_PARAM(enabled);
     430#endif
     431    return { };
     432}
     433
    420434ExceptionOr<void> InternalSettings::setMediaTypeOverride(const String& mediaType)
    421435{
  • trunk/Source/WebCore/testing/InternalSettings.h

    r244582 r244682  
    6262    ExceptionOr<void> setTextAutosizingEnabled(bool);
    6363    ExceptionOr<void> setTextAutosizingWindowSizeOverride(int width, int height);
     64    ExceptionOr<void> setTextAutosizingUsesIdempotentMode(bool);
    6465    ExceptionOr<void> setTextAutosizingFontScaleFactor(float);
    6566    ExceptionOr<void> setMediaTypeOverride(const String&);
     
    156157        bool m_originalTextAutosizingEnabled;
    157158        IntSize m_originalTextAutosizingWindowSizeOverride;
     159        bool m_originalTextAutosizingUsesIdempotentMode;
    158160#endif
    159161
  • trunk/Source/WebCore/testing/InternalSettings.idl

    r244582 r244682  
    5050    [MayThrowException] void setTextAutosizingEnabled(boolean enabled);
    5151    [MayThrowException] void setTextAutosizingWindowSizeOverride(long width, long height);
     52    [MayThrowException] void setTextAutosizingUsesIdempotentMode(boolean enabled);
    5253
    5354    // Media
  • trunk/Source/WebKit/ChangeLog

    r244678 r244682  
     12019-04-25  Myles C. Maxfield  <mmaxfield@apple.com>
     2
     3        [iOS] Implement idempotent mode for text autosizing
     4        https://bugs.webkit.org/show_bug.cgi?id=197250
     5        <rdar://problem/50211034>
     6
     7        Reviewed by Jon Lee.
     8
     9        Push the initial scale down into the page.
     10
     11        * WebProcess/WebPage/ios/WebPageIOS.mm:
     12        (WebKit::WebPage::dynamicViewportSizeUpdate):
     13        (WebKit::WebPage::viewportConfigurationChanged):
     14
    1152019-04-25  Alex Christensen  <achristensen@webkit.org>
    216
  • trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm

    r244667 r244682  
    28522852
    28532853    LOG_WITH_STREAM(VisibleRects, stream << "WebPage::dynamicViewportSizeUpdate setting view layout size to " << viewLayoutSize);
    2854     m_viewportConfiguration.setViewLayoutSize(viewLayoutSize);
     2854    if (m_viewportConfiguration.setViewLayoutSize(viewLayoutSize))
     2855        viewportConfigurationChanged();
    28552856    IntSize newLayoutSize = m_viewportConfiguration.layoutSize();
    28562857
     
    30313032void WebPage::viewportConfigurationChanged(ZoomToInitialScale zoomToInitialScale)
    30323033{
     3034    double initialScale = m_viewportConfiguration.initialScale();
     3035    m_page->setInitialScale(initialScale);
     3036
    30333037    if (setFixedLayoutSize(m_viewportConfiguration.layoutSize()))
    30343038        resetTextAutosizing();
    30353039
    3036     double initialScale = m_viewportConfiguration.initialScale();
    30373040    double scale;
    30383041    if (m_userHasChangedPageScaleFactor && zoomToInitialScale == ZoomToInitialScale::No)
Note: See TracChangeset for help on using the changeset viewer.