[Shadow DOM] Refactoring: invalidateParentDistributionIfNecessary() calls are too...
[WebKit-https.git] / Source / WebCore / html / HTMLSummaryElement.cpp
1 /*
2  * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies)
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public License
15  * along with this library; see the file COPYING.LIB.  If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  *
19  */
20
21 #include "config.h"
22 #include "HTMLSummaryElement.h"
23
24 #if ENABLE(DETAILS_ELEMENT)
25 #include "DetailsMarkerControl.h"
26 #include "HTMLContentElement.h"
27 #include "HTMLDetailsElement.h"
28 #include "HTMLNames.h"
29 #include "KeyboardEvent.h"
30 #include "MouseEvent.h"
31 #include "NodeRenderingContext.h"
32 #include "PlatformMouseEvent.h"
33 #include "RenderBlock.h"
34 #include "ShadowRoot.h"
35
36 namespace WebCore {
37
38 using namespace HTMLNames;
39
40 class SummaryContentElement : public HTMLContentElement {
41 public:
42     static PassRefPtr<SummaryContentElement> create(Document*);
43
44 private:
45     SummaryContentElement(Document* document)
46         : HTMLContentElement(HTMLNames::webkitShadowContentTag, document)
47     {
48     }
49 };
50
51 PassRefPtr<SummaryContentElement> SummaryContentElement::create(Document* document)
52 {
53     return adoptRef(new SummaryContentElement(document));
54 }
55
56 PassRefPtr<HTMLSummaryElement> HTMLSummaryElement::create(const QualifiedName& tagName, Document* document)
57 {
58     RefPtr<HTMLSummaryElement> result = adoptRef(new HTMLSummaryElement(tagName, document));
59     result->createShadowSubtree();
60     return result;
61 }
62
63 HTMLSummaryElement::HTMLSummaryElement(const QualifiedName& tagName, Document* document)
64     : HTMLElement(tagName, document)
65 {
66     ASSERT(hasTagName(summaryTag));
67 }
68
69 RenderObject* HTMLSummaryElement::createRenderer(RenderArena* arena, RenderStyle*)
70 {
71     return new (arena) RenderBlock(this);
72 }
73
74 bool HTMLSummaryElement::childShouldCreateRenderer(const NodeRenderingContext& childContext) const
75 {
76     return childContext.isOnEncapsulationBoundary() && HTMLElement::childShouldCreateRenderer(childContext);
77 }
78
79 void HTMLSummaryElement::createShadowSubtree()
80 {
81     ASSERT(!shadow());
82     RefPtr<ShadowRoot> root = ShadowRoot::create(this, ShadowRoot::UserAgentShadowRoot);
83     root->appendChild(DetailsMarkerControl::create(document()), ASSERT_NO_EXCEPTION, true);
84     root->appendChild(SummaryContentElement::create(document()), ASSERT_NO_EXCEPTION, true);
85 }
86
87 HTMLDetailsElement* HTMLSummaryElement::detailsElement() const
88 {
89     Node* mayDetails = const_cast<HTMLSummaryElement*>(this)->parentNodeForRenderingAndStyle();
90     if (!mayDetails || !mayDetails->hasTagName(detailsTag))
91         return 0;
92     return static_cast<HTMLDetailsElement*>(mayDetails);
93 }
94
95 bool HTMLSummaryElement::isMainSummary() const
96 {
97     if (HTMLDetailsElement* details = detailsElement())
98         return details->findMainSummary() == this;
99
100     return false;
101 }
102
103 static bool isClickableControl(Node* node)
104 {
105     if (!node->isElementNode())
106         return false;
107     Element* element = toElement(node);
108     if (element->isFormControlElement())
109         return true;
110     Element* host = element->shadowHost();
111     return host && host->isFormControlElement();
112 }
113
114 bool HTMLSummaryElement::supportsFocus() const
115 {
116     return isMainSummary();
117 }
118
119 void HTMLSummaryElement::defaultEventHandler(Event* event)
120 {
121     if (isMainSummary() && renderer()) {
122         if (event->type() == eventNames().DOMActivateEvent && !isClickableControl(event->target()->toNode())) {
123             if (HTMLDetailsElement* details = detailsElement())
124                 details->toggleOpen();
125             event->setDefaultHandled();
126             return;
127         }
128
129         if (event->isKeyboardEvent()) {
130             if (event->type() == eventNames().keydownEvent && static_cast<KeyboardEvent*>(event)->keyIdentifier() == "U+0020") {
131                 setActive(true, true);
132                 // No setDefaultHandled() - IE dispatches a keypress in this case.
133                 return;
134             }
135             if (event->type() == eventNames().keypressEvent) {
136                 switch (static_cast<KeyboardEvent*>(event)->charCode()) {
137                 case '\r':
138                     dispatchSimulatedClick(event);
139                     event->setDefaultHandled();
140                     return;
141                 case ' ':
142                     // Prevent scrolling down the page.
143                     event->setDefaultHandled();
144                     return;
145                 }
146             }
147             if (event->type() == eventNames().keyupEvent && static_cast<KeyboardEvent*>(event)->keyIdentifier() == "U+0020") {
148                 if (active())
149                     dispatchSimulatedClick(event);
150                 event->setDefaultHandled();
151                 return;
152             }
153         }
154     }
155
156     HTMLElement::defaultEventHandler(event);
157 }
158
159 bool HTMLSummaryElement::willRespondToMouseClickEvents()
160 {
161     if (isMainSummary() && renderer())
162         return true;
163
164     return HTMLElement::willRespondToMouseClickEvents();
165 }
166
167 }
168
169 #endif