1/*
2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
3 * Copyright (C) 2010 Google Inc. All rights reserved.
4 * Copyright (C) 2012 Samsung Electronics. 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
23#include "config.h"
24#include "ImageInputType.h"
25
26#include "CachedImage.h"
27#include "FormDataList.h"
28#include "HTMLFormElement.h"
29#include "HTMLImageLoader.h"
30#include "HTMLInputElement.h"
31#include "HTMLNames.h"
32#include "HTMLParserIdioms.h"
33#include "InputTypeNames.h"
34#include "MouseEvent.h"
35#include "RenderImage.h"
36#include <wtf/PassOwnPtr.h>
37
38namespace WebCore {
39
40using namespace HTMLNames;
41
42inline ImageInputType::ImageInputType(HTMLInputElement* element)
43    : BaseButtonInputType(element)
44{
45}
46
47PassOwnPtr<InputType> ImageInputType::create(HTMLInputElement* element)
48{
49    return adoptPtr(new ImageInputType(element));
50}
51
52const AtomicString& ImageInputType::formControlType() const
53{
54    return InputTypeNames::image();
55}
56
57bool ImageInputType::isFormDataAppendable() const
58{
59    return true;
60}
61
62bool ImageInputType::appendFormData(FormDataList& encoding, bool) const
63{
64    if (!element()->isActivatedSubmit())
65        return false;
66    const AtomicString& name = element()->name();
67    if (name.isEmpty()) {
68        encoding.appendData("x", m_clickLocation.x());
69        encoding.appendData("y", m_clickLocation.y());
70        return true;
71    }
72
73    DEFINE_STATIC_LOCAL(String, dotXString, (ASCIILiteral(".x")));
74    DEFINE_STATIC_LOCAL(String, dotYString, (ASCIILiteral(".y")));
75    encoding.appendData(name + dotXString, m_clickLocation.x());
76    encoding.appendData(name + dotYString, m_clickLocation.y());
77
78    if (!element()->value().isEmpty())
79        encoding.appendData(name, element()->value());
80    return true;
81}
82
83bool ImageInputType::supportsValidation() const
84{
85    return false;
86}
87
88void ImageInputType::handleDOMActivateEvent(Event* event)
89{
90    RefPtr<HTMLInputElement> element = this->element();
91    if (element->isDisabledFormControl() || !element->form())
92        return;
93    element->setActivatedSubmit(true);
94    if (event->underlyingEvent() && event->underlyingEvent()->isMouseEvent()) {
95        MouseEvent* mouseEvent = static_cast<MouseEvent*>(event->underlyingEvent());
96        m_clickLocation = IntPoint(mouseEvent->offsetX(), mouseEvent->offsetY());
97    } else
98        m_clickLocation = IntPoint();
99    element->form()->prepareForSubmission(event); // Event handlers can run.
100    element->setActivatedSubmit(false);
101    event->setDefaultHandled();
102}
103
104RenderObject* ImageInputType::createRenderer(RenderArena* arena, RenderStyle*) const
105{
106    RenderImage* image = new (arena) RenderImage(element());
107    image->setImageResource(RenderImageResource::create());
108    return image;
109}
110
111void ImageInputType::altAttributeChanged()
112{
113    RenderImage* image = toRenderImage(element()->renderer());
114    if (!image)
115        return;
116    image->updateAltText();
117}
118
119void ImageInputType::srcAttributeChanged()
120{
121    if (!element()->renderer())
122        return;
123    element()->imageLoader()->updateFromElementIgnoringPreviousError();
124}
125
126void ImageInputType::attach()
127{
128    BaseButtonInputType::attach();
129
130    HTMLImageLoader* imageLoader = element()->imageLoader();
131    imageLoader->updateFromElement();
132
133    RenderImage* renderer = toRenderImage(element()->renderer());
134    if (!renderer)
135        return;
136
137    if (imageLoader->hasPendingBeforeLoadEvent())
138        return;
139
140    RenderImageResource* imageResource = renderer->imageResource();
141    imageResource->setCachedImage(imageLoader->image());
142
143    // If we have no image at all because we have no src attribute, set
144    // image height and width for the alt text instead.
145    if (!imageLoader->image() && !imageResource->cachedImage())
146        renderer->setImageSizeForAltText();
147}
148
149bool ImageInputType::shouldRespectAlignAttribute()
150{
151    return true;
152}
153
154bool ImageInputType::canBeSuccessfulSubmitButton()
155{
156    return true;
157}
158
159bool ImageInputType::isImageButton() const
160{
161    return true;
162}
163
164bool ImageInputType::isEnumeratable()
165{
166    return false;
167}
168
169bool ImageInputType::shouldRespectHeightAndWidthAttributes()
170{
171    return true;
172}
173
174unsigned ImageInputType::height() const
175{
176    RefPtr<HTMLInputElement> element = this->element();
177
178    if (!element->renderer()) {
179        // Check the attribute first for an explicit pixel value.
180        unsigned height;
181        if (parseHTMLNonNegativeInteger(element->fastGetAttribute(heightAttr), height))
182            return height;
183
184        // If the image is available, use its height.
185        if (element->hasImageLoader()) {
186            HTMLImageLoader* imageLoader = element->imageLoader();
187            if (imageLoader->image())
188                return imageLoader->image()->imageSizeForRenderer(element->renderer(), 1).height();
189        }
190    }
191
192    element->document()->updateLayout();
193
194    RenderBox* box = element->renderBox();
195    return box ? adjustForAbsoluteZoom(box->contentHeight(), box) : 0;
196}
197
198unsigned ImageInputType::width() const
199{
200    RefPtr<HTMLInputElement> element = this->element();
201
202    if (!element->renderer()) {
203        // Check the attribute first for an explicit pixel value.
204        unsigned width;
205        if (parseHTMLNonNegativeInteger(element->fastGetAttribute(widthAttr), width))
206            return width;
207
208        // If the image is available, use its width.
209        if (element->hasImageLoader()) {
210            HTMLImageLoader* imageLoader = element->imageLoader();
211            if (imageLoader->image())
212                return imageLoader->image()->imageSizeForRenderer(element->renderer(), 1).width();
213        }
214    }
215
216    element->document()->updateLayout();
217
218    RenderBox* box = element->renderBox();
219    return box ? adjustForAbsoluteZoom(box->contentWidth(), box) : 0;
220}
221
222} // namespace WebCore
223