1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "ContentHelper.h"
8 #include "nsContainerFrame.h"
9 #include "nsIContent.h"
10 #include "nsIScrollableFrame.h"
11 #include "nsLayoutUtils.h"
12 #include "nsStyleConsts.h"
19 ContentHelper::GetTouchActionFromFrame(nsIFrame
* aFrame
)
21 // If aFrame is null then return default value
23 return NS_STYLE_TOUCH_ACTION_AUTO
;
26 // The touch-action CSS property applies to: all elements except:
27 // non-replaced inline elements, table rows, row groups, table columns, and column groups
28 bool isNonReplacedInlineElement
= aFrame
->IsFrameOfType(nsIFrame::eLineParticipant
);
29 if (isNonReplacedInlineElement
) {
30 return NS_STYLE_TOUCH_ACTION_AUTO
;
33 const nsStyleDisplay
* disp
= aFrame
->StyleDisplay();
34 bool isTableElement
= disp
->IsInnerTableStyle() &&
35 disp
->mDisplay
!= NS_STYLE_DISPLAY_TABLE_CELL
&&
36 disp
->mDisplay
!= NS_STYLE_DISPLAY_TABLE_CAPTION
;
38 return NS_STYLE_TOUCH_ACTION_AUTO
;
41 return disp
->mTouchAction
;
45 ContentHelper::UpdateAllowedBehavior(uint32_t aTouchActionValue
, bool aConsiderPanning
, TouchBehaviorFlags
& aOutBehavior
)
47 if (aTouchActionValue
!= NS_STYLE_TOUCH_ACTION_AUTO
) {
48 // Double-tap-zooming need property value AUTO
49 aOutBehavior
&= ~AllowedTouchBehavior::DOUBLE_TAP_ZOOM
;
50 if (aTouchActionValue
!= NS_STYLE_TOUCH_ACTION_MANIPULATION
) {
51 // Pinch-zooming need value AUTO or MANIPULATION
52 aOutBehavior
&= ~AllowedTouchBehavior::PINCH_ZOOM
;
56 if (aConsiderPanning
) {
57 if (aTouchActionValue
== NS_STYLE_TOUCH_ACTION_NONE
) {
58 aOutBehavior
&= ~AllowedTouchBehavior::VERTICAL_PAN
;
59 aOutBehavior
&= ~AllowedTouchBehavior::HORIZONTAL_PAN
;
62 // Values pan-x and pan-y set at the same time to the same element do not affect panning constraints.
63 // Therefore we need to check whether pan-x is set without pan-y and the same for pan-y.
64 if ((aTouchActionValue
& NS_STYLE_TOUCH_ACTION_PAN_X
) && !(aTouchActionValue
& NS_STYLE_TOUCH_ACTION_PAN_Y
)) {
65 aOutBehavior
&= ~AllowedTouchBehavior::VERTICAL_PAN
;
66 } else if ((aTouchActionValue
& NS_STYLE_TOUCH_ACTION_PAN_Y
) && !(aTouchActionValue
& NS_STYLE_TOUCH_ACTION_PAN_X
)) {
67 aOutBehavior
&= ~AllowedTouchBehavior::HORIZONTAL_PAN
;
72 ContentHelper::TouchBehaviorFlags
73 ContentHelper::GetAllowedTouchBehavior(nsIWidget
* aWidget
, const nsIntPoint
& aPoint
)
75 nsView
*view
= nsView::GetViewFor(aWidget
);
76 nsIFrame
*viewFrame
= view
->GetFrame();
78 nsPoint relativePoint
= nsLayoutUtils::GetEventCoordinatesRelativeTo(aWidget
, aPoint
, viewFrame
);
80 nsIFrame
*target
= nsLayoutUtils::GetFrameForPoint(viewFrame
, relativePoint
, nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME
);
81 nsIScrollableFrame
*nearestScrollableParent
= nsLayoutUtils::GetNearestScrollableFrame(target
, 0);
82 nsIFrame
* nearestScrollableFrame
= do_QueryFrame(nearestScrollableParent
);
84 // We're walking up the DOM tree until we meet the element with touch behavior and accumulating
85 // touch-action restrictions of all elements in this chain.
86 // The exact quote from the spec, that clarifies more:
87 // To determine the effect of a touch, find the nearest ancestor (starting from the element itself)
88 // that has a default touch behavior. Then examine the touch-action property of each element between
89 // the hit tested element and the element with the default touch behavior (including both the hit
90 // tested element and the element with the default touch behavior). If the touch-action property of
91 // any of those elements disallows the default touch behavior, do nothing. Otherwise allow the element
92 // to start considering the touch for the purposes of executing a default touch behavior.
94 // Currently we support only two touch behaviors: panning and zooming.
95 // For panning we walk up until we meet the first scrollable element (the element that supports panning)
97 // For zooming we walk up until the root element since Firefox currently supports only zooming of the
98 // root frame but not the subframes.
100 bool considerPanning
= true;
101 TouchBehaviorFlags behavior
= AllowedTouchBehavior::VERTICAL_PAN
| AllowedTouchBehavior::HORIZONTAL_PAN
|
102 AllowedTouchBehavior::PINCH_ZOOM
| AllowedTouchBehavior::DOUBLE_TAP_ZOOM
;
104 for (nsIFrame
*frame
= target
; frame
&& frame
->GetContent() && behavior
; frame
= frame
->GetParent()) {
105 UpdateAllowedBehavior(GetTouchActionFromFrame(frame
), considerPanning
, behavior
);
107 if (frame
== nearestScrollableFrame
) {
108 // We met the scrollable element, after it we shouldn't consider touch-action
109 // values for the purpose of panning but only for zooming.
110 considerPanning
= false;