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 "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 43 HTMLBodyElement::HTMLBodyElement(const QualifiedName& tagName, Document* document) 44 : HTMLElement(tagName, document) 45 { 46 ASSERT(hasTagName(bodyTag)); 47 } 48 49 PassRefPtr<HTMLBodyElement> HTMLBodyElement::create(Document* document) 50 { 51 return adoptRef(new HTMLBodyElement(bodyTag, document)); 52 } 53 54 PassRefPtr<HTMLBodyElement> HTMLBodyElement::create(const QualifiedName& tagName, Document* document) 55 { 56 return adoptRef(new HTMLBodyElement(tagName, document)); 57 } 58 59 HTMLBodyElement::~HTMLBodyElement() 60 { 61 if (m_linkDecl) { 62 m_linkDecl->setNode(0); 63 m_linkDecl->setParent(0); 64 } 65 } 66 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 75 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 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 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 206 bool HTMLBodyElement::isURLAttribute(Attribute *attr) const 207 { 208 return attr->name() == backgroundAttr; 209 } 210 211 bool HTMLBodyElement::supportsFocus() const 212 { 213 return rendererIsEditable() || HTMLElement::supportsFocus(); 214 } 215 216 String HTMLBodyElement::aLink() const 217 { 218 return getAttribute(alinkAttr); 219 } 220 221 void HTMLBodyElement::setALink(const String& value) 222 { 223 setAttribute(alinkAttr, value); 224 } 225 226 String HTMLBodyElement::bgColor() const 227 { 228 return getAttribute(bgcolorAttr); 229 } 230 231 void HTMLBodyElement::setBgColor(const String& value) 232 { 233 setAttribute(bgcolorAttr, value); 234 } 235 236 String HTMLBodyElement::link() const 237 { 238 return getAttribute(linkAttr); 239 } 240 241 void HTMLBodyElement::setLink(const String& value) 242 { 243 setAttribute(linkAttr, value); 244 } 245 246 String HTMLBodyElement::text() const 247 { 248 return getAttribute(textAttr); 249 } 250 251 void HTMLBodyElement::setText(const String& value) 252 { 253 setAttribute(textAttr, value); 254 } 255 256 String HTMLBodyElement::vLink() const 257 { 258 return getAttribute(vlinkAttr); 259 } 260 261 void HTMLBodyElement::setVLink(const String& value) 262 { 263 setAttribute(vlinkAttr, value); 264 } 265 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 278 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 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 300 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 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 322 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 331 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 340 void HTMLBodyElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const 341 { 342 HTMLElement::addSubresourceAttributeURLs(urls); 343 344 addSubresourceURL(urls, document()->completeURL(getAttribute(backgroundAttr))); 345 } 346 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