1 | /* |
2 | * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
3 | * (C) 1999 Antti Koivisto (koivisto@kde.org) |
4 | * (C) 2000 Simon Hausmann (hausmann@kde.org) |
5 | * (C) 2001 Dirk Mueller (mueller@kde.org) |
6 | * Copyright (C) 2004-2017 Apple Inc. All rights reserved. |
7 | * |
8 | * This library is free software; you can redistribute it and/or |
9 | * modify it under the terms of the GNU Library General Public |
10 | * License as published by the Free Software Foundation; either |
11 | * version 2 of the License, or (at your option) any later version. |
12 | * |
13 | * This library is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 | * Library General Public License for more details. |
17 | * |
18 | * You should have received a copy of the GNU Library General Public License |
19 | * along with this library; see the file COPYING.LIB. If not, write to |
20 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
21 | * Boston, MA 02110-1301, USA. |
22 | */ |
23 | |
24 | #include "config.h" |
25 | #include "HTMLFrameSetElement.h" |
26 | |
27 | #include "CSSPropertyNames.h" |
28 | #include "DOMWrapperWorld.h" |
29 | #include "Document.h" |
30 | #include "ElementIterator.h" |
31 | #include "Event.h" |
32 | #include "Frame.h" |
33 | #include "FrameLoader.h" |
34 | #include "FrameLoaderClient.h" |
35 | #include "HTMLBodyElement.h" |
36 | #include "HTMLCollection.h" |
37 | #include "HTMLFrameElement.h" |
38 | #include "HTMLNames.h" |
39 | #include "Length.h" |
40 | #include "MouseEvent.h" |
41 | #include "RenderFrameSet.h" |
42 | #include "Text.h" |
43 | #include <wtf/IsoMallocInlines.h> |
44 | |
45 | namespace WebCore { |
46 | |
47 | WTF_MAKE_ISO_ALLOCATED_IMPL(HTMLFrameSetElement); |
48 | |
49 | using namespace HTMLNames; |
50 | |
51 | HTMLFrameSetElement::HTMLFrameSetElement(const QualifiedName& tagName, Document& document) |
52 | : HTMLElement(tagName, document) |
53 | , m_totalRows(1) |
54 | , m_totalCols(1) |
55 | , m_border(6) |
56 | , m_borderSet(false) |
57 | , m_borderColorSet(false) |
58 | , m_frameborder(true) |
59 | , m_frameborderSet(false) |
60 | , m_noresize(false) |
61 | { |
62 | ASSERT(hasTagName(framesetTag)); |
63 | setHasCustomStyleResolveCallbacks(); |
64 | } |
65 | |
66 | Ref<HTMLFrameSetElement> HTMLFrameSetElement::create(const QualifiedName& tagName, Document& document) |
67 | { |
68 | return adoptRef(*new HTMLFrameSetElement(tagName, document)); |
69 | } |
70 | |
71 | bool HTMLFrameSetElement::isPresentationAttribute(const QualifiedName& name) const |
72 | { |
73 | if (name == bordercolorAttr) |
74 | return true; |
75 | return HTMLElement::isPresentationAttribute(name); |
76 | } |
77 | |
78 | void HTMLFrameSetElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStyleProperties& style) |
79 | { |
80 | if (name == bordercolorAttr) |
81 | addHTMLColorToStyle(style, CSSPropertyBorderColor, value); |
82 | else |
83 | HTMLElement::collectStyleForPresentationAttribute(name, value, style); |
84 | } |
85 | |
86 | void HTMLFrameSetElement::parseAttribute(const QualifiedName& name, const AtomicString& value) |
87 | { |
88 | if (name == rowsAttr) { |
89 | // FIXME: What is the right thing to do when removing this attribute? |
90 | // Why not treat it the same way we treat setting it to the empty string? |
91 | if (!value.isNull()) { |
92 | m_rowLengths = newLengthArray(value.string(), m_totalRows); |
93 | // FIXME: Would be nice to optimize the case where m_rowLengths did not change. |
94 | invalidateStyleForSubtree(); |
95 | } |
96 | return; |
97 | } |
98 | |
99 | if (name == colsAttr) { |
100 | // FIXME: What is the right thing to do when removing this attribute? |
101 | // Why not treat it the same way we treat setting it to the empty string? |
102 | if (!value.isNull()) { |
103 | m_colLengths = newLengthArray(value.string(), m_totalCols); |
104 | // FIXME: Would be nice to optimize the case where m_colLengths did not change. |
105 | invalidateStyleForSubtree(); |
106 | } |
107 | return; |
108 | } |
109 | |
110 | if (name == frameborderAttr) { |
111 | if (!value.isNull()) { |
112 | if (equalLettersIgnoringASCIICase(value, "no" ) || value == "0" ) { |
113 | m_frameborder = false; |
114 | m_frameborderSet = true; |
115 | } else if (equalLettersIgnoringASCIICase(value, "yes" ) || value == "1" ) { |
116 | m_frameborderSet = true; |
117 | } |
118 | } else { |
119 | m_frameborder = false; |
120 | m_frameborderSet = false; |
121 | } |
122 | // FIXME: Do we need to trigger repainting? |
123 | return; |
124 | } |
125 | |
126 | if (name == noresizeAttr) { |
127 | // FIXME: This should set m_noresize to false if the value is null. |
128 | m_noresize = true; |
129 | return; |
130 | } |
131 | |
132 | if (name == borderAttr) { |
133 | if (!value.isNull()) { |
134 | m_border = value.toInt(); |
135 | m_borderSet = true; |
136 | } else |
137 | m_borderSet = false; |
138 | // FIXME: Do we need to trigger repainting? |
139 | return; |
140 | } |
141 | |
142 | if (name == bordercolorAttr) { |
143 | m_borderColorSet = !value.isEmpty(); |
144 | // FIXME: Clearly wrong: This can overwrite the value inherited from the parent frameset. |
145 | // FIXME: Do we need to trigger repainting? |
146 | return; |
147 | } |
148 | |
149 | auto& eventName = HTMLBodyElement::eventNameForWindowEventHandlerAttribute(name); |
150 | if (!eventName.isNull()) { |
151 | document().setWindowAttributeEventListener(eventName, name, value, mainThreadNormalWorld()); |
152 | return; |
153 | } |
154 | |
155 | HTMLElement::parseAttribute(name, value); |
156 | } |
157 | |
158 | bool HTMLFrameSetElement::rendererIsNeeded(const RenderStyle& style) |
159 | { |
160 | // For compatibility, frames render even when display: none is set. |
161 | // However, we delay creating a renderer until stylesheets have loaded. |
162 | return !style.isNotFinal(); |
163 | } |
164 | |
165 | RenderPtr<RenderElement> HTMLFrameSetElement::createElementRenderer(RenderStyle&& style, const RenderTreePosition&) |
166 | { |
167 | if (style.hasContent()) |
168 | return RenderElement::createFor(*this, WTFMove(style)); |
169 | |
170 | return createRenderer<RenderFrameSet>(*this, WTFMove(style)); |
171 | } |
172 | |
173 | RefPtr<HTMLFrameSetElement> HTMLFrameSetElement::findContaining(Element* descendant) |
174 | { |
175 | return ancestorsOfType<HTMLFrameSetElement>(*descendant).first(); |
176 | } |
177 | |
178 | void HTMLFrameSetElement::willAttachRenderers() |
179 | { |
180 | // Inherit default settings from parent frameset. |
181 | // FIXME: This is not dynamic. |
182 | const auto containingFrameSet = findContaining(this); |
183 | if (!containingFrameSet) |
184 | return; |
185 | if (!m_frameborderSet) |
186 | m_frameborder = containingFrameSet->hasFrameBorder(); |
187 | if (m_frameborder) { |
188 | if (!m_borderSet) |
189 | m_border = containingFrameSet->border(); |
190 | if (!m_borderColorSet) |
191 | m_borderColorSet = containingFrameSet->hasBorderColor(); |
192 | } |
193 | if (!m_noresize) |
194 | m_noresize = containingFrameSet->noResize(); |
195 | } |
196 | |
197 | void HTMLFrameSetElement::defaultEventHandler(Event& event) |
198 | { |
199 | if (is<MouseEvent>(event) && !m_noresize && is<RenderFrameSet>(renderer())) { |
200 | if (downcast<RenderFrameSet>(*renderer()).userResize(downcast<MouseEvent>(event))) { |
201 | event.setDefaultHandled(); |
202 | return; |
203 | } |
204 | } |
205 | HTMLElement::defaultEventHandler(event); |
206 | } |
207 | |
208 | void HTMLFrameSetElement::willRecalcStyle(Style::Change) |
209 | { |
210 | if (needsStyleRecalc() && renderer()) |
211 | renderer()->setNeedsLayout(); |
212 | } |
213 | |
214 | Node::InsertedIntoAncestorResult HTMLFrameSetElement::insertedIntoAncestor(InsertionType insertionType, ContainerNode& parentOfInsertedTree) |
215 | { |
216 | HTMLElement::insertedIntoAncestor(insertionType, parentOfInsertedTree); |
217 | if (insertionType.connectedToDocument) { |
218 | if (RefPtr<Frame> frame = document().frame()) |
219 | frame->loader().client().dispatchDidBecomeFrameset(document().isFrameSet()); |
220 | } |
221 | |
222 | return InsertedIntoAncestorResult::Done; |
223 | } |
224 | |
225 | void HTMLFrameSetElement::removedFromAncestor(RemovalType removalType, ContainerNode& oldParentOfRemovedTree) |
226 | { |
227 | HTMLElement::removedFromAncestor(removalType, oldParentOfRemovedTree); |
228 | if (removalType.disconnectedFromDocument) { |
229 | if (RefPtr<Frame> frame = document().frame()) |
230 | frame->loader().client().dispatchDidBecomeFrameset(document().isFrameSet()); |
231 | } |
232 | } |
233 | |
234 | WindowProxy* HTMLFrameSetElement::namedItem(const AtomicString& name) |
235 | { |
236 | auto frameElement = makeRefPtr(children()->namedItem(name)); |
237 | if (!is<HTMLFrameElement>(frameElement)) |
238 | return nullptr; |
239 | |
240 | return downcast<HTMLFrameElement>(*frameElement).contentWindow(); |
241 | } |
242 | |
243 | Vector<AtomicString> HTMLFrameSetElement::supportedPropertyNames() const |
244 | { |
245 | // NOTE: Left empty as no specification defines this named getter and we |
246 | // have not historically exposed these named items for enumeration. |
247 | return { }; |
248 | } |
249 | |
250 | } // namespace WebCore |
251 | |