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