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