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