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 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 "CSSStyleSelector.h" 28 #include "CSSStyleSheet.h" 29 #include "CSSValueKeywords.h" 30 #include "EventNames.h" 31 #include "Frame.h" 32 #include "FrameView.h" 33 #include "HTMLFrameElementBase.h" 34 #include "HTMLNames.h" 35 #include "MappedAttribute.h" 36 #include "ScriptEventListener.h" 37 38 #ifdef ANDROID_META_SUPPORT 39 #include "Settings.h" 40 #include "WebViewCore.h" 41 #endif 42 43 namespace WebCore { 44 45 using namespace HTMLNames; 46 47 HTMLBodyElement::HTMLBodyElement(const QualifiedName& tagName, Document* document) 48 : HTMLElement(tagName, document) 49 { 50 ASSERT(hasTagName(bodyTag)); 51 } 52 53 HTMLBodyElement::~HTMLBodyElement() 54 { 55 if (m_linkDecl) { 56 m_linkDecl->setNode(0); 57 m_linkDecl->setParent(0); 58 } 59 } 60 61 void HTMLBodyElement::createLinkDecl() 62 { 63 m_linkDecl = CSSMutableStyleDeclaration::create(); 64 m_linkDecl->setParent(document()->elementSheet()); 65 m_linkDecl->setNode(this); 66 m_linkDecl->setStrictParsing(!document()->inCompatMode()); 67 } 68 69 bool HTMLBodyElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const 70 { 71 if (attrName == backgroundAttr) { 72 result = (MappedAttributeEntry)(eLastEntry + document()->docID()); 73 return false; 74 } 75 76 if (attrName == bgcolorAttr || 77 attrName == textAttr || 78 attrName == marginwidthAttr || 79 attrName == leftmarginAttr || 80 attrName == marginheightAttr || 81 attrName == topmarginAttr || 82 attrName == bgpropertiesAttr) { 83 result = eUniversal; 84 return false; 85 } 86 87 return HTMLElement::mapToEntry(attrName, result); 88 } 89 90 void HTMLBodyElement::parseMappedAttribute(MappedAttribute *attr) 91 { 92 if (attr->name() == backgroundAttr) { 93 String url = deprecatedParseURL(attr->value()); 94 if (!url.isEmpty()) 95 addCSSImageProperty(attr, CSSPropertyBackgroundImage, document()->completeURL(url).string()); 96 } else if (attr->name() == marginwidthAttr || attr->name() == leftmarginAttr) { 97 addCSSLength(attr, CSSPropertyMarginRight, attr->value()); 98 addCSSLength(attr, CSSPropertyMarginLeft, attr->value()); 99 } else if (attr->name() == marginheightAttr || attr->name() == topmarginAttr) { 100 addCSSLength(attr, CSSPropertyMarginBottom, attr->value()); 101 addCSSLength(attr, CSSPropertyMarginTop, attr->value()); 102 } else if (attr->name() == bgcolorAttr) { 103 addCSSColor(attr, CSSPropertyBackgroundColor, attr->value()); 104 } else if (attr->name() == textAttr) { 105 addCSSColor(attr, CSSPropertyColor, attr->value()); 106 } else if (attr->name() == bgpropertiesAttr) { 107 if (equalIgnoringCase(attr->value(), "fixed")) 108 addCSSProperty(attr, CSSPropertyBackgroundAttachment, CSSValueFixed); 109 } else if (attr->name() == vlinkAttr || 110 attr->name() == alinkAttr || 111 attr->name() == linkAttr) { 112 if (attr->isNull()) { 113 if (attr->name() == linkAttr) 114 document()->resetLinkColor(); 115 else if (attr->name() == vlinkAttr) 116 document()->resetVisitedLinkColor(); 117 else 118 document()->resetActiveLinkColor(); 119 } else { 120 if (!m_linkDecl) 121 createLinkDecl(); 122 m_linkDecl->setProperty(CSSPropertyColor, attr->value(), false, false); 123 RefPtr<CSSValue> val = m_linkDecl->getPropertyCSSValue(CSSPropertyColor); 124 if (val && val->isPrimitiveValue()) { 125 Color col = document()->styleSelector()->getColorFromPrimitiveValue(static_cast<CSSPrimitiveValue*>(val.get())); 126 if (attr->name() == linkAttr) 127 document()->setLinkColor(col); 128 else if (attr->name() == vlinkAttr) 129 document()->setVisitedLinkColor(col); 130 else 131 document()->setActiveLinkColor(col); 132 } 133 } 134 135 if (attached()) 136 document()->recalcStyle(Force); 137 } else if (attr->name() == onloadAttr) 138 document()->setWindowAttributeEventListener(eventNames().loadEvent, createAttributeEventListener(document()->frame(), attr)); 139 else if (attr->name() == onbeforeunloadAttr) 140 document()->setWindowAttributeEventListener(eventNames().beforeunloadEvent, createAttributeEventListener(document()->frame(), attr)); 141 else if (attr->name() == onunloadAttr) 142 document()->setWindowAttributeEventListener(eventNames().unloadEvent, createAttributeEventListener(document()->frame(), attr)); 143 else if (attr->name() == onpagehideAttr) 144 document()->setWindowAttributeEventListener(eventNames().pagehideEvent, createAttributeEventListener(document()->frame(), attr)); 145 else if (attr->name() == onpageshowAttr) 146 document()->setWindowAttributeEventListener(eventNames().pageshowEvent, createAttributeEventListener(document()->frame(), attr)); 147 else if (attr->name() == onpopstateAttr) 148 document()->setWindowAttributeEventListener(eventNames().popstateEvent, createAttributeEventListener(document()->frame(), attr)); 149 else if (attr->name() == onblurAttr) 150 document()->setWindowAttributeEventListener(eventNames().blurEvent, createAttributeEventListener(document()->frame(), attr)); 151 else if (attr->name() == onfocusAttr) 152 document()->setWindowAttributeEventListener(eventNames().focusEvent, createAttributeEventListener(document()->frame(), attr)); 153 #if ENABLE(ORIENTATION_EVENTS) 154 else if (attr->name() == onorientationchangeAttr) 155 document()->setWindowAttributeEventListener(eventNames().orientationchangeEvent, createAttributeEventListener(document()->frame(), attr)); 156 #endif 157 else if (attr->name() == onhashchangeAttr) 158 document()->setWindowAttributeEventListener(eventNames().hashchangeEvent, createAttributeEventListener(document()->frame(), attr)); 159 else if (attr->name() == onresizeAttr) 160 document()->setWindowAttributeEventListener(eventNames().resizeEvent, createAttributeEventListener(document()->frame(), attr)); 161 else if (attr->name() == onscrollAttr) 162 document()->setWindowAttributeEventListener(eventNames().scrollEvent, createAttributeEventListener(document()->frame(), attr)); 163 else if (attr->name() == onstorageAttr) 164 document()->setWindowAttributeEventListener(eventNames().storageEvent, createAttributeEventListener(document()->frame(), attr)); 165 else if (attr->name() == ononlineAttr) 166 document()->setWindowAttributeEventListener(eventNames().onlineEvent, createAttributeEventListener(document()->frame(), attr)); 167 else if (attr->name() == onofflineAttr) 168 document()->setWindowAttributeEventListener(eventNames().offlineEvent, createAttributeEventListener(document()->frame(), attr)); 169 else 170 HTMLElement::parseMappedAttribute(attr); 171 } 172 173 void HTMLBodyElement::insertedIntoDocument() 174 { 175 HTMLElement::insertedIntoDocument(); 176 177 // FIXME: Perhaps this code should be in attach() instead of here. 178 Element* ownerElement = document()->ownerElement(); 179 if (ownerElement && (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag))) { 180 HTMLFrameElementBase* ownerFrameElement = static_cast<HTMLFrameElementBase*>(ownerElement); 181 int marginWidth = ownerFrameElement->getMarginWidth(); 182 if (marginWidth != -1) 183 setAttribute(marginwidthAttr, String::number(marginWidth)); 184 int marginHeight = ownerFrameElement->getMarginHeight(); 185 if (marginHeight != -1) 186 setAttribute(marginheightAttr, String::number(marginHeight)); 187 } 188 189 #ifdef ANDROID_META_SUPPORT 190 Settings * settings = document()->settings(); 191 if (settings) { 192 String host = document()->baseURI().host().lower(); 193 if (settings->viewportWidth() == -1 && (host.startsWith("m.") || host.startsWith("mobile.") 194 || host.startsWith("wap.") || host.contains(".m.") || host.contains(".mobile." || host.contains(".wap.")))) { 195 // fit mobile sites directly in the screen 196 settings->setMetadataSettings("width", "device-width"); 197 // update the meta data if it is the top document 198 if (!ownerElement) { 199 FrameView* view = document()->view(); 200 if (view) 201 android::WebViewCore::getWebViewCore(view)->updateViewport(); 202 } 203 } 204 } 205 #endif 206 207 // FIXME: This call to scheduleRelayout should not be needed here. 208 // But without it we hang during WebKit tests; need to fix that and remove this. 209 if (FrameView* view = document()->view()) 210 view->scheduleRelayout(); 211 } 212 213 bool HTMLBodyElement::isURLAttribute(Attribute *attr) const 214 { 215 return attr->name() == backgroundAttr; 216 } 217 218 String HTMLBodyElement::aLink() const 219 { 220 return getAttribute(alinkAttr); 221 } 222 223 void HTMLBodyElement::setALink(const String& value) 224 { 225 setAttribute(alinkAttr, value); 226 } 227 228 String HTMLBodyElement::bgColor() const 229 { 230 return getAttribute(bgcolorAttr); 231 } 232 233 void HTMLBodyElement::setBgColor(const String& value) 234 { 235 setAttribute(bgcolorAttr, value); 236 } 237 238 String HTMLBodyElement::link() const 239 { 240 return getAttribute(linkAttr); 241 } 242 243 void HTMLBodyElement::setLink(const String& value) 244 { 245 setAttribute(linkAttr, value); 246 } 247 248 String HTMLBodyElement::text() const 249 { 250 return getAttribute(textAttr); 251 } 252 253 void HTMLBodyElement::setText(const String& value) 254 { 255 setAttribute(textAttr, value); 256 } 257 258 String HTMLBodyElement::vLink() const 259 { 260 return getAttribute(vlinkAttr); 261 } 262 263 void HTMLBodyElement::setVLink(const String& value) 264 { 265 setAttribute(vlinkAttr, value); 266 } 267 268 static int adjustForZoom(int value, FrameView* frameView) 269 { 270 float zoomFactor = frameView->frame()->zoomFactor(); 271 if (zoomFactor == 1) 272 return value; 273 // Needed because of truncation (rather than rounding) when scaling up. 274 if (zoomFactor > 1) 275 value++; 276 return static_cast<int>(value / zoomFactor); 277 } 278 279 int HTMLBodyElement::scrollLeft() const 280 { 281 // Update the document's layout. 282 Document* doc = document(); 283 doc->updateLayoutIgnorePendingStylesheets(); 284 FrameView* view = doc->view(); 285 return view ? adjustForZoom(view->scrollX(), view) : 0; 286 } 287 288 void HTMLBodyElement::setScrollLeft(int scrollLeft) 289 { 290 FrameView* sview = ownerDocument()->view(); 291 if (sview) { 292 // Update the document's layout 293 document()->updateLayoutIgnorePendingStylesheets(); 294 sview->setScrollPosition(IntPoint(static_cast<int>(scrollLeft * sview->frame()->zoomFactor()), sview->scrollY())); 295 } 296 } 297 298 int HTMLBodyElement::scrollTop() const 299 { 300 // Update the document's layout. 301 Document* doc = document(); 302 doc->updateLayoutIgnorePendingStylesheets(); 303 FrameView* view = doc->view(); 304 return view ? adjustForZoom(view->scrollY(), view) : 0; 305 } 306 307 void HTMLBodyElement::setScrollTop(int scrollTop) 308 { 309 FrameView* sview = ownerDocument()->view(); 310 if (sview) { 311 // Update the document's layout 312 document()->updateLayoutIgnorePendingStylesheets(); 313 sview->setScrollPosition(IntPoint(sview->scrollX(), static_cast<int>(scrollTop * sview->frame()->zoomFactor()))); 314 } 315 } 316 317 int HTMLBodyElement::scrollHeight() const 318 { 319 // Update the document's layout. 320 Document* doc = document(); 321 doc->updateLayoutIgnorePendingStylesheets(); 322 FrameView* view = doc->view(); 323 return view ? adjustForZoom(view->contentsHeight(), view) : 0; 324 } 325 326 int HTMLBodyElement::scrollWidth() const 327 { 328 // Update the document's layout. 329 Document* doc = document(); 330 doc->updateLayoutIgnorePendingStylesheets(); 331 FrameView* view = doc->view(); 332 return view ? adjustForZoom(view->contentsWidth(), view) : 0; 333 } 334 335 void HTMLBodyElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const 336 { 337 HTMLElement::addSubresourceAttributeURLs(urls); 338 339 addSubresourceURL(urls, document()->completeURL(getAttribute(backgroundAttr))); 340 } 341 342 void HTMLBodyElement::didMoveToNewOwnerDocument() 343 { 344 // When moving body elements between documents, we should have to reset the parent sheet for any 345 // link style declarations. If we don't we might crash later. 346 // In practice I can't reproduce this theoretical problem. 347 // webarchive/adopt-attribute-styled-body-webarchive.html tries to make sure this crash won't surface. 348 if (m_linkDecl) 349 m_linkDecl->setParent(document()->elementSheet()); 350 351 HTMLElement::didMoveToNewOwnerDocument(); 352 } 353 354 } // namespace WebCore 355