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, 2006, 2007, 2008, 2009, 2010 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 "Attribute.h"
28 #include "CSSStyleSelector.h"
29 #include "CSSStyleSheet.h"
30 #include "CSSValueKeywords.h"
31 #include "EventNames.h"
32 #include "Frame.h"
33 #include "FrameView.h"
34 #include "HTMLFrameElementBase.h"
35 #include "HTMLNames.h"
36 #include "HTMLParserIdioms.h"
37 #include "ScriptEventListener.h"
38
39 namespace WebCore {
40
41 using namespace HTMLNames;
42
HTMLBodyElement(const QualifiedName & tagName,Document * document)43 HTMLBodyElement::HTMLBodyElement(const QualifiedName& tagName, Document* document)
44 : HTMLElement(tagName, document)
45 {
46 ASSERT(hasTagName(bodyTag));
47 }
48
create(Document * document)49 PassRefPtr<HTMLBodyElement> HTMLBodyElement::create(Document* document)
50 {
51 return adoptRef(new HTMLBodyElement(bodyTag, document));
52 }
53
create(const QualifiedName & tagName,Document * document)54 PassRefPtr<HTMLBodyElement> HTMLBodyElement::create(const QualifiedName& tagName, Document* document)
55 {
56 return adoptRef(new HTMLBodyElement(tagName, document));
57 }
58
~HTMLBodyElement()59 HTMLBodyElement::~HTMLBodyElement()
60 {
61 if (m_linkDecl) {
62 m_linkDecl->setNode(0);
63 m_linkDecl->setParent(0);
64 }
65 }
66
createLinkDecl()67 void HTMLBodyElement::createLinkDecl()
68 {
69 m_linkDecl = CSSMutableStyleDeclaration::create();
70 m_linkDecl->setParent(document()->elementSheet());
71 m_linkDecl->setNode(this);
72 m_linkDecl->setStrictParsing(!document()->inQuirksMode());
73 }
74
mapToEntry(const QualifiedName & attrName,MappedAttributeEntry & result) const75 bool HTMLBodyElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const
76 {
77 if (attrName == backgroundAttr) {
78 result = (MappedAttributeEntry)(eLastEntry + document()->docID());
79 return false;
80 }
81
82 if (attrName == bgcolorAttr ||
83 attrName == textAttr ||
84 attrName == marginwidthAttr ||
85 attrName == leftmarginAttr ||
86 attrName == marginheightAttr ||
87 attrName == topmarginAttr ||
88 attrName == bgpropertiesAttr) {
89 result = eUniversal;
90 return false;
91 }
92
93 return HTMLElement::mapToEntry(attrName, result);
94 }
95
parseMappedAttribute(Attribute * attr)96 void HTMLBodyElement::parseMappedAttribute(Attribute* attr)
97 {
98 if (attr->name() == backgroundAttr) {
99 String url = stripLeadingAndTrailingHTMLSpaces(attr->value());
100 if (!url.isEmpty())
101 addCSSImageProperty(attr, CSSPropertyBackgroundImage, document()->completeURL(url).string());
102 } else if (attr->name() == marginwidthAttr || attr->name() == leftmarginAttr) {
103 addCSSLength(attr, CSSPropertyMarginRight, attr->value());
104 addCSSLength(attr, CSSPropertyMarginLeft, attr->value());
105 } else if (attr->name() == marginheightAttr || attr->name() == topmarginAttr) {
106 addCSSLength(attr, CSSPropertyMarginBottom, attr->value());
107 addCSSLength(attr, CSSPropertyMarginTop, attr->value());
108 } else if (attr->name() == bgcolorAttr) {
109 addCSSColor(attr, CSSPropertyBackgroundColor, attr->value());
110 } else if (attr->name() == textAttr) {
111 addCSSColor(attr, CSSPropertyColor, attr->value());
112 } else if (attr->name() == bgpropertiesAttr) {
113 if (equalIgnoringCase(attr->value(), "fixed"))
114 addCSSProperty(attr, CSSPropertyBackgroundAttachment, CSSValueFixed);
115 } else if (attr->name() == vlinkAttr ||
116 attr->name() == alinkAttr ||
117 attr->name() == linkAttr) {
118 if (attr->isNull()) {
119 if (attr->name() == linkAttr)
120 document()->resetLinkColor();
121 else if (attr->name() == vlinkAttr)
122 document()->resetVisitedLinkColor();
123 else
124 document()->resetActiveLinkColor();
125 } else {
126 if (!m_linkDecl)
127 createLinkDecl();
128 m_linkDecl->setProperty(CSSPropertyColor, attr->value(), false, false);
129 RefPtr<CSSValue> val = m_linkDecl->getPropertyCSSValue(CSSPropertyColor);
130 if (val && val->isPrimitiveValue()) {
131 Color col = document()->styleSelector()->getColorFromPrimitiveValue(static_cast<CSSPrimitiveValue*>(val.get()));
132 if (attr->name() == linkAttr)
133 document()->setLinkColor(col);
134 else if (attr->name() == vlinkAttr)
135 document()->setVisitedLinkColor(col);
136 else
137 document()->setActiveLinkColor(col);
138 }
139 }
140
141 if (attached())
142 document()->recalcStyle(Force);
143 } else if (attr->name() == onloadAttr)
144 document()->setWindowAttributeEventListener(eventNames().loadEvent, createAttributeEventListener(document()->frame(), attr));
145 else if (attr->name() == onbeforeunloadAttr)
146 document()->setWindowAttributeEventListener(eventNames().beforeunloadEvent, createAttributeEventListener(document()->frame(), attr));
147 else if (attr->name() == onunloadAttr)
148 document()->setWindowAttributeEventListener(eventNames().unloadEvent, createAttributeEventListener(document()->frame(), attr));
149 else if (attr->name() == onpagehideAttr)
150 document()->setWindowAttributeEventListener(eventNames().pagehideEvent, createAttributeEventListener(document()->frame(), attr));
151 else if (attr->name() == onpageshowAttr)
152 document()->setWindowAttributeEventListener(eventNames().pageshowEvent, createAttributeEventListener(document()->frame(), attr));
153 else if (attr->name() == onpopstateAttr)
154 document()->setWindowAttributeEventListener(eventNames().popstateEvent, createAttributeEventListener(document()->frame(), attr));
155 else if (attr->name() == onblurAttr)
156 document()->setWindowAttributeEventListener(eventNames().blurEvent, createAttributeEventListener(document()->frame(), attr));
157 else if (attr->name() == onfocusAttr)
158 document()->setWindowAttributeEventListener(eventNames().focusEvent, createAttributeEventListener(document()->frame(), attr));
159 #if ENABLE(ORIENTATION_EVENTS)
160 else if (attr->name() == onorientationchangeAttr)
161 document()->setWindowAttributeEventListener(eventNames().orientationchangeEvent, createAttributeEventListener(document()->frame(), attr));
162 #endif
163 else if (attr->name() == onhashchangeAttr)
164 document()->setWindowAttributeEventListener(eventNames().hashchangeEvent, createAttributeEventListener(document()->frame(), attr));
165 else if (attr->name() == onresizeAttr)
166 document()->setWindowAttributeEventListener(eventNames().resizeEvent, createAttributeEventListener(document()->frame(), attr));
167 else if (attr->name() == onscrollAttr)
168 document()->setWindowAttributeEventListener(eventNames().scrollEvent, createAttributeEventListener(document()->frame(), attr));
169 else if (attr->name() == onselectionchangeAttr)
170 document()->setAttributeEventListener(eventNames().selectionchangeEvent, createAttributeEventListener(document()->frame(), attr));
171 else if (attr->name() == onstorageAttr)
172 document()->setWindowAttributeEventListener(eventNames().storageEvent, createAttributeEventListener(document()->frame(), attr));
173 else if (attr->name() == ononlineAttr)
174 document()->setWindowAttributeEventListener(eventNames().onlineEvent, createAttributeEventListener(document()->frame(), attr));
175 else if (attr->name() == onofflineAttr)
176 document()->setWindowAttributeEventListener(eventNames().offlineEvent, createAttributeEventListener(document()->frame(), attr));
177 else
178 HTMLElement::parseMappedAttribute(attr);
179 }
180
insertedIntoDocument()181 void HTMLBodyElement::insertedIntoDocument()
182 {
183 HTMLElement::insertedIntoDocument();
184
185 // FIXME: Perhaps this code should be in attach() instead of here.
186 Element* ownerElement = document()->ownerElement();
187 if (ownerElement && (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag))) {
188 HTMLFrameElementBase* ownerFrameElement = static_cast<HTMLFrameElementBase*>(ownerElement);
189 int marginWidth = ownerFrameElement->marginWidth();
190 if (marginWidth != -1)
191 setAttribute(marginwidthAttr, String::number(marginWidth));
192 int marginHeight = ownerFrameElement->marginHeight();
193 if (marginHeight != -1)
194 setAttribute(marginheightAttr, String::number(marginHeight));
195 }
196
197 // FIXME: This call to scheduleRelayout should not be needed here.
198 // But without it we hang during WebKit tests; need to fix that and remove this.
199 if (FrameView* view = document()->view())
200 view->scheduleRelayout();
201
202 if (document() && document()->page())
203 document()->page()->updateViewportArguments();
204 }
205
isURLAttribute(Attribute * attr) const206 bool HTMLBodyElement::isURLAttribute(Attribute *attr) const
207 {
208 return attr->name() == backgroundAttr;
209 }
210
supportsFocus() const211 bool HTMLBodyElement::supportsFocus() const
212 {
213 return rendererIsEditable() || HTMLElement::supportsFocus();
214 }
215
aLink() const216 String HTMLBodyElement::aLink() const
217 {
218 return getAttribute(alinkAttr);
219 }
220
setALink(const String & value)221 void HTMLBodyElement::setALink(const String& value)
222 {
223 setAttribute(alinkAttr, value);
224 }
225
bgColor() const226 String HTMLBodyElement::bgColor() const
227 {
228 return getAttribute(bgcolorAttr);
229 }
230
setBgColor(const String & value)231 void HTMLBodyElement::setBgColor(const String& value)
232 {
233 setAttribute(bgcolorAttr, value);
234 }
235
link() const236 String HTMLBodyElement::link() const
237 {
238 return getAttribute(linkAttr);
239 }
240
setLink(const String & value)241 void HTMLBodyElement::setLink(const String& value)
242 {
243 setAttribute(linkAttr, value);
244 }
245
text() const246 String HTMLBodyElement::text() const
247 {
248 return getAttribute(textAttr);
249 }
250
setText(const String & value)251 void HTMLBodyElement::setText(const String& value)
252 {
253 setAttribute(textAttr, value);
254 }
255
vLink() const256 String HTMLBodyElement::vLink() const
257 {
258 return getAttribute(vlinkAttr);
259 }
260
setVLink(const String & value)261 void HTMLBodyElement::setVLink(const String& value)
262 {
263 setAttribute(vlinkAttr, value);
264 }
265
adjustForZoom(int value,Document * document)266 static int adjustForZoom(int value, Document* document)
267 {
268 Frame* frame = document->frame();
269 float zoomFactor = frame->pageZoomFactor() * frame->pageScaleFactor();
270 if (zoomFactor == 1)
271 return value;
272 // Needed because of truncation (rather than rounding) when scaling up.
273 if (zoomFactor > 1)
274 value++;
275 return static_cast<int>(value / zoomFactor);
276 }
277
scrollLeft() const278 int HTMLBodyElement::scrollLeft() const
279 {
280 // Update the document's layout.
281 Document* document = this->document();
282 document->updateLayoutIgnorePendingStylesheets();
283 FrameView* view = document->view();
284 return view ? adjustForZoom(view->scrollX(), document) : 0;
285 }
286
setScrollLeft(int scrollLeft)287 void HTMLBodyElement::setScrollLeft(int scrollLeft)
288 {
289 Document* document = this->document();
290 document->updateLayoutIgnorePendingStylesheets();
291 Frame* frame = document->frame();
292 if (!frame)
293 return;
294 FrameView* view = frame->view();
295 if (!view)
296 return;
297 view->setScrollPosition(IntPoint(static_cast<int>(scrollLeft * frame->pageZoomFactor() * frame->pageScaleFactor()), view->scrollY()));
298 }
299
scrollTop() const300 int HTMLBodyElement::scrollTop() const
301 {
302 // Update the document's layout.
303 Document* document = this->document();
304 document->updateLayoutIgnorePendingStylesheets();
305 FrameView* view = document->view();
306 return view ? adjustForZoom(view->scrollY(), document) : 0;
307 }
308
setScrollTop(int scrollTop)309 void HTMLBodyElement::setScrollTop(int scrollTop)
310 {
311 Document* document = this->document();
312 document->updateLayoutIgnorePendingStylesheets();
313 Frame* frame = document->frame();
314 if (!frame)
315 return;
316 FrameView* view = frame->view();
317 if (!view)
318 return;
319 view->setScrollPosition(IntPoint(view->scrollX(), static_cast<int>(scrollTop * frame->pageZoomFactor() * frame->pageScaleFactor())));
320 }
321
scrollHeight() const322 int HTMLBodyElement::scrollHeight() const
323 {
324 // Update the document's layout.
325 Document* document = this->document();
326 document->updateLayoutIgnorePendingStylesheets();
327 FrameView* view = document->view();
328 return view ? adjustForZoom(view->contentsHeight(), document) : 0;
329 }
330
scrollWidth() const331 int HTMLBodyElement::scrollWidth() const
332 {
333 // Update the document's layout.
334 Document* document = this->document();
335 document->updateLayoutIgnorePendingStylesheets();
336 FrameView* view = document->view();
337 return view ? adjustForZoom(view->contentsWidth(), document) : 0;
338 }
339
addSubresourceAttributeURLs(ListHashSet<KURL> & urls) const340 void HTMLBodyElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
341 {
342 HTMLElement::addSubresourceAttributeURLs(urls);
343
344 addSubresourceURL(urls, document()->completeURL(getAttribute(backgroundAttr)));
345 }
346
didMoveToNewOwnerDocument()347 void HTMLBodyElement::didMoveToNewOwnerDocument()
348 {
349 // When moving body elements between documents, we should have to reset the parent sheet for any
350 // link style declarations. If we don't we might crash later.
351 // In practice I can't reproduce this theoretical problem.
352 // webarchive/adopt-attribute-styled-body-webarchive.html tries to make sure this crash won't surface.
353 if (m_linkDecl)
354 m_linkDecl->setParent(document()->elementSheet());
355
356 HTMLElement::didMoveToNewOwnerDocument();
357 }
358
359 } // namespace WebCore
360