Home | History | Annotate | Download | only in html
      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