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