Changeset 230171 in webkit


Ignore:
Timestamp:
Apr 2, 2018 12:06:44 PM (6 years ago)
Author:
Wenson Hsieh
Message:

[Extra zoom mode] Zoom level is sometimes excessive when zooming to focused form controls
https://bugs.webkit.org/show_bug.cgi?id=184222
<rdar://problem/39063886>

Reviewed by Timothy Hatcher.

Upon interactively focusing an element, we zoom and scroll to reveal that element. The heuristics introduced in
<https://trac.webkit.org/r168744> work by computing a target scale, and then a point to zoom to given that
scale. Currently, this scale is dependent on the computed font size of the form control, such that the form
control would be scaled to have an effective font size of 16.

However, in extra zoom mode, applying these same heuristics (ironically) results in excessive zoom levels, since
scaling the font up to 16 would cause most form controls to zoom so far in that we lose context of surrounding
elements such as labels and other form controls; the fact that the element is highlighted by the focused form
control overlay makes this even more confusing, since part of the focus overlay highlight rect often ends up
outside the viewport.

To fix this, we make a couple of tweaks to focus rect zooming in extra zoom mode. (1) Instead of computing
target zoom level based on font size, try to zoom such that the focused element rect fills up most of the
viewport (similar to double-tap zooming). This ensures that the focused form control overlay's highlight rect
makes sense in most cases, with few exceptions (e.g. the element frame is larger than the viewport). (2)
Introduce a minimum legible font size of 11, and compute the minimium scale needed such that the form control
font would appear to be at least this legible font size. Then, clamp the target scale chosen by (1) to this
minimum scale.

One additional consideration for (1) is that naively scaling to fit the element rect to the viewport (with some
fixed margins) would cause the viewport scale to always change when moving focus between form controls of
different dimensions, even if the current scale is more or less appropriate for all the focusable elements. To
address this, instead of computing a single target zoom scale for an element rect, compute a range of possible
target zoom scales (where the minimum and maximum values depend on the margin we add around the element rect).
If the current scale already falls within this target scale range, then we won't bother adjusting the scale at
all (unless the font size is too small — see (2)). If the current scale falls outside the target scale range, we
then make the minimal adjustment needed to ensure that the element rect fits well within the viewport without
being too small.

  • UIProcess/API/Cocoa/WKWebView.mm:

(-[WKWebView _zoomToFocusRect:selectionRect:insideFixed:fontSize:minimumScale:maximumScale:allowScaling:forceScroll:]):

Move some logic around so that the target scale is computed after computing the visible size. Also renames some
constants local to this function (WKWebViewStandardFontSize, kMinimumHeightToShowContentAboveKeyboard,
UIWebFormAnimationDuration, CaretOffsetFromWindowEdge) such that they now share a consistent naming style.

