Bug 81102 - blur() on shadow host should work when a shadow host contains a focused element in its shadow DOM subtrees.
Summary: blur() on shadow host should work when a shadow host contains a focused eleme...
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: DOM (show other bugs)
Version: 528+ (Nightly build)
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Nobody
URL:
Keywords:
Depends on:
Blocks: 63606
  Show dependency treegraph
 
Reported: 2012-03-14 06:58 PDT by Hayato Ito
Modified: 2012-03-22 05:39 PDT (History)
7 users (show)

See Also:


Attachments
Patch (7.35 KB, patch)
2012-03-15 08:01 PDT, Kaustubh Atrawalkar
no flags Details | Formatted Diff | Diff
Patch (9.26 KB, patch)
2012-03-16 01:12 PDT, Kaustubh Atrawalkar
no flags Details | Formatted Diff | Diff
Updated Patch (9.81 KB, patch)
2012-03-16 02:25 PDT, Kaustubh Atrawalkar
morrita: review-
morrita: commit-queue-
Details | Formatted Diff | Diff
Updated Patch (9.68 KB, patch)
2012-03-16 04:06 PDT, Kaustubh Atrawalkar
no flags Details | Formatted Diff | Diff
Style Fix (9.83 KB, patch)
2012-03-16 04:21 PDT, Kaustubh Atrawalkar
morrita: review-
morrita: commit-queue-
Details | Formatted Diff | Diff
Updated Patch (9.84 KB, patch)
2012-03-16 04:48 PDT, Kaustubh Atrawalkar
morrita: review-
morrita: commit-queue-
Details | Formatted Diff | Diff
Updated Patch (9.85 KB, patch)
2012-03-16 05:25 PDT, Kaustubh Atrawalkar
no flags Details | Formatted Diff | Diff
Updated Patch (9.91 KB, patch)
2012-03-16 05:35 PDT, Kaustubh Atrawalkar
no flags Details | Formatted Diff | Diff
Updated Patch (8.32 KB, patch)
2012-03-16 05:48 PDT, Kaustubh Atrawalkar
no flags Details | Formatted Diff | Diff
Patch (10.19 KB, patch)
2012-03-16 07:09 PDT, Kaustubh Atrawalkar
no flags Details | Formatted Diff | Diff
Updated Patch (10.18 KB, patch)
2012-03-19 00:22 PDT, Kaustubh Atrawalkar
no flags Details | Formatted Diff | Diff
Fixed ChangeLog (10.21 KB, patch)
2012-03-19 00:51 PDT, Kaustubh Atrawalkar
morrita: review-
morrita: commit-queue-
Details | Formatted Diff | Diff
Updated Patch (12.24 KB, patch)
2012-03-19 03:05 PDT, Kaustubh Atrawalkar
morrita: review-
morrita: commit-queue-
Details | Formatted Diff | Diff
Patch (11.31 KB, patch)
2012-03-21 04:51 PDT, Kaustubh Atrawalkar
morrita: review-
morrita: commit-queue-
Details | Formatted Diff | Diff
Updated ChangeLog (11.72 KB, patch)
2012-03-22 02:10 PDT, Kaustubh Atrawalkar
no flags Details | Formatted Diff | Diff
Fixed ChangeLog (11.72 KB, patch)
2012-03-22 04:08 PDT, Kaustubh Atrawalkar
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Hayato Ito 2012-03-14 06:58:26 PDT
The example is here:

var shadowHost = document.createElement("div");
document.body.appendChild(shadowHost);
var shadowRoot = new WebKitShadowRoot(shadowHost);

var childInShadowRoot = document.createElement("p");
childInShadowRoot.tabIndex = "1";
shadowRoot.appendChild(childInShadowRoot);

shouldBe("childInShadowRoot.focus();document.activeElement", "shadowHost");
shouldBe("shadowHost.blur();document.activeElement", "document.body");  // (A)

(A) fails. The current implementation does not blur a focused element when its shadowHost's blur() is called().
Comment 1 Kaustubh Atrawalkar 2012-03-15 07:55:27 PDT
This need to be fixed in Element::blur function to support blurring of ShadowTree children when blur is called on ShadowHost(). Will provide fix soon.
Comment 2 Kaustubh Atrawalkar 2012-03-15 08:01:04 PDT
Created attachment 132048 [details]
Patch
Comment 3 Hayato Ito 2012-03-15 20:35:54 PDT
Comment on attachment 132048 [details]
Patch

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

