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, 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