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
45namespace WebCore {
46
47WTF_MAKE_ISO_ALLOCATED_IMPL(HTMLFrameSetElement);
48
49using namespace HTMLNames;
50
51HTMLFrameSetElement::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
66Ref<HTMLFrameSetElement> HTMLFrameSetElement::create(const QualifiedName& tagName, Document& document)
67{
68 return adoptRef(*new HTMLFrameSetElement(tagName, document));
69}
70
71bool HTMLFrameSetElement::isPresentationAttribute(const QualifiedName& name) const
72{
73 if (name == bordercolorAttr)
74 return true;
75 return HTMLElement::isPresentationAttribute(name);
76}
77
78void 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
86void 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
158bool 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
165RenderPtr<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
173RefPtr<HTMLFrameSetElement> HTMLFrameSetElement::findContaining(Element* descendant)
174{
175 return ancestorsOfType<HTMLFrameSetElement>(*descendant).first();
176}
177
178void 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
197void 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
208void HTMLFrameSetElement::willRecalcStyle(Style::Change)
209{
210 if (needsStyleRecalc() && renderer())
211 renderer()->setNeedsLayout();
212}
213
214Node::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
225void 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
234WindowProxy* 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
243Vector<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