[CTTE] Node subclasses should take a Document by reference in their constructor ...
[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 "CSSImageValue.h"
29 #include "CSSParser.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 #include "StylePropertySet.h"
40
41 namespace WebCore {
42
43 using namespace HTMLNames;
44
45 HTMLBodyElement::HTMLBodyElement(const QualifiedName& tagName, Document& document)
46     : HTMLElement(tagName, document)
47 {
48     ASSERT(hasTagName(bodyTag));
49 }
50
51 PassRefPtr<HTMLBodyElement> HTMLBodyElement::create(Document& document)
52 {
53     return adoptRef(new HTMLBodyElement(bodyTag, document));
54 }
55
56 PassRefPtr<HTMLBodyElement> HTMLBodyElement::create(const QualifiedName& tagName, Document& document)
57 {
58     return adoptRef(new HTMLBodyElement(tagName, document));
59 }
60
61 HTMLBodyElement::~HTMLBodyElement()
62 {
63 }
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, MutableStylePropertySet* style)
73 {
74     if (name == backgroundAttr) {
75         String url = stripLeadingAndTrailingHTMLSpaces(value);
76         if (!url.isEmpty()) {
77             RefPtr<CSSImageValue> imageValue = CSSImageValue::create(document().completeURL(url).string());
78             imageValue->setInitiator(localName());
79             style->setProperty(CSSProperty(CSSPropertyBackgroundImage, imageValue.release()));
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 (equalIgnoringCase(value, "fixed"))
93            addPropertyToPresentationAttributeStyle(style, CSSPropertyBackgroundAttachment, CSSValueFixed);
94     } else
95         HTMLElement::collectStyleForPresentationAttribute(name, value, style);
96 }
97
98 void HTMLBodyElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
99 {
100     if (name == vlinkAttr || name == alinkAttr || name == linkAttr) {
101         if (value.isNull()) {
102             if (name == linkAttr)
103                 document().resetLinkColor();
104             else if (name == vlinkAttr)
105                 document().resetVisitedLinkColor();
106             else
107                 document().resetActiveLinkColor();
108         } else {
109             RGBA32 color;
110             if (CSSParser::parseColor(color, value, !document().inQuirksMode())) {
111                 if (name == linkAttr)
112                     document().setLinkColor(color);
113                 else if (name == vlinkAttr)
114                     document().setVisitedLinkColor(color);
115                 else
116                     document().setActiveLinkColor(color);
117             }
118         }
119
120         setNeedsStyleRecalc();
121     } else if (name == onloadAttr)
122         document().setWindowAttributeEventListener(eventNames().loadEvent, createAttributeEventListener(document().frame(), name, value));
123     else if (name == onbeforeunloadAttr)
124         document().setWindowAttributeEventListener(eventNames().beforeunloadEvent, createAttributeEventListener(document().frame(), name, value));
125     else if (name == onunloadAttr)
126         document().setWindowAttributeEventListener(eventNames().unloadEvent, createAttributeEventListener(document().frame(), name, value));
127     else if (name == onpagehideAttr)
128         document().setWindowAttributeEventListener(eventNames().pagehideEvent, createAttributeEventListener(document().frame(), name, value));
129     else if (name == onpageshowAttr)
130         document().setWindowAttributeEventListener(eventNames().pageshowEvent, createAttributeEventListener(document().frame(), name, value));
131     else if (name == onpopstateAttr)
132         document().setWindowAttributeEventListener(eventNames().popstateEvent, createAttributeEventListener(document().frame(), name, value));
133     else if (name == onblurAttr)
134         document().setWindowAttributeEventListener(eventNames().blurEvent, createAttributeEventListener(document().frame(), name, value));
135     else if (name == onfocusAttr)
136         document().setWindowAttributeEventListener(eventNames().focusEvent, createAttributeEventListener(document().frame(), name, value));
137 #if ENABLE(ORIENTATION_EVENTS)
138     else if (name == onorientationchangeAttr)
139         document().setWindowAttributeEventListener(eventNames().orientationchangeEvent, createAttributeEventListener(document().frame(), name, value));
140 #endif
141     else if (name == onhashchangeAttr)
142         document().setWindowAttributeEventListener(eventNames().hashchangeEvent, createAttributeEventListener(document().frame(), name, value));
143     else if (name == onresizeAttr)
144         document().setWindowAttributeEventListener(eventNames().resizeEvent, createAttributeEventListener(document().frame(), name, value));
145     else if (name == onscrollAttr)
146         document().setWindowAttributeEventListener(eventNames().scrollEvent, createAttributeEventListener(document().frame(), name, value));
147     else if (name == onselectionchangeAttr)
148         document().setAttributeEventListener(eventNames().selectionchangeEvent, createAttributeEventListener(document().frame(), name, value));
149     else if (name == onstorageAttr)
150         document().setWindowAttributeEventListener(eventNames().storageEvent, createAttributeEventListener(document().frame(), name, value));
151     else if (name == ononlineAttr)
152         document().setWindowAttributeEventListener(eventNames().onlineEvent, createAttributeEventListener(document().frame(), name, value));
153     else if (name == onofflineAttr)
154         document().setWindowAttributeEventListener(eventNames().offlineEvent, createAttributeEventListener(document().frame(), name, value));
155     else
156         HTMLElement::parseAttribute(name, value);
157 }
158
159 Node::InsertionNotificationRequest HTMLBodyElement::insertedInto(ContainerNode* insertionPoint)
160 {
161     HTMLElement::insertedInto(insertionPoint);
162     if (insertionPoint->inDocument())
163         return InsertionShouldCallDidNotifySubtreeInsertions;
164     return InsertionDone;
165 }
166
167 void HTMLBodyElement::didNotifySubtreeInsertions(ContainerNode* insertionPoint)
168 {
169     ASSERT_UNUSED(insertionPoint, insertionPoint->inDocument());
170
171     // FIXME: Perhaps this code should be in attach() instead of here.
172     Element* ownerElement = document().ownerElement();
173     if (ownerElement && (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag))) {
174         HTMLFrameElementBase* ownerFrameElement = toHTMLFrameElementBase(ownerElement);
175         int marginWidth = ownerFrameElement->marginWidth();
176         if (marginWidth != -1)
177             setAttribute(marginwidthAttr, String::number(marginWidth));
178         int marginHeight = ownerFrameElement->marginHeight();
179         if (marginHeight != -1)
180             setAttribute(marginheightAttr, String::number(marginHeight));
181     }
182
183     // FIXME: This call to scheduleRelayout should not be needed here.
184     // But without it we hang during WebKit tests; need to fix that and remove this.
185     if (FrameView* view = document().view())
186         view->scheduleRelayout();
187 }
188
189 bool HTMLBodyElement::isURLAttribute(const Attribute& attribute) const
190 {
191     return attribute.name() == backgroundAttr || HTMLElement::isURLAttribute(attribute);
192 }
193
194 bool HTMLBodyElement::supportsFocus() const
195 {
196     return rendererIsEditable() || HTMLElement::supportsFocus();
197 }
198
199 String HTMLBodyElement::aLink() const
200 {
201     return getAttribute(alinkAttr);
202 }
203
204 void HTMLBodyElement::setALink(const String& value)
205 {
206     setAttribute(alinkAttr, value);
207 }
208
209 String HTMLBodyElement::bgColor() const
210 {
211     return getAttribute(bgcolorAttr);
212 }
213
214 void HTMLBodyElement::setBgColor(const String& value)
215 {
216     setAttribute(bgcolorAttr, value);
217 }
218
219 String HTMLBodyElement::link() const
220 {
221     return getAttribute(linkAttr);
222 }
223
224 void HTMLBodyElement::setLink(const String& value)
225 {
226     setAttribute(linkAttr, value);
227 }
228
229 String HTMLBodyElement::text() const
230 {
231     return getAttribute(textAttr);
232 }
233
234 void HTMLBodyElement::setText(const String& value)
235 {
236     setAttribute(textAttr, value);
237 }
238
239 String HTMLBodyElement::vLink() const
240 {
241     return getAttribute(vlinkAttr);
242 }
243
244 void HTMLBodyElement::setVLink(const String& value)
245 {
246     setAttribute(vlinkAttr, value);
247 }
248
249 static int adjustForZoom(int value, Document* document)
250 {
251     Frame* frame = document->frame();
252     float zoomFactor = frame->pageZoomFactor() * frame->frameScaleFactor();
253     if (zoomFactor == 1)
254         return value;
255     // Needed because of truncation (rather than rounding) when scaling up.
256     if (zoomFactor > 1)
257         value++;
258     return static_cast<int>(value / zoomFactor);
259 }
260
261 int HTMLBodyElement::scrollLeft()
262 {
263     if (!document().inQuirksMode())
264         return 0;
265     document().updateLayoutIgnorePendingStylesheets();
266     FrameView* view = document().view();
267     return view ? adjustForZoom(view->scrollX(), &document()) : 0;
268 }
269
270 void HTMLBodyElement::setScrollLeft(int scrollLeft)
271 {
272     document().updateLayoutIgnorePendingStylesheets();
273     Frame* frame = document().frame();
274     if (!frame)
275         return;
276     FrameView* view = frame->view();
277     if (!view)
278         return;
279     view->setScrollPosition(IntPoint(static_cast<int>(scrollLeft * frame->pageZoomFactor() * frame->frameScaleFactor()), view->scrollY()));
280 }
281
282 int HTMLBodyElement::scrollTop()
283 {
284     if (!document().inQuirksMode())
285         return 0;
286     document().updateLayoutIgnorePendingStylesheets();
287     FrameView* view = document().view();
288     return view ? adjustForZoom(view->scrollY(), &document()) : 0;
289 }
290
291 void HTMLBodyElement::setScrollTop(int scrollTop)
292 {
293     document().updateLayoutIgnorePendingStylesheets();
294     Frame* frame = document().frame();
295     if (!frame)
296         return;
297     FrameView* view = frame->view();
298     if (!view)
299         return;
300     view->setScrollPosition(IntPoint(view->scrollX(), static_cast<int>(scrollTop * frame->pageZoomFactor() * frame->frameScaleFactor())));
301 }
302
303 int HTMLBodyElement::scrollHeight()
304 {
305     // Update the document's layout.
306     document().updateLayoutIgnorePendingStylesheets();
307     FrameView* view = document().view();
308     return view ? adjustForZoom(view->contentsHeight(), &document()) : 0;
309 }
310
311 int HTMLBodyElement::scrollWidth()
312 {
313     // Update the document's layout.
314     document().updateLayoutIgnorePendingStylesheets();
315     FrameView* view = document().view();
316     return view ? adjustForZoom(view->contentsWidth(), &document()) : 0;
317 }
318
319 void HTMLBodyElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
320 {
321     HTMLElement::addSubresourceAttributeURLs(urls);
322
323     addSubresourceURL(urls, document().completeURL(getAttribute(backgroundAttr)));
324 }
325
326 } // namespace WebCore