|
1 /* |
|
2 * Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of the License "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: Frame in webkit side |
|
15 * |
|
16 */ |
|
17 |
|
18 #include "config.h" |
|
19 #include <../bidi.h> |
|
20 #include <e32math.h> |
|
21 #include <e32base.h> |
|
22 #include "WebTabbedNavigation.h" |
|
23 #include "WebUtil.h" |
|
24 #include "Document.h" |
|
25 #include "Frame.h" |
|
26 #include "HTMLNames.h" |
|
27 #include "FrameTree.h" |
|
28 #include "BrCtlDefs.h" |
|
29 #include "WebCursor.h" |
|
30 #include "StaticObjectsContainer.h" |
|
31 #include "Page.h" |
|
32 #include "WebView.h" |
|
33 #include "WebFrame.h" |
|
34 #include "WebFrameView.h" |
|
35 #include <wtf/RefPtr.h> |
|
36 #include "EventHandler.h" |
|
37 #include "webkitlogger.h" |
|
38 #include "FocusController.h" |
|
39 #include "RenderListBox.h" |
|
40 #include "HTMLSelectElement.h" |
|
41 |
|
42 using namespace WebCore; |
|
43 using namespace HTMLNames; |
|
44 |
|
45 const int KMaxJumpPercent = 90; |
|
46 const int KScrollWhenNotFound = 5; |
|
47 |
|
48 WebTabbedNavigation::WebTabbedNavigation(WebView* webView) |
|
49 { |
|
50 m_webView = webView; |
|
51 clear(); |
|
52 } |
|
53 |
|
54 WebTabbedNavigation::~WebTabbedNavigation() |
|
55 { |
|
56 } |
|
57 |
|
58 void WebTabbedNavigation::clear() |
|
59 { |
|
60 // Different initialization for mirrored layouts? |
|
61 m_selectedElementRect.SetRect(0, 0, m_webView->Rect().Width(), 0); |
|
62 m_initializedForPage = false; |
|
63 m_firstNavigationOnPage = true; |
|
64 m_focusPosition = TPoint(0,0); |
|
65 m_node = NULL; |
|
66 } |
|
67 |
|
68 void WebTabbedNavigation::initializeForPage() |
|
69 { |
|
70 if (!m_initializedForPage) { |
|
71 if (navigate(0, 1)) { |
|
72 m_initializedForPage = true; |
|
73 m_firstNavigationOnPage = false; |
|
74 } |
|
75 } |
|
76 } |
|
77 |
|
78 |
|
79 bool WebTabbedNavigation::navigate(int horizontalDir, int verticalDir) |
|
80 { |
|
81 if (handleSelectElementScrolling(m_webView, verticalDir)) { |
|
82 StaticObjectsContainer::instance()->webCursor()->cursorUpdate(true); |
|
83 return true; |
|
84 } |
|
85 bool ret = m_firstNavigationOnPage; |
|
86 Frame* focusedFrame = m_webView->page()->focusController()->focusedFrame(); |
|
87 if (focusedFrame == NULL) focusedFrame = m_webView->page()->mainFrame(); |
|
88 if (focusedFrame->document()) { |
|
89 Node* focusNode = focusedFrame->document()->focusedNode(); |
|
90 if (focusNode) { |
|
91 m_node = focusNode; |
|
92 m_selectedElementRect = focusNode->getRect().Rect(); |
|
93 Frame* frame = focusNode->document()->frame(); |
|
94 m_selectedElementRect = TRect(kit(frame)->frameView()->frameCoordsInViewCoords(m_selectedElementRect.iTl), |
|
95 kit(frame)->frameView()->frameCoordsInViewCoords(m_selectedElementRect.iBr)); |
|
96 } |
|
97 } |
|
98 TPoint oldFocusPoint(m_focusPosition); |
|
99 // Move the focus to the edge of the current object |
|
100 if (horizontalDir == -1) { |
|
101 m_focusPosition.iX = m_selectedElementRect.iTl.iX; |
|
102 } |
|
103 else if (horizontalDir == 1) { |
|
104 m_focusPosition.iX = m_selectedElementRect.iBr.iX; |
|
105 } |
|
106 if (verticalDir == -1) { |
|
107 m_focusPosition.iY = m_selectedElementRect.iTl.iY; |
|
108 } |
|
109 else if (verticalDir == 1) { |
|
110 m_focusPosition.iY = m_selectedElementRect.iBr.iY; |
|
111 } |
|
112 wkDebug()<<"WebTabbedNavigation::navigate. x = "<<m_focusPosition.iX<<" y = "<<m_focusPosition.iY<<flush; |
|
113 wkDebug()<<"x1 = "<<m_selectedElementRect.iTl.iX<<" y1 = "<<m_selectedElementRect.iTl.iY<<" x2 = "<<m_selectedElementRect.iBr.iX<<" y2 = "<<m_selectedElementRect.iBr.iY<<flush; |
|
114 |
|
115 // Adjust the move |
|
116 TPoint br; |
|
117 br.iX = m_webView->Rect().iBr.iX * KMaxJumpPercent / m_webView->scalingFactor(); |
|
118 br.iY = m_webView->Rect().iBr.iY * KMaxJumpPercent / m_webView->scalingFactor(); |
|
119 TRect view; |
|
120 // define the view rect where we are looking for a match |
|
121 if (horizontalDir == -1) { |
|
122 view.SetRect(m_focusPosition.iX - br.iX, m_focusPosition.iY - br.iY, m_focusPosition.iX, m_focusPosition.iY + br.iY); |
|
123 } |
|
124 else if (horizontalDir == 1) { |
|
125 view.SetRect(m_focusPosition.iX, m_focusPosition.iY - br.iY, m_focusPosition.iX + br.iX, m_focusPosition.iY + br.iY); |
|
126 } |
|
127 else if (verticalDir == -1) { |
|
128 view.SetRect(m_focusPosition.iX - br.iX, m_focusPosition.iY - br.iY, m_focusPosition.iX + br.iX, m_focusPosition.iY); |
|
129 } |
|
130 else if (verticalDir == 1) { |
|
131 view.SetRect(m_focusPosition.iX - br.iX, m_focusPosition.iY, m_focusPosition.iX + br.iX, m_focusPosition.iY + br.iY); |
|
132 } |
|
133 //wkDebug()<<"view x1 = "<<view.iTl.iX<<" y1 = "<<view.iTl.iY<<" x2 = "<<view.iBr.iX<<" y2 = "<<view.iBr.iY<<flush; |
|
134 // walk all focusable nodes |
|
135 Frame* f = m_webView->page()->mainFrame(); |
|
136 TPoint selectedPoint(0, 0); |
|
137 TRect selectedRect(0, 0, 0, 0); |
|
138 Node* selectedNode = NULL; |
|
139 while ( f ) { |
|
140 PassRefPtr<HTMLCollection> elements = f->document()->all(); |
|
141 TRect frameRect = kit(f)->frameView()->rectInGlobalCoords(); |
|
142 for (Node* n = elements->firstItem(); n; n = elements->nextItem()) { |
|
143 if (n == m_node) continue; |
|
144 if (n->isFocusable() && n->isElementNode() && !n->hasTagName(iframeTag) && !n->hasTagName(frameTag)) { |
|
145 // Does the node intersect with the view rect? |
|
146 TRect nodeRect = n->getRect().Rect(); |
|
147 //wkDebug()<<"Each node rect x1 = "<<nodeRect.iTl.iX<<" y1 = "<<nodeRect.iTl.iY<<" x2 = "<<nodeRect.iBr.iX<<" y2 = "<<nodeRect.iBr.iY<<flush; |
|
148 nodeRect = TRect(kit(f)->frameView()->frameCoordsInViewCoords(nodeRect.iTl), |
|
149 kit(f)->frameView()->frameCoordsInViewCoords(nodeRect.iBr)); |
|
150 if (nodeRect.Intersects(view)) { |
|
151 // Compare nodes and select the best fit |
|
152 TPoint newFocusPoint = potentialFocusPoint(horizontalDir, verticalDir, nodeRect); |
|
153 wkDebug()<<"Matching node rect x1 = "<<nodeRect.iTl.iX<<" y1 = "<<nodeRect.iTl.iY<<" x2 = "<<nodeRect.iBr.iX<<" y2 = "<<nodeRect.iBr.iY<<flush; |
|
154 if (selectNode(horizontalDir, verticalDir, selectedRect, nodeRect, selectedPoint, newFocusPoint)) { |
|
155 // found a better fit |
|
156 selectedNode = n; |
|
157 selectedRect.SetRect(nodeRect.iTl, nodeRect.iBr); |
|
158 selectedPoint = newFocusPoint; |
|
159 } |
|
160 } // if (nodeRect.Intersects(rect[i]) |
|
161 } // if (n->isFocusable() && n->isElementNode()) |
|
162 } // for (Node* n = elements->firstItem(); n; n = elements->nextItem()) |
|
163 f = f->tree()->traverseNext(); |
|
164 } // while ( f ) |
|
165 // Remember new selection |
|
166 TPoint contentPos = m_webView->mainFrame()->frameView()->contentPos(); |
|
167 if (selectedNode) { |
|
168 // Found an element to jump to |
|
169 m_selectedElementRect = selectedRect; |
|
170 m_focusPosition = selectedPoint; |
|
171 m_node = selectedNode; |
|
172 selectedNode->document()->setFocusedNode(selectedNode); |
|
173 m_webView->page()->focusController()->setFocusedFrame(selectedNode->document()->frame()); |
|
174 // And scroll to the selected element |
|
175 RenderLayer *layer = selectedNode->renderer()->enclosingLayer(); |
|
176 if (layer) { |
|
177 layer->scrollRectToVisible(selectedNode->getRect(), RenderLayer::gAlignCenterIfNeeded, RenderLayer::gAlignCenterIfNeeded); |
|
178 TRect newRect = TRect(kit(selectedNode->document()->frame())->frameView()->frameCoordsInViewCoords(selectedNode->getRect().Rect().iTl), |
|
179 kit(selectedNode->document()->frame())->frameView()->frameCoordsInViewCoords(selectedNode->getRect().Rect().iBr)); |
|
180 selectedPoint += (newRect.iTl - selectedRect.iTl); |
|
181 m_focusPosition = selectedPoint; |
|
182 selectedRect = newRect; |
|
183 m_selectedElementRect = selectedRect; |
|
184 StaticObjectsContainer::instance()->webCursor()->updatePositionAndElemType(selectedPoint); |
|
185 // special handling for Select-Multi |
|
186 if (m_webView->focusedElementType() == TBrCtlDefs::EElementSelectMultiBox) { |
|
187 Element* e = static_cast<Element*>(m_node); |
|
188 if (e->isControl()) { |
|
189 HTMLGenericFormElement* ie = static_cast<HTMLGenericFormElement*>( e ); |
|
190 if (ie->type() == "select-multiple") { |
|
191 RenderListBox* render = static_cast<RenderListBox*>(e->renderer()); |
|
192 HTMLSelectElement* selectElement = static_cast<HTMLSelectElement*>( e ); |
|
193 IntRect itemRect = render->itemRect(0, 0, 0); |
|
194 TPoint cursorPoint(StaticObjectsContainer::instance()->webCursor()->position()); |
|
195 int gap = (20 * m_webView->scalingFactor()) / 100; |
|
196 cursorPoint.iX = max(m_focusPosition.iX, m_selectedElementRect.iTl.iX + gap); |
|
197 cursorPoint.iX = std::min(cursorPoint.iX, m_selectedElementRect.iBr.iX - gap); |
|
198 if (verticalDir == -1) { |
|
199 cursorPoint.iY -= (itemRect.height() * m_webView->scalingFactor()) / 125; |
|
200 } |
|
201 if (cursorPoint != StaticObjectsContainer::instance()->webCursor()->position()) { |
|
202 StaticObjectsContainer::instance()->webCursor()->setPosition(cursorPoint); |
|
203 } |
|
204 } |
|
205 } |
|
206 } |
|
207 TPointerEvent event; |
|
208 event.iPosition = StaticObjectsContainer::instance()->webCursor()->position(); |
|
209 event.iModifiers = 0; |
|
210 event.iType = TPointerEvent::EMove; |
|
211 core(m_webView->mainFrame())->eventHandler()->handleMouseMoveEvent(PlatformMouseEvent(event)); |
|
212 wkDebug()<<"Focus position x = "<<selectedPoint.iX<<" y = "<<selectedPoint.iY<<flush; |
|
213 ret = true; |
|
214 } |
|
215 } |
|
216 else { |
|
217 if (!m_firstNavigationOnPage) { |
|
218 m_webView->mainFrame()->frameView()->scrollTo(contentPos + TPoint(horizontalDir * m_webView->Rect().Width() / KScrollWhenNotFound, verticalDir * m_webView->Rect().Height() / KScrollWhenNotFound)); |
|
219 TPoint diff(m_webView->mainFrame()->frameView()->contentPos() - contentPos); |
|
220 if (diff.iX || diff.iY) { |
|
221 m_selectedElementRect.Move(diff); |
|
222 m_focusPosition = oldFocusPoint + diff; |
|
223 m_node = NULL; |
|
224 StaticObjectsContainer::instance()->webCursor()->updatePositionAndElemType(m_focusPosition - m_webView->mainFrame()->frameView()->contentPos()); |
|
225 ret = true; |
|
226 } |
|
227 } |
|
228 } |
|
229 StaticObjectsContainer::instance()->webCursor()->cursorUpdate(true); |
|
230 return ret; |
|
231 } |
|
232 |
|
233 bool WebTabbedNavigation::selectNode(int horizontalDir, int verticalDir, TRect& selectedRect, TRect& newNodeRect, TPoint& selectedPoint, TPoint& newFocusPoint) |
|
234 { |
|
235 if (selectedPoint == TPoint(0, 0)) { // first selected node fixme: ensure not to divert direction too much |
|
236 return true; |
|
237 } |
|
238 int selectedDist = distanceFunction(horizontalDir, verticalDir, selectedRect, selectedPoint); |
|
239 int newDist = distanceFunction(horizontalDir, verticalDir, newNodeRect, newFocusPoint); |
|
240 wkDebug()<<"WebTabbedNavigation::selectNode. selected x = "<<selectedPoint.iX<<" y = "<<selectedPoint.iY<<" new x = "<<newFocusPoint.iX<<" y = "<<newFocusPoint.iY<<"old distance = "<<selectedDist<<" new distance = "<<newDist<<flush; |
|
241 return newDist < selectedDist; |
|
242 } |
|
243 |
|
244 TPoint WebTabbedNavigation::potentialFocusPoint(int horizontalDir, int verticalDir, TRect& newNodeRect) |
|
245 { |
|
246 int x = 0; |
|
247 int y = 0; |
|
248 // Focus points must be inside the element and not on the border in order for the outline to be drawn. |
|
249 if (horizontalDir) { // horizontal |
|
250 if (horizontalDir == -1) { // left |
|
251 x = newNodeRect.iBr.iX - 1; |
|
252 } |
|
253 else if (horizontalDir == 1) { // right |
|
254 x = newNodeRect.iTl.iX + 1; |
|
255 } |
|
256 if (newNodeRect.iBr.iY < m_focusPosition.iY) { |
|
257 y = newNodeRect.iBr.iY - 1; |
|
258 } |
|
259 else if (newNodeRect.iTl.iY > m_focusPosition.iY) { |
|
260 y = newNodeRect.iTl.iY + 1; |
|
261 } |
|
262 else { |
|
263 y = m_focusPosition.iY; |
|
264 } |
|
265 } |
|
266 else { // vertical |
|
267 if (verticalDir == -1) { // up |
|
268 y = newNodeRect.iBr.iY - 1; |
|
269 } |
|
270 else if (verticalDir == 1) { // down |
|
271 y = newNodeRect.iTl.iY + 1; |
|
272 } |
|
273 if (newNodeRect.iBr.iX < m_focusPosition.iX) { |
|
274 x = newNodeRect.iBr.iX - 1; |
|
275 } |
|
276 else if (newNodeRect.iTl.iX > m_focusPosition.iX) { |
|
277 x = newNodeRect.iTl.iX + 1; |
|
278 } |
|
279 else { |
|
280 x = m_focusPosition.iX; |
|
281 } |
|
282 } |
|
283 return TPoint(x, y); |
|
284 } |
|
285 |
|
286 int WebTabbedNavigation::distanceFunction(int horizontalDir, int verticalDir, TRect& rect, TPoint& point) |
|
287 { |
|
288 TReal x, y, euclidianDistance; |
|
289 int sameAxisDist, otherAxisDist, overlap; |
|
290 |
|
291 Math::Pow(x, (m_focusPosition.iX - point.iX), 2.0); |
|
292 Math::Pow(y, (m_focusPosition.iY - point.iY), 2.0); |
|
293 Math::Sqrt(euclidianDistance, x + y); |
|
294 sameAxisDist = horizontalDir * (point.iX - m_focusPosition.iX) + verticalDir * (point.iY - m_focusPosition.iY); |
|
295 otherAxisDist = (horizontalDir) ? (point.iY - m_focusPosition.iY) : (point.iX - m_focusPosition.iX) ; |
|
296 otherAxisDist = (otherAxisDist < 0 ) ? (otherAxisDist * -1) : otherAxisDist; |
|
297 if (horizontalDir) { // horizontal |
|
298 if (rect.iBr.iY < m_selectedElementRect.iTl.iY || rect.iTl.iY > m_selectedElementRect.iBr.iY) { |
|
299 overlap = 0; |
|
300 } |
|
301 else { |
|
302 int top = max(m_selectedElementRect.iTl.iY, rect.iTl.iY); |
|
303 int bottom = std::min(m_selectedElementRect.iBr.iY, rect.iBr.iY); |
|
304 overlap = bottom - top; |
|
305 } |
|
306 } |
|
307 else { // vertical |
|
308 if (rect.iBr.iX < m_selectedElementRect.iTl.iX || rect.iTl.iX > m_selectedElementRect.iBr.iX) { |
|
309 overlap = 0; |
|
310 } |
|
311 else { |
|
312 int top = max(m_selectedElementRect.iTl.iX, rect.iTl.iX); |
|
313 int bottom = std::min(m_selectedElementRect.iBr.iX, rect.iBr.iX); |
|
314 overlap = bottom - top; |
|
315 } |
|
316 } |
|
317 long ed, o; |
|
318 Math::Int(ed, euclidianDistance); |
|
319 Math::Int(o, sqrt(overlap)); |
|
320 return ed + sameAxisDist + 2 * otherAxisDist + o; |
|
321 } |