Location:
trunk/Source/WebKit
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebKit/ChangeLog

    r230169 r230171  
     12018-04-02  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        [Extra zoom mode] Zoom level is sometimes excessive when zooming to focused form controls
     4        https://bugs.webkit.org/show_bug.cgi?id=184222
     5        <rdar://problem/39063886>
     6
     7        Reviewed by Timothy Hatcher.
     8
     9        Upon interactively focusing an element, we zoom and scroll to reveal that element. The heuristics introduced in
     10        <https://trac.webkit.org/r168744> work by computing a target scale, and then a point to zoom to given that
     11        scale. Currently, this scale is dependent on the computed font size of the form control, such that the form
     12        control would be scaled to have an effective font size of 16.
     13
     14        However, in extra zoom mode, applying these same heuristics (ironically) results in excessive zoom levels, since
     15        scaling the font up to 16 would cause most form controls to zoom so far in that we lose context of surrounding
     16        elements such as labels and other form controls; the fact that the element is highlighted by the focused form
     17        control overlay makes this even more confusing, since part of the focus overlay highlight rect often ends up
     18        outside the viewport.
     19
     20        To fix this, we make a couple of tweaks to focus rect zooming in extra zoom mode. (1) Instead of computing
     21        target zoom level based on font size, try to zoom such that the focused element rect fills up most of the
     22        viewport (similar to double-tap zooming). This ensures that the focused form control overlay's highlight rect
     23        makes sense in most cases, with few exceptions (e.g. the element frame is larger than the viewport). (2)
     24        Introduce a minimum legible font size of 11, and compute the minimium scale needed such that the form control
     25        font would appear to be at least this legible font size. Then, clamp the target scale chosen by (1) to this
     26        minimum scale.
     27
     28        One additional consideration for (1) is that naively scaling to fit the element rect to the viewport (with some
     29        fixed margins) would cause the viewport scale to always change when moving focus between form controls of
     30        different dimensions, even if the current scale is more or less appropriate for all the focusable elements. To
     31        address this, instead of computing a single target zoom scale for an element rect, compute a range of possible
     32        target zoom scales (where the minimum and maximum values depend on the margin we add around the element rect).
     33        If the current scale already falls within this target scale range, then we won't bother adjusting the scale at
     34        all (unless the font size is too small — see (2)). If the current scale falls outside the target scale range, we
     35        then make the minimal adjustment needed to ensure that the element rect fits well within the viewport without
     36        being too small.
     37
     38        * UIProcess/API/Cocoa/WKWebView.mm:
     39        (-[WKWebView _zoomToFocusRect:selectionRect:insideFixed:fontSize:minimumScale:maximumScale:allowScaling:forceScroll:]):
     40
     41        Move some logic around so that the target scale is computed after computing the visible size. Also renames some
     42        constants local to this function (WKWebViewStandardFontSize, kMinimumHeightToShowContentAboveKeyboard,
     43        UIWebFormAnimationDuration, CaretOffsetFromWindowEdge) such that they now share a consistent naming style.
     44
    1452018-04-02  Jer Noble  <jer.noble@apple.com>
    246
  • trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm

    r230041 r230171  
    21212121    UNUSED_PARAM(insideFixed);
    21222122
    2123     const double WKWebViewStandardFontSize = 16;
    2124     const double kMinimumHeightToShowContentAboveKeyboard = 106;
    2125     const CFTimeInterval UIWebFormAnimationDuration = 0.25;
    2126     const double CaretOffsetFromWindowEdge = 20;
    2127 
    2128     // Zoom around the element's bounding frame. We use a "standard" size to determine the proper frame.
    2129     double scale = allowScaling ? std::min(std::max(WKWebViewStandardFontSize / fontSize, minimumScale), maximumScale) : contentZoomScale(self);
    2130     CGFloat documentWidth = [_contentView bounds].size.width;
    2131     scale = CGRound(documentWidth * scale) / documentWidth;
     2123    const double minimumHeightToShowContentAboveKeyboard = 106;
     2124    const CFTimeInterval formControlZoomAnimationDuration = 0.25;
     2125    const double caretOffsetFromWindowEdge = 20;
    21322126
    21332127    UIWindow *window = [_scrollView window];
    2134 
    2135     WebCore::FloatRect focusedElementRectInNewScale = focusedElementRectInDocumentCoordinates;
    2136     focusedElementRectInNewScale.scale(scale);
    2137     focusedElementRectInNewScale.moveBy([_contentView frame].origin);
    21382128
    21392129    // Find the portion of the view that is visible on the screen.
     
    21542144        CGFloat heightVisibleBelowFormAssistant = CGRectGetMaxY(visibleScrollViewBoundsInWebViewCoordinates) - CGRectGetMaxY(intersectionBetweenScrollViewAndFormAssistant);
    21552145
    2156         if (heightVisibleAboveFormAssistant >= kMinimumHeightToShowContentAboveKeyboard || heightVisibleBelowFormAssistant < heightVisibleAboveFormAssistant)
     2146        if (heightVisibleAboveFormAssistant >= minimumHeightToShowContentAboveKeyboard || heightVisibleBelowFormAssistant < heightVisibleAboveFormAssistant)
    21572147            visibleSize.height = heightVisibleAboveFormAssistant;
    21582148        else {
     
    21612151        }
    21622152    }
     2153
     2154    // Zoom around the element's bounding frame. We use a "standard" size to determine the proper frame.
     2155    double currentScale = contentZoomScale(self);
     2156    double scale = currentScale;
     2157    if (allowScaling) {
     2158#if ENABLE(EXTRA_ZOOM_MODE)
     2159        const double minimumLegibleFontSize = 11;
     2160        const CGFloat minimumMarginForZoomingToEntireFocusRectInWebViewCoordinates = 10;
     2161        const CGFloat maximumMarginForZoomingToEntireFocusRectInWebViewCoordinates = 35;
     2162
     2163        CGRect minimumTargetRectInDocumentCoordinates = UIRectInsetEdges(focusedElementRectInDocumentCoordinates, UIRectEdgeAll, -minimumMarginForZoomingToEntireFocusRectInWebViewCoordinates / currentScale);
     2164        CGRect maximumTargetRectInDocumentCoordinates = UIRectInsetEdges(focusedElementRectInDocumentCoordinates, UIRectEdgeAll, -maximumMarginForZoomingToEntireFocusRectInWebViewCoordinates / currentScale);
     2165
     2166        double clampedMaximumTargetScale = clampTo<double>(std::min(visibleSize.width / CGRectGetWidth(minimumTargetRectInDocumentCoordinates), visibleSize.height / CGRectGetHeight(minimumTargetRectInDocumentCoordinates)), minimumScale, maximumScale);
     2167        double clampedMinimumTargetScale = clampTo<double>(std::min(visibleSize.width / CGRectGetWidth(maximumTargetRectInDocumentCoordinates), visibleSize.height / CGRectGetHeight(maximumTargetRectInDocumentCoordinates)), minimumScale, maximumScale);
     2168        double targetScaleIgnoringFontSizeConstraints = clampTo<double>(currentScale, clampedMinimumTargetScale, clampedMaximumTargetScale);
     2169        scale = std::max<double>(minimumLegibleFontSize / fontSize, targetScaleIgnoringFontSizeConstraints);
     2170#else
     2171        const double webViewStandardFontSize = 16;
     2172        scale = clampTo<double>(webViewStandardFontSize / fontSize, minimumScale, maximumScale);
     2173#endif
     2174    }
     2175
     2176    CGFloat documentWidth = [_contentView bounds].size.width;
     2177    scale = CGRound(documentWidth * scale) / documentWidth;
     2178
     2179    WebCore::FloatRect focusedElementRectInNewScale = focusedElementRectInDocumentCoordinates;
     2180    focusedElementRectInNewScale.scale(scale);
     2181    focusedElementRectInNewScale.moveBy([_contentView frame].origin);
    21632182
    21642183    BOOL selectionRectIsNotNull = !selectionRectInDocumentCoordinates.isZero();
     
    21942213        selectionRectInNewScale.scale(scale);
    21952214        selectionRectInNewScale.moveBy([_contentView frame].origin);
    2196         minimumAllowableHorizontalOffsetInWebViewCoordinates = CGRectGetMaxX(selectionRectInNewScale) + CaretOffsetFromWindowEdge - visibleSize.width;
    2197         minimumAllowableVerticalOffsetInWebViewCoordinates = CGRectGetMaxY(selectionRectInNewScale) + CaretOffsetFromWindowEdge - visibleSize.height - visibleOffsetFromTop;
     2215        minimumAllowableHorizontalOffsetInWebViewCoordinates = CGRectGetMaxX(selectionRectInNewScale) + caretOffsetFromWindowEdge - visibleSize.width;
     2216        minimumAllowableVerticalOffsetInWebViewCoordinates = CGRectGetMaxY(selectionRectInNewScale) + caretOffsetFromWindowEdge - visibleSize.height - visibleOffsetFromTop;
    21982217    }
    21992218
     
    22262245    WebCore::FloatPoint newCenter = CGPointMake(topLeft.x + unobscuredScrollViewRectInWebViewCoordinates.size.width / 2.0, topLeft.y + unobscuredScrollViewRectInWebViewCoordinates.size.height / 2.0);
    22272246
    2228     if (scale != contentZoomScale(self))
     2247    if (scale != currentScale)
    22292248        _page->willStartUserTriggeredZooming();
    22302249
     
    22332252    // The newCenter has been computed in the new scale, but _zoomToCenter expected the center to be in the original scale.
    22342253    newCenter.scale(1 / scale);
    2235     [_scrollView _zoomToCenter:newCenter
    2236                         scale:scale
    2237                      duration:UIWebFormAnimationDuration
    2238                         force:YES];
     2254    [_scrollView _zoomToCenter:newCenter scale:scale duration:formControlZoomAnimationDuration force:YES];
    22392255}
    22402256
Note: See TracChangeset for help on using the changeset viewer.