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