Fri, 16 Jan 2015 04:50:19 +0100
Replace accessor implementation with direct member state manipulation, by
request https://trac.torproject.org/projects/tor/ticket/9701#comment:32
michael@0 | 1 | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 5 | |
michael@0 | 6 | #include "ContentHelper.h" |
michael@0 | 7 | #include "nsQueryFrame.h" |
michael@0 | 8 | #include "nsIContent.h" |
michael@0 | 9 | #include "nsIScrollableFrame.h" |
michael@0 | 10 | #include "nsLayoutUtils.h" |
michael@0 | 11 | #include "nsStyleConsts.h" |
michael@0 | 12 | #include "nsView.h" |
michael@0 | 13 | |
michael@0 | 14 | namespace mozilla { |
michael@0 | 15 | namespace widget { |
michael@0 | 16 | |
michael@0 | 17 | uint32_t |
michael@0 | 18 | ContentHelper::GetTouchActionFromFrame(nsIFrame* aFrame) |
michael@0 | 19 | { |
michael@0 | 20 | if (!aFrame || !aFrame->GetContent() || !aFrame->GetContent()->GetPrimaryFrame()) { |
michael@0 | 21 | // If frame is invalid or null then return default value. |
michael@0 | 22 | return NS_STYLE_TOUCH_ACTION_AUTO; |
michael@0 | 23 | } |
michael@0 | 24 | |
michael@0 | 25 | if (!aFrame->IsFrameOfType(nsIFrame::eSVG) && !aFrame->IsFrameOfType(nsIFrame::eBlockFrame)) { |
michael@0 | 26 | // Since touch-action property can be applied to only svg and block-level |
michael@0 | 27 | // elements we ignore frames of other types. |
michael@0 | 28 | return NS_STYLE_TOUCH_ACTION_AUTO; |
michael@0 | 29 | } |
michael@0 | 30 | |
michael@0 | 31 | return (aFrame->GetContent()->GetPrimaryFrame()->StyleDisplay()->mTouchAction); |
michael@0 | 32 | } |
michael@0 | 33 | |
michael@0 | 34 | void |
michael@0 | 35 | ContentHelper::UpdateAllowedBehavior(uint32_t aTouchActionValue, bool aConsiderPanning, TouchBehaviorFlags& aOutBehavior) |
michael@0 | 36 | { |
michael@0 | 37 | if (aTouchActionValue != NS_STYLE_TOUCH_ACTION_AUTO) { |
michael@0 | 38 | // Double-tap-zooming need property value AUTO |
michael@0 | 39 | aOutBehavior &= ~AllowedTouchBehavior::DOUBLE_TAP_ZOOM; |
michael@0 | 40 | if (aTouchActionValue != NS_STYLE_TOUCH_ACTION_MANIPULATION) { |
michael@0 | 41 | // Pinch-zooming need value AUTO or MANIPULATION |
michael@0 | 42 | aOutBehavior &= ~AllowedTouchBehavior::PINCH_ZOOM; |
michael@0 | 43 | } |
michael@0 | 44 | } |
michael@0 | 45 | |
michael@0 | 46 | if (aConsiderPanning) { |
michael@0 | 47 | if (aTouchActionValue == NS_STYLE_TOUCH_ACTION_NONE) { |
michael@0 | 48 | aOutBehavior &= ~AllowedTouchBehavior::VERTICAL_PAN; |
michael@0 | 49 | aOutBehavior &= ~AllowedTouchBehavior::HORIZONTAL_PAN; |
michael@0 | 50 | } |
michael@0 | 51 | |
michael@0 | 52 | // Values pan-x and pan-y set at the same time to the same element do not affect panning constraints. |
michael@0 | 53 | // Therefore we need to check whether pan-x is set without pan-y and the same for pan-y. |
michael@0 | 54 | if ((aTouchActionValue & NS_STYLE_TOUCH_ACTION_PAN_X) && !(aTouchActionValue & NS_STYLE_TOUCH_ACTION_PAN_Y)) { |
michael@0 | 55 | aOutBehavior &= ~AllowedTouchBehavior::VERTICAL_PAN; |
michael@0 | 56 | } else if ((aTouchActionValue & NS_STYLE_TOUCH_ACTION_PAN_Y) && !(aTouchActionValue & NS_STYLE_TOUCH_ACTION_PAN_X)) { |
michael@0 | 57 | aOutBehavior &= ~AllowedTouchBehavior::HORIZONTAL_PAN; |
michael@0 | 58 | } |
michael@0 | 59 | } |
michael@0 | 60 | } |
michael@0 | 61 | |
michael@0 | 62 | ContentHelper::TouchBehaviorFlags |
michael@0 | 63 | ContentHelper::GetAllowedTouchBehavior(nsIWidget* aWidget, const nsIntPoint& aPoint) |
michael@0 | 64 | { |
michael@0 | 65 | nsView *view = nsView::GetViewFor(aWidget); |
michael@0 | 66 | nsIFrame *viewFrame = view->GetFrame(); |
michael@0 | 67 | |
michael@0 | 68 | nsPoint relativePoint = nsLayoutUtils::GetEventCoordinatesRelativeTo(aWidget, aPoint, viewFrame); |
michael@0 | 69 | |
michael@0 | 70 | nsIFrame *target = nsLayoutUtils::GetFrameForPoint(viewFrame, relativePoint, nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME); |
michael@0 | 71 | nsIScrollableFrame *nearestScrollableParent = nsLayoutUtils::GetNearestScrollableFrame(target, 0); |
michael@0 | 72 | nsIFrame* nearestScrollableFrame = do_QueryFrame(nearestScrollableParent); |
michael@0 | 73 | |
michael@0 | 74 | // We're walking up the DOM tree until we meet the element with touch behavior and accumulating |
michael@0 | 75 | // touch-action restrictions of all elements in this chain. |
michael@0 | 76 | // The exact quote from the spec, that clarifies more: |
michael@0 | 77 | // To determine the effect of a touch, find the nearest ancestor (starting from the element itself) |
michael@0 | 78 | // that has a default touch behavior. Then examine the touch-action property of each element between |
michael@0 | 79 | // the hit tested element and the element with the default touch behavior (including both the hit |
michael@0 | 80 | // tested element and the element with the default touch behavior). If the touch-action property of |
michael@0 | 81 | // any of those elements disallows the default touch behavior, do nothing. Otherwise allow the element |
michael@0 | 82 | // to start considering the touch for the purposes of executing a default touch behavior. |
michael@0 | 83 | |
michael@0 | 84 | // Currently we support only two touch behaviors: panning and zooming. |
michael@0 | 85 | // For panning we walk up until we meet the first scrollable element (the element that supports panning) |
michael@0 | 86 | // or root element. |
michael@0 | 87 | // For zooming we walk up until the root element since Firefox currently supports only zooming of the |
michael@0 | 88 | // root frame but not the subframes. |
michael@0 | 89 | |
michael@0 | 90 | bool considerPanning = true; |
michael@0 | 91 | TouchBehaviorFlags behavior = AllowedTouchBehavior::VERTICAL_PAN | AllowedTouchBehavior::HORIZONTAL_PAN | |
michael@0 | 92 | AllowedTouchBehavior::PINCH_ZOOM | AllowedTouchBehavior::DOUBLE_TAP_ZOOM; |
michael@0 | 93 | |
michael@0 | 94 | for (nsIFrame *frame = target; frame && frame->GetContent() && behavior; frame = frame->GetParent()) { |
michael@0 | 95 | UpdateAllowedBehavior(GetTouchActionFromFrame(frame), considerPanning, behavior); |
michael@0 | 96 | |
michael@0 | 97 | if (frame == nearestScrollableFrame) { |
michael@0 | 98 | // We met the scrollable element, after it we shouldn't consider touch-action |
michael@0 | 99 | // values for the purpose of panning but only for zooming. |
michael@0 | 100 | considerPanning = false; |
michael@0 | 101 | } |
michael@0 | 102 | } |
michael@0 | 103 | |
michael@0 | 104 | return behavior; |
michael@0 | 105 | } |
michael@0 | 106 | |
michael@0 | 107 | } |
michael@0 | 108 | } |