Create render tree lazily
[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 "HTMLDetailsElement.h"
27 #include "InsertionPoint.h"
28 #include "KeyboardEvent.h"
29 #include "MouseEvent.h"
30 #include "NodeRenderingTraversal.h"
31 #include "PlatformMouseEvent.h"
32 #include "RenderBlockFlow.h"
33
34 namespace WebCore {
35
36 using namespace HTMLNames;
37
38 class SummaryContentElement : public InsertionPoint {
39 public:
40     static PassRefPtr<SummaryContentElement> create(Document&);
41
42 private:
43     SummaryContentElement(Document& document)
44         : InsertionPoint(webkitShadowContentTag, document)
45     {
46     }
47 };
48
49 PassRefPtr<SummaryContentElement> SummaryContentElement::create(Document& document)
50 {
51     return adoptRef(new SummaryContentElement(document));
52 }
53
54 PassRefPtr<HTMLSummaryElement> HTMLSummaryElement::create(const QualifiedName& tagName, Document& document)
55 {
56     RefPtr<HTMLSummaryElement> summary = adoptRef(new HTMLSummaryElement(tagName, document));
57     summary->ensureUserAgentShadowRoot();
58     return summary.release();
59 }
60
61 HTMLSummaryElement::HTMLSummaryElement(const QualifiedName& tagName, Document& document)
62     : HTMLElement(tagName, document)
63 {
64     ASSERT(hasTagName(summaryTag));
65 }
66
67 RenderElement* HTMLSummaryElement::createRenderer(PassRef<RenderStyle> style)
68 {
69     return new RenderBlockFlow(*this, std::move(style));
70 }
71
72 bool HTMLSummaryElement::childShouldCreateRenderer(const Node& child) const
73 {
74     if (child.isPseudoElement())
75         return HTMLElement::childShouldCreateRenderer(child);
76
77     return hasShadowRootOrActiveInsertionPointParent(child) && HTMLElement::childShouldCreateRenderer(child);
78 }
79
80 void HTMLSummaryElement::didAddUserAgentShadowRoot(ShadowRoot* root)
81 {
82     root->appendChild(DetailsMarkerControl::create(document()), ASSERT_NO_EXCEPTION);
83     root->appendChild(SummaryContentElement::create(document()), ASSERT_NO_EXCEPTION);
84 }
85
86 HTMLDetailsElement* HTMLSummaryElement::detailsElement() const
87 {
88     Node* mayDetails = NodeRenderingTraversal::parent(this);
89     if (!mayDetails || !mayDetails->hasTagName(detailsTag))
90         return 0;
91     return toHTMLDetailsElement(mayDetails);
92 }
93
94 bool HTMLSummaryElement::isMainSummary() const
95 {
96     if (HTMLDetailsElement* details = detailsElement())
97         return details->findMainSummary() == this;
98
99     return false;
100 }
101
102 static bool isClickableControl(Node* node)
103 {
104     if (!node->isElementNode())
105         return false;
106     Element* element = toElement(node);
107     if (element->isFormControlElement())
108         return true;
109     Element* host = element->shadowHost();
110     return host && host->isFormControlElement();
111 }
112
113 bool HTMLSummaryElement::supportsFocus() const
114 {
115     return isMainSummary();
116 }
117
118 void HTMLSummaryElement::defaultEventHandler(Event* event)
119 {
120     if (isMainSummary() && renderer()) {
121         if (event->type() == eventNames().DOMActivateEvent && !isClickableControl(event->target()->toNode())) {
122             if (HTMLDetailsElement* details = detailsElement())
123                 details->toggleOpen();
124             event->setDefaultHandled();
125             return;
126         }
127
128         if (event->isKeyboardEvent()) {
129             if (event->type() == eventNames().keydownEvent && static_cast<KeyboardEvent*>(event)->keyIdentifier() == "U+0020") {
130                 setActive(true, true);
131                 // No setDefaultHandled() - IE dispatches a keypress in this case.
132                 return;
133             }
134             if (event->type() == eventNames().keypressEvent) {
135                 switch (static_cast<KeyboardEvent*>(event)->charCode()) {
136                 case '\r':
137                     dispatchSimulatedClick(event);
138                     event->setDefaultHandled();
139                     return;
140                 case ' ':
141                     // Prevent scrolling down the page.
142                     event->setDefaultHandled();
143                     return;
144                 }
145             }
146             if (event->type() == eventNames().keyupEvent && static_cast<KeyboardEvent*>(event)->keyIdentifier() == "U+0020") {
147                 if (active())
148                     dispatchSimulatedClick(event);
149                 event->setDefaultHandled();
150                 return;
151             }
152         }
153     }
154
155     HTMLElement::defaultEventHandler(event);
156 }
157
158 bool HTMLSummaryElement::willRespondToMouseClickEvents()
159 {
160     if (isMainSummary() && renderer())
161         return true;
162
163     return HTMLElement::willRespondToMouseClickEvents();
164 }
165
166 }
167
168 #endif