• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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