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 "HTMLBodyElement.h" |
26 | |
27 | #include "CSSImageValue.h" |
28 | #include "CSSParser.h" |
29 | #include "CSSValueKeywords.h" |
30 | #include "DOMWindow.h" |
31 | #include "DOMWrapperWorld.h" |
32 | #include "EventNames.h" |
33 | #include "HTMLFrameElement.h" |
34 | #include "HTMLIFrameElement.h" |
35 | #include "HTMLNames.h" |
36 | #include "HTMLParserIdioms.h" |
37 | #include "StyleProperties.h" |
38 | #include <wtf/IsoMallocInlines.h> |
39 | #include <wtf/NeverDestroyed.h> |
40 | |
41 | namespace WebCore { |
42 | |
43 | WTF_MAKE_ISO_ALLOCATED_IMPL(HTMLBodyElement); |
44 | |
45 | using namespace HTMLNames; |
46 | |
47 | HTMLBodyElement::HTMLBodyElement(const QualifiedName& tagName, Document& document) |
48 | : HTMLElement(tagName, document) |
49 | { |
50 | ASSERT(hasTagName(bodyTag)); |
51 | } |
52 | |
53 | Ref<HTMLBodyElement> HTMLBodyElement::create(Document& document) |
54 | { |
55 | return adoptRef(*new HTMLBodyElement(bodyTag, document)); |
56 | } |
57 | |
58 | Ref<HTMLBodyElement> HTMLBodyElement::create(const QualifiedName& tagName, Document& document) |
59 | { |
60 | return adoptRef(*new HTMLBodyElement(tagName, document)); |
61 | } |
62 | |
63 | HTMLBodyElement::~HTMLBodyElement() = default; |
64 | |
65 | bool HTMLBodyElement::isPresentationAttribute(const QualifiedName& name) const |
66 | { |
67 | if (name == backgroundAttr || name == marginwidthAttr || name == leftmarginAttr || name == marginheightAttr || name == topmarginAttr || name == bgcolorAttr || name == textAttr || name == bgpropertiesAttr) |
68 | return true; |
69 | return HTMLElement::isPresentationAttribute(name); |
70 | } |
71 | |
72 | void HTMLBodyElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStyleProperties& style) |
73 | { |
74 | if (name == backgroundAttr) { |
75 | String url = stripLeadingAndTrailingHTMLSpaces(value); |
76 | if (!url.isEmpty()) { |
77 | auto imageValue = CSSImageValue::create(document().completeURL(url), LoadedFromOpaqueSource::No); |
78 | imageValue.get().setInitiator(localName()); |
79 | style.setProperty(CSSProperty(CSSPropertyBackgroundImage, WTFMove(imageValue))); |
80 | } |
81 | } else if (name == marginwidthAttr || name == leftmarginAttr) { |
82 | addHTMLLengthToStyle(style, CSSPropertyMarginRight, value); |
83 | addHTMLLengthToStyle(style, CSSPropertyMarginLeft, value); |
84 | } else if (name == marginheightAttr || name == topmarginAttr) { |
85 | addHTMLLengthToStyle(style, CSSPropertyMarginBottom, value); |
86 | addHTMLLengthToStyle(style, CSSPropertyMarginTop, value); |
87 | } else if (name == bgcolorAttr) { |
88 | addHTMLColorToStyle(style, CSSPropertyBackgroundColor, value); |
89 | } else if (name == textAttr) { |
90 | addHTMLColorToStyle(style, CSSPropertyColor, value); |
91 | } else if (name == bgpropertiesAttr) { |
92 | if (equalLettersIgnoringASCIICase(value, "fixed" )) |
93 | addPropertyToPresentationAttributeStyle(style, CSSPropertyBackgroundAttachment, CSSValueFixed); |
94 | } else |
95 | HTMLElement::collectStyleForPresentationAttribute(name, value, style); |
96 | } |
97 | |
98 | HTMLElement::EventHandlerNameMap HTMLBodyElement::createWindowEventHandlerNameMap() |
99 | { |
100 | static const QualifiedName* const table[] = { |
101 | &onafterprintAttr.get(), |
102 | &onbeforeprintAttr.get(), |
103 | &onbeforeunloadAttr.get(), |
104 | &onblurAttr.get(), |
105 | &onerrorAttr.get(), |
106 | &onfocusAttr.get(), |
107 | &onfocusinAttr.get(), |
108 | &onfocusoutAttr.get(), |
109 | &onhashchangeAttr.get(), |
110 | &onlanguagechangeAttr.get(), |
111 | &onloadAttr.get(), |
112 | &onmessageAttr.get(), |
113 | &onofflineAttr.get(), |
114 | &ononlineAttr.get(), |
115 | &onorientationchangeAttr.get(), |
116 | &onpagehideAttr.get(), |
117 | &onpageshowAttr.get(), |
118 | &onpopstateAttr.get(), |
119 | &onresizeAttr.get(), |
120 | &onscrollAttr.get(), |
121 | &onstorageAttr.get(), |
122 | &onunloadAttr.get(), |
123 | &onwebkitmouseforcechangedAttr.get(), |
124 | &onwebkitmouseforcedownAttr.get(), |
125 | &onwebkitmouseforceupAttr.get(), |
126 | &onwebkitmouseforcewillbeginAttr.get(), |
127 | &onwebkitwillrevealbottomAttr.get(), |
128 | &onwebkitwillrevealleftAttr.get(), |
129 | &onwebkitwillrevealrightAttr.get(), |
130 | &onwebkitwillrevealtopAttr.get(), |
131 | }; |
132 | |
133 | EventHandlerNameMap map; |
134 | populateEventHandlerNameMap(map, table); |
135 | return map; |
136 | } |
137 | |
138 | const AtomicString& HTMLBodyElement::eventNameForWindowEventHandlerAttribute(const QualifiedName& attributeName) |
139 | { |
140 | static NeverDestroyed<EventHandlerNameMap> map = createWindowEventHandlerNameMap(); |
141 | return eventNameForEventHandlerAttribute(attributeName, map.get()); |
142 | } |
143 | |
144 | void HTMLBodyElement::parseAttribute(const QualifiedName& name, const AtomicString& value) |
145 | { |
146 | if (name == vlinkAttr || name == alinkAttr || name == linkAttr) { |
147 | if (value.isNull()) { |
148 | if (name == linkAttr) |
149 | document().resetLinkColor(); |
150 | else if (name == vlinkAttr) |
151 | document().resetVisitedLinkColor(); |
152 | else |
153 | document().resetActiveLinkColor(); |
154 | } else { |
155 | Color color = CSSParser::parseColor(value, !document().inQuirksMode()); |
156 | if (color.isValid()) { |
157 | if (name == linkAttr) |
158 | document().setLinkColor(color); |
159 | else if (name == vlinkAttr) |
160 | document().setVisitedLinkColor(color); |
161 | else |
162 | document().setActiveLinkColor(color); |
163 | } |
164 | } |
165 | |
166 | invalidateStyleForSubtree(); |
167 | return; |
168 | } |
169 | |
170 | if (name == onselectionchangeAttr) { |
171 | document().setAttributeEventListener(eventNames().selectionchangeEvent, name, value, mainThreadNormalWorld()); |
172 | return; |
173 | } |
174 | |
175 | auto& eventName = eventNameForWindowEventHandlerAttribute(name); |
176 | if (!eventName.isNull()) { |
177 | document().setWindowAttributeEventListener(eventName, name, value, mainThreadNormalWorld()); |
178 | return; |
179 | } |
180 | |
181 | HTMLElement::parseAttribute(name, value); |
182 | } |
183 | |
184 | Node::InsertedIntoAncestorResult HTMLBodyElement::insertedIntoAncestor(InsertionType insertionType, ContainerNode& parentOfInsertedTree) |
185 | { |
186 | HTMLElement::insertedIntoAncestor(insertionType, parentOfInsertedTree); |
187 | if (!insertionType.connectedToDocument) |
188 | return InsertedIntoAncestorResult::Done; |
189 | |
190 | // FIXME: It's surprising this is web compatible since it means a marginwidth and marginheight attribute can |
191 | // magically appear on the <body> of all documents embedded through <iframe> or <frame>. |
192 | // FIXME: Perhaps this code should be in attach() instead of here. |
193 | auto ownerElement = makeRefPtr(document().ownerElement()); |
194 | if (!is<HTMLFrameElementBase>(ownerElement)) |
195 | return InsertedIntoAncestorResult::Done; |
196 | |
197 | return InsertedIntoAncestorResult::NeedsPostInsertionCallback; |
198 | } |
199 | |
200 | void HTMLBodyElement::didFinishInsertingNode() |
201 | { |
202 | auto ownerElement = makeRefPtr(document().ownerElement()); |
203 | RELEASE_ASSERT(is<HTMLFrameElementBase>(ownerElement)); |
204 | auto& ownerFrameElement = downcast<HTMLFrameElementBase>(*ownerElement); |
205 | |
206 | // Read values from the owner before setting any attributes, since setting an attribute can run arbitrary |
207 | // JavaScript, which might delete the owner element. |
208 | int marginWidth = ownerFrameElement.marginWidth(); |
209 | int marginHeight = ownerFrameElement.marginHeight(); |
210 | |
211 | if (marginWidth != -1) |
212 | setIntegralAttribute(marginwidthAttr, marginWidth); |
213 | if (marginHeight != -1) |
214 | setIntegralAttribute(marginheightAttr, marginHeight); |
215 | } |
216 | |
217 | bool HTMLBodyElement::isURLAttribute(const Attribute& attribute) const |
218 | { |
219 | return attribute.name() == backgroundAttr || HTMLElement::isURLAttribute(attribute); |
220 | } |
221 | |
222 | bool HTMLBodyElement::supportsFocus() const |
223 | { |
224 | return hasEditableStyle() || HTMLElement::supportsFocus(); |
225 | } |
226 | |
227 | void HTMLBodyElement::addSubresourceAttributeURLs(ListHashSet<URL>& urls) const |
228 | { |
229 | HTMLElement::addSubresourceAttributeURLs(urls); |
230 | |
231 | addSubresourceURL(urls, document().completeURL(attributeWithoutSynchronization(backgroundAttr))); |
232 | } |
233 | |
234 | } // namespace WebCore |
235 | |