Bug 78588 - Focus navigation should traverse nodes in reified DOM tree order.
Summary: Focus navigation should traverse nodes in reified DOM tree order.
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: DOM (show other bugs)
Version: 528+ (Nightly build)
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Hayato Ito
URL:
Keywords:
Depends on: 82576
Blocks: 78585
  Show dependency treegraph
 
Reported: 2012-02-14 01:21 PST by Hayato Ito
Modified: 2012-06-04 21:14 PDT (History)
7 users (show)

See Also:


Attachments
wip. depends on reified tree traversal APIs. (63.90 KB, patch)
2012-03-21 01:54 PDT, Hayato Ito
no flags Details | Formatted Diff | Diff
Shadow DOM navigation (61.08 KB, patch)
2012-03-26 23:49 PDT, Hayato Ito
no flags Details | Formatted Diff | Diff
update (56.29 KB, patch)
2012-03-28 00:29 PDT, Hayato Ito
no flags Details | Formatted Diff | Diff
Patch for landing (56.12 KB, patch)
2012-03-28 21:15 PDT, Hayato Ito
no flags Details | Formatted Diff | Diff
Patch for landing (57.07 KB, patch)
2012-03-29 01:45 PDT, Hayato Ito
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Comment 1 Hayato Ito 2012-03-21 01:54:03 PDT
Created attachment 132994 [details]
wip. depends on reified tree traversal APIs.
Comment 2 Hayato Ito 2012-03-22 00:51:50 PDT
I did a micro benchmark using the DOM tree included the newly added LayoutTest for Focus navigation.

The result is:

Before this patch:
Pressing Tab (or Shift-Tab) in 10000 times.
 took 3837.2ms. navigateFocusFoward
 took 4641.6s. navigateFocusBackward


After this patch:
Pressing Tab (or Shift-Tab) in 10000 times.
 took 4614.4ms. navigateFocusFoward
 took 5403.8ms. navigateFocusBackward

