1/* 2 * Copyright (C) 2010, 2011, 2012 Research In Motion Limited. All rights reserved. 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 19#ifndef FatFingers_h 20#define FatFingers_h 21 22#include "HitTestResult.h" 23#include "RenderLayer.h" 24 25#include <BlackBerryPlatformIntRectRegion.h> 26 27#include <utility> 28 29#include <wtf/HashSet.h> 30#include <wtf/ListHashSet.h> 31#include <wtf/Vector.h> 32 33namespace WebCore { 34class Document; 35class Element; 36class IntPoint; 37class IntRect; 38class IntSize; 39class Node; 40} 41 42#define DEBUG_FAT_FINGERS 0 43 44namespace BlackBerry { 45namespace WebKit { 46 47class WebPagePrivate; 48class FatFingersResult; 49class TouchEventHandler; 50 51 52class FatFingers { 53public: 54 enum TargetType { ClickableElement, Text }; 55 56 FatFingers(WebPagePrivate* webpage, const WebCore::IntPoint& contentPos, TargetType); 57 ~FatFingers(); 58 59 const FatFingersResult findBestPoint(); 60 61#if DEBUG_FAT_FINGERS 62 // These debug vars are all in content coordinates. They are public so 63 // they can be read from BackingStore, which will draw a visible rect 64 // around the fat fingers area. 65 static WebCore::IntRect m_debugFatFingerRect; 66 static WebCore::IntPoint m_debugFatFingerClickPosition; 67 static WebCore::IntPoint m_debugFatFingerAdjustedPosition; 68#endif 69 70private: 71 enum MatchingApproachForClickable { ClickableByDefault = 0, MadeClickableByTheWebpage, Done }; 72 73 typedef std::pair<WebCore::Node*, Platform::IntRectRegion> IntersectingRegion; 74 75 bool checkFingerIntersection(const Platform::IntRectRegion&, 76 const Platform::IntRectRegion& remainingFingerRegion, 77 WebCore::Node*, 78 Vector<IntersectingRegion>& intersectingRegions); 79 80 bool findIntersectingRegions(WebCore::Document*, 81 Vector<IntersectingRegion>& intersectingRegions, 82 Platform::IntRectRegion& remainingFingerRegion); 83 84 bool checkForClickableElement(WebCore::Element*, 85 Vector<IntersectingRegion>& intersectingRegions, 86 Platform::IntRectRegion& remainingFingerRegion, 87 WebCore::RenderLayer*& lowestPositionedEnclosingLayerSoFar); 88 89 bool checkForText(WebCore::Node*, 90 Vector<IntersectingRegion>& intersectingRegions, 91 Platform::IntRectRegion& fingerRegion); 92 93 void setSuccessfulFatFingersResult(FatFingersResult&, WebCore::Node*, const WebCore::IntPoint&); 94 95 void getNodesFromRect(WebCore::Document*, const WebCore::IntPoint&, ListHashSet<RefPtr<WebCore::Node> >&); 96 97 bool isElementClickable(WebCore::Element*) const; 98 99 inline WebCore::IntRect fingerRectForPoint(const WebCore::IntPoint&) const; 100 void getAdjustedPaddings(const WebCore::IntPoint&, unsigned& top, unsigned& right, unsigned& bottom, unsigned& left) const; 101 102 WebPagePrivate* m_webPage; 103 WebCore::IntPoint m_contentPos; 104 TargetType m_targetType; 105}; 106 107class FatFingersResult { 108public: 109 110 FatFingersResult(const WebCore::IntPoint& p = WebCore::IntPoint::zero(), const FatFingers::TargetType targetType = FatFingers::ClickableElement) 111 : m_originalPosition(p) 112 , m_adjustedPosition(p) 113 , m_targetType(targetType) 114 , m_positionWasAdjusted(false) 115 , m_isTextInput(false) 116 , m_isValid(false) 117 , m_nodeUnderFatFinger(0) 118 { 119 } 120 121 void reset() 122 { 123 m_originalPosition = m_adjustedPosition = WebCore::IntPoint::zero(); 124 m_positionWasAdjusted = false; 125 m_isTextInput = false; 126 m_isValid = false; 127 m_nodeUnderFatFinger = 0; 128 } 129 130 bool resultMatches(const WebCore::IntPoint& p, const FatFingers::TargetType targetType) const 131 { 132 return m_isValid && p == m_originalPosition && targetType == m_targetType; 133 } 134 135 WebCore::IntPoint originPosition() const { return m_originalPosition; } 136 WebCore::IntPoint adjustedPosition() const { return m_adjustedPosition; } 137 bool positionWasAdjusted() const { return m_isValid && m_positionWasAdjusted; } 138 bool isTextInput() const { return m_isValid && !!m_nodeUnderFatFinger && m_isTextInput; } 139 bool isValid() const { return m_isValid; } 140 141 enum ContentType { ShadowContentAllowed, ShadowContentNotAllowed }; 142 143 WebCore::Node* node(ContentType type = ShadowContentAllowed, bool shouldUseRootEditableElement = false) const 144 { 145 if (!m_nodeUnderFatFinger || !m_nodeUnderFatFinger->inDocument()) 146 return 0; 147 148 WebCore::Node* result = m_nodeUnderFatFinger.get(); 149 150 if (type == ShadowContentAllowed) 151 return result; 152 153 // Shadow trees can be nested. 154 while (result->isInShadowTree()) 155 result = toElement(result->deprecatedShadowAncestorNode()); 156 157 if (!shouldUseRootEditableElement || !result->isElementNode()) 158 return result; 159 160 // Retrieve the top level editable node 161 while (!result->isRootEditableElement()) { 162 WebCore::Element* parentElement = result->parentElement(); 163 if (!parentElement) 164 break; 165 result = parentElement; 166 } 167 168 return result; 169 } 170 171 WebCore::Element* nodeAsElementIfApplicable(ContentType type = ShadowContentAllowed, bool shouldUseRootEditableElement = false) const 172 { 173 WebCore::Node* result = node(type, shouldUseRootEditableElement); 174 if (!result || !result->isElementNode()) 175 return 0; 176 177 return static_cast<WebCore::Element*>(result); 178 } 179 180private: 181 friend class WebKit::FatFingers; 182 friend class WebKit::TouchEventHandler; 183 184 WebCore::IntPoint m_originalPosition; // Main frame contents coordinates. 185 WebCore::IntPoint m_adjustedPosition; // Main frame contents coordinates. 186 FatFingers::TargetType m_targetType; 187 bool m_positionWasAdjusted; 188 bool m_isTextInput; // Check if the element under the touch point will require a VKB be displayed so that the touch down can be suppressed. 189 bool m_isValid; 190 RefPtr<WebCore::Node> m_nodeUnderFatFinger; 191}; 192 193} 194} 195 196#endif // FatFingers_h 197 198