WebCore/html/HTMLImageElement.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     1 /*
       
     2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
       
     3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
       
     4  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010 Apple Inc. All rights reserved.
       
     5  * Copyright (C) 2010 Google Inc. All rights reserved.
       
     6  *
       
     7  * This library is free software; you can redistribute it and/or
       
     8  * modify it under the terms of the GNU Library General Public
       
     9  * License as published by the Free Software Foundation; either
       
    10  * version 2 of the License, or (at your option) any later version.
       
    11  *
       
    12  * This library is distributed in the hope that it will be useful,
       
    13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    15  * Library General Public License for more details.
       
    16  *
       
    17  * You should have received a copy of the GNU Library General Public License
       
    18  * along with this library; see the file COPYING.LIB.  If not, write to
       
    19  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
       
    20  * Boston, MA 02110-1301, USA.
       
    21  */
       
    22 
       
    23 #include "config.h"
       
    24 #include "HTMLImageElement.h"
       
    25 
       
    26 #include "Attribute.h"
       
    27 #include "CSSHelper.h"
       
    28 #include "CSSPropertyNames.h"
       
    29 #include "CSSValueKeywords.h"
       
    30 #include "EventNames.h"
       
    31 #include "FrameView.h"
       
    32 #include "HTMLDocument.h"
       
    33 #include "HTMLFormElement.h"
       
    34 #include "HTMLNames.h"
       
    35 #include "RenderImage.h"
       
    36 #include "ScriptEventListener.h"
       
    37 
       
    38 using namespace std;
       
    39 
       
    40 namespace WebCore {
       
    41 
       
    42 using namespace HTMLNames;
       
    43 
       
    44 HTMLImageElement::HTMLImageElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form)
       
    45     : HTMLElement(tagName, document)
       
    46     , m_imageLoader(this)
       
    47     , ismap(false)
       
    48     , m_form(form)
       
    49     , m_compositeOperator(CompositeSourceOver)
       
    50 {
       
    51     ASSERT(hasTagName(imgTag));
       
    52     if (form)
       
    53         form->registerImgElement(this);
       
    54 }
       
    55 
       
    56 PassRefPtr<HTMLImageElement> HTMLImageElement::create(Document* document)
       
    57 {
       
    58     return adoptRef(new HTMLImageElement(imgTag, document));
       
    59 }
       
    60 
       
    61 PassRefPtr<HTMLImageElement> HTMLImageElement::create(const QualifiedName& tagName, Document* document, HTMLFormElement* form)
       
    62 {
       
    63     return adoptRef(new HTMLImageElement(tagName, document, form));
       
    64 }
       
    65 
       
    66 HTMLImageElement::~HTMLImageElement()
       
    67 {
       
    68     if (m_form)
       
    69         m_form->removeImgElement(this);
       
    70 }
       
    71 
       
    72 PassRefPtr<HTMLImageElement> HTMLImageElement::createForJSConstructor(Document* document, const int* optionalWidth, const int* optionalHeight)
       
    73 {
       
    74     RefPtr<HTMLImageElement> image = adoptRef(new HTMLImageElement(imgTag, document));
       
    75     if (optionalWidth)
       
    76         image->setWidth(*optionalWidth);
       
    77     if (optionalHeight > 0)
       
    78         image->setHeight(*optionalHeight);
       
    79     return image.release();
       
    80 }
       
    81 
       
    82 bool HTMLImageElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const
       
    83 {
       
    84     if (attrName == widthAttr ||
       
    85         attrName == heightAttr ||
       
    86         attrName == vspaceAttr ||
       
    87         attrName == hspaceAttr ||
       
    88         attrName == valignAttr) {
       
    89         result = eUniversal;
       
    90         return false;
       
    91     }
       
    92 
       
    93     if (attrName == borderAttr || attrName == alignAttr) {
       
    94         result = eReplaced; // Shared with embed and iframe elements.
       
    95         return false;
       
    96     }
       
    97 
       
    98     return HTMLElement::mapToEntry(attrName, result);
       
    99 }
       
   100 
       
   101 void HTMLImageElement::parseMappedAttribute(Attribute* attr)
       
   102 {
       
   103     const QualifiedName& attrName = attr->name();
       
   104     if (attrName == altAttr) {
       
   105         if (renderer() && renderer()->isImage())
       
   106             toRenderImage(renderer())->updateAltText();
       
   107     } else if (attrName == srcAttr)
       
   108         m_imageLoader.updateFromElementIgnoringPreviousError();
       
   109     else if (attrName == widthAttr)
       
   110         addCSSLength(attr, CSSPropertyWidth, attr->value());
       
   111     else if (attrName == heightAttr)
       
   112         addCSSLength(attr, CSSPropertyHeight, attr->value());
       
   113     else if (attrName == borderAttr) {
       
   114         // border="noborder" -> border="0"
       
   115         addCSSLength(attr, CSSPropertyBorderWidth, attr->value().toInt() ? attr->value() : "0");
       
   116         addCSSProperty(attr, CSSPropertyBorderTopStyle, CSSValueSolid);
       
   117         addCSSProperty(attr, CSSPropertyBorderRightStyle, CSSValueSolid);
       
   118         addCSSProperty(attr, CSSPropertyBorderBottomStyle, CSSValueSolid);
       
   119         addCSSProperty(attr, CSSPropertyBorderLeftStyle, CSSValueSolid);
       
   120     } else if (attrName == vspaceAttr) {
       
   121         addCSSLength(attr, CSSPropertyMarginTop, attr->value());
       
   122         addCSSLength(attr, CSSPropertyMarginBottom, attr->value());
       
   123     } else if (attrName == hspaceAttr) {
       
   124         addCSSLength(attr, CSSPropertyMarginLeft, attr->value());
       
   125         addCSSLength(attr, CSSPropertyMarginRight, attr->value());
       
   126     } else if (attrName == alignAttr)
       
   127         addHTMLAlignment(attr);
       
   128     else if (attrName == valignAttr)
       
   129         addCSSProperty(attr, CSSPropertyVerticalAlign, attr->value());
       
   130     else if (attrName == usemapAttr) {
       
   131         if (attr->value().string()[0] == '#')
       
   132             usemap = attr->value();
       
   133         else
       
   134             usemap = document()->completeURL(deprecatedParseURL(attr->value())).string();
       
   135         setIsLink(!attr->isNull());
       
   136     } else if (attrName == ismapAttr)
       
   137         ismap = true;
       
   138     else if (attrName == onabortAttr)
       
   139         setAttributeEventListener(eventNames().abortEvent, createAttributeEventListener(this, attr));
       
   140     else if (attrName == onloadAttr)
       
   141         setAttributeEventListener(eventNames().loadEvent, createAttributeEventListener(this, attr));
       
   142     else if (attrName == onbeforeloadAttr)
       
   143         setAttributeEventListener(eventNames().beforeloadEvent, createAttributeEventListener(this, attr));
       
   144     else if (attrName == compositeAttr) {
       
   145         if (!parseCompositeOperator(attr->value(), m_compositeOperator))
       
   146             m_compositeOperator = CompositeSourceOver;
       
   147     } else if (attrName == nameAttr) {
       
   148         const AtomicString& newName = attr->value();
       
   149         if (inDocument() && document()->isHTMLDocument()) {
       
   150             HTMLDocument* document = static_cast<HTMLDocument*>(this->document());
       
   151             document->removeNamedItem(m_name);
       
   152             document->addNamedItem(newName);
       
   153         }
       
   154         m_name = newName;
       
   155     } else if (isIdAttributeName(attr->name())) {
       
   156         const AtomicString& newId = attr->value();
       
   157         if (inDocument() && document()->isHTMLDocument()) {
       
   158             HTMLDocument* document = static_cast<HTMLDocument*>(this->document());
       
   159             document->removeExtraNamedItem(m_id);
       
   160             document->addExtraNamedItem(newId);
       
   161         }
       
   162         m_id = newId;
       
   163         // also call superclass
       
   164         HTMLElement::parseMappedAttribute(attr);
       
   165     } else
       
   166         HTMLElement::parseMappedAttribute(attr);
       
   167 }
       
   168 
       
   169 String HTMLImageElement::altText() const
       
   170 {
       
   171     // lets figure out the alt text.. magic stuff
       
   172     // http://www.w3.org/TR/1998/REC-html40-19980424/appendix/notes.html#altgen
       
   173     // also heavily discussed by Hixie on bugzilla
       
   174     String alt = getAttribute(altAttr);
       
   175     // fall back to title attribute
       
   176     if (alt.isNull())
       
   177         alt = getAttribute(titleAttr);
       
   178     return alt;
       
   179 }
       
   180 
       
   181 RenderObject* HTMLImageElement::createRenderer(RenderArena* arena, RenderStyle* style)
       
   182 {
       
   183      if (style->contentData())
       
   184         return RenderObject::createObject(this, style);
       
   185 
       
   186      return new (arena) RenderImage(this);
       
   187 }
       
   188 
       
   189 void HTMLImageElement::attach()
       
   190 {
       
   191     HTMLElement::attach();
       
   192 
       
   193     if (renderer() && renderer()->isImage() && m_imageLoader.haveFiredBeforeLoadEvent()) {
       
   194         RenderImage* imageObj = toRenderImage(renderer());
       
   195         if (imageObj->hasImage())
       
   196             return;
       
   197         imageObj->setCachedImage(m_imageLoader.image());
       
   198 
       
   199         // If we have no image at all because we have no src attribute, set
       
   200         // image height and width for the alt text instead.
       
   201         if (!m_imageLoader.image() && !imageObj->cachedImage())
       
   202             imageObj->setImageSizeForAltText();
       
   203     }
       
   204 }
       
   205 
       
   206 void HTMLImageElement::insertedIntoDocument()
       
   207 {
       
   208     if (document()->isHTMLDocument()) {
       
   209         HTMLDocument* document = static_cast<HTMLDocument*>(this->document());
       
   210         document->addNamedItem(m_name);
       
   211         document->addExtraNamedItem(m_id);
       
   212     }
       
   213 
       
   214     // If we have been inserted from a renderer-less document,
       
   215     // our loader may have not fetched the image, so do it now.
       
   216     if (!m_imageLoader.image())
       
   217         m_imageLoader.updateFromElement();
       
   218 
       
   219     HTMLElement::insertedIntoDocument();
       
   220 }
       
   221 
       
   222 void HTMLImageElement::removedFromDocument()
       
   223 {
       
   224     if (document()->isHTMLDocument()) {
       
   225         HTMLDocument* document = static_cast<HTMLDocument*>(this->document());
       
   226         document->removeNamedItem(m_name);
       
   227         document->removeExtraNamedItem(m_id);
       
   228     }
       
   229 
       
   230     HTMLElement::removedFromDocument();
       
   231 }
       
   232 
       
   233 void HTMLImageElement::insertedIntoTree(bool deep)
       
   234 {
       
   235     if (!m_form) {
       
   236         // m_form can be non-null if it was set in constructor.
       
   237         for (Node* ancestor = parentNode(); ancestor; ancestor = ancestor->parentNode()) {
       
   238             if (ancestor->hasTagName(formTag)) {
       
   239                 m_form = static_cast<HTMLFormElement*>(ancestor);
       
   240                 m_form->registerImgElement(this);
       
   241                 break;
       
   242             }
       
   243         }
       
   244     }
       
   245 
       
   246     HTMLElement::insertedIntoTree(deep);
       
   247 }
       
   248 
       
   249 void HTMLImageElement::removedFromTree(bool deep)
       
   250 {
       
   251     if (m_form)
       
   252         m_form->removeImgElement(this);
       
   253     m_form = 0;
       
   254     HTMLElement::removedFromTree(deep);
       
   255 }
       
   256 
       
   257 int HTMLImageElement::width(bool ignorePendingStylesheets) const
       
   258 {
       
   259     if (!renderer()) {
       
   260         // check the attribute first for an explicit pixel value
       
   261         bool ok;
       
   262         int width = getAttribute(widthAttr).toInt(&ok);
       
   263         if (ok)
       
   264             return width;
       
   265 
       
   266         // if the image is available, use its width
       
   267         if (m_imageLoader.image()) {
       
   268             float zoomFactor = document()->view() ? document()->view()->pageZoomFactor() : 1.0f;
       
   269             return m_imageLoader.image()->imageSize(zoomFactor).width();
       
   270         }
       
   271     }
       
   272 
       
   273     if (ignorePendingStylesheets)
       
   274         document()->updateLayoutIgnorePendingStylesheets();
       
   275     else
       
   276         document()->updateLayout();
       
   277 
       
   278     return renderBox() ? renderBox()->contentWidth() : 0;
       
   279 }
       
   280 
       
   281 int HTMLImageElement::height(bool ignorePendingStylesheets) const
       
   282 {
       
   283     if (!renderer()) {
       
   284         // check the attribute first for an explicit pixel value
       
   285         bool ok;
       
   286         int height = getAttribute(heightAttr).toInt(&ok);
       
   287         if (ok)
       
   288             return height;
       
   289 
       
   290         // if the image is available, use its height
       
   291         if (m_imageLoader.image()) {
       
   292             float zoomFactor = document()->view() ? document()->view()->pageZoomFactor() : 1.0f;
       
   293             return m_imageLoader.image()->imageSize(zoomFactor).height();
       
   294         }
       
   295     }
       
   296 
       
   297     if (ignorePendingStylesheets)
       
   298         document()->updateLayoutIgnorePendingStylesheets();
       
   299     else
       
   300         document()->updateLayout();
       
   301 
       
   302     return renderBox() ? renderBox()->contentHeight() : 0;
       
   303 }
       
   304 
       
   305 int HTMLImageElement::naturalWidth() const
       
   306 {
       
   307     if (!m_imageLoader.image())
       
   308         return 0;
       
   309 
       
   310     return m_imageLoader.image()->imageSize(1.0f).width();
       
   311 }
       
   312 
       
   313 int HTMLImageElement::naturalHeight() const
       
   314 {
       
   315     if (!m_imageLoader.image())
       
   316         return 0;
       
   317 
       
   318     return m_imageLoader.image()->imageSize(1.0f).height();
       
   319 }
       
   320 
       
   321 bool HTMLImageElement::isURLAttribute(Attribute* attr) const
       
   322 {
       
   323     return attr->name() == srcAttr
       
   324         || attr->name() == lowsrcAttr
       
   325         || attr->name() == longdescAttr
       
   326         || (attr->name() == usemapAttr && attr->value().string()[0] != '#');
       
   327 }
       
   328 
       
   329 const AtomicString& HTMLImageElement::alt() const
       
   330 {
       
   331     return getAttribute(altAttr);
       
   332 }
       
   333 
       
   334 bool HTMLImageElement::draggable() const
       
   335 {
       
   336     // Image elements are draggable by default.
       
   337     return !equalIgnoringCase(getAttribute(draggableAttr), "false");
       
   338 }
       
   339 
       
   340 void HTMLImageElement::setHeight(int value)
       
   341 {
       
   342     setAttribute(heightAttr, String::number(value));
       
   343 }
       
   344 
       
   345 KURL HTMLImageElement::src() const
       
   346 {
       
   347     return document()->completeURL(getAttribute(srcAttr));
       
   348 }
       
   349 
       
   350 void HTMLImageElement::setSrc(const String& value)
       
   351 {
       
   352     setAttribute(srcAttr, value);
       
   353 }
       
   354 
       
   355 void HTMLImageElement::setWidth(int value)
       
   356 {
       
   357     setAttribute(widthAttr, String::number(value));
       
   358 }
       
   359 
       
   360 int HTMLImageElement::x() const
       
   361 {
       
   362     RenderObject* r = renderer();
       
   363     if (!r)
       
   364         return 0;
       
   365 
       
   366     // FIXME: This doesn't work correctly with transforms.
       
   367     FloatPoint absPos = r->localToAbsolute();
       
   368     return absPos.x();
       
   369 }
       
   370 
       
   371 int HTMLImageElement::y() const
       
   372 {
       
   373     RenderObject* r = renderer();
       
   374     if (!r)
       
   375         return 0;
       
   376 
       
   377     // FIXME: This doesn't work correctly with transforms.
       
   378     FloatPoint absPos = r->localToAbsolute();
       
   379     return absPos.y();
       
   380 }
       
   381 
       
   382 bool HTMLImageElement::complete() const
       
   383 {
       
   384     return m_imageLoader.imageComplete();
       
   385 }
       
   386 
       
   387 void HTMLImageElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
       
   388 {
       
   389     HTMLElement::addSubresourceAttributeURLs(urls);
       
   390 
       
   391     addSubresourceURL(urls, src());
       
   392     // FIXME: What about when the usemap attribute begins with "#"?
       
   393     addSubresourceURL(urls, document()->completeURL(getAttribute(usemapAttr)));
       
   394 }
       
   395 
       
   396 void HTMLImageElement::willMoveToNewOwnerDocument()
       
   397 {
       
   398     m_imageLoader.elementWillMoveToNewOwnerDocument();
       
   399     HTMLElement::willMoveToNewOwnerDocument();
       
   400 }
       
   401 
       
   402 }