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 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 "CSSStyleSelector.h"
28 #include "CSSStyleSheet.h"
29 #include "CSSValueKeywords.h"
30 #include "EventNames.h"
31 #include "Frame.h"
32 #include "FrameView.h"
33 #include "HTMLFrameElementBase.h"
34 #include "HTMLNames.h"
35 #include "MappedAttribute.h"
36 #include "ScriptEventListener.h"
37
38 #ifdef ANDROID_META_SUPPORT
39 #include "Settings.h"
40 #include "WebViewCore.h"
41 #endif
42
43 namespace WebCore {
44
45 using namespace HTMLNames;
46
HTMLBodyElement(const QualifiedName & tagName,Document * document)47 HTMLBodyElement::HTMLBodyElement(const QualifiedName& tagName, Document* document)
48 : HTMLElement(tagName, document)
49 {
50 ASSERT(hasTagName(bodyTag));
51 }
52
~HTMLBodyElement()53 HTMLBodyElement::~HTMLBodyElement()
54 {
55 if (m_linkDecl) {
56 m_linkDecl->setNode(0);
57 m_linkDecl->setParent(0);
58 }
59 }
60
createLinkDecl()61 void HTMLBodyElement::createLinkDecl()
62 {
63 m_linkDecl = CSSMutableStyleDeclaration::create();
64 m_linkDecl->setParent(document()->elementSheet());
65 m_linkDecl->setNode(this);
66 m_linkDecl->setStrictParsing(!document()->inCompatMode());
67 }
68
mapToEntry(const QualifiedName & attrName,MappedAttributeEntry & result) const69 bool HTMLBodyElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const
70 {
71 if (attrName == backgroundAttr) {
72 result = (MappedAttributeEntry)(eLastEntry + document()->docID());
73 return false;
74 }
75
76 if (attrName == bgcolorAttr ||
77 attrName == textAttr ||
78 attrName == marginwidthAttr ||
79 attrName == leftmarginAttr ||
80 attrName == marginheightAttr ||
81 attrName == topmarginAttr ||
82 attrName == bgpropertiesAttr) {
83 result = eUniversal;
84 return false;
85 }
86
87 return HTMLElement::mapToEntry(attrName, result);
88 }
89
parseMappedAttribute(MappedAttribute * attr)90 void HTMLBodyElement::parseMappedAttribute(MappedAttribute *attr)
91 {
92 if (attr->name() == backgroundAttr) {
93 String url = deprecatedParseURL(attr->value());
94 if (!url.isEmpty())
95 addCSSImageProperty(attr, CSSPropertyBackgroundImage, document()->completeURL(url).string());
96 } else if (attr->name() == marginwidthAttr || attr->name() == leftmarginAttr) {
97 addCSSLength(attr, CSSPropertyMarginRight, attr->value());
98 addCSSLength(attr, CSSPropertyMarginLeft, attr->value());
99 } else if (attr->name() == marginheightAttr || attr->name() == topmarginAttr) {
100 addCSSLength(attr, CSSPropertyMarginBottom, attr->value());
101 addCSSLength(attr, CSSPropertyMarginTop, attr->value());
102 } else if (attr->name() == bgcolorAttr) {
103 addCSSColor(attr, CSSPropertyBackgroundColor, attr->value());
104 } else if (attr->name() == textAttr) {
105 addCSSColor(attr, CSSPropertyColor, attr->value());
106 } else if (attr->name() == bgpropertiesAttr) {
107 if (equalIgnoringCase(attr->value(), "fixed"))
108 addCSSProperty(attr, CSSPropertyBackgroundAttachment, CSSValueFixed);
109 } else if (attr->name() == vlinkAttr ||
110 attr->name() == alinkAttr ||
111 attr->name() == linkAttr) {
112 if (attr->isNull()) {
113 if (attr->name() == linkAttr)
114 document()->resetLinkColor();
115 else if (attr->name() == vlinkAttr)
116 document()->resetVisitedLinkColor();
117 else
118 document()->resetActiveLinkColor();
119 } else {
120 if (!m_linkDecl)
121 createLinkDecl();
122 m_linkDecl->setProperty(CSSPropertyColor, attr->value(), false, false);
123 RefPtr<CSSValue> val = m_linkDecl->getPropertyCSSValue(CSSPropertyColor);
124 if (val && val->isPrimitiveValue()) {
125 Color col = document()->styleSelector()->getColorFromPrimitiveValue(static_cast<CSSPrimitiveValue*>(val.get()));
126 if (attr->name() == linkAttr)
127 document()->setLinkColor(col);
128 else if (attr->name() == vlinkAttr)
129 document()->setVisitedLinkColor(col);
130 else
131 document()->setActiveLinkColor(col);
132 }
133 }
134
135 if (attached())
136 document()->recalcStyle(Force);
137 } else if (attr->name() == onloadAttr)
138 document()->setWindowAttributeEventListener(eventNames().loadEvent, createAttributeEventListener(document()->frame(), attr));
139 else if (attr->name() == onbeforeunloadAttr)
140 document()->setWindowAttributeEventListener(eventNames().beforeunloadEvent, createAttributeEventListener(document()->frame(), attr));
141 else if (attr->name() == onunloadAttr)
142 document()->setWindowAttributeEventListener(eventNames().unloadEvent, createAttributeEventListener(document()->frame(), attr));
143 else if (attr->name() == onblurAttr)
144 document()->setWindowAttributeEventListener(eventNames().blurEvent, createAttributeEventListener(document()->frame(), attr));
145 else if (attr->name() == onfocusAttr)
146 document()->setWindowAttributeEventListener(eventNames().focusEvent, createAttributeEventListener(document()->frame(), attr));
147 else if (attr->name() == onhashchangeAttr)
148 document()->setWindowAttributeEventListener(eventNames().hashchangeEvent, createAttributeEventListener(document()->frame(), attr));
149 else if (attr->name() == onresizeAttr)
150 document()->setWindowAttributeEventListener(eventNames().resizeEvent, createAttributeEventListener(document()->frame(), attr));
151 else if (attr->name() == onscrollAttr)
152 document()->setWindowAttributeEventListener(eventNames().scrollEvent, createAttributeEventListener(document()->frame(), attr));
153 else if (attr->name() == onstorageAttr)
154 document()->setWindowAttributeEventListener(eventNames().storageEvent, createAttributeEventListener(document()->frame(), attr));
155 else if (attr->name() == ononlineAttr)
156 document()->setWindowAttributeEventListener(eventNames().onlineEvent, createAttributeEventListener(document()->frame(), attr));
157 else if (attr->name() == onofflineAttr)
158 document()->setWindowAttributeEventListener(eventNames().offlineEvent, createAttributeEventListener(document()->frame(), attr));
159 else
160 HTMLElement::parseMappedAttribute(attr);
161 }
162
insertedIntoDocument()163 void HTMLBodyElement::insertedIntoDocument()
164 {
165 HTMLElement::insertedIntoDocument();
166
167 // FIXME: Perhaps this code should be in attach() instead of here.
168 Element* ownerElement = document()->ownerElement();
169 if (ownerElement && (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag))) {
170 HTMLFrameElementBase* ownerFrameElement = static_cast<HTMLFrameElementBase*>(ownerElement);
171 int marginWidth = ownerFrameElement->getMarginWidth();
172 if (marginWidth != -1)
173 setAttribute(marginwidthAttr, String::number(marginWidth));
174 int marginHeight = ownerFrameElement->getMarginHeight();
175 if (marginHeight != -1)
176 setAttribute(marginheightAttr, String::number(marginHeight));
177 }
178
179 #ifdef ANDROID_META_SUPPORT
180 Settings * settings = document()->settings();
181 if (settings) {
182 String host = document()->baseURI().host().lower();
183 if (settings->viewportWidth() == -1 && (host.startsWith("m.") || host.startsWith("mobile.")
184 || host.contains(".m.") || host.contains(".mobile."))) {
185 // fit mobile sites directly in the screen
186 settings->setMetadataSettings("width", "device-width");
187 // update the meta data if it is the top document
188 if (!ownerElement) {
189 FrameView* view = document()->view();
190 if (view)
191 android::WebViewCore::getWebViewCore(view)->updateViewport();
192 }
193 }
194 }
195 #endif
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
isURLAttribute(Attribute * attr) const203 bool HTMLBodyElement::isURLAttribute(Attribute *attr) const
204 {
205 return attr->name() == backgroundAttr;
206 }
207
aLink() const208 String HTMLBodyElement::aLink() const
209 {
210 return getAttribute(alinkAttr);
211 }
212
setALink(const String & value)213 void HTMLBodyElement::setALink(const String& value)
214 {
215 setAttribute(alinkAttr, value);
216 }
217
bgColor() const218 String HTMLBodyElement::bgColor() const
219 {
220 return getAttribute(bgcolorAttr);
221 }
222
setBgColor(const String & value)223 void HTMLBodyElement::setBgColor(const String& value)
224 {
225 setAttribute(bgcolorAttr, value);
226 }
227
link() const228 String HTMLBodyElement::link() const
229 {
230 return getAttribute(linkAttr);
231 }
232
setLink(const String & value)233 void HTMLBodyElement::setLink(const String& value)
234 {
235 setAttribute(linkAttr, value);
236 }
237
text() const238 String HTMLBodyElement::text() const
239 {
240 return getAttribute(textAttr);
241 }
242
setText(const String & value)243 void HTMLBodyElement::setText(const String& value)
244 {
245 setAttribute(textAttr, value);
246 }
247
vLink() const248 String HTMLBodyElement::vLink() const
249 {
250 return getAttribute(vlinkAttr);
251 }
252
setVLink(const String & value)253 void HTMLBodyElement::setVLink(const String& value)
254 {
255 setAttribute(vlinkAttr, value);
256 }
257
adjustForZoom(int value,FrameView * frameView)258 static int adjustForZoom(int value, FrameView* frameView)
259 {
260 float zoomFactor = frameView->frame()->zoomFactor();
261 if (zoomFactor == 1)
262 return value;
263 // Needed because of truncation (rather than rounding) when scaling up.
264 if (zoomFactor > 1)
265 value++;
266 return static_cast<int>(value / zoomFactor);
267 }
268
scrollLeft() const269 int HTMLBodyElement::scrollLeft() const
270 {
271 // Update the document's layout.
272 Document* doc = document();
273 doc->updateLayoutIgnorePendingStylesheets();
274 FrameView* view = doc->view();
275 return view ? adjustForZoom(view->scrollX(), view) : 0;
276 }
277
setScrollLeft(int scrollLeft)278 void HTMLBodyElement::setScrollLeft(int scrollLeft)
279 {
280 FrameView* sview = ownerDocument()->view();
281 if (sview) {
282 // Update the document's layout
283 document()->updateLayoutIgnorePendingStylesheets();
284 sview->setScrollPosition(IntPoint(static_cast<int>(scrollLeft * sview->frame()->zoomFactor()), sview->scrollY()));
285 }
286 }
287
scrollTop() const288 int HTMLBodyElement::scrollTop() const
289 {
290 // Update the document's layout.
291 Document* doc = document();
292 doc->updateLayoutIgnorePendingStylesheets();
293 FrameView* view = doc->view();
294 return view ? adjustForZoom(view->scrollY(), view) : 0;
295 }
296
setScrollTop(int scrollTop)297 void HTMLBodyElement::setScrollTop(int scrollTop)
298 {
299 FrameView* sview = ownerDocument()->view();
300 if (sview) {
301 // Update the document's layout
302 document()->updateLayoutIgnorePendingStylesheets();
303 sview->setScrollPosition(IntPoint(sview->scrollX(), static_cast<int>(scrollTop * sview->frame()->zoomFactor())));
304 }
305 }
306
scrollHeight() const307 int HTMLBodyElement::scrollHeight() const
308 {
309 // Update the document's layout.
310 Document* doc = document();
311 doc->updateLayoutIgnorePendingStylesheets();
312 FrameView* view = doc->view();
313 return view ? adjustForZoom(view->contentsHeight(), view) : 0;
314 }
315
scrollWidth() const316 int HTMLBodyElement::scrollWidth() const
317 {
318 // Update the document's layout.
319 Document* doc = document();
320 doc->updateLayoutIgnorePendingStylesheets();
321 FrameView* view = doc->view();
322 return view ? adjustForZoom(view->contentsWidth(), view) : 0;
323 }
324
addSubresourceAttributeURLs(ListHashSet<KURL> & urls) const325 void HTMLBodyElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
326 {
327 HTMLElement::addSubresourceAttributeURLs(urls);
328
329 addSubresourceURL(urls, document()->completeURL(getAttribute(backgroundAttr)));
330 }
331
didMoveToNewOwnerDocument()332 void HTMLBodyElement::didMoveToNewOwnerDocument()
333 {
334 // When moving body elements between documents, we should have to reset the parent sheet for any
335 // link style declarations. If we don't we might crash later.
336 // In practice I can't reproduce this theoretical problem.
337 // webarchive/adopt-attribute-styled-body-webarchive.html tries to make sure this crash won't surface.
338 if (m_linkDecl)
339 m_linkDecl->setParent(document()->elementSheet());
340
341 HTMLElement::didMoveToNewOwnerDocument();
342 }
343
onblur() const344 EventListener* HTMLBodyElement::onblur() const
345 {
346 return document()->getWindowAttributeEventListener(eventNames().blurEvent);
347 }
348
setOnblur(PassRefPtr<EventListener> eventListener)349 void HTMLBodyElement::setOnblur(PassRefPtr<EventListener> eventListener)
350 {
351 document()->setAttributeEventListener(eventNames().blurEvent, eventListener);
352 }
353
onerror() const354 EventListener* HTMLBodyElement::onerror() const
355 {
356 return document()->getWindowAttributeEventListener(eventNames().errorEvent);
357 }
358
setOnerror(PassRefPtr<EventListener> eventListener)359 void HTMLBodyElement::setOnerror(PassRefPtr<EventListener> eventListener)
360 {
361 document()->setAttributeEventListener(eventNames().errorEvent, eventListener);
362 }
363
onfocus() const364 EventListener* HTMLBodyElement::onfocus() const
365 {
366 return document()->getWindowAttributeEventListener(eventNames().focusEvent);
367 }
368
setOnfocus(PassRefPtr<EventListener> eventListener)369 void HTMLBodyElement::setOnfocus(PassRefPtr<EventListener> eventListener)
370 {
371 document()->setAttributeEventListener(eventNames().focusEvent, eventListener);
372 }
373
onload() const374 EventListener* HTMLBodyElement::onload() const
375 {
376 return document()->getWindowAttributeEventListener(eventNames().loadEvent);
377 }
378
setOnload(PassRefPtr<EventListener> eventListener)379 void HTMLBodyElement::setOnload(PassRefPtr<EventListener> eventListener)
380 {
381 document()->setAttributeEventListener(eventNames().loadEvent, eventListener);
382 }
383
onbeforeunload() const384 EventListener* HTMLBodyElement::onbeforeunload() const
385 {
386 return document()->getWindowAttributeEventListener(eventNames().beforeunloadEvent);
387 }
388
setOnbeforeunload(PassRefPtr<EventListener> eventListener)389 void HTMLBodyElement::setOnbeforeunload(PassRefPtr<EventListener> eventListener)
390 {
391 document()->setAttributeEventListener(eventNames().beforeunloadEvent, eventListener);
392 }
393
onmessage() const394 EventListener* HTMLBodyElement::onmessage() const
395 {
396 return document()->getWindowAttributeEventListener(eventNames().messageEvent);
397 }
398
setOnmessage(PassRefPtr<EventListener> eventListener)399 void HTMLBodyElement::setOnmessage(PassRefPtr<EventListener> eventListener)
400 {
401 document()->setAttributeEventListener(eventNames().messageEvent, eventListener);
402 }
403
onoffline() const404 EventListener* HTMLBodyElement::onoffline() const
405 {
406 return document()->getWindowAttributeEventListener(eventNames().offlineEvent);
407 }
408
setOnoffline(PassRefPtr<EventListener> eventListener)409 void HTMLBodyElement::setOnoffline(PassRefPtr<EventListener> eventListener)
410 {
411 document()->setAttributeEventListener(eventNames().offlineEvent, eventListener);
412 }
413
ononline() const414 EventListener* HTMLBodyElement::ononline() const
415 {
416 return document()->getWindowAttributeEventListener(eventNames().onlineEvent);
417 }
418
setOnonline(PassRefPtr<EventListener> eventListener)419 void HTMLBodyElement::setOnonline(PassRefPtr<EventListener> eventListener)
420 {
421 document()->setAttributeEventListener(eventNames().onlineEvent, eventListener);
422 }
423
onresize() const424 EventListener* HTMLBodyElement::onresize() const
425 {
426 return document()->getWindowAttributeEventListener(eventNames().resizeEvent);
427 }
428
setOnresize(PassRefPtr<EventListener> eventListener)429 void HTMLBodyElement::setOnresize(PassRefPtr<EventListener> eventListener)
430 {
431 document()->setAttributeEventListener(eventNames().resizeEvent, eventListener);
432 }
433
onstorage() const434 EventListener* HTMLBodyElement::onstorage() const
435 {
436 return document()->getWindowAttributeEventListener(eventNames().storageEvent);
437 }
438
setOnstorage(PassRefPtr<EventListener> eventListener)439 void HTMLBodyElement::setOnstorage(PassRefPtr<EventListener> eventListener)
440 {
441 document()->setAttributeEventListener(eventNames().storageEvent, eventListener);
442 }
443
onunload() const444 EventListener* HTMLBodyElement::onunload() const
445 {
446 return document()->getWindowAttributeEventListener(eventNames().unloadEvent);
447 }
448
setOnunload(PassRefPtr<EventListener> eventListener)449 void HTMLBodyElement::setOnunload(PassRefPtr<EventListener> eventListener)
450 {
451 document()->setAttributeEventListener(eventNames().unloadEvent, eventListener);
452 }
453
454 } // namespace WebCore
455