Remove "const" from obviously-non-const accessors
[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         // This tells us that we are removed from document. If our document is later destroyed
120         // (not deleted since we hold a guardRef), our stylesheet list will be null causing a crash
121         // later in document()->styleSelector(). So, we bail out early because we shouldn't be
122         // modifying anything in that document. See webkit bug 62230.
123         if (m_linkDecl && !m_linkDecl->parent())
124             return;
125
126         if (attr->isNull()) {
127             if (attr->name() == linkAttr)
128                 document()->resetLinkColor();
129             else if (attr->name() == vlinkAttr)
130                 document()->resetVisitedLinkColor();
131             else
132                 document()->resetActiveLinkColor();
133         } else {
134             if (!m_linkDecl)
135                 createLinkDecl();
136             m_linkDecl->setProperty(CSSPropertyColor, attr->value(), false, false);
137             RefPtr<CSSValue> val = m_linkDecl->getPropertyCSSValue(CSSPropertyColor);
138             if (val && val->isPrimitiveValue()) {
139                 Color col = document()->styleSelector()->getColorFromPrimitiveValue(static_cast<CSSPrimitiveValue*>(val.get()));
140                 if (attr->name() == linkAttr)
141                     document()->setLinkColor(col);
142                 else if (attr->name() == vlinkAttr)
143                     document()->setVisitedLinkColor(col);
144                 else
145                     document()->setActiveLinkColor(col);
146             }
147         }
148         
149         if (attached())
150             document()->recalcStyle(Force);
151     } else if (attr->name() == onloadAttr)
152         document()->setWindowAttributeEventListener(eventNames().loadEvent, createAttributeEventListener(document()->frame(), attr));
153     else if (attr->name() == onbeforeunloadAttr)
154         document()->setWindowAttributeEventListener(eventNames().beforeunloadEvent, createAttributeEventListener(document()->frame(), attr));
155     else if (attr->name() == onunloadAttr)
156         document()->setWindowAttributeEventListener(eventNames().unloadEvent, createAttributeEventListener(document()->frame(), attr));
157     else if (attr->name() == onpagehideAttr)
158         document()->setWindowAttributeEventListener(eventNames().pagehideEvent, createAttributeEventListener(document()->frame(), attr));
159     else if (attr->name() == onpageshowAttr)
160         document()->setWindowAttributeEventListener(eventNames().pageshowEvent, createAttributeEventListener(document()->frame(), attr));
161     else if (attr->name() == onpopstateAttr)
162         document()->setWindowAttributeEventListener(eventNames().popstateEvent, createAttributeEventListener(document()->frame(), attr));
163     else if (attr->name() == onblurAttr)
164         document()->setWindowAttributeEventListener(eventNames().blurEvent, createAttributeEventListener(document()->frame(), attr));
165     else if (attr->name() == onfocusAttr)
166         document()->setWindowAttributeEventListener(eventNames().focusEvent, createAttributeEventListener(document()->frame(), attr));
167 #if ENABLE(ORIENTATION_EVENTS)
168     else if (attr->name() == onorientationchangeAttr)
169         document()->setWindowAttributeEventListener(eventNames().orientationchangeEvent, createAttributeEventListener(document()->frame(), attr));
170 #endif
171     else if (attr->name() == onhashchangeAttr)
172         document()->setWindowAttributeEventListener(eventNames().hashchangeEvent, createAttributeEventListener(document()->frame(), attr));
173     else if (attr->name() == onresizeAttr)
174         document()->setWindowAttributeEventListener(eventNames().resizeEvent, createAttributeEventListener(document()->frame(), attr));
175     else if (attr->name() == onscrollAttr)
176         document()->setWindowAttributeEventListener(eventNames().scrollEvent, createAttributeEventListener(document()->frame(), attr));
177     else if (attr->name() == onselectionchangeAttr)
178         document()->setAttributeEventListener(eventNames().selectionchangeEvent, createAttributeEventListener(document()->frame(), attr));
179     else if (attr->name() == onstorageAttr)
180         document()->setWindowAttributeEventListener(eventNames().storageEvent, createAttributeEventListener(document()->frame(), attr));
181     else if (attr->name() == ononlineAttr)
182         document()->setWindowAttributeEventListener(eventNames().onlineEvent, createAttributeEventListener(document()->frame(), attr));
183     else if (attr->name() == onofflineAttr)
184         document()->setWindowAttributeEventListener(eventNames().offlineEvent, createAttributeEventListener(document()->frame(), attr));
185     else
186         HTMLElement::parseMappedAttribute(attr);
187 }
188
189 void HTMLBodyElement::insertedIntoDocument()
190 {
191     HTMLElement::insertedIntoDocument();
192
193     // FIXME: Perhaps this code should be in attach() instead of here.
194     Element* ownerElement = document()->ownerElement();
195     if (ownerElement && (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag))) {
196         HTMLFrameElementBase* ownerFrameElement = static_cast<HTMLFrameElementBase*>(ownerElement);
197         int marginWidth = ownerFrameElement->marginWidth();
198         if (marginWidth != -1)
199             setAttribute(marginwidthAttr, String::number(marginWidth));
200         int marginHeight = ownerFrameElement->marginHeight();
201         if (marginHeight != -1)
202             setAttribute(marginheightAttr, String::number(marginHeight));
203     }
204
205     // FIXME: This call to scheduleRelayout should not be needed here.
206     // But without it we hang during WebKit tests; need to fix that and remove this.
207     if (FrameView* view = document()->view())
208         view->scheduleRelayout();
209
210     if (document() && document()->page())
211         document()->page()->updateViewportArguments();
212
213     if (m_linkDecl)
214         m_linkDecl->setParent(document()->elementSheet());
215 }
216
217 void HTMLBodyElement::removedFromDocument()
218 {
219     if (m_linkDecl)
220         m_linkDecl->setParent(0);
221     
222     HTMLElement::removedFromDocument();
223 }
224
225 void HTMLBodyElement::didMoveToNewOwnerDocument()
226 {
227     if (m_linkDecl)
228         m_linkDecl->setParent(document()->elementSheet());
229     
230     HTMLElement::didMoveToNewOwnerDocument();
231 }
232
233 bool HTMLBodyElement::isURLAttribute(Attribute *attr) const
234 {
235     return attr->name() == backgroundAttr;
236 }
237
238 bool HTMLBodyElement::supportsFocus() const
239 {
240     return rendererIsEditable() || HTMLElement::supportsFocus();
241 }
242
243 String HTMLBodyElement::aLink() const
244 {
245     return getAttribute(alinkAttr);
246 }
247
248 void HTMLBodyElement::setALink(const String& value)
249 {
250     setAttribute(alinkAttr, value);
251 }
252
253 String HTMLBodyElement::bgColor() const
254 {
255     return getAttribute(bgcolorAttr);
256 }
257
258 void HTMLBodyElement::setBgColor(const String& value)
259 {
260     setAttribute(bgcolorAttr, value);
261 }
262
263 String HTMLBodyElement::link() const
264 {
265     return getAttribute(linkAttr);
266 }
267
268 void HTMLBodyElement::setLink(const String& value)
269 {
270     setAttribute(linkAttr, value);
271 }
272
273 String HTMLBodyElement::text() const
274 {
275     return getAttribute(textAttr);
276 }
277
278 void HTMLBodyElement::setText(const String& value)
279 {
280     setAttribute(textAttr, value);
281 }
282
283 String HTMLBodyElement::vLink() const
284 {
285     return getAttribute(vlinkAttr);
286 }
287
288 void HTMLBodyElement::setVLink(const String& value)
289 {
290     setAttribute(vlinkAttr, value);
291 }
292
293 static int adjustForZoom(int value, Document* document)
294 {
295     Frame* frame = document->frame();
296     float zoomFactor = frame->pageZoomFactor() * frame->pageScaleFactor();
297     if (zoomFactor == 1)
298         return value;
299     // Needed because of truncation (rather than rounding) when scaling up.
300     if (zoomFactor > 1)
301         value++;
302     return static_cast<int>(value / zoomFactor);
303 }
304
305 int HTMLBodyElement::scrollLeft()
306 {
307     // Update the document's layout.
308     Document* document = this->document();
309     document->updateLayoutIgnorePendingStylesheets();
310     FrameView* view = document->view();
311     return view ? adjustForZoom(view->scrollX(), document) : 0;
312 }
313
314 void HTMLBodyElement::setScrollLeft(int scrollLeft)
315 {
316     Document* document = this->document();
317     document->updateLayoutIgnorePendingStylesheets();
318     Frame* frame = document->frame();
319     if (!frame)
320         return;
321     FrameView* view = frame->view();
322     if (!view)
323         return;
324     view->setScrollPosition(IntPoint(static_cast<int>(scrollLeft * frame->pageZoomFactor() * frame->pageScaleFactor()), view->scrollY()));
325 }
326
327 int HTMLBodyElement::scrollTop()
328 {
329     // Update the document's layout.
330     Document* document = this->document();
331     document->updateLayoutIgnorePendingStylesheets();
332     FrameView* view = document->view();
333     return view ? adjustForZoom(view->scrollY(), document) : 0;
334 }
335
336 void HTMLBodyElement::setScrollTop(int scrollTop)
337 {
338     Document* document = this->document();
339     document->updateLayoutIgnorePendingStylesheets();
340     Frame* frame = document->frame();
341     if (!frame)
342         return;
343     FrameView* view = frame->view();
344     if (!view)
345         return;
346     view->setScrollPosition(IntPoint(view->scrollX(), static_cast<int>(scrollTop * frame->pageZoomFactor() * frame->pageScaleFactor())));
347 }
348
349 int HTMLBodyElement::scrollHeight()
350 {
351     // Update the document's layout.
352     Document* document = this->document();
353     document->updateLayoutIgnorePendingStylesheets();
354     FrameView* view = document->view();
355     return view ? adjustForZoom(view->contentsHeight(), document) : 0;    
356 }
357
358 int HTMLBodyElement::scrollWidth()
359 {
360     // Update the document's layout.
361     Document* document = this->document();
362     document->updateLayoutIgnorePendingStylesheets();
363     FrameView* view = document->view();
364     return view ? adjustForZoom(view->contentsWidth(), document) : 0;    
365 }
366
367 void HTMLBodyElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
368 {
369     HTMLElement::addSubresourceAttributeURLs(urls);
370
371     addSubresourceURL(urls, document()->completeURL(getAttribute(backgroundAttr)));
372 }
373
374 } // namespace WebCore