It becomes 1.2 times slower.
I guess the main reason is ReifiedTreeTraversal APIs (See https://bugs.webkit.org/show_bug.cgi?id=79197#c33).

It might be unfair to compare before/after since the example DOM tree uses a lot of ShadowHosts.

Since FocusNavigation is only invoked by user's interactive action, pressing <tab> key, we don't have to worry about its performance too much.
Comment 3 Hayato Ito 2012-03-26 23:49:58 PDT
Created attachment 133988 [details]
Shadow DOM navigation
Comment 4 Hayato Ito 2012-03-26 23:54:03 PDT
It seems I've removed trailing white spaces accidentally from some files.
If it is not desired, I am happy to recover trailing white spaces.
Comment 5 Dimitri Glazkov (Google) 2012-03-27 10:47:38 PDT
Comment on attachment 133988 [details]
Shadow DOM navigation

View in context: https://bugs.webkit.org/attachment.cgi?id=133988&action=review

My head hurts from reviewing this code. I need to take a break. I promise I'll give it another stab tomorrow.

I feel a bit iffy about freely copying FocusScope. It's fine for now, since it's just a ptr holder. However, adding more data members to the class will have unpleasant side effects of suddenly copying too much stuff.

Also, it would probably be good to put back those trimmed whitespaces.

> Source/WebCore/ChangeLog:24
> +        After finding a *psuedo* focusable element in current focus scope, it tries to resolve a focused element recursively,

*psuedo* -> *pseudo*

> Source/WebCore/page/FocusController.cpp:96
> +FocusScope FocusScope::focusScopeIncluding(Node* node)

focusScopeOf?

> Source/WebCore/page/FocusController.cpp:105
> +FocusScope FocusScope::focusScopeInsideOf(Node* node)

focusScopeOfShadow?

> Source/WebCore/page/FocusController.cpp:391
> +Node* FocusController::findFocusableNodeDeeply(FocusDirection direction, FocusScope scope, Node* start, KeyboardEvent* event)

Deeply -> Recursively?
Comment 6 Hayato Ito 2012-03-28 00:29:42 PDT
Created attachment 134229 [details]
update
Comment 7 Hayato Ito 2012-03-28 00:51:58 PDT
(In reply to comment #5)

> My head hurts from reviewing this code. I need to take a break. I promise I'll give it another stab tomorrow.

Yeah, the algorithm looks complex, but I hope it is not so complicated. The Shadow DOM spec added just a couple of lines about focus navigation, but it is not so easy to implement that exactly. :)

I might add some comments on each functions of FocusController on ChangeLog later. That might be helpful.

> I feel a bit iffy about freely copying FocusScope. It's fine for now, since it's just a ptr holder. However, adding more data members to the class will have unpleasant side effects of suddenly copying too much stuff.

I agree. It's fine for now I think.

> 
> Also, it would probably be good to put back those trimmed whitespaces.

Done. I've restored trimmed white spaces.


View in context: https://bugs.webkit.org/attachment.cgi?id=133988&action=review

>> Source/WebCore/ChangeLog:24
>> +        After finding a *psuedo* focusable element in current focus scope, it tries to resolve a focused element recursively,
> 
> *psuedo* -> *pseudo*

Done.

>> Source/WebCore/page/FocusController.cpp:96
>> +FocusScope FocusScope::focusScopeIncluding(Node* node)
> 
> focusScopeOf?

Done.

>> Source/WebCore/page/FocusController.cpp:105
>> +FocusScope FocusScope::focusScopeInsideOf(Node* node)
> 
> focusScopeOfShadow?

Since FocusScope::FocusScopeOf(Node*) is already used, I'd like to avoid the name of focusScopeOfXXX. It might be confusing since they have different behaviors. So I named it focusScopeOwnedByXXX().

>> Source/WebCore/page/FocusController.cpp:391
>> +Node* FocusController::findFocusableNodeDeeply(FocusDirection direction, FocusScope scope, Node* start, KeyboardEvent* event)
> 
> Deeply -> Recursively?

Done.
Comment 8 Dimitri Glazkov (Google) 2012-03-28 09:26:49 PDT
Comment on attachment 134229 [details]
update

View in context: https://bugs.webkit.org/attachment.cgi?id=134229&action=review

> Source/WebCore/page/FocusController.cpp:298
> +    RefPtr<Node> node = findFocusableNodeAcrossFocusScope(direction, currentNode ? FocusScope::focusScopeOf(currentNode) : FocusScope::focusScopeOf(document), currentNode, event);

The argument looks like it should be written: FocusScope::focusScopeOf(currentNode ? currentNode : document).

> Source/WebCore/page/FocusController.cpp:372
> +        if (foundInInnerFocusScope)
> +            found = foundInInnerFocusScope;
> +        else
> +            found = findFocusableNodeRecursively(direction, scope, currentNode, event);

Also looks like it could be an inline if.

> Source/WebCore/page/FocusController.cpp:394
> +    // start node is exclusive.

Capitalize first word, since it's a sentence.

> Source/WebCore/page/FocusController.cpp:404
> +        if (foundInInnerFocusScope)
> +            return foundInInnerFocusScope;
> +        return findFocusableNodeRecursively(direction, scope, found, event);

I think you hate inline ifs :P
Comment 9 Hayato Ito 2012-03-28 21:11:37 PDT
Thank you for the review. Let me land this patch after addressing your comments.
I'll make some some 'if' statements 'inline' since it's webkit way.

(In reply to comment #8)
> (From update of attachment 134229 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=134229&action=review
> 
> > Source/WebCore/page/FocusController.cpp:298
> > +    RefPtr<Node> node = findFocusableNodeAcrossFocusScope(direction, currentNode ? FocusScope::focusScopeOf(currentNode) : FocusScope::focusScopeOf(document), currentNode, event);
> 
> The argument looks like it should be written: FocusScope::focusScopeOf(currentNode ? currentNode : document).
> 
> > Source/WebCore/page/FocusController.cpp:372
> > +        if (foundInInnerFocusScope)
> > +            found = foundInInnerFocusScope;
> > +        else
> > +            found = findFocusableNodeRecursively(direction, scope, currentNode, event);
> 
> Also looks like it could be an inline if.
> 
> > Source/WebCore/page/FocusController.cpp:394
> > +    // start node is exclusive.
> 
> Capitalize first word, since it's a sentence.
> 
> > Source/WebCore/page/FocusController.cpp:404
> > +        if (foundInInnerFocusScope)
> > +            return foundInInnerFocusScope;
> > +        return findFocusableNodeRecursively(direction, scope, found, event);
> 
> I think you hate inline ifs :P
Comment 10 Hayato Ito 2012-03-28 21:15:06 PDT
Created attachment 134492 [details]
Patch for landing
Comment 11 WebKit Review Bot 2012-03-28 21:59:24 PDT
Comment on attachment 134492 [details]
Patch for landing

Clearing flags on attachment: 134492

Committed r112500: <http://trac.webkit.org/changeset/112500>
Comment 12 WebKit Review Bot 2012-03-28 21:59:29 PDT
All reviewed patches have been landed.  Closing bug.
Comment 13 Csaba Osztrogonác 2012-03-28 23:45:13 PDT
Reopen, because it made tests assert: (at least on GTK and on Qt)

STDERR: ASSERTION FAILED: crossed == NotCrossed
STDERR: ../../Source/WebCore/dom/ReifiedTreeTraversal.cpp(221) : static WebCore::Node* WebCore::ReifiedTreeTraversal::parentNodeOrBackToInsertionPoint(const WebCore::Node*, WebCore::ReifiedTreeTraversal::CrossedUpperBoundary&)
Comment 14 Hayato Ito 2012-03-28 23:47:25 PDT
Thank you for letting me know it. Let me check. I might roll out.

(In reply to comment #13)
> Reopen, because it made tests assert: (at least on GTK and on Qt)
> 
> STDERR: ASSERTION FAILED: crossed == NotCrossed
> STDERR: ../../Source/WebCore/dom/ReifiedTreeTraversal.cpp(221) : static WebCore::Node* WebCore::ReifiedTreeTraversal::parentNodeOrBackToInsertionPoint(const WebCore::Node*, WebCore::ReifiedTreeTraversal::CrossedUpperBoundary&)
Comment 15 Hayato Ito 2012-03-29 00:27:37 PDT
I am rolling out in https://bugs.webkit.org/show_bug.cgi?id=82576.

I could not repro the ASSERTION fail on chromium port, but I could find the cause by taking a look at code around the failed assertion.

Let me roll out at first, land a fix for assertion, and re-land this patch.

(In reply to comment #14)
> Thank you for letting me know it. Let me check. I might roll out.
> 
> (In reply to comment #13)
> > Reopen, because it made tests assert: (at least on GTK and on Qt)
> > 
> > STDERR: ASSERTION FAILED: crossed == NotCrossed
> > STDERR: ../../Source/WebCore/dom/ReifiedTreeTraversal.cpp(221) : static WebCore::Node* WebCore::ReifiedTreeTraversal::parentNodeOrBackToInsertionPoint(const WebCore::Node*, WebCore::ReifiedTreeTraversal::CrossedUpperBoundary&)
Comment 16 Hayato Ito 2012-03-29 01:45:22 PDT
Created attachment 134527 [details]
Patch for landing
Comment 17 WebKit Review Bot 2012-03-29 02:46:07 PDT
Comment on attachment 134527 [details]
Patch for landing

Clearing flags on attachment: 134527

Committed r112511: <http://trac.webkit.org/changeset/112511>
Comment 18 WebKit Review Bot 2012-03-29 02:46:15 PDT
All reviewed patches have been landed.  Closing bug.
Comment 19 Chris Dumez 2012-06-04 06:10:41 PDT
The LayoutTests/fast/dom/shadow/focus-navigation.html in this patch is not going to work on GTK or EFL ports. The reason for that is that those ports don't wrap around when pressing tab and the active element is the last one.

So, the following will not work:
Should move from input-E-0 to input-A-1 in forward
PASS

On GTK/EFL ports, it will go to "body", not input-A-1.

The following test for example takes into consideration the different wrapping behavior in different ports:
LayoutTests/fast/events/tab-imagemap.html

I'm working on enabling Shadow DOM for EFL port (Bug 87732) but I need to skip this test because of this different wrapping behavior.