Bug 979345 - Implement "touch-action: manipulation" CSS value for Pointer Events. r=kats, r=botond, r=dbaron, r=mbrubeck

This commit is contained in:
Maksim Lebedev 2014-04-22 14:27:02 -07:00
parent 6f58a1c0ad
commit 02188c0e1a
12 changed files with 78 additions and 44 deletions

View File

@ -32,8 +32,9 @@ enum AllowedTouchBehavior {
NONE = 0,
VERTICAL_PAN = 1 << 0,
HORIZONTAL_PAN = 1 << 1,
ZOOM = 1 << 2,
UNKNOWN = 1 << 3
PINCH_ZOOM = 1 << 2,
DOUBLE_TAP_ZOOM = 1 << 3,
UNKNOWN = 1 << 4
};
class Layer;

View File

@ -233,7 +233,8 @@ typedef GeckoContentController::APZStateChange APZStateChange;
*/
static const uint32_t DefaultTouchBehavior = AllowedTouchBehavior::VERTICAL_PAN |
AllowedTouchBehavior::HORIZONTAL_PAN |
AllowedTouchBehavior::ZOOM;
AllowedTouchBehavior::PINCH_ZOOM |
AllowedTouchBehavior::DOUBLE_TAP_ZOOM;
/**
* Angle from axis within which we stay axis-locked
@ -781,7 +782,7 @@ nsEventStatus AsyncPanZoomController::OnTouchCancel(const MultiTouchInput& aEven
nsEventStatus AsyncPanZoomController::OnScaleBegin(const PinchGestureInput& aEvent) {
APZC_LOG("%p got a scale-begin in state %d\n", this, mState);
if (!TouchActionAllowZoom()) {
if (!TouchActionAllowPinchZoom()) {
return nsEventStatus_eIgnore;
}
@ -972,7 +973,7 @@ nsEventStatus AsyncPanZoomController::OnSingleTapUp(const TapGestureInput& aEven
APZC_LOG("%p got a single-tap-up in state %d\n", this, mState);
// If mZoomConstraints.mAllowDoubleTapZoom is true we wait for a call to OnSingleTapConfirmed before
// sending event to content
if (!mZoomConstraints.mAllowDoubleTapZoom) {
if (!(mZoomConstraints.mAllowDoubleTapZoom && TouchActionAllowDoubleTapZoom())) {
return GenerateSingleTap(aEvent.mPoint, aEvent.modifiers);
}
return nsEventStatus_eIgnore;
@ -987,14 +988,13 @@ nsEventStatus AsyncPanZoomController::OnDoubleTap(const TapGestureInput& aEvent)
APZC_LOG("%p got a double-tap in state %d\n", this, mState);
nsRefPtr<GeckoContentController> controller = GetGeckoContentController();
if (controller) {
if (mZoomConstraints.mAllowDoubleTapZoom) {
if (mZoomConstraints.mAllowDoubleTapZoom && TouchActionAllowDoubleTapZoom()) {
int32_t modifiers = WidgetModifiersToDOMModifiers(aEvent.modifiers);
CSSPoint geckoScreenPoint;
if (ConvertToGecko(aEvent.mPoint, &geckoScreenPoint)) {
controller->HandleDoubleTap(geckoScreenPoint, modifiers, GetGuid());
}
}
return nsEventStatus_eConsumeNoDefault;
}
return nsEventStatus_eIgnore;
@ -1961,19 +1961,29 @@ void AsyncPanZoomController::CheckContentResponse() {
}
}
bool AsyncPanZoomController::TouchActionAllowZoom() {
bool AsyncPanZoomController::TouchActionAllowPinchZoom() {
if (!mTouchActionPropertyEnabled) {
return true;
}
// Pointer events specification implies all touch points to allow zoom
// to perform it.
for (size_t i = 0; i < mTouchBlockState.mAllowedTouchBehaviors.Length(); i++) {
if (!(mTouchBlockState.mAllowedTouchBehaviors[i] & AllowedTouchBehavior::ZOOM)) {
if (!(mTouchBlockState.mAllowedTouchBehaviors[i] & AllowedTouchBehavior::PINCH_ZOOM)) {
return false;
}
}
return true;
}
bool AsyncPanZoomController::TouchActionAllowDoubleTapZoom() {
if (!mTouchActionPropertyEnabled) {
return true;
}
for (size_t i = 0; i < mTouchBlockState.mAllowedTouchBehaviors.Length(); i++) {
if (!(mTouchBlockState.mAllowedTouchBehaviors[i] & AllowedTouchBehavior::DOUBLE_TAP_ZOOM)) {
return false;
}
}
return true;
}

View File

@ -595,9 +595,14 @@ private:
};
/*
* Returns whether current touch behavior values allow zooming.
* Returns whether current touch behavior values allow pinch-zooming.
*/
bool TouchActionAllowZoom();
bool TouchActionAllowPinchZoom();
/*
* Returns whether current touch behavior values allow double-tap-zooming.
*/
bool TouchActionAllowDoubleTapZoom();
/*
* Returns allowed touch behavior from the mAllowedTouchBehavior array.

View File

@ -415,7 +415,7 @@ TEST_F(AsyncPanZoomControllerTester, PinchWithTouchActionNone) {
nsTArray<uint32_t> values;
values.AppendElement(mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN);
values.AppendElement(mozilla::layers::AllowedTouchBehavior::ZOOM);
values.AppendElement(mozilla::layers::AllowedTouchBehavior::PINCH_ZOOM);
apzc->SetTouchActionEnabled(true);
apzc->SetAllowedTouchBehavior(values);
@ -906,7 +906,7 @@ TEST_F(AsyncPanZoomControllerTester, LongPress) {
TEST_F(AsyncPanZoomControllerTester, LongPressWithTouchAction) {
DoLongPressTest(true, mozilla::layers::AllowedTouchBehavior::HORIZONTAL_PAN
| mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN
| mozilla::layers::AllowedTouchBehavior::ZOOM);
| mozilla::layers::AllowedTouchBehavior::PINCH_ZOOM);
}
TEST_F(AsyncPanZoomControllerTester, LongPressPreventDefault) {
@ -916,7 +916,7 @@ TEST_F(AsyncPanZoomControllerTester, LongPressPreventDefault) {
TEST_F(AsyncPanZoomControllerTester, LongPressPreventDefaultWithTouchAction) {
DoLongPressPreventDefaultTest(true, mozilla::layers::AllowedTouchBehavior::HORIZONTAL_PAN
| mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN
| mozilla::layers::AllowedTouchBehavior::ZOOM);
| mozilla::layers::AllowedTouchBehavior::PINCH_ZOOM);
}
// Layer tree for HitTesting1

View File

@ -372,6 +372,7 @@ CSS_KEY(lowercase, lowercase)
CSS_KEY(ltr, ltr)
CSS_KEY(luminance, luminance)
CSS_KEY(luminosity, luminosity)
CSS_KEY(manipulation, manipulation)
CSS_KEY(manual, manual)
CSS_KEY(margin-box, margin_box)
CSS_KEY(markers, markers)

View File

@ -12405,8 +12405,10 @@ CSSParserImpl::ParseTextOverflow(nsCSSValue& aValue)
bool
CSSParserImpl::ParseTouchAction(nsCSSValue& aValue)
{
if (!ParseVariant(aValue, VARIANT_HK | VARIANT_NONE | VARIANT_AUTO,
nsCSSProps::kTouchActionKTable)) {
// Avaliable values of property touch-action:
// auto | none | [pan-x || pan-y] | manipulation
if (!ParseVariant(aValue, VARIANT_HK, nsCSSProps::kTouchActionKTable)) {
return false;
}
@ -12426,6 +12428,13 @@ CSSParserImpl::ParseTouchAction(nsCSSValue& aValue)
return false;
}
// Auto and None and Manipulation is not allowed in conjunction with others.
if ((intValue | nextIntValue) & (NS_STYLE_TOUCH_ACTION_NONE |
NS_STYLE_TOUCH_ACTION_AUTO |
NS_STYLE_TOUCH_ACTION_MANIPULATION)) {
return false;
}
aValue.SetIntValue(nextIntValue | intValue, eCSSUnit_Enumerated);
}

View File

@ -1620,9 +1620,12 @@ const KTableValue nsCSSProps::kTextTransformKTable[] = {
};
const KTableValue nsCSSProps::kTouchActionKTable[] = {
eCSSKeyword_pan_x, NS_STYLE_TOUCH_ACTION_PAN_X,
eCSSKeyword_pan_y, NS_STYLE_TOUCH_ACTION_PAN_Y,
eCSSKeyword_UNKNOWN, -1
eCSSKeyword_none, NS_STYLE_TOUCH_ACTION_NONE,
eCSSKeyword_auto, NS_STYLE_TOUCH_ACTION_AUTO,
eCSSKeyword_pan_x, NS_STYLE_TOUCH_ACTION_PAN_X,
eCSSKeyword_pan_y, NS_STYLE_TOUCH_ACTION_PAN_Y,
eCSSKeyword_manipulation, NS_STYLE_TOUCH_ACTION_MANIPULATION,
eCSSKeyword_UNKNOWN, -1
};
const KTableValue nsCSSProps::kTransitionTimingFunctionKTable[] = {

View File

@ -1048,8 +1048,8 @@ nsCSSValue::AppendToString(nsCSSProperty aProperty, nsAString& aResult,
case eCSSProperty_touch_action:
nsStyleUtil::AppendBitmaskCSSValue(aProperty, intValue,
NS_STYLE_TOUCH_ACTION_PAN_X,
NS_STYLE_TOUCH_ACTION_PAN_Y,
NS_STYLE_TOUCH_ACTION_NONE,
NS_STYLE_TOUCH_ACTION_MANIPULATION,
aResult);
break;

View File

@ -4063,20 +4063,14 @@ nsComputedDOMStyle::DoGetTouchAction()
int32_t intValue = StyleDisplay()->mTouchAction;
// None and Auto values aren't allowed to be in conjunction with
// other values.
if (NS_STYLE_TOUCH_ACTION_AUTO == intValue) {
val->SetIdent(eCSSKeyword_auto);
} else if (NS_STYLE_TOUCH_ACTION_NONE == intValue) {
val->SetIdent(eCSSKeyword_none);
} else {
nsAutoString valueStr;
nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_touch_action,
intValue, NS_STYLE_TOUCH_ACTION_PAN_X,
NS_STYLE_TOUCH_ACTION_PAN_Y, valueStr);
val->SetString(valueStr);
}
// None and Auto and Manipulation values aren't allowed
// to be in conjunction with other values.
// But there are all checks in CSSParserImpl::ParseTouchAction
nsAutoString valueStr;
nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_touch_action, intValue,
NS_STYLE_TOUCH_ACTION_NONE, NS_STYLE_TOUCH_ACTION_MANIPULATION,
valueStr);
val->SetString(valueStr);
return val;
}

View File

@ -779,6 +779,7 @@ static inline mozilla::css::Side operator++(mozilla::css::Side& side, int) {
#define NS_STYLE_TOUCH_ACTION_AUTO (1 << 1)
#define NS_STYLE_TOUCH_ACTION_PAN_X (1 << 2)
#define NS_STYLE_TOUCH_ACTION_PAN_Y (1 << 3)
#define NS_STYLE_TOUCH_ACTION_MANIPULATION (1 << 4)
// See nsStyleDisplay
#define NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE 0

View File

@ -4373,10 +4373,17 @@ if (SpecialPowers.getBoolPref("layout.css.touch_action.enabled")) {
inherited: false,
type: CSS_TYPE_LONGHAND,
initial_values: ["auto"],
other_values: ["none", "pan-x", "pan-y", "pan-x pan-y", "pan-y pan-x"],
other_values: ["none", "pan-x", "pan-y", "pan-x pan-y", "pan-y pan-x", "manipulation"],
invalid_values: ["zoom", "pinch", "tap", "10px", "2", "auto pan-x", "pan-x auto", "none pan-x", "pan-x none",
"auto pan-y", "pan-y auto", "none pan-y", "pan-y none",
"pan-x pan-y none", "none pan-x pan-y", "pan-x pan-y auto", "auto pan-x pan-y"]
"auto pan-y", "pan-y auto", "none pan-y", "pan-y none", "pan-x pan-x", "pan-y pan-y",
"pan-x pan-y none", "pan-x none pan-y", "none pan-x pan-y", "pan-y pan-x none", "pan-y none pan-x", "none pan-y pan-x",
"pan-x pan-y auto", "pan-x auto pan-y", "auto pan-x pan-y", "pan-y pan-x auto", "pan-y auto pan-x", "auto pan-y pan-x",
"pan-x pan-y zoom", "pan-x zoom pan-y", "zoom pan-x pan-y", "pan-y pan-x zoom", "pan-y zoom pan-x", "zoom pan-y pan-x",
"pan-x pan-y pan-x", "pan-x pan-x pan-y", "pan-y pan-x pan-x", "pan-y pan-x pan-y", "pan-y pan-y pan-x", "pan-x pan-y pan-y",
"manipulation none", "none manipulation", "manipulation auto", "auto manipulation", "manipulation zoom", "zoom manipulation",
"manipulation manipulation", "manipulation pan-x", "pan-x manipulation", "manipulation pan-y", "pan-y manipulation",
"manipulation pan-x pan-y", "pan-x manipulation pan-y", "pan-x pan-y manipulation",
"manipulation pan-y pan-x", "pan-y manipulation pan-x", "pan-y pan-x manipulation"]
};
}

View File

@ -35,9 +35,12 @@ void
ContentHelper::UpdateAllowedBehavior(uint32_t aTouchActionValue, bool aConsiderPanning, TouchBehaviorFlags& aOutBehavior)
{
if (aTouchActionValue != NS_STYLE_TOUCH_ACTION_AUTO) {
// Dropping zoom flag since zooming requires touch-action values of all touches
// to be AUTO.
aOutBehavior &= ~AllowedTouchBehavior::ZOOM;
// Double-tap-zooming need property value AUTO
aOutBehavior &= ~AllowedTouchBehavior::DOUBLE_TAP_ZOOM;
if (aTouchActionValue != NS_STYLE_TOUCH_ACTION_MANIPULATION) {
// Pinch-zooming need value AUTO or MANIPULATION
aOutBehavior &= ~AllowedTouchBehavior::PINCH_ZOOM;
}
}
if (aConsiderPanning) {
@ -86,7 +89,7 @@ ContentHelper::GetAllowedTouchBehavior(nsIWidget* aWidget, const nsIntPoint& aPo
bool considerPanning = true;
TouchBehaviorFlags behavior = AllowedTouchBehavior::VERTICAL_PAN | AllowedTouchBehavior::HORIZONTAL_PAN |
AllowedTouchBehavior::ZOOM;
AllowedTouchBehavior::PINCH_ZOOM |
for (nsIFrame *frame = target; frame && frame->GetContent() && behavior; frame = frame->GetParent()) {
UpdateAllowedBehavior(GetTouchActionFromFrame(frame), considerPanning, behavior);
@ -102,4 +105,4 @@ ContentHelper::GetAllowedTouchBehavior(nsIWidget* aWidget, const nsIntPoint& aPo
}
}
}
}