COMMIT_MESSAGE

 1Spatial Navigation: Initial code simplification in FocusController.cpp and SpatialNavigation.cpp
 2
 3Reviewed by NOBODY (OOPS!).
 4Patch by Antonio Gomes <tonikitoo@webkit.org>
 5
 6No behaviour change at this point. Mostly moving code around to the place
 7where it should live in.
 8
 9WebCore::distanceInDirection method was handling much of the logic not strictly only
 10related to the distance between nodes acquisition itself. This method was simplified and
 11renamed to 'WebCore::distanceDataForNode'. It now is responsible for not only getting the
 12distance, but also parent document distance, alignment and parent document alignment to the
 13current focused node. All assignement logic previously there was moved to updateFocusCandidateIfCloser.
 14
 15findFocusableNodeInDirection and deepFindFocusableNodeInDirection method had their logic
 16also simplified based on the changes above.
 17
 18No behaviour change at this point. Mostly moving code around to the place
 19where it should live in.
 20
 21* page/FocusController.cpp:
 22(WebCore::FocusController::advanceFocusDirectionally):
 23(WebCore::updateFocusCandidateIfCloser):
 24(WebCore::FocusController::findFocusableNodeInDirection):
 25(WebCore::FocusController::deepFindFocusableNodeInDirection):
 26* page/FocusController.h:
 27* page/SpatialNavigation.cpp:
 28(WebCore::distanceDataForNode):
 29(WebCore::renderRectRelativeToRootDocument):
 30* page/SpatialNavigation.h:

WebCore/ChangeLog

112010-03-15 Antonio Gomes <tonikitoo@webkit.org>
22
 3 Reviewed by NOBODY (OOPS!).
 4 Patch by Antonio Gomes <tonikitoo@webkit.org>
 5
 6 Spatial Navigation: Initial code simplification in FocusController.cpp and SpatialNavigation.cpp
 7
 8 WebCore::distanceInDirection method was handling much of the logic not strictly related
 9 only to the distance between nodes acquisition itself. This method was simplified and
 10 renamed to 'WebCore::distanceDataForNode'. It now is responsible for not only getting the
 11 distance, but also parent document distance, alignment and parent document alignment to the
 12 current focused node. All assignement logic previously there was moved to updateFocusCandidateIfCloser.
 13
 14 findFocusableNodeInDirection and deepFindFocusableNodeInDirection method had their logic
 15 also simplified based on the changes above.
 16
 17 No behaviour change at this point. Mostly moving code around to the place
 18 where it should live in.
 19
 20 * page/FocusController.cpp:
 21 (WebCore::FocusController::advanceFocusDirectionally):
 22 (WebCore::updateFocusCandidateIfCloser):
 23 (WebCore::FocusController::findFocusableNodeInDirection):
 24 (WebCore::FocusController::deepFindFocusableNodeInDirection):
 25 * page/FocusController.h:
 26 * page/SpatialNavigation.cpp:
 27 (WebCore::distanceDataForNode):
 28 (WebCore::renderRectRelativeToRootDocument):
 29 * page/SpatialNavigation.h:
 30
 312010-03-15 Antonio Gomes <tonikitoo@webkit.org>
 32
333 Reviewed by Gustavo Noronha.
434 Patch by Antonio Gomes <tonikitoo@webkit.org>
535

WebCore/page/FocusController.cpp

