Changeset 239314 in webkit
- Timestamp:
- Dec 17, 2018 8:04:44 PM (5 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r239313 r239314 1 2018-12-17 Wenson Hsieh <wenson_hsieh@apple.com> 2 3 [iOS] Focusing a large editable element always scrolls to the top of the element 4 https://bugs.webkit.org/show_bug.cgi?id=192745 5 <rdar://problem/46758445> 6 7 Reviewed by Tim Horton. 8 9 Add a new layout test to verify that we don't scroll unnecessarily when focusing a tall editable element, whose 10 top offset is already near the top of the viewport. 11 12 * editing/selection/ios/no-scrolling-when-focusing-large-editable-area-expected.txt: Added. 13 * editing/selection/ios/no-scrolling-when-focusing-large-editable-area.html: Added. 14 1 15 2018-12-17 Ryosuke Niwa <rniwa@webkit.org> 2 16 -
trunk/Source/WebKit/ChangeLog
r239313 r239314 1 2018-12-17 Wenson Hsieh <wenson_hsieh@apple.com> 2 3 [iOS] Focusing a large editable element always scrolls to the top of the element 4 https://bugs.webkit.org/show_bug.cgi?id=192745 5 <rdar://problem/46758445> 6 7 Reviewed by Tim Horton. 8 9 Currently, when focusing form controls or editable elements, we try to scroll such that the focused element rect 10 is centered within the visible area. In the case of very large focusable elements whose dimensions exceed the 11 width or height of the visible area, we instead scroll such that the top left point of the element is at the top 12 left corner of the visible area. 13 14 However, this results in unnecessary scrolling if the top of the element is already near the top of the visible 15 area. For WebKit2-based rich text editors that have an editable body element with a top content inset that 16 contains additional content, this means we will always scroll the additional content away when focusing the 17 editable body. 18 19 To avoid this behavior, adjust focused element zooming logic for editable elements that are too large to be 20 centered in the visible area, such that we only scroll the top left position of the focused element to the top 21 half or top right of the visible area, respectively. This reduces the amount of scrolling when focusing large 22 editable elements, while still making it clear which element is being focused. 23 24 * Platform/spi/ios/UIKitSPI.h: 25 * UIProcess/API/Cocoa/WKWebView.mm: 26 (-[WKWebView _zoomToFocusRect:selectionRect:insideFixed:fontSize:minimumScale:maximumScale:allowScaling:forceScroll:]): 27 28 Make some small adjustments to improve the readability of this method by using `clampTo` instead of clamping 29 values by comparing and setting values. 30 31 Also, fix an existing bug wherein focusable elements that are meant to be centered within the visible area are 32 currently offset by half the difference between the bottom inset amount and the top inset amount, in the case 33 where the `_obscuredInsets` SPI is used to specify content insets for the web view (i.e., MobileSafari). 34 35 * UIProcess/API/Cocoa/WKWebViewInternal.h: 36 37 Make a couple of arguments `const FloatRect&` instead of just `FloatRect`. 38 1 39 2018-12-17 Ryosuke Niwa <rniwa@webkit.org> 2 40 -
trunk/Source/WebKit/Platform/spi/ios/UIKitSPI.h
r239059 r239314 349 349 @property (nonatomic, getter=_indicatorInsetAdjustmentBehavior, setter=_setIndicatorInsetAdjustmentBehavior:) UIScrollViewIndicatorInsetAdjustmentBehavior indicatorInsetAdjustmentBehavior; 350 350 @property (nonatomic, readonly) UIEdgeInsets _systemContentInset; 351 @property (nonatomic, readonly) UIEdgeInsets _effectiveContentInset; 351 352 @end 352 353 -
trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm
r239310 r239314 2226 2226 2227 2227 // focusedElementRect and selectionRect are both in document coordinates. 2228 - (void)_zoomToFocusRect:( WebCore::FloatRect)focusedElementRectInDocumentCoordinates selectionRect:(WebCore::FloatRect)selectionRectInDocumentCoordinates insideFixed:(BOOL)insideFixed2228 - (void)_zoomToFocusRect:(const WebCore::FloatRect&)focusedElementRectInDocumentCoordinates selectionRect:(const WebCore::FloatRect&)selectionRectInDocumentCoordinates insideFixed:(BOOL)insideFixed 2229 2229 fontSize:(float)fontSize minimumScale:(double)minimumScale maximumScale:(double)maximumScale allowScaling:(BOOL)allowScaling forceScroll:(BOOL)forceScroll 2230 2230 { … … 2306 2306 } 2307 2307 2308 // We want to zoom to the left/top corner of the DOM node, with as much spacing on all sides as we2309 // can get based on the visible area after zooming (workingFrame).The spacing in either dimension is half the2308 // We want to center the focused element within the viewport, with as much spacing on all sides as 2309 // we can get based on the visible area after zooming. The spacing in either dimension is half the 2310 2310 // difference between the size of the DOM node and the size of the visible frame. 2311 CGFloat horizontalSpaceInWebViewCoordinates = std::max((visibleSize.width - focusedElementRectInNewScale.width()) / 2.0, 0.0); 2312 CGFloat verticalSpaceInWebViewCoordinates = std::max((visibleSize.height - focusedElementRectInNewScale.height()) / 2.0, 0.0); 2313 2314 CGPoint topLeft; 2315 topLeft.x = focusedElementRectInNewScale.x() - horizontalSpaceInWebViewCoordinates; 2316 topLeft.y = focusedElementRectInNewScale.y() - verticalSpaceInWebViewCoordinates - visibleOffsetFromTop; 2311 // If the element is too wide to be horizontally centered or too tall to be vertically centered, we 2312 // instead scroll such that the left edge or top edge of the element is within the left half or top 2313 // half of the viewport, respectively. 2314 CGFloat horizontalSpaceInWebViewCoordinates = (visibleSize.width - focusedElementRectInNewScale.width()) / 2.0; 2315 CGFloat verticalSpaceInWebViewCoordinates = (visibleSize.height - focusedElementRectInNewScale.height()) / 2.0; 2316 2317 auto topLeft = CGPointZero; 2318 auto scrollViewInsets = [_scrollView _effectiveContentInset]; 2319 auto currentTopLeft = [_scrollView contentOffset]; 2320 2321 if (_haveSetObscuredInsets) { 2322 currentTopLeft.x += _obscuredInsets.left; 2323 currentTopLeft.y += _obscuredInsets.top; 2324 } 2325 2326 if (horizontalSpaceInWebViewCoordinates > 0) 2327 topLeft.x = focusedElementRectInNewScale.x() - horizontalSpaceInWebViewCoordinates; 2328 else { 2329 auto minimumOffsetToRevealLeftEdge = std::max(-scrollViewInsets.left, focusedElementRectInNewScale.x() - visibleSize.width / 2); 2330 auto maximumOffsetToRevealLeftEdge = focusedElementRectInNewScale.x(); 2331 topLeft.x = clampTo<double>(currentTopLeft.x, minimumOffsetToRevealLeftEdge, maximumOffsetToRevealLeftEdge); 2332 } 2333 2334 if (verticalSpaceInWebViewCoordinates > 0) 2335 topLeft.y = focusedElementRectInNewScale.y() - verticalSpaceInWebViewCoordinates; 2336 else { 2337 auto minimumOffsetToRevealTopEdge = std::max(-scrollViewInsets.top, focusedElementRectInNewScale.y() - visibleSize.height / 2); 2338 auto maximumOffsetToRevealTopEdge = focusedElementRectInNewScale.y(); 2339 topLeft.y = clampTo<double>(currentTopLeft.y, minimumOffsetToRevealTopEdge, maximumOffsetToRevealTopEdge); 2340 } 2341 2342 topLeft.y -= visibleOffsetFromTop; 2343 2344 WebCore::FloatRect documentBoundsInNewScale = [_contentView bounds]; 2345 documentBoundsInNewScale.scale(scale); 2346 documentBoundsInNewScale.moveBy([_contentView frame].origin); 2317 2347 2318 2348 CGFloat minimumAllowableHorizontalOffsetInWebViewCoordinates = -INFINITY; 2319 2349 CGFloat minimumAllowableVerticalOffsetInWebViewCoordinates = -INFINITY; 2350 CGFloat maximumAllowableHorizontalOffsetInWebViewCoordinates = CGRectGetMaxX(documentBoundsInNewScale) - visibleSize.width; 2351 CGFloat maximumAllowableVerticalOffsetInWebViewCoordinates = CGRectGetMaxY(documentBoundsInNewScale) - visibleSize.height; 2352 2320 2353 if (selectionRectIsNotNull) { 2321 2354 WebCore::FloatRect selectionRectInNewScale = selectionRectInDocumentCoordinates; 2322 2355 selectionRectInNewScale.scale(scale); 2323 2356 selectionRectInNewScale.moveBy([_contentView frame].origin); 2357 // Adjust the min and max allowable scroll offsets, such that the selection rect remains visible. 2324 2358 minimumAllowableHorizontalOffsetInWebViewCoordinates = CGRectGetMaxX(selectionRectInNewScale) + caretOffsetFromWindowEdge - visibleSize.width; 2325 2359 minimumAllowableVerticalOffsetInWebViewCoordinates = CGRectGetMaxY(selectionRectInNewScale) + caretOffsetFromWindowEdge - visibleSize.height - visibleOffsetFromTop; 2326 } 2327 2328 WebCore::FloatRect documentBoundsInNewScale = [_contentView bounds]; 2329 documentBoundsInNewScale.scale(scale); 2330 documentBoundsInNewScale.moveBy([_contentView frame].origin); 2360 maximumAllowableHorizontalOffsetInWebViewCoordinates = std::min(maximumAllowableHorizontalOffsetInWebViewCoordinates, CGRectGetMinX(selectionRectInNewScale) - caretOffsetFromWindowEdge); 2361 maximumAllowableVerticalOffsetInWebViewCoordinates = std::min(maximumAllowableVerticalOffsetInWebViewCoordinates, CGRectGetMinY(selectionRectInNewScale) - caretOffsetFromWindowEdge - visibleOffsetFromTop); 2362 } 2331 2363 2332 2364 // Constrain the left edge in document coordinates so that: 2333 2365 // - it isn't so small that the scrollVisibleRect isn't visible on the screen 2334 2366 // - it isn't so great that the document's right edge is less than the right edge of the screen 2335 if (selectionRectIsNotNull && topLeft.x < minimumAllowableHorizontalOffsetInWebViewCoordinates) 2336 topLeft.x = minimumAllowableHorizontalOffsetInWebViewCoordinates; 2337 else { 2338 CGFloat maximumAllowableHorizontalOffset = CGRectGetMaxX(documentBoundsInNewScale) - visibleSize.width; 2339 if (topLeft.x > maximumAllowableHorizontalOffset) 2340 topLeft.x = maximumAllowableHorizontalOffset; 2341 } 2367 topLeft.x = clampTo<CGFloat>(topLeft.x, minimumAllowableHorizontalOffsetInWebViewCoordinates, maximumAllowableHorizontalOffsetInWebViewCoordinates); 2342 2368 2343 2369 // Constrain the top edge in document coordinates so that: 2344 2370 // - it isn't so small that the scrollVisibleRect isn't visible on the screen 2345 2371 // - it isn't so great that the document's bottom edge is higher than the top of the form assistant 2346 if (selectionRectIsNotNull && topLeft.y < minimumAllowableVerticalOffsetInWebViewCoordinates) 2347 topLeft.y = minimumAllowableVerticalOffsetInWebViewCoordinates; 2348 else { 2349 CGFloat maximumAllowableVerticalOffset = CGRectGetMaxY(documentBoundsInNewScale) - visibleSize.height; 2350 if (topLeft.y > maximumAllowableVerticalOffset) 2351 topLeft.y = maximumAllowableVerticalOffset; 2352 } 2353 2354 WebCore::FloatPoint newCenter = CGPointMake(topLeft.x + unobscuredScrollViewRectInWebViewCoordinates.size.width / 2.0, topLeft.y + unobscuredScrollViewRectInWebViewCoordinates.size.height / 2.0); 2372 topLeft.y = clampTo<CGFloat>(topLeft.y, minimumAllowableVerticalOffsetInWebViewCoordinates, maximumAllowableVerticalOffsetInWebViewCoordinates); 2373 2374 if (_haveSetObscuredInsets) { 2375 // This looks unintuitive, but is necessary in order to precisely center the focused element in the visible area. 2376 // The top left position already accounts for top and left obscured insets - i.e., a topLeft of (0, 0) corresponds 2377 // to the top- and left-most point below (and to the right of) the top inset area and left inset areas, respectively. 2378 // However, when telling WKScrollView to scroll to a given center position, this center position is computed relative 2379 // to the coordinate space of the scroll view. Thus, to compute our center position from the top left position, we 2380 // need to first move the top left position up and to the left, and then add half the width and height of the content 2381 // area (including obscured insets). 2382 topLeft.x -= _obscuredInsets.left; 2383 topLeft.y -= _obscuredInsets.top; 2384 } 2385 2386 WebCore::FloatPoint newCenter = CGPointMake(topLeft.x + CGRectGetWidth(self.bounds) / 2, topLeft.y + CGRectGetHeight(self.bounds) / 2); 2355 2387 2356 2388 if (scale != currentScale) -
trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewInternal.h
r238771 r239314 102 102 - (void)_scrollToContentScrollPosition:(WebCore::FloatPoint)scrollPosition scrollOrigin:(WebCore::IntPoint)scrollOrigin; 103 103 - (BOOL)_scrollToRect:(WebCore::FloatRect)targetRect origin:(WebCore::FloatPoint)origin minimumScrollDistance:(float)minimumScrollDistance; 104 - (void)_zoomToFocusRect:( WebCore::FloatRect)focusedElementRect selectionRect:(WebCore::FloatRect)selectionRectInDocumentCoordinates insideFixed:(BOOL)insideFixed fontSize:(float)fontSize minimumScale:(double)minimumScale maximumScale:(double)maximumScale allowScaling:(BOOL)allowScaling forceScroll:(BOOL)forceScroll;104 - (void)_zoomToFocusRect:(const WebCore::FloatRect&)focusedElementRect selectionRect:(const WebCore::FloatRect&)selectionRectInDocumentCoordinates insideFixed:(BOOL)insideFixed fontSize:(float)fontSize minimumScale:(double)minimumScale maximumScale:(double)maximumScale allowScaling:(BOOL)allowScaling forceScroll:(BOOL)forceScroll; 105 105 - (BOOL)_zoomToRect:(WebCore::FloatRect)targetRect withOrigin:(WebCore::FloatPoint)origin fitEntireRect:(BOOL)fitEntireRect minimumScale:(double)minimumScale maximumScale:(double)maximumScale minimumScrollDistance:(float)minimumScrollDistance; 106 106 - (void)_zoomOutWithOrigin:(WebCore::FloatPoint)origin animated:(BOOL)animated;
Note: See TracChangeset
for help on using the changeset viewer.