blob: 6e5c35bab3b284b63daed7b3b751eb3abaf61878 [file] [log] [blame]
/*
* Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 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 "third_party/blink/renderer/core/html/forms/image_input_type.h"
#include "third_party/blink/renderer/core/css/style_change_reason.h"
#include "third_party/blink/renderer/core/dom/shadow_root.h"
#include "third_party/blink/renderer/core/events/mouse_event.h"
#include "third_party/blink/renderer/core/frame/web_feature.h"
#include "third_party/blink/renderer/core/html/forms/form_data.h"
#include "third_party/blink/renderer/core/html/forms/html_form_element.h"
#include "third_party/blink/renderer/core/html/forms/html_input_element.h"
#include "third_party/blink/renderer/core/html/html_image_fallback_helper.h"
#include "third_party/blink/renderer/core/html/html_image_loader.h"
#include "third_party/blink/renderer/core/html/parser/html_parser_idioms.h"
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/input_type_names.h"
#include "third_party/blink/renderer/core/layout/adjust_for_absolute_zoom.h"
#include "third_party/blink/renderer/core/layout/layout_block_flow.h"
#include "third_party/blink/renderer/core/layout/layout_image.h"
#include "third_party/blink/renderer/core/layout/layout_inline.h"
#include "third_party/blink/renderer/core/layout/layout_object_factory.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
namespace blink {
ImageInputType::ImageInputType(HTMLInputElement& element)
: BaseButtonInputType(element), use_fallback_content_(false) {}
void ImageInputType::CountUsage() {
CountUsageIfVisible(WebFeature::kInputTypeImage);
}
const AtomicString& ImageInputType::FormControlType() const {
return input_type_names::kImage;
}
bool ImageInputType::IsFormDataAppendable() const {
return true;
}
void ImageInputType::AppendToFormData(FormData& form_data) const {
if (!GetElement().IsActivatedSubmit())
return;
const AtomicString& name = GetElement().GetName();
if (name.IsEmpty()) {
form_data.AppendFromElement("x", click_location_.X());
form_data.AppendFromElement("y", click_location_.Y());
return;
}
DEFINE_STATIC_LOCAL(String, dot_x_string, (".x"));
DEFINE_STATIC_LOCAL(String, dot_y_string, (".y"));
form_data.AppendFromElement(name + dot_x_string, click_location_.X());
form_data.AppendFromElement(name + dot_y_string, click_location_.Y());
}
String ImageInputType::ResultForDialogSubmit() const {
StringBuilder result;
result.AppendNumber(click_location_.X());
result.Append(',');
result.AppendNumber(click_location_.Y());
return result.ToString();
}
bool ImageInputType::SupportsValidation() const {
return false;
}
static IntPoint ExtractClickLocation(const Event& event) {
const auto* mouse_event = DynamicTo<MouseEvent>(event.UnderlyingEvent());
if (!event.UnderlyingEvent() || !mouse_event)
return IntPoint();
if (!mouse_event->HasPosition())
return IntPoint();
return IntPoint(mouse_event->offsetX(), mouse_event->offsetY());
}
void ImageInputType::HandleDOMActivateEvent(Event& event) {
if (GetElement().IsDisabledFormControl() || !GetElement().Form())
return;
click_location_ = ExtractClickLocation(event);
// Event handlers can run.
GetElement().Form()->PrepareForSubmission(&event, &GetElement());
event.SetDefaultHandled();
}
LayoutObject* ImageInputType::CreateLayoutObject(const ComputedStyle& style,
LegacyLayout legacy) const {
if (use_fallback_content_) {
if (style.Display() == EDisplay::kInline)
return new LayoutInline(&GetElement());
return LayoutObjectFactory::CreateBlockFlow(GetElement(), style, legacy);
}
LayoutImage* image = new LayoutImage(&GetElement());
image->SetImageResource(MakeGarbageCollected<LayoutImageResource>());
return image;
}
void ImageInputType::AltAttributeChanged() {
if (GetElement().UserAgentShadowRoot()) {
Element* text =
GetElement().UserAgentShadowRoot()->getElementById("alttext");
String value = GetElement().AltText();
if (text && text->textContent() != value)
text->setTextContent(GetElement().AltText());
}
}
void ImageInputType::SrcAttributeChanged() {
if (!GetElement().GetLayoutObject())
return;
GetElement().EnsureImageLoader().UpdateFromElement(
ImageLoader::kUpdateIgnorePreviousError);
}
void ImageInputType::ValueAttributeChanged() {
if (use_fallback_content_)
return;
BaseButtonInputType::ValueAttributeChanged();
}
void ImageInputType::StartResourceLoading() {
BaseButtonInputType::StartResourceLoading();
HTMLImageLoader& image_loader = GetElement().EnsureImageLoader();
image_loader.UpdateFromElement();
}
void ImageInputType::OnAttachWithLayoutObject() {
LayoutObject* layout_object = GetElement().GetLayoutObject();
DCHECK(layout_object);
if (!layout_object->IsLayoutImage())
return;
HTMLImageLoader& image_loader = GetElement().EnsureImageLoader();
LayoutImageResource* image_resource =
To<LayoutImage>(layout_object)->ImageResource();
image_resource->SetImageResource(image_loader.GetContent());
}
bool ImageInputType::ShouldRespectAlignAttribute() {
return true;
}
bool ImageInputType::CanBeSuccessfulSubmitButton() {
return true;
}
bool ImageInputType::IsEnumeratable() {
return false;
}
bool ImageInputType::ShouldRespectHeightAndWidthAttributes() {
return true;
}
unsigned ImageInputType::Height() const {
if (!GetElement().GetLayoutObject()) {
// Check the attribute first for an explicit pixel value.
unsigned height;
if (ParseHTMLNonNegativeInteger(
GetElement().FastGetAttribute(html_names::kHeightAttr), height))
return height;
// If the image is available, use its height.
HTMLImageLoader* image_loader = GetElement().ImageLoader();
if (image_loader && image_loader->GetContent()) {
return image_loader->GetContent()
->IntrinsicSize(kRespectImageOrientation)
.Height();
}
}
GetElement().GetDocument().UpdateStyleAndLayout(
DocumentUpdateReason::kJavaScript);
LayoutBox* box = GetElement().GetLayoutBox();
return box ? AdjustForAbsoluteZoom::AdjustInt(box->ContentHeight().ToInt(),
box)
: 0;
}
unsigned ImageInputType::Width() const {
if (!GetElement().GetLayoutObject()) {
// Check the attribute first for an explicit pixel value.
unsigned width;
if (ParseHTMLNonNegativeInteger(
GetElement().FastGetAttribute(html_names::kWidthAttr), width))
return width;
// If the image is available, use its width.
HTMLImageLoader* image_loader = GetElement().ImageLoader();
if (image_loader && image_loader->GetContent()) {
return image_loader->GetContent()
->IntrinsicSize(kRespectImageOrientation)
.Width();
}
}
GetElement().GetDocument().UpdateStyleAndLayout(
DocumentUpdateReason::kJavaScript);
LayoutBox* box = GetElement().GetLayoutBox();
return box ? AdjustForAbsoluteZoom::AdjustInt(box->ContentWidth().ToInt(),
box)
: 0;
}
bool ImageInputType::HasLegalLinkAttribute(const QualifiedName& name) const {
return name == html_names::kSrcAttr ||
BaseButtonInputType::HasLegalLinkAttribute(name);
}
const QualifiedName& ImageInputType::SubResourceAttributeName() const {
return html_names::kSrcAttr;
}
void ImageInputType::EnsureFallbackContent() {
if (use_fallback_content_)
return;
SetUseFallbackContent();
ReattachFallbackContent();
}
void ImageInputType::SetUseFallbackContent() {
if (use_fallback_content_)
return;
use_fallback_content_ = true;
if (GetElement().GetDocument().InStyleRecalc())
return;
if (ShadowRoot* root = GetElement().UserAgentShadowRoot())
root->RemoveChildren();
CreateShadowSubtree();
}
void ImageInputType::EnsurePrimaryContent() {
if (!use_fallback_content_)
return;
use_fallback_content_ = false;
if (ShadowRoot* root = GetElement().UserAgentShadowRoot())
root->RemoveChildren();
CreateShadowSubtree();
ReattachFallbackContent();
}
void ImageInputType::ReattachFallbackContent() {
if (!GetElement().GetDocument().InStyleRecalc()) {
// ComputedStyle depends on use_fallback_content_. Trigger recalc.
GetElement().SetNeedsStyleRecalc(
kLocalStyleChange,
StyleChangeReasonForTracing::Create(style_change_reason::kUseFallback));
// LayoutObject type depends on use_fallback_content_. Trigger re-attach.
GetElement().SetForceReattachLayoutTree();
}
}
void ImageInputType::CreateShadowSubtree() {
if (!use_fallback_content_) {
BaseButtonInputType::CreateShadowSubtree();
return;
}
HTMLImageFallbackHelper::CreateAltTextShadowTree(GetElement());
}
void ImageInputType::CustomStyleForLayoutObject(ComputedStyle& style) {
if (use_fallback_content_)
HTMLImageFallbackHelper::CustomStyleForAltText(GetElement(), style);
}
} // namespace blink