|
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: Implemetation of CWebKiCursor |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 #include "config.h" |
|
20 #include "../../bidi.h" |
|
21 #include <stdlib.h> |
|
22 #include "StaticObjectsContainer.h" |
|
23 #include "WebView.h" |
|
24 #include "WebFrame.h" |
|
25 #include "WebFrameView.h" |
|
26 #include "WebFrameBridge.h" |
|
27 #include "Frame.h" |
|
28 #include "Document.h" |
|
29 #include "Node.h" |
|
30 #include "Element.h" |
|
31 #include "HTMLImageElement.h" |
|
32 #include "RenderImage.h" |
|
33 #include "BrCtl.h" |
|
34 #include "HTMLNames.h" |
|
35 #include "HTMLElement.h" |
|
36 #include "MouseEvent.h" |
|
37 #include "EventNames.h" |
|
38 #include "WebUtil.h" |
|
39 #include "SettingsContainer.h" |
|
40 #include "WebCursor.h" |
|
41 #include "Page.h" |
|
42 #include "FocusController.h" |
|
43 #include <AknUtils.h> |
|
44 #include "PlatformScrollbar.h" |
|
45 |
|
46 #include "eikon.hrh" |
|
47 |
|
48 |
|
49 const int KMiddleStep = 8; |
|
50 const int KFlipAdjust =12; |
|
51 const int KCursorIncremental = 17; // 17 pixels |
|
52 const int KTransparencyTime = 8000*1000; //8s |
|
53 const int KTransparencyMoveThreshold = 15; |
|
54 |
|
55 const int KAggressiveSearch = 50; |
|
56 |
|
57 #define KCursorOffset TPoint(-3,-4) |
|
58 |
|
59 using namespace WebCore; |
|
60 using namespace EventNames; |
|
61 using namespace HTMLNames; |
|
62 |
|
63 // ============================= LOCAL FUNCTIONS =============================== |
|
64 |
|
65 inline IntPoint nearestPointInRect(const IntPoint &point, const IntRect &rect) |
|
66 { |
|
67 //Error condition |
|
68 if (rect.isEmpty()) return IntPoint(0,0); |
|
69 |
|
70 int y = std::max(rect.y(), std::min(rect.bottom(), point.y())); |
|
71 int x = std::max(rect.x(), std::min(rect.right(), point.x())); |
|
72 |
|
73 return IntPoint(x,y); |
|
74 } |
|
75 |
|
76 TInt TransparencyTimerCb(TAny* any) |
|
77 { |
|
78 WebCursor* c = static_cast<WebCursor*>(any); |
|
79 c->setTransparent(true); |
|
80 return EFalse; |
|
81 } |
|
82 |
|
83 // ============================ MEMBER FUNCTIONS =============================== |
|
84 |
|
85 // ----------------------------------------------------------------------------- |
|
86 // CWebKitCursor::NewL |
|
87 // Two-phased constructor. |
|
88 // ----------------------------------------------------------------------------- |
|
89 WebCursor* WebCursor::NewL() |
|
90 { |
|
91 WebCursor* self = new (ELeave) WebCursor(); |
|
92 CleanupStack::PushL( self ); |
|
93 self->ConstructL(); |
|
94 CleanupStack::Pop(); |
|
95 return self; |
|
96 } |
|
97 |
|
98 // ----------------------------------------------------------------------------- |
|
99 // WebCursor::WebCursor |
|
100 // Constructor. |
|
101 // ----------------------------------------------------------------------------- |
|
102 WebCursor::WebCursor() : |
|
103 m_pos(TPoint(KInitialOffset,KInitialOffset)) |
|
104 , m_previousLr(0) |
|
105 , m_previousTb(0) |
|
106 , m_view(0) |
|
107 , m_visible(true) |
|
108 , m_flipcounter(0) |
|
109 , m_type(PointerCursor) |
|
110 , m_flipCounter(0) |
|
111 { |
|
112 } |
|
113 |
|
114 // ----------------------------------------------------------------------------- |
|
115 // WebCursor::~WebCursor |
|
116 // Deconstructor. |
|
117 // ----------------------------------------------------------------------------- |
|
118 WebCursor::~WebCursor() |
|
119 { |
|
120 m_sprite.Close(); |
|
121 delete m_transarrowmask; |
|
122 delete m_transtimer; |
|
123 } |
|
124 |
|
125 // ----------------------------------------------------------------------------- |
|
126 // WebCursor::ConstructL |
|
127 // ----------------------------------------------------------------------------- |
|
128 void WebCursor::ConstructL() |
|
129 { |
|
130 m_transtimer = CPeriodic::NewL(CActive::EPriorityStandard); |
|
131 m_visible = !AknLayoutUtils::PenEnabled(); |
|
132 } |
|
133 |
|
134 // ----------------------------------------------------------------------------- |
|
135 // WebCursor::SetCurrentView |
|
136 // ----------------------------------------------------------------------------- |
|
137 void WebCursor::setCurrentView(WebView& view) |
|
138 { |
|
139 if (!m_view) |
|
140 { |
|
141 m_view = &view; |
|
142 constructSprite(); |
|
143 } |
|
144 m_view = &view; |
|
145 setOpaqueUntil(KTransparencyTime); |
|
146 m_transcount = 0; |
|
147 } |
|
148 |
|
149 // ----------------------------------------------------------------------------- |
|
150 // WebCursor::ConstructSprite |
|
151 // ----------------------------------------------------------------------------- |
|
152 void WebCursor::constructSprite() |
|
153 { |
|
154 |
|
155 //tot:fixme |
|
156 m_arrow = StaticObjectsContainer::instance()->webCannedImages()->getImage(WebCannedImages::EImageArrowBitmap); |
|
157 m_hand = StaticObjectsContainer::instance()->webCannedImages()->getImage(WebCannedImages::EImageFingerBitmap); |
|
158 m_ibeam = StaticObjectsContainer::instance()->webCannedImages()->getImage(WebCannedImages::EImageIBeam); |
|
159 m_selectMulti = StaticObjectsContainer::instance()->webCannedImages()->getImage(WebCannedImages::EImageSelectMulti); |
|
160 //iSmartLinkPhoneImage = StaticObjectsContainer::instance()->webCannedImages()->getImage(WebCannedImages::EImageSmartLinkPhone); |
|
161 //iSmartLinkEmailImage = StaticObjectsContainer::instance()->webCannedImages()->getImage(WebCannedImages::EImageSmartLinkEmail); |
|
162 m_wait = StaticObjectsContainer::instance()->webCannedImages()->getImage(WebCannedImages::EImageWaitArrowBitmap); |
|
163 TSize s = m_arrow.m_msk->SizeInPixels(); |
|
164 m_transarrowmask = new (ELeave) CFbsBitmap(); |
|
165 m_transarrowmask->Create(s,m_arrow.m_msk->DisplayMode()); |
|
166 CFbsBitmapDevice* dev = CFbsBitmapDevice::NewL(m_transarrowmask); |
|
167 CleanupStack::PushL(dev); |
|
168 CFbsBitGc* gc; |
|
169 User::LeaveIfError(dev->CreateContext(gc)); |
|
170 gc->BitBlt(TPoint(0,0),m_arrow.m_msk); |
|
171 m_transarrowmask->LockHeap(); |
|
172 TUint8* data = (TUint8*)m_transarrowmask->DataAddress(); |
|
173 TUint8* end = data + s.iWidth*s.iHeight; |
|
174 // divide all pixels by 3 |
|
175 while ( data<end ) |
|
176 { |
|
177 *(data++) /= 3; |
|
178 } |
|
179 m_transarrowmask->UnlockHeap(); |
|
180 delete gc; |
|
181 CleanupStack::PopAndDestroy(); |
|
182 ///////////////////////////////// |
|
183 m_sprite = RWsSprite(m_view->ControlEnv()->WsSession()); |
|
184 RWindowTreeNode *window = (RDrawableWindow* )m_view->brCtl()->CCoeControlParent()->DrawableWindow(); |
|
185 m_sprite.Construct(*window,TPoint(KInitialOffset,KInitialOffset),ESpriteNoChildClip); |
|
186 |
|
187 TSpriteMember spriteMem; |
|
188 spriteMem.iBitmap = 0; |
|
189 spriteMem.iMaskBitmap = 0; |
|
190 spriteMem.iInvertMask = ETrue; |
|
191 |
|
192 m_sprite.AppendMember(spriteMem); |
|
193 m_sprite.Activate(); |
|
194 } |
|
195 |
|
196 // ----------------------------------------------------------------------------- |
|
197 // WebCursor::CursorUpdate |
|
198 // ----------------------------------------------------------------------------- |
|
199 void WebCursor::setCursor(CursorTypes type) |
|
200 { |
|
201 m_sprite.SetPosition( m_pos ); |
|
202 m_type = type; |
|
203 if (m_visible) { |
|
204 TSpriteMember spriteMem; |
|
205 switch( type ) |
|
206 { |
|
207 case PointerCursor: |
|
208 default: |
|
209 { |
|
210 spriteMem.iBitmap = m_waiton ? m_wait.m_img : m_arrow.m_img; |
|
211 spriteMem.iMaskBitmap = m_waiton ? m_wait.m_img : |
|
212 (m_transparent && m_transcount > KTransparencyMoveThreshold ? m_transarrowmask : m_arrow.m_msk); |
|
213 break; |
|
214 } |
|
215 case HandCursor: |
|
216 { |
|
217 spriteMem.iBitmap = m_hand.m_img; |
|
218 spriteMem.iMaskBitmap = m_hand.m_msk; |
|
219 break; |
|
220 } |
|
221 case IBeamCursor: |
|
222 { |
|
223 /*tot:fixme if ( m_view->FocusedElementType() == TBrCtlDefs::EElementSmartLinkTel ) |
|
224 { |
|
225 spriteMem.iBitmap = iSmartLinkPhoneImage.m_img; |
|
226 spriteMem.iMaskBitmap = iSmartLinkPhoneImage.m_msk; |
|
227 } |
|
228 else if ( m_view->FocusedElementType() == TBrCtlDefs::EElementSmartLinkEmail ) |
|
229 { |
|
230 spriteMem.iBitmap = iSmartLinkEmailImage.m_img; |
|
231 spriteMem.iMaskBitmap = iSmartLinkEmailImage.m_msk; |
|
232 } |
|
233 else*/ |
|
234 { |
|
235 spriteMem.iBitmap = m_ibeam.m_img; |
|
236 spriteMem.iMaskBitmap = m_ibeam.m_msk; |
|
237 } |
|
238 break; |
|
239 } |
|
240 case SelectMultiCursor: |
|
241 { |
|
242 spriteMem.iBitmap = m_selectMulti.m_img; |
|
243 spriteMem.iMaskBitmap = m_selectMulti.m_msk; |
|
244 break; |
|
245 } |
|
246 } |
|
247 spriteMem.iOffset = KCursorOffset; |
|
248 spriteMem.iInvertMask = ETrue; |
|
249 m_sprite.UpdateMember( 0, spriteMem ); |
|
250 } else { |
|
251 TSpriteMember spriteMem; |
|
252 spriteMem.iBitmap = 0; |
|
253 spriteMem.iMaskBitmap = 0; |
|
254 spriteMem.iInvertMask = ETrue; |
|
255 m_sprite.UpdateMember( 0, spriteMem ); |
|
256 } |
|
257 } |
|
258 |
|
259 // ----------------------------------------------------------------------------- |
|
260 // WebCursor::CursorUpdate |
|
261 // ----------------------------------------------------------------------------- |
|
262 void WebCursor::cursorUpdate(bool visible) |
|
263 { |
|
264 if (!m_view || !m_view->brCtl()->settings()) |
|
265 return; |
|
266 if ( m_view->showCursor() ) { |
|
267 m_visible = visible && (!m_view->brCtl()->settings()->getTabbedNavigation() || m_view->focusedElementType() == TBrCtlDefs::EElementSelectMultiBox); // check for tabbedNavigation here because it is called from so many places. |
|
268 } |
|
269 |
|
270 resetTransparency(); |
|
271 CursorTypes type = PointerCursor; |
|
272 TBrCtlDefs::TBrCtlElementType elType = m_view->focusedElementType(); |
|
273 if (m_visible) { |
|
274 if (elType == TBrCtlDefs::EElementNone || elType == TBrCtlDefs::EElementBrokenImage) |
|
275 type = PointerCursor; |
|
276 else if (elType == TBrCtlDefs::EElementSmartLinkTel || elType == TBrCtlDefs::EElementSmartLinkEmail) |
|
277 type = IBeamCursor; |
|
278 else if (m_view->brCtl()->settings()->getTabbedNavigation() && elType == TBrCtlDefs::EElementSelectMultiBox) |
|
279 type = SelectMultiCursor; |
|
280 else |
|
281 type = HandCursor; |
|
282 } |
|
283 setCursor(type); |
|
284 } |
|
285 |
|
286 |
|
287 |
|
288 // ----------------------------------------------------------------------------- |
|
289 // CWebKitCursor::getFrameAtPoint |
|
290 // ----------------------------------------------------------------------------- |
|
291 WebFrame* WebCursor::getFrameAtPoint(const TPoint& viewPos_) |
|
292 { |
|
293 if (!m_view) |
|
294 return 0; |
|
295 WebFrame* frameAtPoint = m_view->mainFrame()->frameAtPoint(viewPos_); |
|
296 if (!frameAtPoint) |
|
297 frameAtPoint = m_view->mainFrame(); |
|
298 return frameAtPoint; |
|
299 } |
|
300 |
|
301 // ----------------------------------------------------------------------------- |
|
302 // WebCursor::Reset |
|
303 // ----------------------------------------------------------------------------- |
|
304 void WebCursor::reset() |
|
305 { |
|
306 m_view->setFocusedElementType(TBrCtlDefs::EElementNone); |
|
307 cursorUpdate(true); |
|
308 m_nodeRect = TRect(); |
|
309 } |
|
310 |
|
311 // ----------------------------------------------------------------------------- |
|
312 // WebCursor::SetWaitCursor |
|
313 // ----------------------------------------------------------------------------- |
|
314 void WebCursor::setWaitCursor(bool waiton) |
|
315 { |
|
316 m_waiton = waiton; |
|
317 if (m_waiton) |
|
318 setCursor(PointerCursor); |
|
319 else |
|
320 cursorUpdate(m_visible); |
|
321 } |
|
322 |
|
323 // ----------------------------------------------------------------------------- |
|
324 // WebCursor::OffsetCursor |
|
325 // ----------------------------------------------------------------------------- |
|
326 void WebCursor::offsetCursor(const TPoint& offset) |
|
327 { |
|
328 m_pos -= offset; |
|
329 m_nodeRect.Move(-offset.iX,-offset.iY); |
|
330 } |
|
331 |
|
332 // ----------------------------------------------------------------------------- |
|
333 // WebCursor::SetTransparent |
|
334 // ----------------------------------------------------------------------------- |
|
335 void WebCursor::setTransparent(bool transparent) |
|
336 { |
|
337 if (transparent) |
|
338 m_transtimer->Cancel(); |
|
339 if (m_transparent != transparent) { |
|
340 m_transparent = transparent; |
|
341 // only pointer cursor is transparent |
|
342 if (m_transparent && m_view->focusedElementType() == TBrCtlDefs::EElementNone) |
|
343 setCursor(PointerCursor); |
|
344 else |
|
345 cursorUpdate(m_visible); |
|
346 } |
|
347 } |
|
348 |
|
349 // ----------------------------------------------------------------------------- |
|
350 // WebCursor::SetOpaqueUntil |
|
351 // ----------------------------------------------------------------------------- |
|
352 void WebCursor::setOpaqueUntil(int microsecs) |
|
353 { |
|
354 setTransparent(false); |
|
355 m_transtimer->Cancel(); |
|
356 m_transtimer->Start(microsecs,0,TCallBack(TransparencyTimerCb,this)); |
|
357 } |
|
358 |
|
359 // ----------------------------------------------------------------------------- |
|
360 // WebCursor::IncreaseTransparencyMoveCount |
|
361 // ----------------------------------------------------------------------------- |
|
362 void WebCursor::increaseTransparencyMoveCount() |
|
363 { |
|
364 ++m_transcount; |
|
365 } |
|
366 |
|
367 // ----------------------------------------------------------------------------- |
|
368 // WebCursor::ResetTransparency |
|
369 // ----------------------------------------------------------------------------- |
|
370 void WebCursor::resetTransparency() |
|
371 { |
|
372 m_transcount = 0; |
|
373 setOpaqueUntil(KTransparencyTime); |
|
374 } |
|
375 |
|
376 //------------------------------------------------------------------------------- |
|
377 // WebCursor::innerRect() |
|
378 //------------------------------------------------------------------------------- |
|
379 void WebCursor::innerRect(TRect& rect) |
|
380 { |
|
381 TPoint c = rect.Center(); |
|
382 int z = m_view->scalingFactor(); |
|
383 int dx = KCursorIncremental * z / 100; |
|
384 int dy = KCursorIncremental * z / 100; |
|
385 |
|
386 dx = Max(dx, 2 * rect.Width() / 5); |
|
387 dy = Max(dy, 2 * rect.Height() / 5); |
|
388 |
|
389 rect.Shrink(dx, dy); |
|
390 |
|
391 if (!rect.IsNormalized()) { |
|
392 rect.SetRect(c, c); |
|
393 } |
|
394 } |
|
395 |
|
396 //------------------------------------------------------------------------------- |
|
397 // WebCursor::frameHasContentToScroll() |
|
398 //------------------------------------------------------------------------------- |
|
399 bool WebCursor::frameHasContentToScroll(WebFrame* frame, TPoint& delta) |
|
400 { |
|
401 WebFrameView* rfv = frame->frameView(); |
|
402 TPoint contentpos = rfv->contentPos(); |
|
403 TSize contentsize = rfv->contentSize(); |
|
404 bool hasContentToScrollY = false; |
|
405 bool hasContentToScrollX = false; |
|
406 |
|
407 if (delta.iY > 0) |
|
408 { |
|
409 hasContentToScrollY = (contentpos.iY < (contentsize.iHeight - rfv->rect().Height())); |
|
410 } |
|
411 else if (delta.iY < 0) |
|
412 { |
|
413 hasContentToScrollY = (contentpos.iY > 0); |
|
414 } |
|
415 |
|
416 if (delta.iX > 0) |
|
417 { |
|
418 hasContentToScrollX = (contentpos.iX < (contentsize.iWidth - rfv->rect().Width())); |
|
419 } |
|
420 else if (delta.iX < 0) |
|
421 { |
|
422 hasContentToScrollX = (contentpos.iX > 0); |
|
423 } |
|
424 |
|
425 return hasContentToScrollY || hasContentToScrollX; |
|
426 |
|
427 } |
|
428 |
|
429 //------------------------------------------------------------------------------- |
|
430 // WebCursor::determineScrollingFrame() |
|
431 //------------------------------------------------------------------------------- |
|
432 WebFrame* WebCursor::determineScrollingFrame(int border1, int border2, int pos, |
|
433 WebFrame* fr1, WebFrame* fr2, TPoint& delta) |
|
434 { |
|
435 WebFrame* ret = NULL; |
|
436 |
|
437 if (pos < border1 && pos < border2) return ret; //"magic" line has not been reached |
|
438 if (pos >= border1 && pos >= border2) { |
|
439 if (border1 > border2) { |
|
440 ret = frameHasContentToScroll(fr2, delta) ? fr2 : fr1; |
|
441 } |
|
442 else { |
|
443 ret = frameHasContentToScroll(fr1, delta) ? fr1 : fr2; |
|
444 } |
|
445 } |
|
446 else if (border1 <= pos && pos <= border2) {//"magic" line of fr1 was hit first |
|
447 ret = fr1; |
|
448 } |
|
449 else if (border2 <= pos && pos <= border1) {//"magic" line of fr2 was hit first |
|
450 ret = fr2; |
|
451 } |
|
452 return ret; |
|
453 } |
|
454 |
|
455 |
|
456 //------------------------------------------------------------------------------- |
|
457 // WebCursor::calculateScrollableFrameView() |
|
458 // TODO: Investigate diagonal events, especially in the light of IFrames. |
|
459 //------------------------------------------------------------------------------- |
|
460 WebFrame* WebCursor::calculateScrollableFrameView(TPoint& pos, TPoint& delta, TRect& fRect, bool autoscroll) |
|
461 { |
|
462 WebFrame* frame = getFrameAtPoint(pos); |
|
463 WebFrame* ret_frame = NULL; |
|
464 WebFrameView* mfView = m_view->mainFrame()->frameView(); |
|
465 TPoint docContPos = mfView->toViewCoords(mfView->contentPos()); |
|
466 int z = m_view->scalingFactor(); |
|
467 m_incrLimit.iX = Abs(delta.iX) * 2 * z / 100; |
|
468 m_incrLimit.iY = Abs(delta.iY) * 2 * z / 100; |
|
469 |
|
470 |
|
471 for (; frame; frame = frame->parentFrame()) { |
|
472 bool hScroll = frame->frameView()->hScrollbar()->isEnabled(); |
|
473 bool vScroll = frame->frameView()->vScrollbar()->isEnabled(); |
|
474 // Dont scroll a frameset |
|
475 if (frame->parentFrame() && frame->parentFrame()->isFrameSet()) { |
|
476 continue; |
|
477 } |
|
478 else if (frame->parentFrame() && !hScroll && !vScroll) { |
|
479 continue; |
|
480 } |
|
481 else if (!frame->parentFrame()) { //main view |
|
482 hScroll = true; |
|
483 vScroll = true; |
|
484 } |
|
485 |
|
486 |
|
487 WebFrame* pf = frame->parentFrame() ? frame->parentFrame() : m_view->mainFrame(); |
|
488 WebFrameView* pfv = pf->frameView(); |
|
489 WebFrameView* ppfv = pf->parentFrame() ? pf->parentFrame()->frameView() : NULL; |
|
490 TRect pfRect = pfv->rect(); |
|
491 if (ppfv) {// parent frame is not a main frame |
|
492 pfRect = TRect(ppfv->frameCoordsInViewCoords(pfRect.iTl), |
|
493 ppfv->frameCoordsInViewCoords(pfRect.iBr)); |
|
494 } |
|
495 |
|
496 WebFrameView* fv = frame->frameView(); |
|
497 TRect framerect = fv ->rect(); |
|
498 if (frame->parentFrame()) {// frame is not a main frame |
|
499 framerect = TRect(pfv->frameCoordsInViewCoords(framerect.iTl), |
|
500 pfv->frameCoordsInViewCoords(framerect.iBr)); |
|
501 } |
|
502 |
|
503 TRect pfInnerRect = pfRect; |
|
504 innerRect(pfInnerRect); |
|
505 TRect fInnerRect = framerect; |
|
506 innerRect(fInnerRect); |
|
507 |
|
508 |
|
509 // See which "magic" line we crossed first |
|
510 if (delta.iY > 0) { //scroll down. |
|
511 ret_frame = determineScrollingFrame(pfInnerRect.iBr.iY, fInnerRect.iBr.iY, pos.iY, pf, frame, delta); |
|
512 m_incrLimit.iY = Min (m_incrLimit.iY, Abs(framerect.iBr.iY - pos.iY)); |
|
513 } |
|
514 else if (delta.iY < 0) { //scroll up. |
|
515 ret_frame = determineScrollingFrame(-pfInnerRect.iTl.iY, -fInnerRect.iTl.iY, -pos.iY, pf, frame, delta); |
|
516 m_incrLimit.iY = Min (m_incrLimit.iY, Abs(pos.iY - framerect.iTl.iY)); |
|
517 } |
|
518 |
|
519 if (delta.iX > 0) { |
|
520 ret_frame = determineScrollingFrame(pfInnerRect.iBr.iX, fInnerRect.iBr.iX, pos.iX, pf, frame, delta); |
|
521 m_incrLimit.iX = Min (m_incrLimit.iX, Abs(framerect.iBr.iX - pos.iX)); |
|
522 } |
|
523 else if (delta.iX < 0) { |
|
524 ret_frame = determineScrollingFrame(-pfInnerRect.iTl.iX, -fInnerRect.iTl.iX, -pos.iX, pf, frame, delta); |
|
525 m_incrLimit.iX = Min (m_incrLimit.iX, Abs(pos.iX - framerect.iTl.iX)); |
|
526 } |
|
527 |
|
528 fRect = (ret_frame == frame) ? framerect : pfRect; |
|
529 |
|
530 if (ret_frame) { |
|
531 if (!ret_frame->parentFrame()) { |
|
532 m_incrLimit.iX = Abs(delta.iX) * 2 * z / 100; |
|
533 m_incrLimit.iY = Abs(delta.iY) * 2 * z / 100; |
|
534 } |
|
535 |
|
536 if (!frameHasContentToScroll(ret_frame, delta)) { |
|
537 ret_frame = NULL; |
|
538 m_incrLimit.iX = KCursorIncremental * z / 100; |
|
539 m_incrLimit.iY = KCursorIncremental * z / 100; |
|
540 } |
|
541 |
|
542 if (ret_frame) { |
|
543 m_incrLimit.iX = Max(m_incrLimit.iX, KMiddleStep); |
|
544 m_incrLimit.iY = Max(m_incrLimit.iY, KMiddleStep); |
|
545 break; |
|
546 } |
|
547 } |
|
548 else { |
|
549 m_incrLimit.iX = Abs(delta.iX) * 2 * z / 100; |
|
550 m_incrLimit.iY = Abs(delta.iY) * 2 * z / 100; |
|
551 } |
|
552 } |
|
553 |
|
554 return ret_frame; |
|
555 } |
|
556 |
|
557 |
|
558 //------------------------------------------------------------------------------- |
|
559 // Method that scrolls and moves the cursor based on the navigation algorithm |
|
560 // TODO: Investigate "autoscroll" and diagonal events from real HW and the |
|
561 // diagonal event simulator wedge. |
|
562 //------------------------------------------------------------------------------- |
|
563 void WebCursor::scrollAndMoveCursor(int dir, int scrollRange, bool autoscroll) |
|
564 { |
|
565 if (!m_view) |
|
566 return; |
|
567 |
|
568 int lr = 0; |
|
569 int tb = 0; |
|
570 int deltaX; |
|
571 int deltaY; |
|
572 |
|
573 switch (dir) |
|
574 { |
|
575 |
|
576 case EKeyUpArrow: // North |
|
577 tb = -1; |
|
578 break; |
|
579 |
|
580 case EKeyRightUpArrow: // Northeast |
|
581 case EStdKeyDevice11: // : Extra KeyEvent supports diagonal event simulator wedge |
|
582 tb = -1; |
|
583 lr = +2; // Make it run closer to 45 degrees |
|
584 break; |
|
585 |
|
586 case EKeyRightArrow: // East |
|
587 lr = +1; |
|
588 break; |
|
589 |
|
590 case EKeyRightDownArrow: // Southeast |
|
591 case EStdKeyDevice12: // : Extra KeyEvent supports diagonal event simulator wedge |
|
592 tb = +1; |
|
593 lr = +2; |
|
594 break; |
|
595 |
|
596 case EKeyDownArrow: // South |
|
597 tb = +1; |
|
598 break; |
|
599 |
|
600 case EKeyLeftDownArrow: // Southwest |
|
601 case EStdKeyDevice13: // : Extra KeyEvent supports diagonal event simulator wedge |
|
602 tb = +1; |
|
603 lr = -2; |
|
604 break; |
|
605 |
|
606 case EKeyLeftArrow: // West |
|
607 lr = -1; |
|
608 break; |
|
609 |
|
610 case EKeyLeftUpArrow: // Northwest |
|
611 case EStdKeyDevice10: // : Extra KeyEvent supports diagonal event simulator wedge |
|
612 tb = -1; |
|
613 lr = -2; |
|
614 break; |
|
615 |
|
616 default: |
|
617 break; |
|
618 |
|
619 } |
|
620 |
|
621 deltaX = lr * scrollRange/2; |
|
622 deltaY = tb * scrollRange; |
|
623 |
|
624 TPoint delta = TPoint(deltaX, deltaY); |
|
625 WebFrame* frame = NULL; |
|
626 WebFrameView* fv = NULL; |
|
627 TPoint oldpos; |
|
628 TRect inRect = TRect(); |
|
629 bool needScroll = false; |
|
630 |
|
631 frame = calculateScrollableFrameView(m_pos, delta, inRect, autoscroll); |
|
632 needScroll = (frame != NULL); |
|
633 if (!frame) { |
|
634 frame = m_view->mainFrame(); |
|
635 } |
|
636 fv = frame->frameView(); |
|
637 oldpos = fv->contentPos(); |
|
638 |
|
639 if (autoscroll || m_view->pageView()) { |
|
640 // scroll |
|
641 fv->scrollTo(oldpos + delta); |
|
642 |
|
643 if (!m_view->pageView()) { |
|
644 TPoint cp = position(); |
|
645 if (fv->contentPos() == oldpos) { |
|
646 // not scrolling, move the cursor instead |
|
647 cp.iX += deltaX; |
|
648 cp.iY += deltaY; |
|
649 } else { |
|
650 // move cursor slowly out of the way |
|
651 cp.iX += deltaX/6; |
|
652 cp.iY += deltaY/6; |
|
653 } |
|
654 // limit the movement, don't scroll out of the view area |
|
655 if (lr != 0) { |
|
656 cp.iX = (lr < 0) ? Max(inRect.iTl.iX + 8, cp.iX) : Min(inRect.iBr.iX - 8, cp.iX); |
|
657 } |
|
658 if (tb != 0) { |
|
659 cp.iY = (tb < 0) ? Max(inRect.iTl.iY + 8, cp.iY) : Min(inRect.iBr.iY - 8, cp.iY); |
|
660 } |
|
661 if (cp.iX == (inRect.iTl.iX + 8) || (cp.iX == inRect.iBr.iX - 8) || |
|
662 (cp.iY == inRect.iTl.iY + 8) || (cp.iY == inRect.iBr.iY - 8)) { |
|
663 } |
|
664 setPosition(cp); |
|
665 reset(); |
|
666 } |
|
667 return; |
|
668 } |
|
669 if (!handleSelectElementScrolling(m_view, tb)) { |
|
670 // link snapping |
|
671 moveCursor( lr,tb,scrollRange); |
|
672 } |
|
673 |
|
674 TPoint newpos(oldpos); |
|
675 newpos += TPoint(lr*scrollRange/2, tb*scrollRange); |
|
676 newpos = fv->nearestPointInFrame(newpos); |
|
677 |
|
678 int adjustedScrollRange = Abs(lr*(newpos.iX - oldpos.iX)) + Abs(tb*(newpos.iY - oldpos.iY)); |
|
679 |
|
680 if (lr==0) |
|
681 increaseTransparencyMoveCount(); |
|
682 else |
|
683 resetTransparency(); |
|
684 |
|
685 if (adjustedScrollRange) { |
|
686 TPoint p = position(); |
|
687 if ( needScroll ) { |
|
688 innerRect(inRect); |
|
689 int deltax = (lr != 0 ) ? ( (lr > 0) ? (p.iX - inRect.iBr.iX) : (inRect.iTl.iX - p.iX ) ) : 0 ; |
|
690 int deltay = (tb != 0 ) ? ( (tb > 0) ? (p.iY - inRect.iBr.iY ) : (inRect.iTl.iY - p.iY) ) : 0 ; |
|
691 deltax = Min(adjustedScrollRange, deltax); |
|
692 deltay = Min(adjustedScrollRange, deltay); |
|
693 TPoint offset(fv->toViewCoords(TPoint(lr*deltax,tb*deltay))); |
|
694 offsetCursor(offset); |
|
695 fv->scrollTo(oldpos+TPoint(lr*deltax , tb*deltay)); |
|
696 } else { |
|
697 if (m_view->pageView()) |
|
698 m_view->brCtl()->DrawNow(); |
|
699 } |
|
700 } |
|
701 } |
|
702 |
|
703 // ----------------------------------------------------------------------------- |
|
704 // WebCursor::setPosition |
|
705 // ----------------------------------------------------------------------------- |
|
706 void WebCursor::updatePositionAndElemType(const TPoint& pt) |
|
707 { |
|
708 m_pos = pt; |
|
709 m_sprite.SetPosition(pt); |
|
710 WebFrame* frame = getFrameAtPoint(pt); |
|
711 TBrCtlDefs::TBrCtlElementType elType; |
|
712 TRect r; |
|
713 TPoint point(frame->frameView()->viewCoordsInFrameCoords(m_pos)); |
|
714 if (m_view && navigableNodeUnderCursor(*frame, point, elType, r)) { |
|
715 m_view->setFocusedElementType(elType); |
|
716 } |
|
717 } |
|
718 |
|
719 // ----------------------------------------------------------------------------- |
|
720 // WebCursor::movecursor |
|
721 // ----------------------------------------------------------------------------- |
|
722 void WebCursor::moveCursor(int lr,int tb, int scrollRange) |
|
723 { |
|
724 TPoint cp(m_pos); |
|
725 int z = m_view->scalingFactor(); |
|
726 |
|
727 //Flipping is set to true only if the user make 3 consective moves in opposite direction |
|
728 //ie if the user went in up down up direction then we apply the flipping logic |
|
729 if ( ( lr*m_previousLr == -1 || tb*m_previousTb == -1) ) |
|
730 { |
|
731 m_flipcounter++ ; |
|
732 } |
|
733 else m_flipcounter = 0; |
|
734 |
|
735 m_previousLr = lr; |
|
736 m_previousTb = tb; |
|
737 |
|
738 if (m_view->focusedElementType() == TBrCtlDefs::EElementAnchor && !m_nodeRect.IsEmpty() && m_flipcounter <= 1 ) { |
|
739 TSize nodeSizeInDocCoords(m_view->mainFrame()->frameView()->toDocCoords(m_nodeRect.Size())); |
|
740 if ( tb == 0 && nodeSizeInDocCoords.iWidth < scrollRange) { |
|
741 cp.iX = (lr == -1) ? Min(cp.iX , Max(m_nodeRect.iTl.iX, cp.iX - m_incrLimit.iX)) : |
|
742 Max(cp.iX, Min(m_nodeRect.iBr.iX, cp.iX + m_incrLimit.iX)); |
|
743 } |
|
744 if ( lr == 0 && nodeSizeInDocCoords.iHeight < scrollRange) { |
|
745 cp.iY = (tb == -1) ? Min(cp.iY, Max(m_nodeRect.iTl.iY, cp.iY - m_incrLimit.iY)) : |
|
746 Max(cp.iY, Min(m_nodeRect.iBr.iY, cp.iY + m_incrLimit.iY)); |
|
747 } |
|
748 } |
|
749 |
|
750 m_incrLimit.iX -= Abs(m_pos.iX - cp.iX); |
|
751 m_incrLimit.iY -= Abs(m_pos.iY - cp.iY); |
|
752 |
|
753 cp.iX += lr*Min(KCursorIncremental*z/100, m_incrLimit.iX); |
|
754 cp.iY += tb*Min(KCursorIncremental*z/100, m_incrLimit.iY); |
|
755 |
|
756 TRect rec(TPoint(0,0), m_view->offscreenRect().Size()); |
|
757 // limit the movement, don't scroll out of the view area |
|
758 cp.iX = Min(rec.Width(), Max( 0 , cp.iX)); |
|
759 cp.iY = Min(rec.Height(), Max( 0 , cp.iY)); |
|
760 |
|
761 TPoint rPos[] = { cp, cp }; |
|
762 rPos[0] -= TPoint(lr*KMiddleStep*z/100,tb*KMiddleStep*z/100); |
|
763 |
|
764 // user is trying hard to focus a small element |
|
765 if ( m_flipcounter > 1 ) |
|
766 { |
|
767 int flipDistance = KFlipAdjust * z/(100 * (m_flipcounter - 1)); |
|
768 rPos[0] = m_pos + TPoint(lr * flipDistance/2,tb * flipDistance/2); |
|
769 rPos[1] = m_pos + TPoint(lr * flipDistance,tb * flipDistance); |
|
770 } |
|
771 |
|
772 m_pos = rPos[0]; |
|
773 |
|
774 for ( int i = 0;i < 2; i++ ) |
|
775 { |
|
776 WebFrame* frame = getFrameAtPoint(rPos[i]); |
|
777 if ( !frame ) continue; |
|
778 |
|
779 m_view->page()->focusController()->setFocusedFrame(core(frame)); |
|
780 TPoint pt = frame->frameView()->viewCoordsInFrameCoords(rPos[i]); |
|
781 |
|
782 // now let's do the probing |
|
783 TBrCtlDefs::TBrCtlElementType elType = TBrCtlDefs::EElementNone; |
|
784 TRect nr = TRect(); |
|
785 |
|
786 bool test = navigableNodeUnderCursor(*frame, pt, elType, nr); |
|
787 |
|
788 TRect rt(frame->frameView()->frameCoordsInViewCoords(nr.iTl),m_view->mainFrame()->frameView()->toViewCoords(nr.Size())); |
|
789 rt.Intersection(rec); |
|
790 |
|
791 if (i == 0 && ( !test || (m_view->focusedElementType() == elType && rt == m_nodeRect)) ) continue; |
|
792 |
|
793 if ( i == 1 && !test && m_flipCounter <= 1 && !m_nodeRect.IsEmpty()) |
|
794 { |
|
795 //Go to webcore to figure out a possible node |
|
796 TRect searchRect = calcSearchRect(lr,tb, scrollRange); |
|
797 TPoint cp(m_pos); |
|
798 WebFrame* f = getFrameAtPoint(cp); |
|
799 if ( !f ) continue; |
|
800 |
|
801 cp = f->frameView()->viewCoordsInFrameCoords(cp); |
|
802 bool found = determineCursorPosition(*f, elType, nr, searchRect, cp, false); |
|
803 if ( found ) |
|
804 { |
|
805 m_pos = f->frameView()->frameCoordsInViewCoords(cp); |
|
806 |
|
807 m_nodeRect = TRect(f->frameView()->frameCoordsInViewCoords(nr.iTl),m_view->mainFrame()->frameView()->toViewCoords(nr.Size()) ); |
|
808 m_nodeRect.Intersection(rec); |
|
809 m_view->setFocusedElementType(elType); |
|
810 return; |
|
811 } |
|
812 } |
|
813 |
|
814 m_pos = frame->frameView()->frameCoordsInViewCoords(pt); |
|
815 m_nodeRect = rt; |
|
816 m_view->setFocusedElementType(elType); |
|
817 return; |
|
818 } |
|
819 } |
|
820 |
|
821 |
|
822 bool WebCursor::navigableNodeUnderCursor(WebFrame& webFrame, TPoint& aPoint, TBrCtlDefs::TBrCtlElementType& aElType, TRect& aFocusRect) const |
|
823 { |
|
824 Frame* coreFrame = core(&webFrame); |
|
825 if (!coreFrame->renderer() ) |
|
826 return false; |
|
827 |
|
828 Element* node = coreFrame->document()->elementFromPoint(aPoint.iX, aPoint.iY); |
|
829 |
|
830 if (node) { |
|
831 return coreFrame->bridge()->getTypeFromElement(node, aElType, aFocusRect); |
|
832 } |
|
833 |
|
834 return false; |
|
835 } |
|
836 |
|
837 bool WebCursor::determineCursorPosition( WebFrame& webFrame, TBrCtlDefs::TBrCtlElementType& aElType, |
|
838 TRect& aFocusRect, TRect& aSearchRect, |
|
839 TPoint &aCursorPosition, bool aInitialize) |
|
840 { |
|
841 // FIXME: cursor navigation not implemented |
|
842 IntRect searchRt(aSearchRect); |
|
843 IntPoint pt(aCursorPosition.iX,aCursorPosition.iY); |
|
844 bool found = false; |
|
845 |
|
846 if (aInitialize && core(&webFrame)->document()->focusedNode()) { |
|
847 IntRect nodeRect = core(&webFrame)->document()->focusedNode()->getRect(); |
|
848 if (nodeRect.intersects(searchRt)) { |
|
849 IntRect rt = nodeRect; |
|
850 rt.intersect(searchRt); |
|
851 pt = IntPoint( rt.x() + rt.width()>>1, rt.y() + rt.height()>>1 ); |
|
852 found = true; |
|
853 } |
|
854 } |
|
855 |
|
856 found = decideCursorPosition(webFrame, searchRt, pt); |
|
857 TPoint newPos(pt.x(),pt.y()); |
|
858 |
|
859 bool retest = false; |
|
860 if (found) |
|
861 retest = navigableNodeUnderCursor(webFrame, newPos,aElType,aFocusRect); |
|
862 |
|
863 if (!retest) |
|
864 return false; |
|
865 |
|
866 aCursorPosition = newPos; |
|
867 return retest; |
|
868 } |
|
869 |
|
870 |
|
871 TRect WebCursor::calcSearchRect(int lr, int tb, int scrollRange) |
|
872 { |
|
873 TRect searchRect; |
|
874 TPoint pt(m_nodeRect.iTl); |
|
875 TSize nodeSz(m_view->mainFrame()->frameView()->toDocCoords(m_nodeRect.Size())); |
|
876 |
|
877 WebFrame* focused = getFrameAtPoint(m_pos); |
|
878 if (!focused) |
|
879 return searchRect; |
|
880 pt = focused->frameView()->viewCoordsInFrameCoords(pt); |
|
881 |
|
882 if (focused) { |
|
883 TSize sz( (lr == 0) ? nodeSz.iWidth: scrollRange , (tb == 0) ? nodeSz.iHeight:scrollRange); |
|
884 pt.iX += (tb != 0) ? 0 : (lr == -1) ? -scrollRange: nodeSz.iWidth ; |
|
885 pt.iY += (lr != 0) ? 0 : (tb == -1) ? -scrollRange: nodeSz.iHeight ; |
|
886 searchRect = TRect(pt,sz); |
|
887 |
|
888 TBrCtlDefs::TBrCtlElementType elType = m_view->focusedElementType(); |
|
889 if ( elType == TBrCtlDefs::EElementInputBox |
|
890 || elType == TBrCtlDefs::EElementTextAreaBox |
|
891 || elType == TBrCtlDefs::EElementRadioButtonUnSelected |
|
892 || elType == TBrCtlDefs::EElementButton |
|
893 || elType == TBrCtlDefs::EElementCheckBoxUnChecked |
|
894 || elType == TBrCtlDefs::EElementCheckBoxChecked |
|
895 || elType == TBrCtlDefs::EElementRadioButtonSelected ) |
|
896 increaseSearchRect(lr, tb, searchRect); |
|
897 } |
|
898 return searchRect; |
|
899 } |
|
900 |
|
901 void WebCursor::increaseSearchRect(int lr,int tb,TRect& aRect) |
|
902 { |
|
903 int width(aRect.Width()); |
|
904 int height(aRect.Height()); |
|
905 |
|
906 // enlarge the search rect for aggressive probing, the origninal ccb implementation is faulty. |
|
907 if (lr) { |
|
908 if (lr > 0) |
|
909 aRect.SetWidth(width + width*KAggressiveSearch/100); // right |
|
910 else |
|
911 aRect.iTl.iX -= width*KAggressiveSearch/100; // left |
|
912 } else if (tb) { |
|
913 if (tb > 0) |
|
914 aRect.SetHeight(height + height*KAggressiveSearch/100); // down |
|
915 else |
|
916 aRect.iTl.iY -= height*KAggressiveSearch/100; // up |
|
917 } |
|
918 m_flipCounter = 0; |
|
919 } |
|
920 |
|
921 bool WebCursor::decideCursorPosition(WebFrame& webFrame, const IntRect& searchRect, IntPoint& cursorPosition) |
|
922 { |
|
923 int distance = -1; |
|
924 bool found = false; |
|
925 IntPoint cp = cursorPosition; |
|
926 |
|
927 const int minWidth = 5; |
|
928 const int minHeight = 5; |
|
929 |
|
930 Vector<WebCore::IntRect>& recList = *(webFrame.bridge()->focusableRectList()); |
|
931 |
|
932 if (recList.isEmpty()) |
|
933 return false; |
|
934 |
|
935 for (int i = 0;i < recList.size();i++) { |
|
936 IntRect nr = recList[i]; |
|
937 |
|
938 //Resize the rect so that the cursor is comfortably inside the box |
|
939 nr.inflate(-2); |
|
940 |
|
941 if (!nr.intersects(searchRect)) continue; |
|
942 |
|
943 IntRect intersectRect = nr; |
|
944 intersectRect.intersect(searchRect); |
|
945 |
|
946 if ( (nr.width() != intersectRect.width() && intersectRect.width() < minWidth) |
|
947 || (nr.height() != intersectRect.height() && intersectRect.height() < minHeight) ) |
|
948 continue; |
|
949 |
|
950 intersectRect.inflate(-1); |
|
951 found = true; |
|
952 |
|
953 IntPoint np = nearestPointInRect(cp,intersectRect); |
|
954 int disFromCursor = (np.x() - cp.x())*(np.x() - cp.x()) |
|
955 + (np.y() - cp.y())*(np.y() - cp.y()); |
|
956 |
|
957 if (distance == -1 || distance > disFromCursor) { |
|
958 distance = disFromCursor; |
|
959 cursorPosition = np; |
|
960 } |
|
961 } |
|
962 |
|
963 return found; |
|
964 } |
|
965 |
|
966 WebFrame* WebCursor::getFrameUnderCursor() |
|
967 { |
|
968 return getFrameAtPoint(m_pos); |
|
969 } |
|
970 |
|
971 |
|
972 |
|
973 // END OF FILE |