- Revision
- 170600
- Author
- [email protected]
- Date
- 2014-06-30 15:10:56 -0700 (Mon, 30 Jun 2014)
Log Message
[iOS][WK2] Move tap highlight to the inverseScaleRootView
https://bugs.webkit.org/show_bug.cgi?id=134424
<rdar://problem/17480880>
Patch by Benjamin Poulain <[email protected]> on 2014-06-30
Reviewed by Tim Horton.
Enrica introduced the inverseScaleRootView that is a dynamic version of _highlightRootView.
This patch moves the tap highlight from its own inverse root to inverseScaleRootView. This provides better handling
of scale, better behavior on crash, and remove one extra view from the hierarchy.
The code is pretty much the same, just moved around. Some of the changes:
Now the code needs to handle repainting live when the view scale. To do that, _showTapHighlightXXX was split in two:
-_showTapHighlight to setup the view.
-_updateTapHighlight to update the view based on the current scale.
Since the view updates live on scaling, we need to recompute the coordinates for each update. To do that, the _potentialTapHighlightInformation
was generalized to handle all cases of highlight.
Since we can no longer test for the nullity of _potentialTapHighlightInformation,
a new attribute is introduced for that: _hasTapHighlightForPotentialTap.
The last bit of change concern reentering the tap highlight. This becomes quite simple:
1) _isTapHighlightIDValid is updated before the animation starts
so that it can be set again during an animation.
2) The animation checks the "finished" flags before removing the view from its superview
to avoid breaking the new animation.
* UIProcess/API/Cocoa/WKWebView.mm:
(withinEpsilon): Deleted.
* UIProcess/ios/WKContentView.mm:
(-[WKContentView didUpdateVisibleRect:unobscuredRect:unobscuredRectInScrollViewCoordinates:scale:minimumScale:inStableState:isChangingObscuredInsetsInteractively:]):
Make _updateUnscaledView conditional to scale changes, that thing isn't cheap!
* UIProcess/ios/WKContentViewInteraction.h:
(withinEpsilon):
Move withinEpsilon() from WKContentView to use it from both classes.
* UIProcess/ios/WKContentViewInteraction.mm:
(-[WKContentView cleanupInteraction]):
(-[WKContentView _updateUnscaledView]):
(-[WKContentView _updateTapHighlight]):
(-[WKContentView _showTapHighlight]):
(-[WKContentView _didGetTapHighlightForRequest:color:quads:topLeftRadius:topRightRadius:bottomLeftRadius:bottomRightRadius:]):
(-[WKContentView _cancelInteraction]):
(-[WKContentView _finishInteraction]):
(-[WKContentView _singleTapDidReset:]):
(-[WKContentView _singleTapCommited:]):
(-[WKContentView _showTapHighlightWithColor:quads:topLeftRadius:topRightRadius:bottomLeftRadius:bottomRightRadius:]): Deleted.
Modified Paths
Diff
Modified: trunk/Source/WebKit2/ChangeLog (170599 => 170600)
--- trunk/Source/WebKit2/ChangeLog 2014-06-30 21:53:58 UTC (rev 170599)
+++ trunk/Source/WebKit2/ChangeLog 2014-06-30 22:10:56 UTC (rev 170600)
@@ -1,3 +1,56 @@
+2014-06-30 Benjamin Poulain <[email protected]>
+
+ [iOS][WK2] Move tap highlight to the inverseScaleRootView
+ https://bugs.webkit.org/show_bug.cgi?id=134424
+ <rdar://problem/17480880>
+
+ Reviewed by Tim Horton.
+
+ Enrica introduced the inverseScaleRootView that is a dynamic version of _highlightRootView.
+
+ This patch moves the tap highlight from its own inverse root to inverseScaleRootView. This provides better handling
+ of scale, better behavior on crash, and remove one extra view from the hierarchy.
+
+ The code is pretty much the same, just moved around. Some of the changes:
+
+ Now the code needs to handle repainting live when the view scale. To do that, _showTapHighlightXXX was split in two:
+ -_showTapHighlight to setup the view.
+ -_updateTapHighlight to update the view based on the current scale.
+
+ Since the view updates live on scaling, we need to recompute the coordinates for each update. To do that, the _potentialTapHighlightInformation
+ was generalized to handle all cases of highlight.
+
+ Since we can no longer test for the nullity of _potentialTapHighlightInformation,
+ a new attribute is introduced for that: _hasTapHighlightForPotentialTap.
+
+ The last bit of change concern reentering the tap highlight. This becomes quite simple:
+ 1) _isTapHighlightIDValid is updated before the animation starts
+ so that it can be set again during an animation.
+ 2) The animation checks the "finished" flags before removing the view from its superview
+ to avoid breaking the new animation.
+
+ * UIProcess/API/Cocoa/WKWebView.mm:
+ (withinEpsilon): Deleted.
+ * UIProcess/ios/WKContentView.mm:
+ (-[WKContentView didUpdateVisibleRect:unobscuredRect:unobscuredRectInScrollViewCoordinates:scale:minimumScale:inStableState:isChangingObscuredInsetsInteractively:]):
+ Make _updateUnscaledView conditional to scale changes, that thing isn't cheap!
+
+ * UIProcess/ios/WKContentViewInteraction.h:
+ (withinEpsilon):
+ Move withinEpsilon() from WKContentView to use it from both classes.
+
+ * UIProcess/ios/WKContentViewInteraction.mm:
+ (-[WKContentView cleanupInteraction]):
+ (-[WKContentView _updateUnscaledView]):
+ (-[WKContentView _updateTapHighlight]):
+ (-[WKContentView _showTapHighlight]):
+ (-[WKContentView _didGetTapHighlightForRequest:color:quads:topLeftRadius:topRightRadius:bottomLeftRadius:bottomRightRadius:]):
+ (-[WKContentView _cancelInteraction]):
+ (-[WKContentView _finishInteraction]):
+ (-[WKContentView _singleTapDidReset:]):
+ (-[WKContentView _singleTapCommited:]):
+ (-[WKContentView _showTapHighlightWithColor:quads:topLeftRadius:topRightRadius:bottomLeftRadius:bottomRightRadius:]): Deleted.
+
2014-06-30 Anders Carlsson <[email protected]>
Add code for encoding legacy session history entries
Modified: trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm (170599 => 170600)
--- trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm 2014-06-30 21:53:58 UTC (rev 170599)
+++ trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm 2014-06-30 22:10:56 UTC (rev 170600)
@@ -739,11 +739,6 @@
_usesMinimalUI = NO;
}
-static inline bool withinEpsilon(float a, float b)
-{
- return fabs(a - b) < std::numeric_limits<float>::epsilon();
-}
-
static void changeContentOffsetBoundedInValidRange(UIScrollView *scrollView, WebCore::FloatPoint contentOffset)
{
UIEdgeInsets contentInsets = scrollView.contentInset;
Modified: trunk/Source/WebKit2/UIProcess/ios/WKContentView.mm (170599 => 170600)
--- trunk/Source/WebKit2/UIProcess/ios/WKContentView.mm 2014-06-30 21:53:58 UTC (rev 170599)
+++ trunk/Source/WebKit2/UIProcess/ios/WKContentView.mm 2014-06-30 22:10:56 UTC (rev 170600)
@@ -556,6 +556,8 @@
- (void)didUpdateVisibleRect:(CGRect)visibleRect unobscuredRect:(CGRect)unobscuredRect unobscuredRectInScrollViewCoordinates:(CGRect)unobscuredRectInScrollViewCoordinates
scale:(CGFloat)zoomScale minimumScale:(CGFloat)minimumScale inStableState:(BOOL)isStableState isChangingObscuredInsetsInteractively:(BOOL)isChangingObscuredInsetsInteractively
{
+ double oldDisplayedContentScale = _page->displayedContentScale();
+
double timestamp = monotonicallyIncreasingTime();
HistoricalVelocityData::VelocityData velocityData;
if (!isStableState)
@@ -572,7 +574,9 @@
if (auto drawingArea = _page->drawingArea())
drawingArea->updateDebugIndicator();
- [self _updateUnscaledView];
+
+ if (!withinEpsilon(oldDisplayedContentScale, zoomScale))
+ [self _updateUnscaledView];
}
- (void)setMinimumSize:(CGSize)size
Modified: trunk/Source/WebKit2/UIProcess/ios/WKContentViewInteraction.h (170599 => 170600)
--- trunk/Source/WebKit2/UIProcess/ios/WKContentViewInteraction.h 2014-06-30 21:53:58 UTC (rev 170599)
+++ trunk/Source/WebKit2/UIProcess/ios/WKContentViewInteraction.h 2014-06-30 22:10:56 UTC (rev 170600)
@@ -100,7 +100,6 @@
RetainPtr<UITextInputTraits> _traits;
RetainPtr<UIWebFormAccessory> _formAccessoryView;
- RetainPtr<UIView> _highlightRootView;
RetainPtr<_UIHighlightView> _highlightView;
RetainPtr<UIView> _inverseScaleRootView;
RetainPtr<NSString> _markedText;
@@ -122,7 +121,7 @@
WebCore::IntSize bottomLeftRadius;
WebCore::IntSize bottomRightRadius;
};
- std::unique_ptr<TapHighlightInformation> _potentialTapHighlightInformation;
+ TapHighlightInformation _tapHighlightInformation;
WebKit::WKAutoCorrectionData _autocorrectionData;
WebKit::InteractionInformationAtPosition _positionInformation;
@@ -136,6 +135,7 @@
BOOL _hasValidPositionInformation;
BOOL _isTapHighlightIDValid;
BOOL _potentialTapInProgress;
+ BOOL _hasTapHighlightForPotentialTap;
BOOL _selectionNeedsUpdate;
BOOL _usingGestureForSelection;
BOOL _inspectorNodeSearchEnabled;
@@ -185,4 +185,9 @@
- (void)_disableInspectorNodeSearch;
@end
+static inline bool withinEpsilon(float a, float b)
+{
+ return fabs(a - b) < std::numeric_limits<float>::epsilon();
+}
+
#endif // PLATFORM(IOS)
Modified: trunk/Source/WebKit2/UIProcess/ios/WKContentViewInteraction.mm (170599 => 170600)
--- trunk/Source/WebKit2/UIProcess/ios/WKContentViewInteraction.mm 2014-06-30 21:53:58 UTC (rev 170599)
+++ trunk/Source/WebKit2/UIProcess/ios/WKContentViewInteraction.mm 2014-06-30 22:10:56 UTC (rev 170600)
@@ -71,6 +71,7 @@
static const float highlightDelay = 0.12;
static const float tapAndHoldDelay = 0.75;
+const CGFloat minimumTapHighlightRadius = 2.0;
@interface WKTextRange : UITextRange {
CGRect _startRect;
@@ -267,7 +268,6 @@
[_formInputSession invalidate];
_formInputSession = nil;
[_highlightView removeFromSuperview];
- [_highlightRootView removeFromSuperview];
[_inverseScaleRootView removeFromSuperview];
[_touchEventGestureRecognizer setDelegate:nil];
[self removeGestureRecognizer:_touchEventGestureRecognizer.get()];
@@ -339,6 +339,7 @@
[_inverseScaleRootView setTransform:CGAffineTransformMakeScale(inverseScale, inverseScale)];
_selectionNeedsUpdate = YES;
[self _updateChangedSelection];
+ [self _updateTapHighlight];
}
- (void)_enableInspectorNodeSearch
@@ -507,35 +508,25 @@
return true;
}
-- (void)_showTapHighlightWithColor:(const WebCore::Color&)color quads:(const Vector<WebCore::FloatQuad>&)highlightedQuads topLeftRadius:(const WebCore::IntSize&)topLeftRadius topRightRadius:(const WebCore::IntSize&)topRightRadius bottomLeftRadius:(const WebCore::IntSize&)bottomLeftRadius bottomRightRadius:(const WebCore::IntSize&)bottomRightRadius
+static NSValue *nsSizeForTapHighlightBorderRadius(WebCore::IntSize borderRadius)
{
- if (!highlightedQuadsAreSmallerThanRect(highlightedQuads, _page->unobscuredContentRect()))
+ return [NSValue valueWithCGSize:CGSizeMake(borderRadius.width() + minimumTapHighlightRadius, borderRadius.height() + minimumTapHighlightRadius)]
+}
+
+- (void)_updateTapHighlight
+{
+ if (![_highlightView superview])
return;
- const CGFloat UIWebViewMinimumHighlightRadius = 2.0;
-
- if (!_highlightRootView) {
- _highlightRootView = adoptNS([[UIView alloc] init]);
- [_highlightRootView setOpaque:NO];
- [_highlightRootView layer].anchorPoint = CGPointMake(0, 0);
-
- _highlightView = adoptNS([[_UIHighlightView alloc] initWithFrame:CGRectZero]);
- [_highlightView setOpaque:NO];
- [_highlightView setCornerRadius:UIWebViewMinimumHighlightRadius];
- [_highlightRootView addSubview:_highlightView.get()];
- }
- [self addSubview:_highlightRootView.get()];
- CGFloat selfScale = [[self layer] transform].m11;
- CGFloat highlightViewScale = 1 / selfScale;
- [_highlightRootView setTransform:CGAffineTransformMakeScale(highlightViewScale, highlightViewScale)];
-
{
- RetainPtr<UIColor> highlightUIKitColor = adoptNS([[UIColor alloc] initWithRed:(color.red() / 255.0) green:(color.green() / 255.0) blue:(color.blue() / 255.0) alpha:(color.alpha() / 255.0)]);
+ RetainPtr<UIColor> highlightUIKitColor = adoptNS([[UIColor alloc] initWithCGColor:cachedCGColor(_tapHighlightInformation.color, WebCore::ColorSpaceDeviceRGB)]);
[_highlightView setColor:highlightUIKitColor.get()];
}
+ CGFloat selfScale = self.layer.transform.m11;
bool allHighlightRectsAreRectilinear = true;
float deviceScaleFactor = _page->deviceScaleFactor();
+ const Vector<WebCore::FloatQuad>& highlightedQuads = _tapHighlightInformation.quads;
const size_t quadCount = highlightedQuads.size();
RetainPtr<NSMutableArray> rects = adoptNS([[NSMutableArray alloc] initWithCapacity:static_cast<const NSUInteger>(quadCount)]);
for (size_t i = 0; i < quadCount; ++i) {
@@ -543,7 +534,7 @@
if (quad.isRectilinear()) {
FloatRect boundingBox = quad.boundingBox();
boundingBox.scale(selfScale);
- boundingBox.inflate(UIWebViewMinimumHighlightRadius);
+ boundingBox.inflate(minimumTapHighlightRadius);
CGRect pixelAlignedRect = static_cast<CGRect>(enclosingRectExtendedToDevicePixels(boundingBox, deviceScaleFactor));
[rects addObject:[NSValue valueWithCGRect:pixelAlignedRect]];
} else {
@@ -560,7 +551,7 @@
for (size_t i = 0; i < quadCount; ++i) {
FloatQuad quad = highlightedQuads[i];
quad.scale(selfScale, selfScale);
- FloatQuad extendedQuad = inflateQuad(quad, UIWebViewMinimumHighlightRadius);
+ FloatQuad extendedQuad = inflateQuad(quad, minimumTapHighlightRadius);
[quads addObject:[NSValue valueWithCGPoint:extendedQuad.p1()]];
[quads addObject:[NSValue valueWithCGPoint:extendedQuad.p2()]];
[quads addObject:[NSValue valueWithCGPoint:extendedQuad.p3()]];
@@ -570,35 +561,48 @@
}
RetainPtr<NSMutableArray> borderRadii = adoptNS([[NSMutableArray alloc] initWithCapacity:4]);
- [borderRadii addObject:[NSValue valueWithCGSize:CGSizeMake(topLeftRadius.width() + UIWebViewMinimumHighlightRadius, topLeftRadius.height() + UIWebViewMinimumHighlightRadius)]];
- [borderRadii addObject:[NSValue valueWithCGSize:CGSizeMake(topRightRadius.width() + UIWebViewMinimumHighlightRadius, topRightRadius.height() + UIWebViewMinimumHighlightRadius)]];
- [borderRadii addObject:[NSValue valueWithCGSize:CGSizeMake(bottomLeftRadius.width() + UIWebViewMinimumHighlightRadius, bottomLeftRadius.height() + UIWebViewMinimumHighlightRadius)]];
- [borderRadii addObject:[NSValue valueWithCGSize:CGSizeMake(bottomRightRadius.width() + UIWebViewMinimumHighlightRadius, bottomRightRadius.height() + UIWebViewMinimumHighlightRadius)]];
+ [borderRadii addObject:nsSizeForTapHighlightBorderRadius(_tapHighlightInformation.topLeftRadius)];
+ [borderRadii addObject:nsSizeForTapHighlightBorderRadius(_tapHighlightInformation.topRightRadius)];
+ [borderRadii addObject:nsSizeForTapHighlightBorderRadius(_tapHighlightInformation.bottomLeftRadius)];
+ [borderRadii addObject:nsSizeForTapHighlightBorderRadius(_tapHighlightInformation.bottomRightRadius)];
[_highlightView setCornerRadii:borderRadii.get()];
}
+- (void)_showTapHighlight
+{
+ if (!highlightedQuadsAreSmallerThanRect(_tapHighlightInformation.quads, _page->unobscuredContentRect()))
+ return;
+
+ if (!_highlightView) {
+ _highlightView = adoptNS([[_UIHighlightView alloc] initWithFrame:CGRectZero]);
+ [_highlightView setOpaque:NO];
+ [_highlightView setCornerRadius:minimumTapHighlightRadius];
+ }
+ [_highlightView layer].opacity = 1;
+ [_inverseScaleRootView addSubview:_highlightView.get()];
+ [self _updateTapHighlight];
+}
+
- (void)_didGetTapHighlightForRequest:(uint64_t)requestID color:(const WebCore::Color&)color quads:(const Vector<WebCore::FloatQuad>&)highlightedQuads topLeftRadius:(const WebCore::IntSize&)topLeftRadius topRightRadius:(const WebCore::IntSize&)topRightRadius bottomLeftRadius:(const WebCore::IntSize&)bottomLeftRadius bottomRightRadius:(const WebCore::IntSize&)bottomRightRadius
{
if (!_isTapHighlightIDValid || _latestTapHighlightID != requestID)
return;
+ _isTapHighlightIDValid = NO;
+
+ _tapHighlightInformation.color = color;
+ _tapHighlightInformation.quads = highlightedQuads;
+ _tapHighlightInformation.topLeftRadius = topLeftRadius;
+ _tapHighlightInformation.topRightRadius = topRightRadius;
+ _tapHighlightInformation.bottomLeftRadius = bottomLeftRadius;
+ _tapHighlightInformation.bottomRightRadius = bottomRightRadius;
+
if (_potentialTapInProgress) {
- _potentialTapHighlightInformation = std::make_unique<TapHighlightInformation>();
- _potentialTapHighlightInformation->color = color;
- _potentialTapHighlightInformation->quads = highlightedQuads;
- _potentialTapHighlightInformation->topLeftRadius = topLeftRadius;
- _potentialTapHighlightInformation->topRightRadius = topRightRadius;
- _potentialTapHighlightInformation->bottomLeftRadius = bottomLeftRadius;
- _potentialTapHighlightInformation->bottomRightRadius = bottomRightRadius;
+ _hasTapHighlightForPotentialTap = YES;
return;
}
- [self _showTapHighlightWithColor:color
- quads:highlightedQuads
- topLeftRadius:topLeftRadius
- topRightRadius:topRightRadius
- bottomLeftRadius:bottomLeftRadius
- bottomRightRadius:bottomRightRadius];
+ [self _showTapHighlight];
}
- (void)_cancelLongPressGestureRecognizer
@@ -798,20 +802,18 @@
- (void)_cancelInteraction
{
- _isTapHighlightIDValid = NO;
- [_highlightRootView removeFromSuperview];
+ [_highlightView removeFromSuperview];
}
- (void)_finishInteraction
{
[UIView animateWithDuration:0.1
animations:^{
- [[_highlightRootView layer] setOpacity:0];
+ [_highlightView layer].opacity = 0;
}
- completion:^(BOOL){
- _isTapHighlightIDValid = NO;
- [_highlightRootView removeFromSuperview];
- [[_highlightRootView layer] setOpacity:1];
+ completion:^(BOOL finished){
+ if (finished)
+ [_highlightView removeFromSuperview];
}];
}
@@ -917,7 +919,6 @@
ASSERT(gestureRecognizer == _singleTapGestureRecognizer);
if (_potentialTapInProgress) {
_potentialTapInProgress = NO;
- _potentialTapHighlightInformation = nullptr;
[self _cancelInteraction];
_page->cancelPotentialTap();
}
@@ -952,14 +953,9 @@
_potentialTapInProgress = NO;
- if (_potentialTapHighlightInformation) {
- [self _showTapHighlightWithColor:_potentialTapHighlightInformation->color
- quads:_potentialTapHighlightInformation->quads
- topLeftRadius:_potentialTapHighlightInformation->topLeftRadius
- topRightRadius:_potentialTapHighlightInformation->topRightRadius
- bottomLeftRadius:_potentialTapHighlightInformation->bottomLeftRadius
- bottomRightRadius:_potentialTapHighlightInformation->bottomRightRadius];
- _potentialTapHighlightInformation = nullptr;
+ if (_hasTapHighlightForPotentialTap) {
+ [self _showTapHighlight];
+ _hasTapHighlightForPotentialTap = NO;
}
_page->commitPotentialTap();