| /* |
| * Copyright (C) 2004-2018 Apple Inc. All rights reserved. |
| * Copyright (C) 2010 Google Inc. All rights reserved. |
| * Copyright (C) 2012 Samsung Electronics. All rights reserved. |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Library General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Library General Public License for more details. |
| * |
| * You should have received a copy of the GNU Library General Public License |
| * along with this library; see the file COPYING.LIB. If not, write to |
| * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| * Boston, MA 02110-1301, USA. |
| * |
| */ |
| |
| #include "config.h" |
| #include "ImageInputType.h" |
| |
| #include "CachedImage.h" |
| #include "DOMFormData.h" |
| #include "HTMLFormElement.h" |
| #include "HTMLImageLoader.h" |
| #include "HTMLInputElement.h" |
| #include "HTMLNames.h" |
| #include "HTMLParserIdioms.h" |
| #include "InputTypeNames.h" |
| #include "MouseEvent.h" |
| #include "RenderImage.h" |
| #include <wtf/NeverDestroyed.h> |
| |
| namespace WebCore { |
| |
| using namespace HTMLNames; |
| |
| ImageInputType::ImageInputType(HTMLInputElement& element) |
| : BaseButtonInputType(element) |
| { |
| } |
| |
| const AtomString& ImageInputType::formControlType() const |
| { |
| return InputTypeNames::image(); |
| } |
| |
| bool ImageInputType::isFormDataAppendable() const |
| { |
| return true; |
| } |
| |
| bool ImageInputType::appendFormData(DOMFormData& formData, bool) const |
| { |
| ASSERT(element()); |
| if (!element()->isActivatedSubmit()) |
| return false; |
| |
| auto& name = element()->name(); |
| if (name.isEmpty()) { |
| formData.append("x"_s, String::number(m_clickLocation.x())); |
| formData.append("y"_s, String::number(m_clickLocation.y())); |
| return true; |
| } |
| |
| formData.append(makeString(name, ".x"), String::number(m_clickLocation.x())); |
| formData.append(makeString(name, ".y"), String::number(m_clickLocation.y())); |
| |
| auto value = element()->value(); |
| if (!value.isEmpty()) |
| formData.append(name, value); |
| |
| return true; |
| } |
| |
| bool ImageInputType::supportsValidation() const |
| { |
| return false; |
| } |
| |
| void ImageInputType::handleDOMActivateEvent(Event& event) |
| { |
| ASSERT(element()); |
| Ref<HTMLInputElement> protectedElement(*element()); |
| if (protectedElement->isDisabledFormControl() || !protectedElement->form()) |
| return; |
| |
| Ref<HTMLFormElement> protectedForm(*protectedElement->form()); |
| |
| protectedElement->setActivatedSubmit(true); |
| |
| m_clickLocation = IntPoint(); |
| if (event.underlyingEvent()) { |
| Event& underlyingEvent = *event.underlyingEvent(); |
| if (is<MouseEvent>(underlyingEvent)) { |
| MouseEvent& mouseEvent = downcast<MouseEvent>(underlyingEvent); |
| if (!mouseEvent.isSimulated()) |
| m_clickLocation = IntPoint(mouseEvent.offsetX(), mouseEvent.offsetY()); |
| } |
| } |
| |
| // Update layout before processing form actions in case the style changes |
| // the Form or button relationships. |
| protectedElement->document().updateLayoutIgnorePendingStylesheets(); |
| |
| if (auto currentForm = protectedElement->form()) |
| currentForm->prepareForSubmission(event); // Event handlers can run. |
| |
| protectedElement->setActivatedSubmit(false); |
| event.setDefaultHandled(); |
| } |
| |
| RenderPtr<RenderElement> ImageInputType::createInputRenderer(RenderStyle&& style) |
| { |
| ASSERT(element()); |
| return createRenderer<RenderImage>(*element(), WTFMove(style)); |
| } |
| |
| void ImageInputType::attributeChanged(const QualifiedName& name) |
| { |
| if (name == altAttr) { |
| if (auto* element = this->element()) { |
| auto* renderer = element->renderer(); |
| if (is<RenderImage>(renderer)) |
| downcast<RenderImage>(*renderer).updateAltText(); |
| } |
| } else if (name == srcAttr) { |
| if (auto* element = this->element()) { |
| if (element->renderer()) |
| element->ensureImageLoader().updateFromElementIgnoringPreviousError(); |
| } |
| } |
| BaseButtonInputType::attributeChanged(name); |
| } |
| |
| void ImageInputType::attach() |
| { |
| BaseButtonInputType::attach(); |
| |
| ASSERT(element()); |
| HTMLImageLoader& imageLoader = element()->ensureImageLoader(); |
| imageLoader.updateFromElement(); |
| |
| auto* renderer = downcast<RenderImage>(element()->renderer()); |
| if (!renderer) |
| return; |
| |
| if (imageLoader.hasPendingBeforeLoadEvent()) |
| return; |
| |
| auto& imageResource = renderer->imageResource(); |
| imageResource.setCachedImage(imageLoader.image()); |
| |
| // If we have no image at all because we have no src attribute, set |
| // image height and width for the alt text instead. |
| if (!imageLoader.image() && !imageResource.cachedImage()) |
| renderer->setImageSizeForAltText(); |
| } |
| |
| bool ImageInputType::shouldRespectAlignAttribute() |
| { |
| return true; |
| } |
| |
| bool ImageInputType::canBeSuccessfulSubmitButton() |
| { |
| return true; |
| } |
| |
| bool ImageInputType::isImageButton() const |
| { |
| return true; |
| } |
| |
| bool ImageInputType::isEnumeratable() |
| { |
| return false; |
| } |
| |
| bool ImageInputType::shouldRespectHeightAndWidthAttributes() |
| { |
| return true; |
| } |
| |
| unsigned ImageInputType::height() const |
| { |
| ASSERT(element()); |
| Ref<HTMLInputElement> element(*this->element()); |
| |
| element->document().updateLayout(); |
| |
| if (auto* renderer = element->renderer()) |
| return adjustForAbsoluteZoom(downcast<RenderBox>(*renderer).contentHeight(), *renderer); |
| |
| // Check the attribute first for an explicit pixel value. |
| if (auto optionalHeight = parseHTMLNonNegativeInteger(element->attributeWithoutSynchronization(heightAttr))) |
| return optionalHeight.value(); |
| |
| // If the image is available, use its height. |
| auto* imageLoader = element->imageLoader(); |
| if (imageLoader && imageLoader->image()) |
| return imageLoader->image()->imageSizeForRenderer(element->renderer(), 1).height().toUnsigned(); |
| |
| return 0; |
| } |
| |
| unsigned ImageInputType::width() const |
| { |
| ASSERT(element()); |
| Ref<HTMLInputElement> element(*this->element()); |
| |
| element->document().updateLayout(); |
| |
| if (auto* renderer = element->renderer()) |
| return adjustForAbsoluteZoom(downcast<RenderBox>(*renderer).contentWidth(), *renderer); |
| |
| // Check the attribute first for an explicit pixel value. |
| if (auto optionalWidth = parseHTMLNonNegativeInteger(element->attributeWithoutSynchronization(widthAttr))) |
| return optionalWidth.value(); |
| |
| // If the image is available, use its width. |
| auto* imageLoader = element->imageLoader(); |
| if (imageLoader && imageLoader->image()) |
| return imageLoader->image()->imageSizeForRenderer(element->renderer(), 1).width().toUnsigned(); |
| |
| return 0; |
| } |
| |
| } // namespace WebCore |