@@bool FocusController::advanceFocusDirectionally(FocusDirection direction, Keyboa
304304 // Move up in the chain of nested frames.
305305 frame = frame->tree()->top();
306306
307  FocusCandidate focusCandidate;
308  findFocusableNodeInDirection(frame->document(), focusedNode, direction, event, focusCandidate);
 307 FocusCandidate focusCandidate, helper;
 308 findFocusableNodeInDirection(frame->document(), focusedNode, direction, event, focusCandidate, helper);
309309
310310 Node* node = focusCandidate.node;
311311 if (!node || !node->isElementNode()) {

@@bool FocusController::advanceFocusDirectionally(FocusDirection direction, Keyboa
342342 return true;
343343}
344344
345 static void updateFocusCandidateIfCloser(Node* focusedNode, Node* candidate, long long distance, FocusCandidate& closestFocusCandidate)
 345// FIXME_tonikitoo: simplify the logic here !
 346static void updateFocusCandidateIfCloser(Node* focusedNode, FocusCandidate candidate, FocusCandidate& closest)
346347{
347  // Bail out if |distance| is bigger than the current closest candidate.
348  if (distance >= closestFocusCandidate.distance)
 348 bool sameDocument = candidate.document() == closest.document();
 349 if (sameDocument) {
 350 if (closest.alignment > candidate.alignment
 351 || (closest.parentAlignment && candidate.alignment > closest.parentAlignment))
 352 return;
 353 } else if (closest.alignment > candidate.alignment
 354 && (closest.parentAlignment && candidate.alignment > closest.parentAlignment))
349355 return;
350356
351  // If |focusedNode| and |candidate| are in the same document AND
352  // current |closestFocusCandidadte| is not in an {i}frame that is
353  // preferable to get focused.
354  if (focusedNode->document() == candidate->document()
355  && distance < closestFocusCandidate.parentDistance) {
356  closestFocusCandidate.node = candidate;
357  closestFocusCandidate.distance = distance;
358  closestFocusCandidate.parentDistance = maxDistance();
359  } else if (focusedNode->document() != candidate->document()) {
360  // If the |focusedNode| is in an inner document and the |candidate| is
361  // in a different document, we only consider to change focus if there is
362  // not another already good focusable candidate in the same document as
363  // |focusedNode|.
364  if (!((isInRootDocument(candidate) && !isInRootDocument(focusedNode))
365  && closestFocusCandidate.node
366  && focusedNode->document() == closestFocusCandidate.node->document())) {
367  closestFocusCandidate.node = candidate;
368  closestFocusCandidate.distance = distance;
369  }
 357 if (candidate.alignment != None
 358 || (closest.node && closest.parentAlignment >= candidate.alignment
 359 && (closest.document() == candidate.document())
 360 && candidate.alignment > None)) {
 361
 362 // If we are now in an higher precedent case, lets reset the current |closest|'s
 363 // |distance| so we force it to be bigger than any result we will get from
 364 // |spatialDistance()| (see below).
 365 if (closest.alignment < candidate.alignment
 366 && closest.parentAlignment < candidate.alignment)
 367 closest.distance = maxDistance();
 368
 369 closest.alignment = candidate.alignment;
 370 }
 371
 372 // Bail out if candidate's distance is bigger than the closest candidate's distance.
 373 if (candidate.distance >= closest.distance)
 374 return;
 375
 376 // If |focusedNode| and |candidate| are in the same document AND current
 377 // |closest| is not in an {i}frame that is preferable to get focused ...
 378 if (focusedNode->document() == candidate.document()
 379 && candidate.distance < closest.parentDistance)
 380 closest = candidate;
 381 else if (focusedNode->document() != candidate.document()) {
 382 // If the |focusedNode| is in an inner document and |candidate| is in a
 383 // different document, we only consider to change focus if there is not
 384 // another already good focusable candidate in the same document as |focusedNode|.
 385 if (!((isInRootDocument(candidate.node) && !isInRootDocument(focusedNode))
 386 && !closest.isNull()
 387 && focusedNode->document() == closest.document()))
 388 closest = candidate;
370389 }
371390}
372391
373 void FocusController::findFocusableNodeInDirection(Document* document, Node* focusedNode, FocusDirection direction, KeyboardEvent* event, FocusCandidate& closestFocusCandidate)
 392void FocusController::findFocusableNodeInDirection(Document* document, Node* focusedNode,
 393 FocusDirection direction, KeyboardEvent* event,
 394 FocusCandidate& closestFocusCandidate,
 395 FocusCandidate& helper)
374396{
375397 ASSERT(document);
376398
377  // Walk all the child nodes and update focusCandidate if we find a nearer node.
378  for (Node* candidate = document->firstChild(); candidate; candidate = candidate->traverseNextNode()) {
 399 // Walk all the child nodes and update |closestFocusCandidate| if we find a nearer node.
 400 for (Node* dest = document->firstChild(); dest; dest = dest->traverseNextNode()) {
379401 // Inner documents case.
380  if (candidate->isFrameOwnerElement())
381  deepFindFocusableNodeInDirection(focusedNode, candidate, direction, event, closestFocusCandidate);
382  else if (candidate != focusedNode && candidate->isKeyboardFocusable(event)) {
383  long long distance = distanceInDirection(focusedNode, candidate,
384  direction, closestFocusCandidate);
385  updateFocusCandidateIfCloser(focusedNode, candidate, distance, closestFocusCandidate);
 402 if (dest->isFrameOwnerElement())
 403 deepFindFocusableNodeInDirection(focusedNode, dest, direction, event, closestFocusCandidate, helper);
 404 else if (dest != focusedNode && dest->isKeyboardFocusable(event)) {
 405 FocusCandidate currentFocusCandidate(dest);
 406
 407 // If |helper| is not Null, it means that we are in a recursive call from
 408 // deepFineFocusableNodeInDirection (i.e. processing an element in an iframe).
 409 // In this case, |helper| holds the information data (distance, alignment, etc)
 410 // of iframe element itself.
 411 if (!helper.isNull()) {
 412 currentFocusCandidate.parentAlignment = helper.parentAlignment;
 413 currentFocusCandidate.parentDistance= helper.parentDistance;
 414 }
 415
 416 distanceDataForNode(direction, focusedNode, currentFocusCandidate);
 417 updateFocusCandidateIfCloser(focusedNode, currentFocusCandidate, closestFocusCandidate);
386418 }
387419 }
388420}
389421
390 void FocusController::deepFindFocusableNodeInDirection(Node* focusedNode, Node* candidate, FocusDirection direction, KeyboardEvent* event, FocusCandidate& closestFocusCandidate)
 422void FocusController::deepFindFocusableNodeInDirection(Node* focusedNode, Node* candidate,
 423 FocusDirection direction, KeyboardEvent* event,
 424 FocusCandidate& closestFocusCandidate,
 425 FocusCandidate& helper)
391426{
392427 HTMLFrameOwnerElement* owner = static_cast<HTMLFrameOwnerElement*>(candidate);
393428 if (!owner->contentFrame())

@@void FocusController::deepFindFocusableNodeInDirection(Node* focusedNode, Node*
398433 return;
399434
400435 if (innerDocument == focusedNode->document())
401  findFocusableNodeInDirection(innerDocument, focusedNode, direction, event, closestFocusCandidate);
 436 findFocusableNodeInDirection(innerDocument, focusedNode, direction, event, closestFocusCandidate, helper);
402437 else {
403438 // Check if the current {i}frame element itself is a good candidate
404439 // to move focus to. If it is, then we traverse its inner nodes.
405  // Lets pass a copy of the best candidate, to not get fooled by a
406  // frame without focusable elements.
407  FocusCandidate focusCandidateCopy = closestFocusCandidate;
408  long long distance = distanceInDirection(focusedNode, candidate, direction, focusCandidateCopy);
409  if (distance < focusCandidateCopy.distance) {
410  focusCandidateCopy.parentAlignment = focusCandidateCopy.alignment;
411  focusCandidateCopy.parentDistance = distance;
412 
413  findFocusableNodeInDirection(innerDocument, focusedNode, direction, event, focusCandidateCopy);
414 
415  // If we really have an inner closer focus candidate node, take it.
416  if (closestFocusCandidate.node != focusCandidateCopy.node)
417  closestFocusCandidate = focusCandidateCopy;
 440 helper = FocusCandidate(candidate);
 441 distanceDataForNode(direction, focusedNode, helper);
 442
 443 // FIXME: What about aligment?
 444 if (helper.distance < closestFocusCandidate.distance) {
 445 helper.parentAlignment = helper.alignment;
 446 helper.parentDistance = helper.distance;
 447
 448 findFocusableNodeInDirection(innerDocument, focusedNode, direction, event, closestFocusCandidate, helper);
418449 }
 450
 451 // Emptify |helper|.
 452 helper = FocusCandidate();
419453 }
420454}
421455

WebCore/page/FocusController.h

@@private:
6363 bool advanceFocusDirectionally(FocusDirection, KeyboardEvent*);
6464 bool advanceFocusInDocumentOrder(FocusDirection, KeyboardEvent*, bool initialFocus);
6565
66  void findFocusableNodeInDirection(Document*, Node*, FocusDirection, KeyboardEvent*, FocusCandidate&);
67  void deepFindFocusableNodeInDirection(Node*, Node*, FocusDirection, KeyboardEvent*, FocusCandidate&);
 66 void findFocusableNodeInDirection(Document*, Node*, FocusDirection, KeyboardEvent*, FocusCandidate&, FocusCandidate&);
 67 void deepFindFocusableNodeInDirection(Node*, Node*, FocusDirection, KeyboardEvent*, FocusCandidate&, FocusCandidate&);
6868
6969 Page* m_page;
7070 RefPtr<Frame> m_focusedFrame;

WebCore/page/SpatialNavigation.cpp

@@static bool areRectsPartiallyAligned(FocusDirection, const IntRect&, const IntRe
4747static bool isRectInDirection(FocusDirection, const IntRect&, const IntRect&);
4848static void deflateIfOverlapped(IntRect&, IntRect&);
4949
50 long long distanceInDirection(Node* start, Node* dest, FocusDirection direction, FocusCandidate& candidate)
 50void distanceDataForNode(FocusDirection direction, Node* start, FocusCandidate& candidate)
5151{
5252 RenderObject* startRender = start->renderer();
53  if (!startRender)
54  return maxDistance();
 53 if (!startRender) {
 54 candidate.distance = maxDistance();
 55 return;
 56 }
5557
56  RenderObject* destRender = dest->renderer();
57  if (!destRender)
58  return maxDistance();
 58 RenderObject* destRender = candidate.node->renderer();
 59 if (!destRender) {
 60 candidate.distance = maxDistance();
 61 return;
 62 }
5963
6064 IntRect curRect = renderRectRelativeToRootDocument(startRender);
6165 IntRect targetRect = renderRectRelativeToRootDocument(destRender);

@@long long distanceInDirection(Node* start, Node* dest, FocusDirection direction,
6569 deflateIfOverlapped(curRect, targetRect);
6670
6771 if (curRect.isEmpty() || targetRect.isEmpty()
68  || targetRect.x() < 0 || targetRect.y() < 0)
69  return maxDistance();
 72 || targetRect.x() < 0 || targetRect.y() < 0) {
 73 candidate.distance = maxDistance();
 74 return;
 75 }
7076
71  if (!isRectInDirection(direction, curRect, targetRect))
72  return maxDistance();
 77 if (!isRectInDirection(direction, curRect, targetRect)) {
 78 candidate.distance = maxDistance();
 79 return;
 80 }
7381
7482 // The distance between two nodes is not to be considered alone when evaluating/looking
7583 // for the best focus candidate node. Alignment of rects can be also a good point to be
7684 // considered in order to make the algorithm to behavior in a more intuitive way.
77  RectsAlignment alignment = alignmentForRects(direction, curRect, targetRect);
78 
79  bool sameDocument = candidate.node && dest->document() == candidate.node->document();
80  if (sameDocument) {
81  if (candidate.alignment > alignment || (candidate.parentAlignment && alignment > candidate.parentAlignment))
82  return maxDistance();
83  } else if (candidate.alignment > alignment && (candidate.parentAlignment && alignment > candidate.parentAlignment))
84  return maxDistance();
85 
86  // FIXME_tonikitoo: simplify the logic here !
87  if (alignment != None
88  || (candidate.node && candidate.parentAlignment >= alignment
89  && (candidate.node->document() == dest->document())
90  && alignment > None)) {
91 
92  // If we are now in an higher precedent case, lets reset the current |candidate|'s
93  // |distance| so we force it to be bigger than the result we will get from
94  // |spatialDistance| (see below).
95  if (candidate.alignment < alignment && candidate.parentAlignment < alignment)
96  candidate.distance = maxDistance();
97 
98  candidate.alignment = alignment;
99  }
100 
101  return spatialDistance(direction, curRect, targetRect);
 85 candidate.alignment = alignmentForRects(direction, curRect, targetRect);
 86 candidate.distance = spatialDistance(direction, curRect, targetRect);
10287}
10388
10489// FIXME: This function does not behave correctly with transformed frames.

WebCore/page/SpatialNavigation.h

@@struct FocusCandidate {
118118 RectsAlignment parentAlignment;
119119};
120120
121 long long distanceInDirection(Node*, Node*, FocusDirection, FocusCandidate&);
 121void distanceDataForNode(FocusDirection direction, Node* start, FocusCandidate& candidate);
122122bool scrollInDirection(Frame*, FocusDirection);
123123void scrollIntoView(Element*);
124124bool hasOffscreenRect(Node*);