1 /* 2 * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org) 3 * (C) 1999 Antti Koivisto (koivisto (at) kde.org) 4 * (C) 2000 Simon Hausmann (hausmann (at) kde.org) 5 * (C) 2001 Dirk Mueller (mueller (at) 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 "core/html/HTMLBodyElement.h" 26 27 #include "CSSValueKeywords.h" 28 #include "HTMLNames.h" 29 #include "bindings/v8/ScriptEventListener.h" 30 #include "core/css/CSSImageValue.h" 31 #include "core/css/CSSParser.h" 32 #include "core/css/StylePropertySet.h" 33 #include "core/dom/Attribute.h" 34 #include "core/dom/EventNames.h" 35 #include "core/html/HTMLFrameElementBase.h" 36 #include "core/html/parser/HTMLParserIdioms.h" 37 #include "core/page/Frame.h" 38 #include "core/page/FrameView.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 ScriptWrappable::init(this); 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()->textLinkColors().resetLinkColor(); 104 else if (name == vlinkAttr) 105 document()->textLinkColors().resetVisitedLinkColor(); 106 else 107 document()->textLinkColors().resetActiveLinkColor(); 108 } else { 109 RGBA32 color; 110 if (CSSParser::parseColor(color, value, !document()->inQuirksMode())) { 111 if (name == linkAttr) 112 document()->textLinkColors().setLinkColor(color); 113 else if (name == vlinkAttr) 114 document()->textLinkColors().setVisitedLinkColor(color); 115 else 116 document()->textLinkColors().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 ASSERT(document()); 171 172 // FIXME: Perhaps this code should be in attach() instead of here. 173 Element* ownerElement = document()->ownerElement(); 174 if (ownerElement && (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag))) { 175 HTMLFrameElementBase* ownerFrameElement = static_cast<HTMLFrameElementBase*>(ownerElement); 176 int marginWidth = ownerFrameElement->marginWidth(); 177 if (marginWidth != -1) 178 setAttribute(marginwidthAttr, String::number(marginWidth)); 179 int marginHeight = ownerFrameElement->marginHeight(); 180 if (marginHeight != -1) 181 setAttribute(marginheightAttr, String::number(marginHeight)); 182 } 183 184 // FIXME: This call to scheduleRelayout should not be needed here. 185 // But without it we hang during WebKit tests; need to fix that and remove this. 186 if (FrameView* view = document()->view()) 187 view->scheduleRelayout(); 188 } 189 190 bool HTMLBodyElement::isURLAttribute(const Attribute& attribute) const 191 { 192 return attribute.name() == backgroundAttr || HTMLElement::isURLAttribute(attribute); 193 } 194 195 bool HTMLBodyElement::supportsFocus() const 196 { 197 // This override is needed because the inherited method bails if the parent is editable. 198 // The <body> should be focusable even if <html> is editable. 199 return rendererIsEditable() || HTMLElement::supportsFocus(); 200 } 201 202 String HTMLBodyElement::aLink() const 203 { 204 return getAttribute(alinkAttr); 205 } 206 207 void HTMLBodyElement::setALink(const String& value) 208 { 209 setAttribute(alinkAttr, value); 210 } 211 212 String HTMLBodyElement::bgColor() const 213 { 214 return getAttribute(bgcolorAttr); 215 } 216 217 void HTMLBodyElement::setBgColor(const String& value) 218 { 219 setAttribute(bgcolorAttr, value); 220 } 221 222 String HTMLBodyElement::link() const 223 { 224 return getAttribute(linkAttr); 225 } 226 227 void HTMLBodyElement::setLink(const String& value) 228 { 229 setAttribute(linkAttr, value); 230 } 231 232 String HTMLBodyElement::text() const 233 { 234 return getAttribute(textAttr); 235 } 236 237 void HTMLBodyElement::setText(const String& value) 238 { 239 setAttribute(textAttr, value); 240 } 241 242 String HTMLBodyElement::vLink() const 243 { 244 return getAttribute(vlinkAttr); 245 } 246 247 void HTMLBodyElement::setVLink(const String& value) 248 { 249 setAttribute(vlinkAttr, value); 250 } 251 252 static int adjustForZoom(int value, Document* document) 253 { 254 Frame* frame = document->frame(); 255 float zoomFactor = frame->pageZoomFactor(); 256 if (zoomFactor == 1) 257 return value; 258 // Needed because of truncation (rather than rounding) when scaling up. 259 if (zoomFactor > 1) 260 value++; 261 return static_cast<int>(value / zoomFactor); 262 } 263 264 int HTMLBodyElement::scrollLeft() 265 { 266 // Update the document's layout. 267 Document* document = this->document(); 268 document->updateLayoutIgnorePendingStylesheets(); 269 FrameView* view = document->view(); 270 return view ? adjustForZoom(view->scrollX(), document) : 0; 271 } 272 273 void HTMLBodyElement::setScrollLeft(int scrollLeft) 274 { 275 Document* document = this->document(); 276 document->updateLayoutIgnorePendingStylesheets(); 277 Frame* frame = document->frame(); 278 if (!frame) 279 return; 280 FrameView* view = frame->view(); 281 if (!view) 282 return; 283 view->setScrollPosition(IntPoint(static_cast<int>(scrollLeft * frame->pageZoomFactor()), view->scrollY())); 284 } 285 286 int HTMLBodyElement::scrollTop() 287 { 288 // Update the document's layout. 289 Document* document = this->document(); 290 document->updateLayoutIgnorePendingStylesheets(); 291 FrameView* view = document->view(); 292 return view ? adjustForZoom(view->scrollY(), document) : 0; 293 } 294 295 void HTMLBodyElement::setScrollTop(int scrollTop) 296 { 297 Document* document = this->document(); 298 document->updateLayoutIgnorePendingStylesheets(); 299 Frame* frame = document->frame(); 300 if (!frame) 301 return; 302 FrameView* view = frame->view(); 303 if (!view) 304 return; 305 view->setScrollPosition(IntPoint(view->scrollX(), static_cast<int>(scrollTop * frame->pageZoomFactor()))); 306 } 307 308 int HTMLBodyElement::scrollHeight() 309 { 310 // Update the document's layout. 311 Document* document = this->document(); 312 document->updateLayoutIgnorePendingStylesheets(); 313 FrameView* view = document->view(); 314 return view ? adjustForZoom(view->contentsHeight(), document) : 0; 315 } 316 317 int HTMLBodyElement::scrollWidth() 318 { 319 // Update the document's layout. 320 Document* document = this->document(); 321 document->updateLayoutIgnorePendingStylesheets(); 322 FrameView* view = document->view(); 323 return view ? adjustForZoom(view->contentsWidth(), document) : 0; 324 } 325 326 void HTMLBodyElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const 327 { 328 HTMLElement::addSubresourceAttributeURLs(urls); 329 330 addSubresourceURL(urls, document()->completeURL(getAttribute(backgroundAttr))); 331 } 332 333 } // namespace WebCore 334