> Source/WebCore/dom/Element.cpp:1600
> +    } else if (hasShadowRoot()) {

You can make this function more simple, avoiding duplication of duplication L1616-1619.
Element::blur could be:

void Element::blur()
{
  ...
  Node* focused = doc->focusedNode();
  ...
  if (hasShadowRoot) {
    ...
    ..
    // Omit L1616-1619
  }

  if (focused != this)
   return;

  if (doc->frame())
      doc->frame()->page()->focusController()->setFocusedNode(0, doc->frame());
  else
      doc->setFocusedNode(0);
}

> LayoutTests/fast/dom/shadow/shadow-root-blur-expected.txt:1
> +This tests the activeElement property of a ShadowRoot.

Need to update.

> LayoutTests/fast/dom/shadow/shadow-root-blur.html:31
> +// First ShodowHost

It's optional, but you might want to use some functions on LayoutTests/fast/dom/shadow/resources/shadow-dom.js.
Using createDOM and createShadowRoot, you don't have to construct Shadow DOM tree manually and make tree in one expression.

That helps reviewers to understand the tree structure easily and you don't have to add comments which only explain the tree structure.

> LayoutTests/fast/dom/shadow/shadow-root-blur.html:73
> +evalAndLog("shadowHostInside.blur();");

Could you add the following test case?

shouldBe("childInTreeTwo.focus();document.activeElement", "shadowHost");
evalAndLog("shadowHost.blur();");
shouldBe(...);
shouldBe(...);
...
Comment 4 Hayato Ito 2012-03-15 20:38:56 PDT
Could you verify the 'blur' event is called on ShadowHost?
I guess it should work, but we need to make sure by a test case.


(In reply to comment #2)
> Created an attachment (id=132048) [details]
> Patch
Comment 5 Kaustubh Atrawalkar 2012-03-16 01:12:58 PDT
Created attachment 132226 [details]
Patch
Comment 6 Hayato Ito 2012-03-16 02:18:01 PDT
Comment on attachment 132226 [details]
Patch

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

> Source/WebCore/dom/Element.cpp:1608
> +    // if shadowHost is not found return. This handles case where focused node

Could you modify this comment?
I think we can remove a comment of 'if shadowHost is not found return.'  since it does not explain the exact situation here.

> LayoutTests/fast/dom/shadow/shadow-root-blur.html:41
> +shouldBe("getElementInShadowTreeStack('shadowHostA/').activeElement", "null");

We should rename getElementInShadowTreeStack since it can return ShadowRoot, which is not Element.
That is an unintentional usage for me that it can return ShadowRoot. So we should rename it to getNodeInShadowTreeStack.

Could you update shadow-dom.js and other files which use getElementInShadowTreeStack?
It is okay that you will do it in another patch. If you do it in another patch, please add 'FIXME: Rename ...' comment on getElemetnInShadowTreeStack in shadow-dom.js.
Comment 7 Kaustubh Atrawalkar 2012-03-16 02:25:52 PDT
Created attachment 132233 [details]
Updated Patch

Thanks Hayato for the review. I have updated the comment and added FIXME. Will do it in the next patch. I will file a bug soon.
Comment 8 Hayato Ito 2012-03-16 02:40:58 PDT
Looks good to me. Thank you for fixing.
You need r+ from reviewers.
Comment 9 Hajime Morrita 2012-03-16 03:10:11 PDT
Comment on attachment 132233 [details]
Updated Patch

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

The approach seems sane. Could you reorganize code a bit?

> Source/WebCore/dom/Element.cpp:1599
> +    if (hasShadowRoot()) {

It looks TreeScope or ShadowRoot should have focusNode(). 
In general, it is good practice to separate finding something and modifying something.
In this case, the function can be splited into two part:
- Checking if the focus is in the shadow tree or myself, and
- unsetting the current focus.

> LayoutTests/fast/dom/shadow/shadow-root-blur.html:1
> +<!DOCTYPE html>

This test looks great!
Comment 10 Kaustubh Atrawalkar 2012-03-16 04:06:44 PDT
Created attachment 132243 [details]
Updated Patch

Reorganized the code to make it systematic.
Comment 11 WebKit Review Bot 2012-03-16 04:10:39 PDT
Attachment 132243 [details] did not pass style-queue:

Failed to run "['Tools/Scripts/check-webkit-style', '--diff-files', u'LayoutTests/ChangeLog', u'LayoutTests/fast..." exit_code: 1
Source/WebCore/dom/Element.cpp:1596:  Use 0 instead of NULL.  [readability/null] [5]
Total errors found: 1 in 6 files


If any of these errors are false positives, please file a bug against check-webkit-style.
Comment 12 Kaustubh Atrawalkar 2012-03-16 04:21:38 PDT
Created attachment 132246 [details]
Style Fix

Style issue fixed. ChangeLog updated.
Comment 13 Hajime Morrita 2012-03-16 04:22:37 PDT
Comment on attachment 132243 [details]
Updated Patch

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

> Source/WebCore/dom/Element.cpp:1592
> +{

I find this method confusing. What are we are really looking for here?
Maybe what we want have is Element::nodeIsInShadowTree(Node*) or TreeScope::contains(Node*) or something.
I'm sorry that my original suggestion was wrong. But it's hard to explain...
Comment 14 Hajime Morrita 2012-03-16 04:23:44 PDT
Comment on attachment 132246 [details]
Style Fix

Oops the patch was crossing the comment. Please check the comment on previous patch.
Comment 15 Kaustubh Atrawalkar 2012-03-16 04:31:14 PDT
(In reply to comment #14)
> (From update of attachment 132246 [details])
> Oops the patch was crossing the comment. Please check the comment on previous patch.

No problem. I check the comments on the earlier patch. What we looking for here is if the element on which blur is called and the element which is focused are in the same treeScope for ShadowTree. I think nodeIsInShadowTree sounds a good function. This will check if the same, if focused node is in the same treeScope of the element (which calls blur).
Comment 16 Kaustubh Atrawalkar 2012-03-16 04:48:12 PDT
Created attachment 132250 [details]
Updated Patch
Comment 17 Hajime Morrita 2012-03-16 04:59:17 PDT
Comment on attachment 132250 [details]
Updated Patch

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

Almost good. Could you take care of small points?

> Source/WebCore/dom/Element.cpp:1591
> +bool Element::nodeIsInShadowTree(Node* focused)

|focused| looks too specific name.
This method doesn't need to mention about focus.

> Source/WebCore/dom/Element.cpp:1594
> +    if (hasShadowRoot()) {

Let's return here.
WebKit prefers early return style.

> Source/WebCore/dom/Element.cpp:1613
> +    Node* focusedNode = doc->focusedNode();

Yeah, this looks making more sense.
Comment 18 Hajime Morrita 2012-03-16 05:14:05 PDT
Comment on attachment 132250 [details]
Updated Patch

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

>> Source/WebCore/dom/Element.cpp:1591
>> +bool Element::nodeIsInShadowTree(Node* focused)
> 
> |focused| looks too specific name.
> This method doesn't need to mention about focus.

Also, it looks we can ASSERT(focused != this) because the check is done by the caller site.
It will clarify the point because this function check if the "node is in shadow tree."
Comment 19 Kaustubh Atrawalkar 2012-03-16 05:25:19 PDT
Created attachment 132257 [details]
Updated Patch

Added ASSERT to make sure node == this check has been done by caller site.
Comment 20 Hayato Ito 2012-03-16 05:32:20 PDT
Could you share code between Element::blur() and TreeScope::activeElement()?

Very rough idea is:

Element::blue()
{
  if (treeScope()->activeElement() == this) {
    doBlur();
  ...
}
Comment 21 Kaustubh Atrawalkar 2012-03-16 05:35:19 PDT
Created attachment 132259 [details]
Updated Patch
Comment 22 Kaustubh Atrawalkar 2012-03-16 05:48:13 PDT
Created attachment 132261 [details]
Updated Patch

Code sharing made it simple :)
Comment 23 Hayato Ito 2012-03-16 05:54:58 PDT
Comment on attachment 132261 [details]
Updated Patch

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

> Source/WebCore/dom/Element.cpp:1595
> +    if (treeScope()->activeElement() == this) {

You can not use the result of activeElement() 'as is' since it may return document.body if there is no focused node.

Could you check whether we can call document.body.blur() and it work correctly or not?
Comment 24 Kaustubh Atrawalkar 2012-03-16 06:26:01 PDT
(In reply to comment #23)
> (From update of attachment 132261 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=132261&action=review
> 
> > Source/WebCore/dom/Element.cpp:1595
> > +    if (treeScope()->activeElement() == this) {
> 
> You can not use the result of activeElement() 'as is' since it may return document.body if there is no focused node.
> 
> Could you check whether we can call document.body.blur() and it work correctly or not?

document.body.blur() does not give any error. but body.blur will result in nothing as body's focus can not be unset. Tried that without the change in blur(). 
Steps -
Focus an element. 
call blur on body. 
Focus still remains on the element.
Comment 25 Kaustubh Atrawalkar 2012-03-16 07:09:56 PDT
Created attachment 132277 [details]
Patch

Patch with TreeScope::activElement splited
Comment 26 Hayato Ito 2012-03-18 19:53:01 PDT
Comment on attachment 132277 [details]
Patch

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

> Source/WebCore/dom/TreeScope.cpp:190
> +    Document* document = rootNode()->document();

Could you move this line to inside of 'if' statement (L192)? Since 'document' is used only in the if statement.

> Source/WebCore/dom/TreeScope.h:50
> +    Node* focusedNodeInTree();

I don't think focusedNodeInTree() is intuitive name because the meaning of 'Tree' here is not clear.
focusedNodeInTreeScope() might be better. Or focusedNode() is simply enough in this context.
Comment 27 Kaustubh Atrawalkar 2012-03-19 00:22:46 PDT
Created attachment 132552 [details]
Updated Patch

Updated as per comments from Hayato. Can u review once?
Comment 28 Hayato Ito 2012-03-19 00:27:48 PDT
Comment on attachment 132552 [details]
Updated Patch

Looks good to me. Thank you.

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

> Source/WebCore/ChangeLog:13
> +        (WebCore::TreeScope::focusedNodeInTree):

You need to update ChageLog.
Comment 29 Kaustubh Atrawalkar 2012-03-19 00:51:04 PDT
Created attachment 132554 [details]
Fixed ChangeLog

Aah..missed that :) Thanks.
Comment 30 Hajime Morrita 2012-03-19 01:36:18 PDT
Comment on attachment 132554 [details]
Fixed ChangeLog

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

This looks a good direction! Thanks for clarification. Could you iterate once more?

> Source/WebCore/dom/TreeScope.cpp:188
> +Element* TreeScope::activeElement()

We can make activeElement() virtual. then we know if this is document more clearly.
Comment 31 Kaustubh Atrawalkar 2012-03-19 03:05:01 PDT
Created attachment 132566 [details]
Updated Patch

Updated patch.
Comment 32 Hajime Morrita 2012-03-19 03:22:28 PDT
Comment on attachment 132566 [details]
Updated Patch

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

I'm confused. Apparently the previous patch is much simpler, no?

> Source/WebCore/dom/TreeScope.cpp:172
> +        return this == document ? document->body() : 0;

Why do we have this check even after introducing the virtual method?
Is it for eliminating this, right?

> Source/WebCore/dom/TreeScope.h:51
> +    virtual Element* activeElement();

It looks nobody inherits this.
Comment 33 Kaustubh Atrawalkar 2012-03-19 03:31:10 PDT
(In reply to comment #32)
> (From update of attachment 132566 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=132566&action=review
> 
> I'm confused. Apparently the previous patch is much simpler, no?
> 
> > Source/WebCore/dom/TreeScope.cpp:172
> > +        return this == document ? document->body() : 0;
> 
> Why do we have this check even after introducing the virtual method?
> Is it for eliminating this, right?
> 
> > Source/WebCore/dom/TreeScope.h:51
> > +    virtual Element* activeElement();
> 
> It looks nobody inherits this.

Yes, both ShadowRoot & HTMLDocument shares the same code in TreeScope::activeElement().
Comment 34 Hajime Morrita 2012-03-19 03:45:27 PDT
Comment on attachment 132554 [details]
Fixed ChangeLog

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

> Source/WebCore/dom/TreeScope.cpp:193
> +        return this == document ? document->body() : 0;

If you have override this as Document::activeElement(), you can do this check there instead of here.
The point is that Document is a subclass of TreeScope and we can take this logic as a specialization for Document.
Comment 35 Hajime Morrita 2012-03-19 03:46:07 PDT
Comment on attachment 132566 [details]
Updated Patch

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

>>> Source/WebCore/dom/TreeScope.cpp:172
>>> +        return this == document ? document->body() : 0;
>> 
>> Why do we have this check even after introducing the virtual method?
>> Is it for eliminating this, right?
> 
> Yes, both ShadowRoot & HTMLDocument shares the same code in TreeScope::activeElement().

Then the document specific behavior should be in Document::activeElement(), not TreeScope::activeElement().
Comment 36 Kaustubh Atrawalkar 2012-03-19 03:49:05 PDT
(In reply to comment #35)
> (From update of attachment 132566 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=132566&action=review
> 
> >>> Source/WebCore/dom/TreeScope.cpp:172
> >>> +        return this == document ? document->body() : 0;
> >> 
> >> Why do we have this check even after introducing the virtual method?
> >> Is it for eliminating this, right?
> > 
> > Yes, both ShadowRoot & HTMLDocument shares the same code in TreeScope::activeElement().
> 
> Then the document specific behavior should be in Document::activeElement(), not TreeScope::activeElement().

The reason I have this code in TreeScope is, activeElement property is for HTMLDocument class and not Document class. And ShadowRoot is derived from TreeScope. So the common base class is TreeScope.
Comment 37 Hajime Morrita 2012-03-20 19:05:11 PDT
(In reply to comment #36)
> (In reply to comment #35)
> > (From update of attachment 132566 [details] [details])
> > View in context: https://bugs.webkit.org/attachment.cgi?id=132566&action=review
> > 
> > >>> Source/WebCore/dom/TreeScope.cpp:172
> > >>> +        return this == document ? document->body() : 0;
> > >> 
> > >> Why do we have this check even after introducing the virtual method?
> > >> Is it for eliminating this, right?
> > > 
> > > Yes, both ShadowRoot & HTMLDocument shares the same code in TreeScope::activeElement().
> > 
> > Then the document specific behavior should be in Document::activeElement(), not TreeScope::activeElement().
> 

> The reason I have this code in TreeScope is, activeElement property is for HTMLDocument class and not Document class. And ShadowRoot is derived from TreeScope. So the common base class is TreeScope.
It's fine to have activeElement in Document. HTMLDocument.
Then you can override it in HTMLDocument. Superclass shouldn't know about its subclass if possible.
That's what runtime polymorphism (virtual) is designed for.
Comment 38 Hajime Morrita 2012-03-21 02:47:51 PDT
I think I got your point. This comment is for the second last patch:
We can just have two separate activeElement() implementation.
one is for ShadowRoot and another is for Document (or HTMLDocument.)
Since the hard part is done in focusedNode(), such duplication will be fine.
Comment 39 Kaustubh Atrawalkar 2012-03-21 02:55:26 PDT
(In reply to comment #38)
> I think I got your point. This comment is for the second last patch:
> We can just have two separate activeElement() implementation.
> one is for ShadowRoot and another is for Document (or HTMLDocument.)
> Since the hard part is done in focusedNode(), such duplication will be fine.

Ok, so to brief here is what it will be - Move HTMLDocument::activeElement() imlpementation to Document so that it can share the code between blur()
 & ShadowRoot will have separate activeElement implementation. Remove treeScope::activeElement().
Comment 40 Kaustubh Atrawalkar 2012-03-21 04:51:57 PDT
Created attachment 133012 [details]
Patch

Updated patch as per discussion.
Comment 41 Hajime Morrita 2012-03-22 01:07:35 PDT
Comment on attachment 133012 [details]
Patch

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

Code looks good! what we only miss is changelog explanation.
Thanks to exercise this long iteration.

> Source/WebCore/ChangeLog:7
> +

Could you have some explanation here?
It's recent trend: http://markmail.org/message/aov6bcu7he4tbyoy
Comment 42 Kaustubh Atrawalkar 2012-03-22 02:10:50 PDT
Created attachment 133209 [details]
Updated ChangeLog
Comment 43 Kaustubh Atrawalkar 2012-03-22 04:08:22 PDT
Created attachment 133218 [details]
Fixed ChangeLog
Comment 44 WebKit Review Bot 2012-03-22 05:39:02 PDT
Comment on attachment 133218 [details]
Fixed ChangeLog

Clearing flags on attachment: 133218

Committed r111672: <http://trac.webkit.org/changeset/111672>
Comment 45 WebKit Review Bot 2012-03-22 05:39:10 PDT
All reviewed patches have been landed.  Closing bug.