WebCore:
[WebKit-https.git] / WebCore / html / HTMLImageElement.cpp
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 Apple Inc. All rights reserved.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public License
17  * along with this library; see the file COPYING.LIB.  If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21
22 #include "config.h"
23 #include "HTMLImageElement.h"
24
25 #include "CSSHelper.h"
26 #include "CSSPropertyNames.h"
27 #include "CSSValueKeywords.h"
28 #include "EventNames.h"
29 #include "HTMLDocument.h"
30 #include "HTMLFormElement.h"
31 #include "HTMLNames.h"
32 #include "RenderImage.h"
33
34 using namespace std;
35
36 namespace WebCore {
37
38 using namespace EventNames;
39 using namespace HTMLNames;
40
41 HTMLImageElement::HTMLImageElement(Document* doc, HTMLFormElement* f)
42     : HTMLElement(imgTag, doc)
43     , m_imageLoader(this)
44     , ismap(false)
45     , m_form(f)
46     , m_compositeOperator(CompositeSourceOver)
47 {
48     if (f)
49         f->registerImgElement(this);
50 }
51
52 HTMLImageElement::HTMLImageElement(const QualifiedName& tagName, Document* doc)
53     : HTMLElement(tagName, doc)
54     , m_imageLoader(this)
55     , ismap(false)
56     , m_form(0)
57     , m_compositeOperator(CompositeSourceOver)
58 {
59 }
60
61 HTMLImageElement::~HTMLImageElement()
62 {
63     if (m_form)
64         m_form->removeImgElement(this);
65 }
66
67 bool HTMLImageElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const
68 {
69     if (attrName == widthAttr ||
70         attrName == heightAttr ||
71         attrName == vspaceAttr ||
72         attrName == hspaceAttr ||
73         attrName == valignAttr) {
74         result = eUniversal;
75         return false;
76     }
77     
78     if (attrName == borderAttr || attrName == alignAttr) {
79         result = eReplaced; // Shared with embed and iframe elements.
80         return false;
81     }
82
83     return HTMLElement::mapToEntry(attrName, result);
84 }
85
86 void HTMLImageElement::parseMappedAttribute(MappedAttribute* attr)
87 {
88     const QualifiedName& attrName = attr->name();
89     if (attrName == altAttr) {
90         if (renderer() && renderer()->isImage())
91             static_cast<RenderImage*>(renderer())->updateAltText();
92     } else if (attrName == srcAttr)
93         m_imageLoader.updateFromElement();
94     else if (attrName == widthAttr)
95         addCSSLength(attr, CSS_PROP_WIDTH, attr->value());
96     else if (attrName == heightAttr)
97         addCSSLength(attr, CSS_PROP_HEIGHT, attr->value());
98     else if (attrName == borderAttr) {
99         // border="noborder" -> border="0"
100         addCSSLength(attr, CSS_PROP_BORDER_WIDTH, attr->value().toInt() ? attr->value() : "0");
101         addCSSProperty(attr, CSS_PROP_BORDER_TOP_STYLE, CSS_VAL_SOLID);
102         addCSSProperty(attr, CSS_PROP_BORDER_RIGHT_STYLE, CSS_VAL_SOLID);
103         addCSSProperty(attr, CSS_PROP_BORDER_BOTTOM_STYLE, CSS_VAL_SOLID);
104         addCSSProperty(attr, CSS_PROP_BORDER_LEFT_STYLE, CSS_VAL_SOLID);
105     } else if (attrName == vspaceAttr) {
106         addCSSLength(attr, CSS_PROP_MARGIN_TOP, attr->value());
107         addCSSLength(attr, CSS_PROP_MARGIN_BOTTOM, attr->value());
108     } else if (attrName == hspaceAttr) {
109         addCSSLength(attr, CSS_PROP_MARGIN_LEFT, attr->value());
110         addCSSLength(attr, CSS_PROP_MARGIN_RIGHT, attr->value());
111     } else if (attrName == alignAttr)
112         addHTMLAlignment(attr);
113     else if (attrName == valignAttr)
114         addCSSProperty(attr, CSS_PROP_VERTICAL_ALIGN, attr->value());
115     else if (attrName == usemapAttr) {
116         if (attr->value().domString()[0] == '#')
117             usemap = attr->value();
118         else
119             usemap = document()->completeURL(parseURL(attr->value()));
120         m_isLink = !attr->isNull();
121     } else if (attrName == ismapAttr)
122         ismap = true;
123     else if (attrName == onabortAttr)
124         setHTMLEventListener(abortEvent, attr);
125     else if (attrName == onloadAttr)
126         setHTMLEventListener(loadEvent, attr);
127     else if (attrName == compositeAttr) {
128         if (!parseCompositeOperator(attr->value(), m_compositeOperator))
129             m_compositeOperator = CompositeSourceOver;
130     } else if (attrName == nameAttr) {
131         String newNameAttr = attr->value();
132         if (inDocument() && document()->isHTMLDocument()) {
133             HTMLDocument* doc = static_cast<HTMLDocument*>(document());
134             doc->removeNamedItem(oldNameAttr);
135             doc->addNamedItem(newNameAttr);
136         }
137         oldNameAttr = newNameAttr;
138     } else if (attr->name() == idAttr) {
139         String newIdAttr = attr->value();
140         if (inDocument() && document()->isHTMLDocument()) {
141             HTMLDocument *doc = static_cast<HTMLDocument *>(document());
142             doc->removeDocExtraNamedItem(oldIdAttr);
143             doc->addDocExtraNamedItem(newIdAttr);
144         }
145         oldIdAttr = newIdAttr;
146         // also call superclass
147         HTMLElement::parseMappedAttribute(attr);
148     } else
149         HTMLElement::parseMappedAttribute(attr);
150 }
151
152 String HTMLImageElement::altText() const
153 {
154     // lets figure out the alt text.. magic stuff
155     // http://www.w3.org/TR/1998/REC-html40-19980424/appendix/notes.html#altgen
156     // also heavily discussed by Hixie on bugzilla
157     String alt = getAttribute(altAttr);
158     // fall back to title attribute
159     if (alt.isNull())
160         alt = getAttribute(titleAttr);
161     return alt;
162 }
163
164 RenderObject* HTMLImageElement::createRenderer(RenderArena* arena, RenderStyle* style)
165 {
166      if (style->contentData())
167         return RenderObject::createObject(this, style);
168      
169      return new (arena) RenderImage(this);
170 }
171
172 void HTMLImageElement::attach()
173 {
174     HTMLElement::attach();
175
176     if (renderer() && renderer()->isImage()) {
177         RenderImage* imageObj = static_cast<RenderImage*>(renderer());
178         imageObj->setCachedImage(m_imageLoader.image());
179         
180         // If we have no image at all because we have no src attribute, set
181         // image height and width for the alt text instead.
182         if (!m_imageLoader.image() && !imageObj->cachedImage())
183             imageObj->setImageSizeForAltText();
184     }
185 }
186
187 void HTMLImageElement::insertedIntoDocument()
188 {
189     if (document()->isHTMLDocument()) {
190         HTMLDocument* doc = static_cast<HTMLDocument*>(document());
191
192         doc->addNamedItem(oldNameAttr);
193         doc->addDocExtraNamedItem(oldIdAttr);
194     }
195
196     HTMLElement::insertedIntoDocument();
197 }
198
199 void HTMLImageElement::removedFromDocument()
200 {
201     if (document()->isHTMLDocument()) {
202         HTMLDocument* doc = static_cast<HTMLDocument*>(document());
203
204         doc->removeNamedItem(oldNameAttr);
205         doc->removeDocExtraNamedItem(oldIdAttr);
206     }
207
208     HTMLElement::removedFromDocument();
209 }
210
211 int HTMLImageElement::width(bool ignorePendingStylesheets) const
212 {
213     if (!renderer()) {
214         // check the attribute first for an explicit pixel value
215         bool ok;
216         int width = getAttribute(widthAttr).toInt(&ok);
217         if (ok)
218             return width;
219         
220         // if the image is available, use its width
221         if (m_imageLoader.image())
222             return m_imageLoader.image()->imageSize().width();
223     }
224
225     if (ignorePendingStylesheets)
226         document()->updateLayoutIgnorePendingStylesheets();
227     else
228         document()->updateLayout();
229
230     return renderer() ? renderer()->contentWidth() : 0;
231 }
232
233 int HTMLImageElement::height(bool ignorePendingStylesheets) const
234 {
235     if (!renderer()) {
236         // check the attribute first for an explicit pixel value
237         bool ok;
238         int height = getAttribute(heightAttr).toInt(&ok);
239         if (ok)
240             return height;
241         
242         // if the image is available, use its height
243         if (m_imageLoader.image())
244             return m_imageLoader.image()->imageSize().height();        
245     }
246
247     if (ignorePendingStylesheets)
248         document()->updateLayoutIgnorePendingStylesheets();
249     else
250         document()->updateLayout();
251
252     return renderer() ? renderer()->contentHeight() : 0;
253 }
254
255 int HTMLImageElement::naturalWidth() const
256 {
257     if (!m_imageLoader.image())
258         return 0;
259
260     return m_imageLoader.image()->imageSize().width();
261 }
262
263 int HTMLImageElement::naturalHeight() const
264 {
265     if (!m_imageLoader.image())
266         return 0;
267     
268     return m_imageLoader.image()->imageSize().height();
269 }
270     
271 bool HTMLImageElement::isURLAttribute(Attribute* attr) const
272 {
273     return attr->name() == srcAttr
274         || attr->name() == lowsrcAttr
275         || attr->name() == longdescAttr
276         || (attr->name() == usemapAttr && attr->value().domString()[0] != '#');
277 }
278
279 String HTMLImageElement::name() const
280 {
281     return getAttribute(nameAttr);
282 }
283
284 void HTMLImageElement::setName(const String& value)
285 {
286     setAttribute(nameAttr, value);
287 }
288
289 String HTMLImageElement::align() const
290 {
291     return getAttribute(alignAttr);
292 }
293
294 void HTMLImageElement::setAlign(const String& value)
295 {
296     setAttribute(alignAttr, value);
297 }
298
299 String HTMLImageElement::alt() const
300 {
301     return getAttribute(altAttr);
302 }
303
304 void HTMLImageElement::setAlt(const String& value)
305 {
306     setAttribute(altAttr, value);
307 }
308
309 String HTMLImageElement::border() const
310 {
311     return getAttribute(borderAttr);
312 }
313
314 void HTMLImageElement::setBorder(const String& value)
315 {
316     setAttribute(borderAttr, value);
317 }
318
319 void HTMLImageElement::setHeight(int value)
320 {
321     setAttribute(heightAttr, String::number(value));
322 }
323
324 int HTMLImageElement::hspace() const
325 {
326     // ### return actual value
327     return getAttribute(hspaceAttr).toInt();
328 }
329
330 void HTMLImageElement::setHspace(int value)
331 {
332     setAttribute(hspaceAttr, String::number(value));
333 }
334
335 bool HTMLImageElement::isMap() const
336 {
337     return !getAttribute(ismapAttr).isNull();
338 }
339
340 void HTMLImageElement::setIsMap(bool isMap)
341 {
342     setAttribute(ismapAttr, isMap ? "" : 0);
343 }
344
345 String HTMLImageElement::longDesc() const
346 {
347     return document()->completeURL(getAttribute(longdescAttr));
348 }
349
350 void HTMLImageElement::setLongDesc(const String& value)
351 {
352     setAttribute(longdescAttr, value);
353 }
354
355 String HTMLImageElement::lowsrc() const
356 {
357     return document()->completeURL(getAttribute(lowsrcAttr));
358 }
359
360 void HTMLImageElement::setLowsrc(const String& value)
361 {
362     setAttribute(lowsrcAttr, value);
363 }
364
365 String HTMLImageElement::src() const
366 {
367     return document()->completeURL(getAttribute(srcAttr));
368 }
369
370 void HTMLImageElement::setSrc(const String& value)
371 {
372     setAttribute(srcAttr, value);
373 }
374
375 String HTMLImageElement::useMap() const
376 {
377     return getAttribute(usemapAttr);
378 }
379
380 void HTMLImageElement::setUseMap(const String& value)
381 {
382     setAttribute(usemapAttr, value);
383 }
384
385 int HTMLImageElement::vspace() const
386 {
387     // ### return actual vspace
388     return getAttribute(vspaceAttr).toInt();
389 }
390
391 void HTMLImageElement::setVspace(int value)
392 {
393     setAttribute(vspaceAttr, String::number(value));
394 }
395
396 void HTMLImageElement::setWidth(int value)
397 {
398     setAttribute(widthAttr, String::number(value));
399 }
400
401 int HTMLImageElement::x() const
402 {
403     RenderObject* r = renderer();
404     if (!r)
405         return 0;
406     int x, y;
407     r->absolutePosition(x, y);
408     return x;
409 }
410
411 int HTMLImageElement::y() const
412 {
413     RenderObject* r = renderer();
414     if (!r)
415         return 0;
416     int x, y;
417     r->absolutePosition(x, y);
418     return y;
419 }
420
421 bool HTMLImageElement::complete() const
422 {
423     return m_imageLoader.imageComplete();
424 }
425
426 }