Bug 979345 - Implement "touch-action: manipulation" CSS value for Pointer Events. r=kats, r=botond, r=dbaron, r=mbrubeck
☠☠ backed out by 3215c7fc090b ☠ ☠
authorMaksim Lebedev <alessarik@gmail.com>
Tue, 22 Apr 2014 14:27:02 -0700
changeset 198168 039b15c9b84e10c738f47c81ff03deb4fabd0a66
parent 198167 1e1d541b2f3c3cd532f6ed8ade50336e998d2db6
child 198169 a12ca6c8b89bff34ed3e60161da911f90ed87b4c
push id3624
push userasasaki@mozilla.com
push dateMon, 09 Jun 2014 21:49:01 +0000
treeherdermozilla-beta@b1a5da15899a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskats, botond, dbaron, mbrubeck
bugs979345
milestone31.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 979345 - Implement "touch-action: manipulation" CSS value for Pointer Events. r=kats, r=botond, r=dbaron, r=mbrubeck
gfx/layers/apz/src/APZCTreeManager.h
gfx/layers/apz/src/AsyncPanZoomController.cpp
gfx/layers/apz/src/AsyncPanZoomController.h
gfx/tests/gtest/TestAsyncPanZoomController.cpp
layout/style/nsCSSKeywordList.h
layout/style/nsCSSParser.cpp
layout/style/nsCSSProps.cpp
layout/style/nsCSSValue.cpp
layout/style/nsComputedDOMStyle.cpp
layout/style/nsStyleConsts.h
layout/style/test/property_database.js
widget/xpwidgets/ContentHelper.cpp
--- a/gfx/layers/apz/src/APZCTreeManager.h
+++ b/gfx/layers/apz/src/APZCTreeManager.h
@@ -27,18 +27,19 @@ namespace mozilla {
 class InputData;
 
 namespace layers {
 
 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;
 class AsyncPanZoomController;
 class CompositorParent;
 
 /**
  * ****************** NOTE ON LOCK ORDERING IN APZ **************************
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -228,17 +228,18 @@ typedef GeckoContentController::APZState
  * documentation for the skate size multipliers above).
  */
 
 /**
  * Default touch behavior (is used when not touch behavior is set).
  */
 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
  */
 static const double AXIS_LOCK_ANGLE = M_PI / 6.0; // 30 degrees
 
 /**
  * The distance in inches the user must pan before axis lock can be broken
@@ -776,17 +777,17 @@ nsEventStatus AsyncPanZoomController::On
   OnTouchEndOrCancel();
   SetState(NOTHING);
   return nsEventStatus_eConsumeNoDefault;
 }
 
 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;
   }
 
   if (!mZoomConstraints.mAllowZoom) {
     return nsEventStatus_eConsumeNoDefault;
   }
 
   SetState(PINCHING);
@@ -967,39 +968,38 @@ void AsyncPanZoomController::OnTouchEndO
         GetGuid(), APZStateChange::EndTouch, mTouchBlockState.mSingleTapOccurred);
   }
 }
 
 nsEventStatus AsyncPanZoomController::OnSingleTapUp(const TapGestureInput& aEvent) {
   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;
 }
 
 nsEventStatus AsyncPanZoomController::OnSingleTapConfirmed(const TapGestureInput& aEvent) {
   APZC_LOG("%p got a single-tap-confirmed in state %d\n", this, mState);
   return GenerateSingleTap(aEvent.mPoint, aEvent.modifiers);
 }
 
 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;
 }
 
 nsEventStatus AsyncPanZoomController::OnCancelTap(const TapGestureInput& aEvent) {
   APZC_LOG("%p got a cancel-tap in state %d\n", this, mState);
   // XXX: Implement this.
@@ -1956,29 +1956,39 @@ void AsyncPanZoomController::CheckConten
 
       mTouchQueue.RemoveElementAt(0);
     }
 
     mHandlingTouchQueue = false;
   }
 }
 
-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;
 }
 
 AsyncPanZoomController::TouchBehaviorFlags
 AsyncPanZoomController::GetTouchBehavior(uint32_t touchIndex) {
   if (touchIndex < mTouchBlockState.mAllowedTouchBehaviors.Length()) {
     return mTouchBlockState.mAllowedTouchBehaviors[touchIndex];
   }
--- a/gfx/layers/apz/src/AsyncPanZoomController.h
+++ b/gfx/layers/apz/src/AsyncPanZoomController.h
@@ -590,19 +590,24 @@ private:
     // Specifies whether mPreventDefault property is set for this touch events block.
     bool mPreventDefaultSet;
 
     // Specifies whether a single tap event was generated during this touch block.
     bool mSingleTapOccurred;
   };
 
   /*
-   * 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.
    * In case apzc didn't receive touch behavior values within the timeout
    * it returns default value.
    */
   TouchBehaviorFlags GetTouchBehavior(uint32_t touchIndex);
 
--- a/gfx/tests/gtest/TestAsyncPanZoomController.cpp
+++ b/gfx/tests/gtest/TestAsyncPanZoomController.cpp
@@ -410,17 +410,17 @@ TEST_F(AsyncPanZoomControllerTester, Pin
 
   // Apzc's OnScaleEnd method calls once SendAsyncScrollDOMEvent and RequestContentRepaint methods,
   // therefore we're setting these specific values.
   EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(AtMost(1));
   EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(AtMost(1));
 
   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);
   ApzcPinch(apzc, 250, 300, 1.25);
 
   // The frame metrics should stay the same since touch-action:none makes
   // apzc ignore pinch gestures.
   fm = apzc->GetFrameMetrics();
@@ -901,27 +901,27 @@ DoLongPressPreventDefaultTest(bool aShou
 
 TEST_F(AsyncPanZoomControllerTester, LongPress) {
   DoLongPressTest(false, mozilla::layers::AllowedTouchBehavior::NONE);
 }
 
 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) {
   DoLongPressPreventDefaultTest(false, mozilla::layers::AllowedTouchBehavior::NONE);
 }
 
 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
 static already_AddRefed<mozilla::layers::Layer>
 CreateTestLayerTree1(nsRefPtr<LayerManager>& aLayerManager, nsTArray<nsRefPtr<Layer> >& aLayers) {
   const char* layerTreeSyntax = "c(ttcc)";
   // LayerID                     0 1234
   nsIntRegion layerVisibleRegion[] = {
--- a/layout/style/nsCSSKeywordList.h
+++ b/layout/style/nsCSSKeywordList.h
@@ -367,16 +367,17 @@ CSS_KEY(looped, looped)
 CSS_KEY(lower-alpha, lower_alpha)
 CSS_KEY(lower-greek, lower_greek)
 CSS_KEY(lower-latin, lower_latin)
 CSS_KEY(lower-roman, lower_roman)
 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)
 CSS_KEY(matrix, matrix)
 CSS_KEY(matrix3d, matrix3d)
 CSS_KEY(max-content, max_content)
 CSS_KEY(medium, medium)
 CSS_KEY(menu, menu)
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -12400,18 +12400,20 @@ CSSParserImpl::ParseTextOverflow(nsCSSVa
     aValue = left;
   }
   return true;
 }
 
 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;
   }
 
   // Auto and None keywords aren't allowed in conjunction with others.
   // Also inherit, initial and unset values are available.
   if (eCSSUnit_Enumerated != aValue.GetUnit()) {
     return true;
   }
@@ -12421,16 +12423,23 @@ CSSParserImpl::ParseTouchAction(nsCSSVal
   if (ParseEnum(nextValue, nsCSSProps::kTouchActionKTable)) {
     int32_t nextIntValue = nextValue.GetIntValue();
 
     // duplicates aren't allowed.
     if (nextIntValue & intValue) {
       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);
   }
 
   return true;
 }
 
 bool
 CSSParserImpl::ParseTextCombineUpright(nsCSSValue& aValue)
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -1615,19 +1615,22 @@ const KTableValue nsCSSProps::kTextTrans
   eCSSKeyword_capitalize, NS_STYLE_TEXT_TRANSFORM_CAPITALIZE,
   eCSSKeyword_lowercase, NS_STYLE_TEXT_TRANSFORM_LOWERCASE,
   eCSSKeyword_uppercase, NS_STYLE_TEXT_TRANSFORM_UPPERCASE,
   eCSSKeyword_full_width, NS_STYLE_TEXT_TRANSFORM_FULLWIDTH,
   eCSSKeyword_UNKNOWN,-1
 };
 
 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[] = {
   eCSSKeyword_ease, NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE,
   eCSSKeyword_linear, NS_STYLE_TRANSITION_TIMING_FUNCTION_LINEAR,
   eCSSKeyword_ease_in, NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE_IN,
   eCSSKeyword_ease_out, NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE_OUT,
   eCSSKeyword_ease_in_out, NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE_IN_OUT,
--- a/layout/style/nsCSSValue.cpp
+++ b/layout/style/nsCSSValue.cpp
@@ -1043,18 +1043,18 @@ nsCSSValue::AppendToString(nsCSSProperty
     case eCSSProperty_grid_row_start:
     case eCSSProperty_grid_row_end:
       // "span" is the only enumerated-unit value for these properties
       aResult.AppendLiteral("span");
       break;
 
     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;
 
     default:
       const nsAFlatCString& name = nsCSSProps::LookupPropertyValue(aProperty, intValue);
       AppendASCIItoUTF16(name, aResult);
       break;
     }
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -4058,30 +4058,24 @@ nsComputedDOMStyle::DoGetPageBreakInside
 
 CSSValue*
 nsComputedDOMStyle::DoGetTouchAction()
 {
   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
 
   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;
 }
 
 CSSValue*
 nsComputedDOMStyle::DoGetHeight()
 {
   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
 
--- a/layout/style/nsStyleConsts.h
+++ b/layout/style/nsStyleConsts.h
@@ -774,16 +774,17 @@ static inline mozilla::css::Side operato
 #define NS_STYLE_TEXT_TRANSFORM_UPPERCASE       3
 #define NS_STYLE_TEXT_TRANSFORM_FULLWIDTH       4
 
 // See nsStyleDisplay
 #define NS_STYLE_TOUCH_ACTION_NONE            (1 << 0)
 #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
 #define NS_STYLE_TRANSITION_TIMING_FUNCTION_LINEAR       1
 #define NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE_IN      2
 #define NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE_OUT     3
 #define NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE_IN_OUT  4
 #define NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_START   5
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -4368,20 +4368,27 @@ function get_computed_value(cs, property
 }
 
 if (SpecialPowers.getBoolPref("layout.css.touch_action.enabled")) {
     gCSSProperties["touch-action"] = {
         domProp: "touchAction",
         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"]
     };
 }
 
 if (SpecialPowers.getBoolPref("layout.css.vertical-text.enabled")) {
 	var verticalTextProperties = {
 		"writing-mode": {
 			domProp: "writingMode",
 			inherited: true,
--- a/widget/xpwidgets/ContentHelper.cpp
+++ b/widget/xpwidgets/ContentHelper.cpp
@@ -30,19 +30,22 @@ ContentHelper::GetTouchActionFromFrame(n
 
   return (aFrame->GetContent()->GetPrimaryFrame()->StyleDisplay()->mTouchAction);
 }
 
 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) {
     if (aTouchActionValue == NS_STYLE_TOUCH_ACTION_NONE) {
       aOutBehavior &= ~AllowedTouchBehavior::VERTICAL_PAN;
       aOutBehavior &= ~AllowedTouchBehavior::HORIZONTAL_PAN;
     }
 
@@ -81,25 +84,25 @@ ContentHelper::GetAllowedTouchBehavior(n
   // Currently we support only two touch behaviors: panning and zooming.
   // For panning we walk up until we meet the first scrollable element (the element that supports panning)
   // or root element.
   // For zooming we walk up until the root element since Firefox currently supports only zooming of the
   // root frame but not the subframes.
 
   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);
 
     if (frame == nearestScrollableFrame) {
       // We met the scrollable element, after it we shouldn't consider touch-action
       // values for the purpose of panning but only for zooming.
       considerPanning = false;
     }
   }
 
   return behavior;
 }
 
 }
-}
\ No newline at end of file
+}