1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4  *           (C) 2001 Dirk Mueller (mueller@kde.org)
5  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All
6  * rights reserved.
7  *           (C) 2006 Alexey Proskuryakov (ap@nypop.com)
8  * Copyright (C) 2007 Samuel Weinig (sam@webkit.org)
9  * Copyright (C) 2010 Google Inc. All rights reserved.
10  * Copyright (C) 2008 Torch Mobile Inc. All rights reserved.
11  * (http://www.torchmobile.com/)
12  * Copyright (C) 2012 Samsung Electronics. All rights reserved.
13  *
14  * This library is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU Library General Public
16  * License as published by the Free Software Foundation; either
17  * version 2 of the License, or (at your option) any later version.
18  *
19  * This library is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22  * Library General Public License for more details.
23  *
24  * You should have received a copy of the GNU Library General Public License
25  * along with this library; see the file COPYING.LIB.  If not, write to
26  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
27  * Boston, MA 02110-1301, USA.
28  *
29  */
30 
31 #include "third_party/blink/renderer/core/html/forms/html_input_element.h"
32 
33 #include "third_party/blink/public/mojom/choosers/date_time_chooser.mojom-blink.h"
34 #include "third_party/blink/public/platform/task_type.h"
35 #include "third_party/blink/public/strings/grit/blink_strings.h"
36 #include "third_party/blink/renderer/bindings/core/v8/js_event_handler_for_content_attribute.h"
37 #include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
38 #include "third_party/blink/renderer/bindings/core/v8/v8_focus_options.h"
39 #include "third_party/blink/renderer/core/accessibility/ax_object_cache.h"
40 #include "third_party/blink/renderer/core/css/css_property_names.h"
41 #include "third_party/blink/renderer/core/css/style_change_reason.h"
42 #include "third_party/blink/renderer/core/dom/document.h"
43 #include "third_party/blink/renderer/core/dom/events/scoped_event_queue.h"
44 #include "third_party/blink/renderer/core/dom/id_target_observer.h"
45 #include "third_party/blink/renderer/core/dom/node_computed_style.h"
46 #include "third_party/blink/renderer/core/dom/shadow_root.h"
47 #include "third_party/blink/renderer/core/dom/v0_insertion_point.h"
48 #include "third_party/blink/renderer/core/editing/frame_selection.h"
49 #include "third_party/blink/renderer/core/editing/spellcheck/spell_checker.h"
50 #include "third_party/blink/renderer/core/events/before_text_inserted_event.h"
51 #include "third_party/blink/renderer/core/events/keyboard_event.h"
52 #include "third_party/blink/renderer/core/events/mouse_event.h"
53 #include "third_party/blink/renderer/core/fileapi/file_list.h"
54 #include "third_party/blink/renderer/core/frame/deprecation.h"
55 #include "third_party/blink/renderer/core/frame/local_frame.h"
56 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
57 #include "third_party/blink/renderer/core/html/forms/color_chooser.h"
58 #include "third_party/blink/renderer/core/html/forms/date_time_chooser.h"
59 #include "third_party/blink/renderer/core/html/forms/email_input_type.h"
60 #include "third_party/blink/renderer/core/html/forms/file_input_type.h"
61 #include "third_party/blink/renderer/core/html/forms/form_controller.h"
62 #include "third_party/blink/renderer/core/html/forms/html_data_list_element.h"
63 #include "third_party/blink/renderer/core/html/forms/html_data_list_options_collection.h"
64 #include "third_party/blink/renderer/core/html/forms/html_form_element.h"
65 #include "third_party/blink/renderer/core/html/forms/html_option_element.h"
66 #include "third_party/blink/renderer/core/html/forms/input_type.h"
67 #include "third_party/blink/renderer/core/html/forms/search_input_type.h"
68 #include "third_party/blink/renderer/core/html/forms/text_input_type.h"
69 #include "third_party/blink/renderer/core/html/html_collection.h"
70 #include "third_party/blink/renderer/core/html/html_image_loader.h"
71 #include "third_party/blink/renderer/core/html/parser/html_parser_idioms.h"
72 #include "third_party/blink/renderer/core/html_names.h"
73 #include "third_party/blink/renderer/core/input_type_names.h"
74 #include "third_party/blink/renderer/core/layout/adjust_for_absolute_zoom.h"
75 #include "third_party/blink/renderer/core/layout/layout_box.h"
76 #include "third_party/blink/renderer/core/page/chrome_client.h"
77 #include "third_party/blink/renderer/core/page/page.h"
78 #include "third_party/blink/renderer/platform/bindings/exception_messages.h"
79 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
80 #include "third_party/blink/renderer/platform/bindings/to_v8.h"
81 #include "third_party/blink/renderer/platform/heap/heap.h"
82 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
83 #include "third_party/blink/renderer/platform/language.h"
84 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
85 #include "third_party/blink/renderer/platform/text/platform_locale.h"
86 #include "third_party/blink/renderer/platform/wtf/math_extras.h"
87 #include "ui/base/ui_base_features.h"
88 
89 namespace blink {
90 
91 namespace {
92 
93 const unsigned kMaxEmailFieldLength = 254;
94 
95 }  // namespace
96 
97 using ValueMode = InputType::ValueMode;
98 
99 class ListAttributeTargetObserver : public IdTargetObserver {
100  public:
101   ListAttributeTargetObserver(const AtomicString& id, HTMLInputElement*);
102 
103   void Trace(Visitor*) const override;
104   void IdTargetChanged() override;
105 
106  private:
107   Member<HTMLInputElement> element_;
108 };
109 
110 const int kDefaultSize = 20;
111 
HTMLInputElement(Document & document,const CreateElementFlags flags)112 HTMLInputElement::HTMLInputElement(Document& document,
113                                    const CreateElementFlags flags)
114     : TextControlElement(html_names::kInputTag, document),
115       size_(kDefaultSize),
116       has_dirty_value_(false),
117       is_checked_(false),
118       dirty_checkedness_(false),
119       is_indeterminate_(false),
120       is_activated_submit_(false),
121       autocomplete_(kUninitialized),
122       has_non_empty_list_(false),
123       state_restored_(false),
124       parsing_in_progress_(flags.IsCreatedByParser()),
125       can_receive_dropped_files_(false),
126       should_reveal_password_(false),
127       needs_to_update_view_value_(true),
128       is_placeholder_visible_(false),
129       has_been_password_field_(false),
130       // |input_type_| is lazily created when constructed by the parser to avoid
131       // constructing unnecessarily a text InputType and its shadow subtree,
132       // just to destroy them when the |type| attribute gets set by the parser
133       // to something else than 'text'.
134       input_type_(flags.IsCreatedByParser()
135                       ? nullptr
136                       : MakeGarbageCollected<TextInputType>(*this)),
137       input_type_view_(input_type_ ? input_type_->CreateView() : nullptr) {
138   SetHasCustomStyleCallbacks();
139 
140   if (!flags.IsCreatedByParser()) {
141     DCHECK(input_type_view_->NeedsShadowSubtree());
142     CreateUserAgentShadowRoot();
143     CreateShadowSubtree();
144   }
145 }
146 
Trace(Visitor * visitor) const147 void HTMLInputElement::Trace(Visitor* visitor) const {
148   visitor->Trace(input_type_);
149   visitor->Trace(input_type_view_);
150   visitor->Trace(list_attribute_target_observer_);
151   visitor->Trace(image_loader_);
152   TextControlElement::Trace(visitor);
153 }
154 
HasPendingActivity() const155 bool HTMLInputElement::HasPendingActivity() const {
156   return ImageLoader() && ImageLoader()->HasPendingActivity();
157 }
158 
EnsureImageLoader()159 HTMLImageLoader& HTMLInputElement::EnsureImageLoader() {
160   if (!image_loader_)
161     image_loader_ = MakeGarbageCollected<HTMLImageLoader>(this);
162   return *image_loader_;
163 }
164 
165 HTMLInputElement::~HTMLInputElement() = default;
166 
GetName() const167 const AtomicString& HTMLInputElement::GetName() const {
168   return name_.IsNull() ? g_empty_atom : name_;
169 }
170 
FilesFromFileInputFormControlState(const FormControlState & state)171 Vector<String> HTMLInputElement::FilesFromFileInputFormControlState(
172     const FormControlState& state) {
173   return FileInputType::FilesFromFormControlState(state);
174 }
175 
ShouldAutocomplete() const176 bool HTMLInputElement::ShouldAutocomplete() const {
177   if (autocomplete_ != kUninitialized)
178     return autocomplete_ == kOn;
179   return TextControlElement::ShouldAutocomplete();
180 }
181 
IsValidValue(const String & value) const182 bool HTMLInputElement::IsValidValue(const String& value) const {
183   if (!input_type_->CanSetStringValue()) {
184     NOTREACHED();
185     return false;
186   }
187   return !input_type_->TypeMismatchFor(value) &&
188          !input_type_->StepMismatch(value) &&
189          !input_type_->RangeUnderflow(value) &&
190          !input_type_->RangeOverflow(value) &&
191          !TooLong(value, kIgnoreDirtyFlag) &&
192          !TooShort(value, kIgnoreDirtyFlag) &&
193          !input_type_->PatternMismatch(value) &&
194          !input_type_->ValueMissing(value);
195 }
196 
TooLong() const197 bool HTMLInputElement::TooLong() const {
198   return TooLong(value(), kCheckDirtyFlag);
199 }
200 
TooShort() const201 bool HTMLInputElement::TooShort() const {
202   return TooShort(value(), kCheckDirtyFlag);
203 }
204 
TypeMismatch() const205 bool HTMLInputElement::TypeMismatch() const {
206   return input_type_->TypeMismatch();
207 }
208 
ValueMissing() const209 bool HTMLInputElement::ValueMissing() const {
210   return input_type_->ValueMissing(value());
211 }
212 
HasBadInput() const213 bool HTMLInputElement::HasBadInput() const {
214   return input_type_view_->HasBadInput();
215 }
216 
PatternMismatch() const217 bool HTMLInputElement::PatternMismatch() const {
218   return input_type_->PatternMismatch(value());
219 }
220 
TooLong(const String & value,NeedsToCheckDirtyFlag check) const221 bool HTMLInputElement::TooLong(const String& value,
222                                NeedsToCheckDirtyFlag check) const {
223   return input_type_->TooLong(value, check);
224 }
225 
TooShort(const String & value,NeedsToCheckDirtyFlag check) const226 bool HTMLInputElement::TooShort(const String& value,
227                                 NeedsToCheckDirtyFlag check) const {
228   return input_type_->TooShort(value, check);
229 }
230 
RangeUnderflow() const231 bool HTMLInputElement::RangeUnderflow() const {
232   return input_type_->RangeUnderflow(value());
233 }
234 
RangeOverflow() const235 bool HTMLInputElement::RangeOverflow() const {
236   return input_type_->RangeOverflow(value());
237 }
238 
validationMessage() const239 String HTMLInputElement::validationMessage() const {
240   if (!willValidate())
241     return String();
242   if (CustomError())
243     return CustomValidationMessage();
244 
245   return input_type_->ValidationMessage(*input_type_view_).first;
246 }
247 
ValidationSubMessage() const248 String HTMLInputElement::ValidationSubMessage() const {
249   if (CustomError())
250     return String();
251   return input_type_->ValidationMessage(*input_type_view_).second;
252 }
253 
Minimum() const254 double HTMLInputElement::Minimum() const {
255   return input_type_->Minimum();
256 }
257 
Maximum() const258 double HTMLInputElement::Maximum() const {
259   return input_type_->Maximum();
260 }
261 
StepMismatch() const262 bool HTMLInputElement::StepMismatch() const {
263   return input_type_->StepMismatch(value());
264 }
265 
GetAllowedValueStep(Decimal * step) const266 bool HTMLInputElement::GetAllowedValueStep(Decimal* step) const {
267   return input_type_->GetAllowedValueStep(step);
268 }
269 
CreateStepRange(AnyStepHandling any_step_handling) const270 StepRange HTMLInputElement::CreateStepRange(
271     AnyStepHandling any_step_handling) const {
272   return input_type_->CreateStepRange(any_step_handling);
273 }
274 
FindClosestTickMarkValue(const Decimal & value)275 Decimal HTMLInputElement::FindClosestTickMarkValue(const Decimal& value) {
276   return input_type_->FindClosestTickMarkValue(value);
277 }
278 
stepUp(int n,ExceptionState & exception_state)279 void HTMLInputElement::stepUp(int n, ExceptionState& exception_state) {
280   input_type_->StepUp(n, exception_state);
281 }
282 
stepDown(int n,ExceptionState & exception_state)283 void HTMLInputElement::stepDown(int n, ExceptionState& exception_state) {
284   input_type_->StepUp(-1.0 * n, exception_state);
285 }
286 
blur()287 void HTMLInputElement::blur() {
288   input_type_view_->Blur();
289 }
290 
DefaultBlur()291 void HTMLInputElement::DefaultBlur() {
292   TextControlElement::blur();
293 }
294 
HasCustomFocusLogic() const295 bool HTMLInputElement::HasCustomFocusLogic() const {
296   return input_type_view_->HasCustomFocusLogic();
297 }
298 
IsKeyboardFocusable() const299 bool HTMLInputElement::IsKeyboardFocusable() const {
300   return input_type_->IsKeyboardFocusable();
301 }
302 
MayTriggerVirtualKeyboard() const303 bool HTMLInputElement::MayTriggerVirtualKeyboard() const {
304   return input_type_->MayTriggerVirtualKeyboard();
305 }
306 
ShouldHaveFocusAppearance() const307 bool HTMLInputElement::ShouldHaveFocusAppearance() const {
308   // For FormControlsRefresh don't draw focus ring for an input that has its
309   // popup open.
310   if (::features::IsFormControlsRefreshEnabled() &&
311       input_type_view_->HasOpenedPopup())
312     return false;
313 
314   return TextControlElement::ShouldHaveFocusAppearance();
315 }
316 
UpdateFocusAppearanceWithOptions(SelectionBehaviorOnFocus selection_behavior,const FocusOptions * options)317 void HTMLInputElement::UpdateFocusAppearanceWithOptions(
318     SelectionBehaviorOnFocus selection_behavior,
319     const FocusOptions* options) {
320   if (IsTextField()) {
321     switch (selection_behavior) {
322       case SelectionBehaviorOnFocus::kReset:
323         select();
324         break;
325       case SelectionBehaviorOnFocus::kRestore:
326         RestoreCachedSelection();
327         break;
328       case SelectionBehaviorOnFocus::kNone:
329         return;
330     }
331     // TODO(tkent): scrollRectToVisible is a workaround of a bug of
332     // FrameSelection::revealSelection().  It doesn't scroll correctly in a
333     // case of RangeSelection. crbug.com/443061.
334     GetDocument().EnsurePaintLocationDataValidForNode(
335         this, DocumentUpdateReason::kFocus);
336     if (!options->preventScroll()) {
337       if (GetLayoutObject()) {
338         GetLayoutObject()->ScrollRectToVisible(
339             BoundingBoxForScrollIntoView(),
340             ScrollAlignment::CreateScrollIntoViewParams());
341       }
342       if (GetDocument().GetFrame())
343         GetDocument().GetFrame()->Selection().RevealSelection();
344     }
345   } else {
346     TextControlElement::UpdateFocusAppearanceWithOptions(selection_behavior,
347                                                          options);
348   }
349 }
350 
EndEditing()351 void HTMLInputElement::EndEditing() {
352   DCHECK(GetDocument().IsActive());
353   if (!GetDocument().IsActive())
354     return;
355 
356   if (!IsTextField())
357     return;
358 
359   LocalFrame* frame = GetDocument().GetFrame();
360   frame->GetSpellChecker().DidEndEditingOnTextField(this);
361   frame->GetPage()->GetChromeClient().DidEndEditingOnTextField(*this);
362 
363   MaybeReportPiiMetrics();
364 }
365 
DispatchFocusInEvent(const AtomicString & event_type,Element * old_focused_element,mojom::blink::FocusType type,InputDeviceCapabilities * source_capabilities)366 void HTMLInputElement::DispatchFocusInEvent(
367     const AtomicString& event_type,
368     Element* old_focused_element,
369     mojom::blink::FocusType type,
370     InputDeviceCapabilities* source_capabilities) {
371   if (event_type == event_type_names::kDOMFocusIn)
372     input_type_view_->HandleFocusInEvent(old_focused_element, type);
373   HTMLFormControlElementWithState::DispatchFocusInEvent(
374       event_type, old_focused_element, type, source_capabilities);
375 }
376 
HandleBlurEvent()377 void HTMLInputElement::HandleBlurEvent() {
378   input_type_view_->HandleBlurEvent();
379 }
380 
setType(const AtomicString & type)381 void HTMLInputElement::setType(const AtomicString& type) {
382   setAttribute(html_names::kTypeAttr, type);
383 }
384 
InitializeTypeInParsing()385 void HTMLInputElement::InitializeTypeInParsing() {
386   DCHECK(parsing_in_progress_);
387   DCHECK(!input_type_);
388   DCHECK(!input_type_view_);
389 
390   const AtomicString& new_type_name =
391       InputType::NormalizeTypeName(FastGetAttribute(html_names::kTypeAttr));
392   input_type_ = InputType::Create(*this, new_type_name);
393   input_type_view_ = input_type_->CreateView();
394   String default_value = FastGetAttribute(html_names::kValueAttr);
395   if (input_type_->GetValueMode() == ValueMode::kValue)
396     non_attribute_value_ = SanitizeValue(default_value);
397   has_been_password_field_ |= new_type_name == input_type_names::kPassword;
398 
399   if (input_type_view_->NeedsShadowSubtree()) {
400     CreateUserAgentShadowRoot();
401     CreateShadowSubtree();
402   }
403 
404   UpdateWillValidateCache();
405 
406   if (!default_value.IsNull())
407     input_type_->WarnIfValueIsInvalid(default_value);
408 
409   input_type_view_->UpdateView();
410 }
411 
UpdateType()412 void HTMLInputElement::UpdateType() {
413   DCHECK(input_type_);
414   DCHECK(input_type_view_);
415 
416   const AtomicString& new_type_name =
417       InputType::NormalizeTypeName(FastGetAttribute(html_names::kTypeAttr));
418   if (input_type_->FormControlType() == new_type_name)
419     return;
420 
421   InputType* new_type = InputType::Create(*this, new_type_name);
422   RemoveFromRadioButtonGroup();
423 
424   ValueMode old_value_mode = input_type_->GetValueMode();
425   bool did_respect_height_and_width =
426       input_type_->ShouldRespectHeightAndWidthAttributes();
427   bool could_be_successful_submit_button = CanBeSuccessfulSubmitButton();
428 
429   input_type_view_->ClosePopupView();
430   input_type_view_->DestroyShadowSubtree();
431   DropInnerEditorElement();
432   SetForceReattachLayoutTree();
433 
434   if (input_type_->SupportsRequired() != new_type->SupportsRequired() &&
435       IsRequired()) {
436     PseudoStateChanged(CSSSelector::kPseudoRequired);
437     PseudoStateChanged(CSSSelector::kPseudoOptional);
438   }
439   if (input_type_->SupportsReadOnly() != new_type->SupportsReadOnly()) {
440     PseudoStateChanged(CSSSelector::kPseudoReadOnly);
441     PseudoStateChanged(CSSSelector::kPseudoReadWrite);
442   }
443   if (input_type_->IsCheckable() != new_type->IsCheckable()) {
444     PseudoStateChanged(CSSSelector::kPseudoChecked);
445   }
446   PseudoStateChanged(CSSSelector::kPseudoIndeterminate);
447   if (input_type_->IsSteppable() || new_type->IsSteppable()) {
448     PseudoStateChanged(CSSSelector::kPseudoInRange);
449     PseudoStateChanged(CSSSelector::kPseudoOutOfRange);
450   }
451   if (input_type_->ShouldRespectListAttribute() !=
452       new_type->ShouldRespectListAttribute())
453     PseudoStateChanged(CSSSelector::kPseudoHasDatalist);
454 
455   bool placeholder_changed =
456       input_type_->SupportsPlaceholder() != new_type->SupportsPlaceholder();
457 
458   has_been_password_field_ |= new_type_name == input_type_names::kPassword;
459 
460   // 7. Let previouslySelectable be true if setRangeText() previously applied
461   // to the element, and false otherwise.
462   const bool previously_selectable = input_type_->SupportsSelectionAPI();
463 
464   input_type_view_->WillBeDestroyed();
465   input_type_ = new_type;
466   input_type_view_ = input_type_->CreateView();
467   if (input_type_view_->NeedsShadowSubtree()) {
468     EnsureUserAgentShadowRoot();
469     CreateShadowSubtree();
470   }
471 
472   UpdateWillValidateCache();
473 
474   if (placeholder_changed) {
475     // We need to update the UA shadow and then the placeholder visibility flag
476     // here. Otherwise it would happen as part of attaching the layout tree
477     // which would be too late in order to make style invalidation work for
478     // the upcoming frame.
479     UpdatePlaceholderText();
480     UpdatePlaceholderVisibility();
481     PseudoStateChanged(CSSSelector::kPseudoPlaceholderShown);
482   }
483 
484   ValueMode new_value_mode = input_type_->GetValueMode();
485 
486   // https://html.spec.whatwg.org/C/#input-type-change
487   //
488   // 1. If the previous state of the element's type attribute put the value IDL
489   // attribute in the value mode, and the element's value is not the empty
490   // string, and the new state of the element's type attribute puts the value
491   // IDL attribute in either the default mode or the default/on mode, then set
492   // the element's value content attribute to the element's value.
493   if (old_value_mode == ValueMode::kValue &&
494       (new_value_mode == ValueMode::kDefault ||
495        new_value_mode == ValueMode::kDefaultOn)) {
496     if (HasDirtyValue())
497       setAttribute(html_names::kValueAttr, AtomicString(non_attribute_value_));
498     non_attribute_value_ = String();
499     has_dirty_value_ = false;
500   }
501   // 2. Otherwise, if the previous state of the element's type attribute put the
502   // value IDL attribute in any mode other than the value mode, and the new
503   // state of the element's type attribute puts the value IDL attribute in the
504   // value mode, then set the value of the element to the value of the value
505   // content attribute, if there is one, or the empty string otherwise, and then
506   // set the control's dirty value flag to false.
507   else if (old_value_mode != ValueMode::kValue &&
508            new_value_mode == ValueMode::kValue) {
509     AtomicString value_string = FastGetAttribute(html_names::kValueAttr);
510     input_type_->WarnIfValueIsInvalid(value_string);
511     non_attribute_value_ = SanitizeValue(value_string);
512     has_dirty_value_ = false;
513   }
514   // 3. Otherwise, if the previous state of the element's type attribute put the
515   // value IDL attribute in any mode other than the filename mode, and the new
516   // state of the element's type attribute puts the value IDL attribute in the
517   // filename mode, then set the value of the element to the empty string.
518   else if (old_value_mode != ValueMode::kFilename &&
519            new_value_mode == ValueMode::kFilename) {
520     non_attribute_value_ = String();
521     has_dirty_value_ = false;
522 
523   } else {
524     // ValueMode wasn't changed, or kDefault <-> kDefaultOn.
525     if (!HasDirtyValue()) {
526       String default_value = FastGetAttribute(html_names::kValueAttr);
527       if (!default_value.IsNull())
528         input_type_->WarnIfValueIsInvalid(default_value);
529     }
530 
531     if (new_value_mode == ValueMode::kValue) {
532       String new_value = SanitizeValue(non_attribute_value_);
533       if (!EqualIgnoringNullity(new_value, non_attribute_value_)) {
534         if (HasDirtyValue())
535           setValue(new_value);
536         else
537           SetNonDirtyValue(new_value);
538       }
539     }
540   }
541 
542   needs_to_update_view_value_ = true;
543   input_type_view_->UpdateView();
544 
545   if (did_respect_height_and_width !=
546       input_type_->ShouldRespectHeightAndWidthAttributes()) {
547     DCHECK(GetElementData());
548     AttributeCollection attributes = AttributesWithoutUpdate();
549     if (const Attribute* height = attributes.Find(html_names::kHeightAttr)) {
550       TextControlElement::AttributeChanged(AttributeModificationParams(
551           html_names::kHeightAttr, height->Value(), height->Value(),
552           AttributeModificationReason::kDirectly));
553     }
554     if (const Attribute* width = attributes.Find(html_names::kWidthAttr)) {
555       TextControlElement::AttributeChanged(AttributeModificationParams(
556           html_names::kWidthAttr, width->Value(), width->Value(),
557           AttributeModificationReason::kDirectly));
558     }
559     if (const Attribute* align = attributes.Find(html_names::kAlignAttr)) {
560       TextControlElement::AttributeChanged(AttributeModificationParams(
561           html_names::kAlignAttr, align->Value(), align->Value(),
562           AttributeModificationReason::kDirectly));
563     }
564   }
565 
566   // UA Shadow tree was recreated. We need to set selection again. We do it
567   // later in order to avoid force layout.
568   if (GetDocument().FocusedElement() == this)
569     GetDocument().UpdateFocusAppearanceAfterLayout();
570 
571   // TODO(tkent): Should we dispatch a change event?
572   ClearValueBeforeFirstUserEdit();
573 
574   // 5. Signal a type change for the element. (The Radio Button state uses
575   // this, in particular.)
576   AddToRadioButtonGroup();
577 
578   // 8. Let nowSelectable be true if setRangeText() now applies to the element,
579   // and false otherwise.
580   const bool now_selectable = input_type_->SupportsSelectionAPI();
581 
582   // 9. If previouslySelectable is false and nowSelectable is true, set the
583   // element's text entry cursor position to the beginning of the text control,
584   // and set its selection direction to "none".
585   if (!previously_selectable && now_selectable)
586     SetSelectionRange(0, 0, kSelectionHasNoDirection);
587 
588   SetNeedsValidityCheck();
589   if ((could_be_successful_submit_button || CanBeSuccessfulSubmitButton()) &&
590       formOwner() && isConnected())
591     formOwner()->InvalidateDefaultButtonStyle();
592   NotifyFormStateChanged();
593 }
594 
SubtreeHasChanged()595 void HTMLInputElement::SubtreeHasChanged() {
596   input_type_view_->SubtreeHasChanged();
597   // When typing in an input field, childrenChanged is not called, so we need to
598   // force the directionality check.
599   CalculateAndAdjustDirectionality();
600 }
601 
FormControlType() const602 const AtomicString& HTMLInputElement::FormControlType() const {
603   return input_type_->FormControlType();
604 }
605 
ShouldSaveAndRestoreFormControlState() const606 bool HTMLInputElement::ShouldSaveAndRestoreFormControlState() const {
607   if (!input_type_->ShouldSaveAndRestoreFormControlState())
608     return false;
609   return TextControlElement::ShouldSaveAndRestoreFormControlState();
610 }
611 
SaveFormControlState() const612 FormControlState HTMLInputElement::SaveFormControlState() const {
613   return input_type_view_->SaveFormControlState();
614 }
615 
RestoreFormControlState(const FormControlState & state)616 void HTMLInputElement::RestoreFormControlState(const FormControlState& state) {
617   input_type_view_->RestoreFormControlState(state);
618   state_restored_ = true;
619 }
620 
CanStartSelection() const621 bool HTMLInputElement::CanStartSelection() const {
622   if (!IsTextField())
623     return false;
624   return TextControlElement::CanStartSelection();
625 }
626 
selectionStartForBinding(ExceptionState & exception_state) const627 base::Optional<uint32_t> HTMLInputElement::selectionStartForBinding(
628     ExceptionState& exception_state) const {
629   if (!input_type_->SupportsSelectionAPI())
630     return base::nullopt;
631   return TextControlElement::selectionStart();
632 }
633 
selectionEndForBinding(ExceptionState & exception_state) const634 base::Optional<uint32_t> HTMLInputElement::selectionEndForBinding(
635     ExceptionState& exception_state) const {
636   if (!input_type_->SupportsSelectionAPI())
637     return base::nullopt;
638   return TextControlElement::selectionEnd();
639 }
640 
selectionDirectionForBinding(ExceptionState & exception_state) const641 String HTMLInputElement::selectionDirectionForBinding(
642     ExceptionState& exception_state) const {
643   if (!input_type_->SupportsSelectionAPI()) {
644     return String();
645   }
646   return TextControlElement::selectionDirection();
647 }
648 
setSelectionStartForBinding(base::Optional<uint32_t> start,ExceptionState & exception_state)649 void HTMLInputElement::setSelectionStartForBinding(
650     base::Optional<uint32_t> start,
651     ExceptionState& exception_state) {
652   if (!input_type_->SupportsSelectionAPI()) {
653     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
654                                       "The input element's type ('" +
655                                           input_type_->FormControlType() +
656                                           "') does not support selection.");
657     return;
658   }
659   TextControlElement::setSelectionStart(start.value_or(0));
660 }
661 
setSelectionEndForBinding(base::Optional<uint32_t> end,ExceptionState & exception_state)662 void HTMLInputElement::setSelectionEndForBinding(
663     base::Optional<uint32_t> end,
664     ExceptionState& exception_state) {
665   if (!input_type_->SupportsSelectionAPI()) {
666     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
667                                       "The input element's type ('" +
668                                           input_type_->FormControlType() +
669                                           "') does not support selection.");
670     return;
671   }
672   TextControlElement::setSelectionEnd(end.value_or(0));
673 }
674 
setSelectionDirectionForBinding(const String & direction,ExceptionState & exception_state)675 void HTMLInputElement::setSelectionDirectionForBinding(
676     const String& direction,
677     ExceptionState& exception_state) {
678   if (!input_type_->SupportsSelectionAPI()) {
679     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
680                                       "The input element's type ('" +
681                                           input_type_->FormControlType() +
682                                           "') does not support selection.");
683     return;
684   }
685   TextControlElement::setSelectionDirection(direction);
686 }
687 
setSelectionRangeForBinding(unsigned start,unsigned end,ExceptionState & exception_state)688 void HTMLInputElement::setSelectionRangeForBinding(
689     unsigned start,
690     unsigned end,
691     ExceptionState& exception_state) {
692   if (!input_type_->SupportsSelectionAPI()) {
693     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
694                                       "The input element's type ('" +
695                                           input_type_->FormControlType() +
696                                           "') does not support selection.");
697     return;
698   }
699   TextControlElement::setSelectionRangeForBinding(start, end);
700 }
701 
setSelectionRangeForBinding(unsigned start,unsigned end,const String & direction,ExceptionState & exception_state)702 void HTMLInputElement::setSelectionRangeForBinding(
703     unsigned start,
704     unsigned end,
705     const String& direction,
706     ExceptionState& exception_state) {
707   if (!input_type_->SupportsSelectionAPI()) {
708     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
709                                       "The input element's type ('" +
710                                           input_type_->FormControlType() +
711                                           "') does not support selection.");
712     return;
713   }
714   TextControlElement::setSelectionRangeForBinding(start, end, direction);
715 }
716 
717 // This function can be used to allow tests to set the selection
718 // range for Number inputs, which do not support the ordinary
719 // selection API.
SetSelectionRangeForTesting(unsigned start,unsigned end,ExceptionState & exception_state)720 void HTMLInputElement::SetSelectionRangeForTesting(
721     unsigned start,
722     unsigned end,
723     ExceptionState& exception_state) {
724   if (FormControlType() != input_type_names::kNumber) {
725     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
726                                       "The input element's type ('" +
727                                           input_type_->FormControlType() +
728                                           "') is not a number input.");
729   }
730   TextControlElement::setSelectionRangeForBinding(start, end);
731 }
732 
AccessKeyAction(bool send_mouse_events)733 void HTMLInputElement::AccessKeyAction(bool send_mouse_events) {
734   input_type_view_->AccessKeyAction(send_mouse_events);
735 }
736 
IsPresentationAttribute(const QualifiedName & name) const737 bool HTMLInputElement::IsPresentationAttribute(
738     const QualifiedName& name) const {
739   // FIXME: Remove type check.
740   if (name == html_names::kVspaceAttr || name == html_names::kHspaceAttr ||
741       name == html_names::kAlignAttr || name == html_names::kWidthAttr ||
742       name == html_names::kHeightAttr ||
743       (name == html_names::kBorderAttr && type() == input_type_names::kImage))
744     return true;
745   return TextControlElement::IsPresentationAttribute(name);
746 }
747 
CollectStyleForPresentationAttribute(const QualifiedName & name,const AtomicString & value,MutableCSSPropertyValueSet * style)748 void HTMLInputElement::CollectStyleForPresentationAttribute(
749     const QualifiedName& name,
750     const AtomicString& value,
751     MutableCSSPropertyValueSet* style) {
752   if (name == html_names::kVspaceAttr) {
753     AddHTMLLengthToStyle(style, CSSPropertyID::kMarginTop, value);
754     AddHTMLLengthToStyle(style, CSSPropertyID::kMarginBottom, value);
755   } else if (name == html_names::kHspaceAttr) {
756     AddHTMLLengthToStyle(style, CSSPropertyID::kMarginLeft, value);
757     AddHTMLLengthToStyle(style, CSSPropertyID::kMarginRight, value);
758   } else if (name == html_names::kAlignAttr) {
759     if (input_type_->ShouldRespectAlignAttribute())
760       ApplyAlignmentAttributeToStyle(value, style);
761   } else if (name == html_names::kWidthAttr) {
762     if (input_type_->ShouldRespectHeightAndWidthAttributes())
763       AddHTMLLengthToStyle(style, CSSPropertyID::kWidth, value);
764   } else if (name == html_names::kHeightAttr) {
765     if (input_type_->ShouldRespectHeightAndWidthAttributes())
766       AddHTMLLengthToStyle(style, CSSPropertyID::kHeight, value);
767   } else if (name == html_names::kBorderAttr &&
768              type() == input_type_names::kImage) {  // FIXME: Remove type check.
769     ApplyBorderAttributeToStyle(value, style);
770   } else {
771     TextControlElement::CollectStyleForPresentationAttribute(name, value,
772                                                              style);
773   }
774 }
775 
ParseAttribute(const AttributeModificationParams & params)776 void HTMLInputElement::ParseAttribute(
777     const AttributeModificationParams& params) {
778   DCHECK(input_type_);
779   DCHECK(input_type_view_);
780   const QualifiedName& name = params.name;
781   const AtomicString& value = params.new_value;
782 
783   if (name == html_names::kNameAttr) {
784     RemoveFromRadioButtonGroup();
785     name_ = value;
786     AddToRadioButtonGroup();
787     TextControlElement::ParseAttribute(params);
788   } else if (name == html_names::kAutocompleteAttr) {
789     if (EqualIgnoringASCIICase(value, "off")) {
790       autocomplete_ = kOff;
791     } else {
792       if (value.IsEmpty())
793         autocomplete_ = kUninitialized;
794       else
795         autocomplete_ = kOn;
796     }
797   } else if (name == html_names::kTypeAttr) {
798     UpdateType();
799   } else if (name == html_names::kValueAttr) {
800     // We only need to setChanged if the form is looking at the default value
801     // right now.
802     if (!HasDirtyValue()) {
803       if (input_type_->GetValueMode() == ValueMode::kValue)
804         non_attribute_value_ = SanitizeValue(value);
805       UpdatePlaceholderVisibility();
806       SetNeedsStyleRecalc(
807           kSubtreeStyleChange,
808           StyleChangeReasonForTracing::FromAttribute(html_names::kValueAttr));
809       needs_to_update_view_value_ = true;
810     }
811     SetNeedsValidityCheck();
812     input_type_->WarnIfValueIsInvalidAndElementIsVisible(value);
813     input_type_->InRangeChanged();
814     input_type_view_->ValueAttributeChanged();
815   } else if (name == html_names::kCheckedAttr) {
816     // Another radio button in the same group might be checked by state
817     // restore. We shouldn't call setChecked() even if this has the checked
818     // attribute. So, delay the setChecked() call until
819     // finishParsingChildren() is called if parsing is in progress.
820     if ((!parsing_in_progress_ ||
821          !GetDocument().GetFormController().HasControlStates()) &&
822         !dirty_checkedness_) {
823       setChecked(!value.IsNull());
824       dirty_checkedness_ = false;
825     }
826     PseudoStateChanged(CSSSelector::kPseudoDefault);
827   } else if (name == html_names::kMaxlengthAttr) {
828     SetNeedsValidityCheck();
829   } else if (name == html_names::kMinlengthAttr) {
830     SetNeedsValidityCheck();
831   } else if (name == html_names::kSizeAttr) {
832     unsigned size = 0;
833     if (value.IsEmpty() || !ParseHTMLNonNegativeInteger(value, size) ||
834         size == 0 || size > 0x7fffffffu)
835       size = kDefaultSize;
836     if (size_ != size) {
837       size_ = size;
838       if (GetLayoutObject()) {
839         GetLayoutObject()
840             ->SetNeedsLayoutAndIntrinsicWidthsRecalcAndFullPaintInvalidation(
841                 layout_invalidation_reason::kAttributeChanged);
842       }
843     }
844   } else if (name == html_names::kAltAttr) {
845     input_type_view_->AltAttributeChanged();
846   } else if (name == html_names::kSrcAttr) {
847     input_type_view_->SrcAttributeChanged();
848   } else if (name == html_names::kUsemapAttr ||
849              name == html_names::kAccesskeyAttr) {
850     // FIXME: ignore for the moment
851   } else if (name == html_names::kOnsearchAttr) {
852     // Search field and slider attributes all just cause updateFromElement to be
853     // called through style recalcing.
854     SetAttributeEventListener(event_type_names::kSearch,
855                               JSEventHandlerForContentAttribute::Create(
856                                   GetExecutionContext(), name, value));
857   } else if (name == html_names::kIncrementalAttr) {
858     UseCounter::Count(GetDocument(), WebFeature::kIncrementalAttribute);
859   } else if (name == html_names::kMinAttr) {
860     input_type_view_->MinOrMaxAttributeChanged();
861     input_type_->SanitizeValueInResponseToMinOrMaxAttributeChange();
862     input_type_->InRangeChanged();
863     SetNeedsValidityCheck();
864     UseCounter::Count(GetDocument(), WebFeature::kMinAttribute);
865   } else if (name == html_names::kMaxAttr) {
866     input_type_view_->MinOrMaxAttributeChanged();
867     input_type_->SanitizeValueInResponseToMinOrMaxAttributeChange();
868     input_type_->InRangeChanged();
869     SetNeedsValidityCheck();
870     UseCounter::Count(GetDocument(), WebFeature::kMaxAttribute);
871   } else if (name == html_names::kMultipleAttr) {
872     input_type_view_->MultipleAttributeChanged();
873     SetNeedsValidityCheck();
874   } else if (name == html_names::kStepAttr) {
875     input_type_view_->StepAttributeChanged();
876     SetNeedsValidityCheck();
877     UseCounter::Count(GetDocument(), WebFeature::kStepAttribute);
878   } else if (name == html_names::kPatternAttr) {
879     SetNeedsValidityCheck();
880     UseCounter::Count(GetDocument(), WebFeature::kPatternAttribute);
881   } else if (name == html_names::kReadonlyAttr) {
882     TextControlElement::ParseAttribute(params);
883     input_type_view_->ReadonlyAttributeChanged();
884   } else if (name == html_names::kListAttr) {
885     has_non_empty_list_ = !value.IsEmpty();
886     if (has_non_empty_list_) {
887       ResetListAttributeTargetObserver();
888       ListAttributeTargetChanged();
889     }
890     PseudoStateChanged(CSSSelector::kPseudoHasDatalist);
891     UseCounter::Count(GetDocument(), WebFeature::kListAttribute);
892   } else if (name == html_names::kWebkitdirectoryAttr) {
893     TextControlElement::ParseAttribute(params);
894     UseCounter::Count(GetDocument(), WebFeature::kPrefixedDirectoryAttribute);
895   } else {
896     if (name == html_names::kFormactionAttr)
897       LogUpdateAttributeIfIsolatedWorldAndInDocument("input", params);
898     TextControlElement::ParseAttribute(params);
899   }
900 }
901 
ParserDidSetAttributes()902 void HTMLInputElement::ParserDidSetAttributes() {
903   DCHECK(parsing_in_progress_);
904   InitializeTypeInParsing();
905 }
906 
FinishParsingChildren()907 void HTMLInputElement::FinishParsingChildren() {
908   parsing_in_progress_ = false;
909   DCHECK(input_type_);
910   DCHECK(input_type_view_);
911   TextControlElement::FinishParsingChildren();
912   if (!state_restored_) {
913     bool checked = FastHasAttribute(html_names::kCheckedAttr);
914     if (checked)
915       setChecked(checked);
916     dirty_checkedness_ = false;
917   }
918 }
919 
LayoutObjectIsNeeded(const ComputedStyle & style) const920 bool HTMLInputElement::LayoutObjectIsNeeded(const ComputedStyle& style) const {
921   return input_type_->LayoutObjectIsNeeded() &&
922          TextControlElement::LayoutObjectIsNeeded(style);
923 }
924 
925 // TODO(crbug.com/1040826): Remove this override.
TypeShouldForceLegacyLayout() const926 bool HTMLInputElement::TypeShouldForceLegacyLayout() const {
927   return input_type_view_->TypeShouldForceLegacyLayout();
928 }
929 
CreateLayoutObject(const ComputedStyle & style,LegacyLayout legacy)930 LayoutObject* HTMLInputElement::CreateLayoutObject(const ComputedStyle& style,
931                                                    LegacyLayout legacy) {
932   return input_type_view_->CreateLayoutObject(style, legacy);
933 }
934 
AttachLayoutTree(AttachContext & context)935 void HTMLInputElement::AttachLayoutTree(AttachContext& context) {
936   TextControlElement::AttachLayoutTree(context);
937   if (GetLayoutObject())
938     input_type_->OnAttachWithLayoutObject();
939   input_type_->CountUsage();
940 }
941 
DetachLayoutTree(bool performing_reattach)942 void HTMLInputElement::DetachLayoutTree(bool performing_reattach) {
943   TextControlElement::DetachLayoutTree(performing_reattach);
944   needs_to_update_view_value_ = true;
945   input_type_view_->ClosePopupView();
946 }
947 
AltText() const948 String HTMLInputElement::AltText() const {
949   // http://www.w3.org/TR/1998/REC-html40-19980424/appendix/notes.html#altgen
950   // also heavily discussed by Hixie on bugzilla
951   // note this is intentionally different to HTMLImageElement::altText()
952   String alt = FastGetAttribute(html_names::kAltAttr);
953   // fall back to title attribute
954   if (alt.IsNull())
955     alt = FastGetAttribute(html_names::kTitleAttr);
956   if (alt.IsNull())
957     alt = FastGetAttribute(html_names::kValueAttr);
958   if (alt.IsNull())
959     alt = GetLocale().QueryString(IDS_FORM_INPUT_ALT);
960   return alt;
961 }
962 
CanBeSuccessfulSubmitButton() const963 bool HTMLInputElement::CanBeSuccessfulSubmitButton() const {
964   return input_type_->CanBeSuccessfulSubmitButton();
965 }
966 
IsActivatedSubmit() const967 bool HTMLInputElement::IsActivatedSubmit() const {
968   return is_activated_submit_;
969 }
970 
SetActivatedSubmit(bool flag)971 void HTMLInputElement::SetActivatedSubmit(bool flag) {
972   is_activated_submit_ = flag;
973 }
974 
AppendToFormData(FormData & form_data)975 void HTMLInputElement::AppendToFormData(FormData& form_data) {
976   if (input_type_->IsFormDataAppendable())
977     input_type_->AppendToFormData(form_data);
978 }
979 
ResultForDialogSubmit()980 String HTMLInputElement::ResultForDialogSubmit() {
981   return input_type_->ResultForDialogSubmit();
982 }
983 
ResetImpl()984 void HTMLInputElement::ResetImpl() {
985   if (input_type_->GetValueMode() == ValueMode::kValue) {
986     SetNonDirtyValue(DefaultValue());
987     SetNeedsValidityCheck();
988   } else if (input_type_->GetValueMode() == ValueMode::kFilename) {
989     SetNonDirtyValue(String());
990     SetNeedsValidityCheck();
991   }
992 
993   setChecked(FastHasAttribute(html_names::kCheckedAttr));
994   dirty_checkedness_ = false;
995 }
996 
IsTextField() const997 bool HTMLInputElement::IsTextField() const {
998   return input_type_->IsTextField();
999 }
1000 
HasBeenPasswordField() const1001 bool HTMLInputElement::HasBeenPasswordField() const {
1002   return has_been_password_field_;
1003 }
1004 
DispatchChangeEventIfNeeded()1005 void HTMLInputElement::DispatchChangeEventIfNeeded() {
1006   if (isConnected() && input_type_->ShouldSendChangeEventAfterCheckedChanged())
1007     DispatchChangeEvent();
1008 }
1009 
DispatchInputAndChangeEventIfNeeded()1010 void HTMLInputElement::DispatchInputAndChangeEventIfNeeded() {
1011   if (isConnected() &&
1012       input_type_->ShouldSendChangeEventAfterCheckedChanged()) {
1013     DispatchInputEvent();
1014     DispatchChangeEvent();
1015   }
1016 }
1017 
checked() const1018 bool HTMLInputElement::checked() const {
1019   input_type_->ReadingChecked();
1020   return is_checked_;
1021 }
1022 
setChecked(bool now_checked,TextFieldEventBehavior event_behavior)1023 void HTMLInputElement::setChecked(bool now_checked,
1024                                   TextFieldEventBehavior event_behavior) {
1025   dirty_checkedness_ = true;
1026   if (checked() == now_checked)
1027     return;
1028 
1029   input_type_->WillUpdateCheckedness(now_checked);
1030   is_checked_ = now_checked;
1031 
1032   if (RadioButtonGroupScope* scope = GetRadioButtonGroupScope())
1033     scope->UpdateCheckedState(this);
1034   InvalidateIfHasEffectiveAppearance();
1035   SetNeedsValidityCheck();
1036 
1037   // Ideally we'd do this from the layout tree (matching
1038   // LayoutTextView), but it's not possible to do it at the moment
1039   // because of the way the code is structured.
1040   if (GetLayoutObject()) {
1041     if (AXObjectCache* cache =
1042             GetLayoutObject()->GetDocument().ExistingAXObjectCache())
1043       cache->CheckedStateChanged(this);
1044   }
1045 
1046   // Only send a change event for items in the document (avoid firing during
1047   // parsing) and don't send a change event for a radio button that's getting
1048   // unchecked to match other browsers. DOM is not a useful standard for this
1049   // because it says only to fire change events at "lose focus" time, which is
1050   // definitely wrong in practice for these types of elements.
1051   if (event_behavior == TextFieldEventBehavior::kDispatchInputAndChangeEvent &&
1052       isConnected() &&
1053       input_type_->ShouldSendChangeEventAfterCheckedChanged()) {
1054     DispatchInputEvent();
1055   }
1056 
1057   PseudoStateChanged(CSSSelector::kPseudoChecked);
1058 }
1059 
setIndeterminate(bool new_value)1060 void HTMLInputElement::setIndeterminate(bool new_value) {
1061   if (indeterminate() == new_value)
1062     return;
1063 
1064   is_indeterminate_ = new_value;
1065 
1066   PseudoStateChanged(CSSSelector::kPseudoIndeterminate);
1067 
1068   InvalidateIfHasEffectiveAppearance();
1069 
1070   if (AXObjectCache* cache = GetDocument().ExistingAXObjectCache())
1071     cache->CheckedStateChanged(this);
1072 }
1073 
size() const1074 unsigned HTMLInputElement::size() const {
1075   return size_;
1076 }
1077 
SizeShouldIncludeDecoration(int & preferred_size) const1078 bool HTMLInputElement::SizeShouldIncludeDecoration(int& preferred_size) const {
1079   return input_type_view_->SizeShouldIncludeDecoration(kDefaultSize,
1080                                                        preferred_size);
1081 }
1082 
CloneNonAttributePropertiesFrom(const Element & source,CloneChildrenFlag flag)1083 void HTMLInputElement::CloneNonAttributePropertiesFrom(const Element& source,
1084                                                        CloneChildrenFlag flag) {
1085   const auto& source_element = To<HTMLInputElement>(source);
1086 
1087   non_attribute_value_ = source_element.non_attribute_value_;
1088   has_dirty_value_ = source_element.has_dirty_value_;
1089   setChecked(source_element.is_checked_);
1090   dirty_checkedness_ = source_element.dirty_checkedness_;
1091   is_indeterminate_ = source_element.is_indeterminate_;
1092   input_type_->CopyNonAttributeProperties(source_element);
1093 
1094   TextControlElement::CloneNonAttributePropertiesFrom(source, flag);
1095 
1096   needs_to_update_view_value_ = true;
1097   input_type_view_->UpdateView();
1098 }
1099 
value() const1100 String HTMLInputElement::value() const {
1101   switch (input_type_->GetValueMode()) {
1102     case ValueMode::kFilename:
1103       return input_type_->ValueInFilenameValueMode();
1104     case ValueMode::kDefault:
1105       return FastGetAttribute(html_names::kValueAttr);
1106     case ValueMode::kDefaultOn: {
1107       AtomicString value_string = FastGetAttribute(html_names::kValueAttr);
1108       return value_string.IsNull() ? "on" : value_string;
1109     }
1110     case ValueMode::kValue:
1111       return non_attribute_value_;
1112   }
1113   NOTREACHED();
1114   return g_empty_string;
1115 }
1116 
ValueOrDefaultLabel() const1117 String HTMLInputElement::ValueOrDefaultLabel() const {
1118   String value = this->value();
1119   if (!value.IsNull())
1120     return value;
1121   return input_type_->DefaultLabel();
1122 }
1123 
SetValueForUser(const String & value)1124 void HTMLInputElement::SetValueForUser(const String& value) {
1125   // Call setValue and make it send a change event.
1126   setValue(value, TextFieldEventBehavior::kDispatchChangeEvent);
1127 }
1128 
SetSuggestedValue(const String & value)1129 void HTMLInputElement::SetSuggestedValue(const String& value) {
1130   if (!input_type_->CanSetSuggestedValue())
1131     return;
1132   needs_to_update_view_value_ = true;
1133   TextControlElement::SetSuggestedValue(SanitizeValue(value));
1134   SetNeedsStyleRecalc(
1135       kSubtreeStyleChange,
1136       StyleChangeReasonForTracing::Create(style_change_reason::kControlValue));
1137   input_type_view_->UpdateView();
1138 }
1139 
SetEditingValue(const String & value)1140 void HTMLInputElement::SetEditingValue(const String& value) {
1141   if (!GetLayoutObject() || !IsTextField())
1142     return;
1143   SetInnerEditorValue(value);
1144   SubtreeHasChanged();
1145 
1146   unsigned max = value.length();
1147   SetSelectionRange(max, max);
1148   DispatchInputEvent();
1149 }
1150 
SetInnerEditorValue(const String & value)1151 void HTMLInputElement::SetInnerEditorValue(const String& value) {
1152   TextControlElement::SetInnerEditorValue(value);
1153   needs_to_update_view_value_ = false;
1154 }
1155 
setValue(const String & value,ExceptionState & exception_state,TextFieldEventBehavior event_behavior)1156 void HTMLInputElement::setValue(const String& value,
1157                                 ExceptionState& exception_state,
1158                                 TextFieldEventBehavior event_behavior) {
1159   // FIXME: Remove type check.
1160   if (type() == input_type_names::kFile && !value.IsEmpty()) {
1161     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
1162                                       "This input element accepts a filename, "
1163                                       "which may only be programmatically set "
1164                                       "to the empty string.");
1165     return;
1166   }
1167   setValue(value, event_behavior);
1168 }
1169 
setValue(const String & value,TextFieldEventBehavior event_behavior,TextControlSetValueSelection selection)1170 void HTMLInputElement::setValue(const String& value,
1171                                 TextFieldEventBehavior event_behavior,
1172                                 TextControlSetValueSelection selection) {
1173   input_type_->WarnIfValueIsInvalidAndElementIsVisible(value);
1174   if (!input_type_->CanSetValue(value))
1175     return;
1176 
1177   // Clear the suggested value. Use the base class version to not trigger a view
1178   // update.
1179   TextControlElement::SetSuggestedValue(String());
1180 
1181   // Set autofilled to false, as the value might have been set by the website.
1182   // If the field was autofilled, it'll be set to true from that method.
1183   SetAutofillState(WebAutofillState::kNotFilled);
1184 
1185   EventQueueScope scope;
1186   String sanitized_value = SanitizeValue(value);
1187   bool value_changed = sanitized_value != this->value();
1188 
1189   SetLastChangeWasNotUserEdit();
1190   needs_to_update_view_value_ = true;
1191 
1192   input_type_->SetValue(sanitized_value, value_changed, event_behavior,
1193                         selection);
1194   input_type_view_->DidSetValue(sanitized_value, value_changed);
1195 
1196   if (value_changed) {
1197     NotifyFormStateChanged();
1198     if (value.IsEmpty() && HasBeenPasswordField() && GetDocument().GetPage()) {
1199       GetDocument().GetPage()->GetChromeClient().PasswordFieldReset(*this);
1200     }
1201   }
1202 }
1203 
SetNonAttributeValue(const String & sanitized_value)1204 void HTMLInputElement::SetNonAttributeValue(const String& sanitized_value) {
1205   // This is a common code for ValueMode::kValue.
1206   DCHECK_EQ(input_type_->GetValueMode(), ValueMode::kValue);
1207   non_attribute_value_ = sanitized_value;
1208   has_dirty_value_ = true;
1209   SetNeedsValidityCheck();
1210   input_type_->InRangeChanged();
1211 }
1212 
SetNonAttributeValueByUserEdit(const String & sanitized_value)1213 void HTMLInputElement::SetNonAttributeValueByUserEdit(
1214     const String& sanitized_value) {
1215   SetValueBeforeFirstUserEditIfNotSet();
1216   SetNonAttributeValue(sanitized_value);
1217   CheckIfValueWasReverted(sanitized_value);
1218 }
1219 
SetNonDirtyValue(const String & new_value)1220 void HTMLInputElement::SetNonDirtyValue(const String& new_value) {
1221   setValue(new_value);
1222   has_dirty_value_ = false;
1223 }
1224 
HasDirtyValue() const1225 bool HTMLInputElement::HasDirtyValue() const {
1226   return has_dirty_value_;
1227 }
1228 
UpdateView()1229 void HTMLInputElement::UpdateView() {
1230   input_type_view_->UpdateView();
1231 }
1232 
valueAsDate(ScriptState * script_state) const1233 ScriptValue HTMLInputElement::valueAsDate(ScriptState* script_state) const {
1234   UseCounter::Count(GetDocument(), WebFeature::kInputElementValueAsDateGetter);
1235   // TODO(crbug.com/988343): InputType::ValueAsDate() should return
1236   // base::Optional<base::Time>.
1237   double date = input_type_->ValueAsDate();
1238   v8::Isolate* isolate = script_state->GetIsolate();
1239   if (!std::isfinite(date))
1240     return ScriptValue::CreateNull(isolate);
1241   return ScriptValue(isolate, ToV8(base::Time::FromJsTime(date), script_state));
1242 }
1243 
setValueAsDate(ScriptState * script_state,const ScriptValue & value,ExceptionState & exception_state)1244 void HTMLInputElement::setValueAsDate(ScriptState* script_state,
1245                                       const ScriptValue& value,
1246                                       ExceptionState& exception_state) {
1247   UseCounter::Count(GetDocument(), WebFeature::kInputElementValueAsDateSetter);
1248   base::Optional<base::Time> date =
1249       NativeValueTraits<IDLNullable<IDLDate>>::NativeValue(
1250           script_state->GetIsolate(), value.V8Value(), exception_state);
1251   if (exception_state.HadException())
1252     return;
1253   input_type_->SetValueAsDate(date, exception_state);
1254 }
1255 
valueAsNumber() const1256 double HTMLInputElement::valueAsNumber() const {
1257   return input_type_->ValueAsDouble();
1258 }
1259 
setValueAsNumber(double new_value,ExceptionState & exception_state,TextFieldEventBehavior event_behavior)1260 void HTMLInputElement::setValueAsNumber(double new_value,
1261                                         ExceptionState& exception_state,
1262                                         TextFieldEventBehavior event_behavior) {
1263   // http://www.whatwg.org/specs/web-apps/current-work/multipage/common-input-element-attributes.html#dom-input-valueasnumber
1264   // On setting, if the new value is infinite, then throw a TypeError exception.
1265   if (std::isinf(new_value)) {
1266     exception_state.ThrowTypeError(
1267         ExceptionMessages::NotAFiniteNumber(new_value));
1268     return;
1269   }
1270   input_type_->SetValueAsDouble(new_value, event_behavior, exception_state);
1271 }
1272 
RatioValue() const1273 Decimal HTMLInputElement::RatioValue() const {
1274   DCHECK_EQ(type(), input_type_names::kRange);
1275   const StepRange step_range(CreateStepRange(kRejectAny));
1276   const Decimal old_value =
1277       ParseToDecimalForNumberType(value(), step_range.DefaultValue());
1278   return step_range.ProportionFromValue(step_range.ClampValue(old_value));
1279 }
1280 
SetValueFromRenderer(const String & value)1281 void HTMLInputElement::SetValueFromRenderer(const String& value) {
1282   // File upload controls will never use this.
1283   DCHECK_NE(type(), input_type_names::kFile);
1284 
1285   // Clear the suggested value. Use the base class version to not trigger a view
1286   // update.
1287   TextControlElement::SetSuggestedValue(String());
1288 
1289   // Renderer and our event handler are responsible for sanitizing values.
1290   DCHECK(value == input_type_->SanitizeUserInputValue(value) ||
1291          input_type_->SanitizeUserInputValue(value).IsEmpty());
1292 
1293   DCHECK(!value.IsNull());
1294   SetValueBeforeFirstUserEditIfNotSet();
1295   non_attribute_value_ = value;
1296   has_dirty_value_ = true;
1297   needs_to_update_view_value_ = false;
1298   CheckIfValueWasReverted(value);
1299 
1300   // Input event is fired by the Node::defaultEventHandler for editable
1301   // controls.
1302   if (!IsTextField())
1303     DispatchInputEvent();
1304   NotifyFormStateChanged();
1305 
1306   SetNeedsValidityCheck();
1307 
1308   // Clear autofill flag (and yellow background) on user edit.
1309   SetAutofillState(WebAutofillState::kNotFilled);
1310 }
1311 
PreDispatchEventHandler(Event & event)1312 EventDispatchHandlingState* HTMLInputElement::PreDispatchEventHandler(
1313     Event& event) {
1314   if (event.type() == event_type_names::kTextInput &&
1315       input_type_view_->ShouldSubmitImplicitly(event)) {
1316     event.stopPropagation();
1317     return nullptr;
1318   }
1319   if (event.type() != event_type_names::kClick)
1320     return nullptr;
1321 
1322   auto* mouse_event = DynamicTo<MouseEvent>(event);
1323   if (!mouse_event ||
1324       mouse_event->button() !=
1325           static_cast<int16_t>(WebPointerProperties::Button::kLeft))
1326     return nullptr;
1327   return input_type_view_->WillDispatchClick();
1328 }
1329 
PostDispatchEventHandler(Event & event,EventDispatchHandlingState * state)1330 void HTMLInputElement::PostDispatchEventHandler(
1331     Event& event,
1332     EventDispatchHandlingState* state) {
1333   if (!state)
1334     return;
1335   input_type_view_->DidDispatchClick(event,
1336                                      *static_cast<ClickHandlingState*>(state));
1337 }
1338 
DefaultEventHandler(Event & evt)1339 void HTMLInputElement::DefaultEventHandler(Event& evt) {
1340   auto* mouse_event = DynamicTo<MouseEvent>(evt);
1341   if (mouse_event && evt.type() == event_type_names::kClick &&
1342       mouse_event->button() ==
1343           static_cast<int16_t>(WebPointerProperties::Button::kLeft)) {
1344     input_type_view_->HandleClickEvent(To<MouseEvent>(evt));
1345     if (evt.DefaultHandled())
1346       return;
1347   }
1348 
1349   auto* keyboad_event = DynamicTo<KeyboardEvent>(evt);
1350   if (keyboad_event && evt.type() == event_type_names::kKeydown) {
1351     input_type_view_->HandleKeydownEvent(*keyboad_event);
1352     if (evt.DefaultHandled())
1353       return;
1354   }
1355 
1356   // Call the base event handler before any of our own event handling for almost
1357   // all events in text fields.  Makes editing keyboard handling take precedence
1358   // over the keydown and keypress handling in this function.
1359   bool call_base_class_early =
1360       IsTextField() && (evt.type() == event_type_names::kKeydown ||
1361                         evt.type() == event_type_names::kKeypress);
1362   if (call_base_class_early) {
1363     TextControlElement::DefaultEventHandler(evt);
1364     if (evt.DefaultHandled())
1365       return;
1366   }
1367 
1368   // DOMActivate events cause the input to be "activated" - in the case of image
1369   // and submit inputs, this means actually submitting the form. For reset
1370   // inputs, the form is reset. These events are sent when the user clicks on
1371   // the element, or presses enter while it is the active element. JavaScript
1372   // code wishing to activate the element must dispatch a DOMActivate event - a
1373   // click event will not do the job.
1374   if (evt.type() == event_type_names::kDOMActivate) {
1375     input_type_view_->HandleDOMActivateEvent(evt);
1376     if (evt.DefaultHandled())
1377       return;
1378   }
1379 
1380   // Use key press event here since sending simulated mouse events
1381   // on key down blocks the proper sending of the key press event.
1382   if (keyboad_event && evt.type() == event_type_names::kKeypress) {
1383     input_type_view_->HandleKeypressEvent(*keyboad_event);
1384     if (evt.DefaultHandled())
1385       return;
1386   }
1387 
1388   if (keyboad_event && evt.type() == event_type_names::kKeyup) {
1389     input_type_view_->HandleKeyupEvent(*keyboad_event);
1390     if (evt.DefaultHandled())
1391       return;
1392   }
1393 
1394   if (input_type_view_->ShouldSubmitImplicitly(evt)) {
1395     // FIXME: Remove type check.
1396     if (type() == input_type_names::kSearch) {
1397       GetDocument()
1398           .GetTaskRunner(TaskType::kUserInteraction)
1399           ->PostTask(FROM_HERE, WTF::Bind(&HTMLInputElement::OnSearch,
1400                                           WrapPersistent(this)));
1401     }
1402     // Form submission finishes editing, just as loss of focus does.
1403     // If there was a change, send the event now.
1404     DispatchFormControlChangeEvent();
1405 
1406     HTMLFormElement* form_for_submission =
1407         input_type_view_->FormForSubmission();
1408     // Form may never have been present, or may have been destroyed by code
1409     // responding to the change event.
1410     if (form_for_submission) {
1411       form_for_submission->SubmitImplicitly(evt,
1412                                             CanTriggerImplicitSubmission());
1413     }
1414     evt.SetDefaultHandled();
1415     return;
1416   }
1417 
1418   if (evt.IsBeforeTextInsertedEvent()) {
1419     input_type_view_->HandleBeforeTextInsertedEvent(
1420         static_cast<BeforeTextInsertedEvent&>(evt));
1421   }
1422 
1423   if (mouse_event && evt.type() == event_type_names::kMousedown) {
1424     input_type_view_->HandleMouseDownEvent(*mouse_event);
1425     if (evt.DefaultHandled())
1426       return;
1427   }
1428 
1429   input_type_view_->ForwardEvent(evt);
1430 
1431   if (!call_base_class_early && !evt.DefaultHandled())
1432     TextControlElement::DefaultEventHandler(evt);
1433 }
1434 
CreateShadowSubtree()1435 void HTMLInputElement::CreateShadowSubtree() {
1436   input_type_view_->CreateShadowSubtree();
1437 }
1438 
HasActivationBehavior() const1439 bool HTMLInputElement::HasActivationBehavior() const {
1440   return true;
1441 }
1442 
WillRespondToMouseClickEvents()1443 bool HTMLInputElement::WillRespondToMouseClickEvents() {
1444   // FIXME: Consider implementing willRespondToMouseClickEvents() in InputType
1445   // if more accurate results are necessary.
1446   if (!IsDisabledFormControl())
1447     return true;
1448 
1449   return TextControlElement::WillRespondToMouseClickEvents();
1450 }
1451 
IsURLAttribute(const Attribute & attribute) const1452 bool HTMLInputElement::IsURLAttribute(const Attribute& attribute) const {
1453   return attribute.GetName() == html_names::kSrcAttr ||
1454          attribute.GetName() == html_names::kFormactionAttr ||
1455          TextControlElement::IsURLAttribute(attribute);
1456 }
1457 
HasLegalLinkAttribute(const QualifiedName & name) const1458 bool HTMLInputElement::HasLegalLinkAttribute(const QualifiedName& name) const {
1459   return input_type_->HasLegalLinkAttribute(name) ||
1460          TextControlElement::HasLegalLinkAttribute(name);
1461 }
1462 
SubResourceAttributeName() const1463 const QualifiedName& HTMLInputElement::SubResourceAttributeName() const {
1464   return input_type_->SubResourceAttributeName();
1465 }
1466 
DefaultValue() const1467 const AtomicString& HTMLInputElement::DefaultValue() const {
1468   return FastGetAttribute(html_names::kValueAttr);
1469 }
1470 
IsRFC2616TokenCharacter(UChar ch)1471 static inline bool IsRFC2616TokenCharacter(UChar ch) {
1472   return IsASCII(ch) && ch > ' ' && ch != '"' && ch != '(' && ch != ')' &&
1473          ch != ',' && ch != '/' && (ch < ':' || ch > '@') &&
1474          (ch < '[' || ch > ']') && ch != '{' && ch != '}' && ch != 0x7f;
1475 }
1476 
IsValidMIMEType(const String & type)1477 static bool IsValidMIMEType(const String& type) {
1478   size_t slash_position = type.find('/');
1479   if (slash_position == kNotFound || !slash_position ||
1480       slash_position == type.length() - 1)
1481     return false;
1482   for (wtf_size_t i = 0; i < type.length(); ++i) {
1483     if (!IsRFC2616TokenCharacter(type[i]) && i != slash_position)
1484       return false;
1485   }
1486   return true;
1487 }
1488 
IsValidFileExtension(const String & type)1489 static bool IsValidFileExtension(const String& type) {
1490   if (type.length() < 2)
1491     return false;
1492   return type[0] == '.';
1493 }
1494 
ParseAcceptAttribute(const String & accept_string,bool (* predicate)(const String &))1495 static Vector<String> ParseAcceptAttribute(const String& accept_string,
1496                                            bool (*predicate)(const String&)) {
1497   Vector<String> types;
1498   if (accept_string.IsEmpty())
1499     return types;
1500 
1501   Vector<String> split_types;
1502   accept_string.Split(',', false, split_types);
1503   for (const String& split_type : split_types) {
1504     String trimmed_type = StripLeadingAndTrailingHTMLSpaces(split_type);
1505     if (trimmed_type.IsEmpty())
1506       continue;
1507     if (!predicate(trimmed_type))
1508       continue;
1509     types.push_back(trimmed_type.DeprecatedLower());
1510   }
1511 
1512   return types;
1513 }
1514 
AcceptMIMETypes() const1515 Vector<String> HTMLInputElement::AcceptMIMETypes() const {
1516   return ParseAcceptAttribute(FastGetAttribute(html_names::kAcceptAttr),
1517                               IsValidMIMEType);
1518 }
1519 
AcceptFileExtensions() const1520 Vector<String> HTMLInputElement::AcceptFileExtensions() const {
1521   return ParseAcceptAttribute(FastGetAttribute(html_names::kAcceptAttr),
1522                               IsValidFileExtension);
1523 }
1524 
Alt() const1525 const AtomicString& HTMLInputElement::Alt() const {
1526   return FastGetAttribute(html_names::kAltAttr);
1527 }
1528 
Multiple() const1529 bool HTMLInputElement::Multiple() const {
1530   return FastHasAttribute(html_names::kMultipleAttr);
1531 }
1532 
setSize(unsigned size,ExceptionState & exception_state)1533 void HTMLInputElement::setSize(unsigned size, ExceptionState& exception_state) {
1534   if (size == 0) {
1535     exception_state.ThrowDOMException(
1536         DOMExceptionCode::kIndexSizeError,
1537         "The value provided is 0, which is an invalid size.");
1538   } else {
1539     SetUnsignedIntegralAttribute(html_names::kSizeAttr,
1540                                  size ? size : kDefaultSize, kDefaultSize);
1541   }
1542 }
1543 
Src() const1544 KURL HTMLInputElement::Src() const {
1545   return GetDocument().CompleteURL(FastGetAttribute(html_names::kSrcAttr));
1546 }
1547 
files() const1548 FileList* HTMLInputElement::files() const {
1549   return input_type_->Files();
1550 }
1551 
setFiles(FileList * files)1552 void HTMLInputElement::setFiles(FileList* files) {
1553   input_type_->SetFiles(files);
1554 }
1555 
ReceiveDroppedFiles(const DragData * drag_data)1556 bool HTMLInputElement::ReceiveDroppedFiles(const DragData* drag_data) {
1557   return input_type_->ReceiveDroppedFiles(drag_data);
1558 }
1559 
DroppedFileSystemId()1560 String HTMLInputElement::DroppedFileSystemId() {
1561   return input_type_->DroppedFileSystemId();
1562 }
1563 
CanReceiveDroppedFiles() const1564 bool HTMLInputElement::CanReceiveDroppedFiles() const {
1565   return can_receive_dropped_files_;
1566 }
1567 
SetCanReceiveDroppedFiles(bool can_receive_dropped_files)1568 void HTMLInputElement::SetCanReceiveDroppedFiles(
1569     bool can_receive_dropped_files) {
1570   if (!!can_receive_dropped_files_ == can_receive_dropped_files)
1571     return;
1572   can_receive_dropped_files_ = can_receive_dropped_files;
1573   if (HTMLInputElement* button = UploadButton())
1574     button->SetActive(can_receive_dropped_files);
1575 }
1576 
UploadButton() const1577 HTMLInputElement* HTMLInputElement::UploadButton() const {
1578   return input_type_view_->UploadButton();
1579 }
1580 
SanitizeValue(const String & proposed_value) const1581 String HTMLInputElement::SanitizeValue(const String& proposed_value) const {
1582   return input_type_->SanitizeValue(proposed_value);
1583 }
1584 
LocalizeValue(const String & proposed_value) const1585 String HTMLInputElement::LocalizeValue(const String& proposed_value) const {
1586   if (proposed_value.IsNull())
1587     return proposed_value;
1588   return input_type_->LocalizeValue(proposed_value);
1589 }
1590 
IsInRange() const1591 bool HTMLInputElement::IsInRange() const {
1592   return willValidate() && input_type_->IsInRange(value());
1593 }
1594 
IsOutOfRange() const1595 bool HTMLInputElement::IsOutOfRange() const {
1596   return willValidate() && input_type_->IsOutOfRange(value());
1597 }
1598 
IsRequiredFormControl() const1599 bool HTMLInputElement::IsRequiredFormControl() const {
1600   return input_type_->SupportsRequired() && IsRequired();
1601 }
1602 
MatchesReadOnlyPseudoClass() const1603 bool HTMLInputElement::MatchesReadOnlyPseudoClass() const {
1604   return input_type_->SupportsReadOnly() && IsReadOnly();
1605 }
1606 
MatchesReadWritePseudoClass() const1607 bool HTMLInputElement::MatchesReadWritePseudoClass() const {
1608   return input_type_->SupportsReadOnly() && !IsReadOnly();
1609 }
1610 
OnSearch()1611 void HTMLInputElement::OnSearch() {
1612   input_type_->DispatchSearchEvent();
1613 }
1614 
UpdateClearButtonVisibility()1615 void HTMLInputElement::UpdateClearButtonVisibility() {
1616   input_type_view_->UpdateClearButtonVisibility();
1617 }
1618 
WillChangeForm()1619 void HTMLInputElement::WillChangeForm() {
1620   if (input_type_)
1621     RemoveFromRadioButtonGroup();
1622   TextControlElement::WillChangeForm();
1623 }
1624 
DidChangeForm()1625 void HTMLInputElement::DidChangeForm() {
1626   TextControlElement::DidChangeForm();
1627   if (input_type_)
1628     AddToRadioButtonGroup();
1629 }
1630 
InsertedInto(ContainerNode & insertion_point)1631 Node::InsertionNotificationRequest HTMLInputElement::InsertedInto(
1632     ContainerNode& insertion_point) {
1633   TextControlElement::InsertedInto(insertion_point);
1634   if (insertion_point.isConnected() && !Form())
1635     AddToRadioButtonGroup();
1636   ResetListAttributeTargetObserver();
1637   LogAddElementIfIsolatedWorldAndInDocument("input", html_names::kTypeAttr,
1638                                             html_names::kFormactionAttr);
1639   return kInsertionShouldCallDidNotifySubtreeInsertions;
1640 }
1641 
RemovedFrom(ContainerNode & insertion_point)1642 void HTMLInputElement::RemovedFrom(ContainerNode& insertion_point) {
1643   input_type_view_->ClosePopupView();
1644   if (insertion_point.isConnected() && !Form())
1645     RemoveFromRadioButtonGroup();
1646   TextControlElement::RemovedFrom(insertion_point);
1647   DCHECK(!isConnected());
1648   ResetListAttributeTargetObserver();
1649 }
1650 
DidMoveToNewDocument(Document & old_document)1651 void HTMLInputElement::DidMoveToNewDocument(Document& old_document) {
1652   if (ImageLoader())
1653     ImageLoader()->ElementDidMoveToNewDocument();
1654 
1655   // FIXME: Remove type check.
1656   if (type() == input_type_names::kRadio)
1657     GetTreeScope().GetRadioButtonGroupScope().RemoveButton(this);
1658 
1659   TextControlElement::DidMoveToNewDocument(old_document);
1660 }
1661 
RecalcWillValidate() const1662 bool HTMLInputElement::RecalcWillValidate() const {
1663   return input_type_->SupportsValidation() &&
1664          TextControlElement::RecalcWillValidate();
1665 }
1666 
RequiredAttributeChanged()1667 void HTMLInputElement::RequiredAttributeChanged() {
1668   TextControlElement::RequiredAttributeChanged();
1669   if (RadioButtonGroupScope* scope = GetRadioButtonGroupScope())
1670     scope->RequiredAttributeChanged(this);
1671   input_type_view_->RequiredAttributeChanged();
1672 }
1673 
DisabledAttributeChanged()1674 void HTMLInputElement::DisabledAttributeChanged() {
1675   TextControlElement::DisabledAttributeChanged();
1676   input_type_view_->DisabledAttributeChanged();
1677 }
1678 
SelectColorInColorChooser(const Color & color)1679 void HTMLInputElement::SelectColorInColorChooser(const Color& color) {
1680   if (ColorChooserClient* client = input_type_->GetColorChooserClient())
1681     client->DidChooseColor(color);
1682 }
1683 
EndColorChooserForTesting()1684 void HTMLInputElement::EndColorChooserForTesting() {
1685   input_type_view_->ClosePopupView();
1686 }
1687 
list() const1688 HTMLElement* HTMLInputElement::list() const {
1689   return DataList();
1690 }
1691 
DataList() const1692 HTMLDataListElement* HTMLInputElement::DataList() const {
1693   if (!has_non_empty_list_)
1694     return nullptr;
1695 
1696   if (!input_type_->ShouldRespectListAttribute())
1697     return nullptr;
1698 
1699   return DynamicTo<HTMLDataListElement>(
1700       GetTreeScope().getElementById(FastGetAttribute(html_names::kListAttr)));
1701 }
1702 
HasValidDataListOptions() const1703 bool HTMLInputElement::HasValidDataListOptions() const {
1704   HTMLDataListElement* data_list = DataList();
1705   if (!data_list)
1706     return false;
1707   HTMLDataListOptionsCollection* options = data_list->options();
1708   for (unsigned i = 0; HTMLOptionElement* option = options->Item(i); ++i) {
1709     if (!option->value().IsEmpty() && !option->IsDisabledFormControl())
1710       return true;
1711   }
1712   return false;
1713 }
1714 
1715 HeapVector<Member<HTMLOptionElement>>
FilteredDataListOptions() const1716 HTMLInputElement::FilteredDataListOptions() const {
1717   HeapVector<Member<HTMLOptionElement>> filtered;
1718   HTMLDataListElement* data_list = DataList();
1719   if (!data_list)
1720     return filtered;
1721 
1722   String value = InnerEditorValue();
1723   if (Multiple() && type() == input_type_names::kEmail) {
1724     Vector<String> emails;
1725     value.Split(',', true, emails);
1726     if (!emails.IsEmpty())
1727       value = emails.back().StripWhiteSpace();
1728   }
1729 
1730   HTMLDataListOptionsCollection* options = data_list->options();
1731   filtered.ReserveCapacity(options->length());
1732   value = value.FoldCase();
1733   for (unsigned i = 0; i < options->length(); ++i) {
1734     HTMLOptionElement* option = options->Item(i);
1735     DCHECK(option);
1736     if (!value.IsEmpty()) {
1737       // Firefox shows OPTIONs with matched labels, Edge shows OPTIONs
1738       // with matches values. We show both.
1739       if (option->value().FoldCase().Find(value) == kNotFound &&
1740           option->label().FoldCase().Find(value) == kNotFound)
1741         continue;
1742     }
1743     if (option->value().IsEmpty() || option->IsDisabledFormControl())
1744       continue;
1745     filtered.push_back(option);
1746   }
1747   return filtered;
1748 }
1749 
SetListAttributeTargetObserver(ListAttributeTargetObserver * new_observer)1750 void HTMLInputElement::SetListAttributeTargetObserver(
1751     ListAttributeTargetObserver* new_observer) {
1752   if (list_attribute_target_observer_)
1753     list_attribute_target_observer_->Unregister();
1754   list_attribute_target_observer_ = new_observer;
1755 }
1756 
ResetListAttributeTargetObserver()1757 void HTMLInputElement::ResetListAttributeTargetObserver() {
1758   const AtomicString& value = FastGetAttribute(html_names::kListAttr);
1759   if (!value.IsNull() && isConnected()) {
1760     SetListAttributeTargetObserver(
1761         MakeGarbageCollected<ListAttributeTargetObserver>(value, this));
1762   } else {
1763     SetListAttributeTargetObserver(nullptr);
1764   }
1765 }
1766 
ListAttributeTargetChanged()1767 void HTMLInputElement::ListAttributeTargetChanged() {
1768   input_type_view_->ListAttributeTargetChanged();
1769   PseudoStateChanged(CSSSelector::kPseudoHasDatalist);
1770 }
1771 
IsSteppable() const1772 bool HTMLInputElement::IsSteppable() const {
1773   return input_type_->IsSteppable();
1774 }
1775 
IsTextButton() const1776 bool HTMLInputElement::IsTextButton() const {
1777   return input_type_->IsTextButton();
1778 }
1779 
IsEnumeratable() const1780 bool HTMLInputElement::IsEnumeratable() const {
1781   return input_type_->IsEnumeratable();
1782 }
1783 
IsLabelable() const1784 bool HTMLInputElement::IsLabelable() const {
1785   return input_type_->IsInteractiveContent();
1786 }
1787 
MatchesDefaultPseudoClass() const1788 bool HTMLInputElement::MatchesDefaultPseudoClass() const {
1789   return input_type_->MatchesDefaultPseudoClass();
1790 }
1791 
scrollWidth()1792 int HTMLInputElement::scrollWidth() {
1793   if (!IsTextField())
1794     return TextControlElement::scrollWidth();
1795   // If in preview state, fake the scroll width to prevent that any information
1796   // about the suggested content can be derived from the size.
1797   if (!SuggestedValue().IsEmpty())
1798     return clientWidth();
1799 
1800   GetDocument().UpdateStyleAndLayoutForNode(this,
1801                                             DocumentUpdateReason::kJavaScript);
1802   const auto* editor = InnerEditorElement();
1803   const auto* editor_box = editor ? editor->GetLayoutBox() : nullptr;
1804   const auto* box = GetLayoutBox();
1805   if (!editor_box || !box)
1806     return TextControlElement::scrollWidth();
1807   // Adjust scrollWidth to include input element horizontal paddings and
1808   // decoration width.
1809   LayoutUnit adjustment = box->ClientWidth() - editor_box->ClientWidth();
1810   return AdjustForAbsoluteZoom::AdjustLayoutUnit(
1811              editor_box->ScrollWidth() + adjustment, box->StyleRef())
1812       .Round();
1813 }
1814 
scrollHeight()1815 int HTMLInputElement::scrollHeight() {
1816   if (!IsTextField())
1817     return TextControlElement::scrollHeight();
1818 
1819   // If in preview state, fake the scroll height to prevent that any information
1820   // about the suggested content can be derived from the size.
1821   if (!SuggestedValue().IsEmpty())
1822     return clientHeight();
1823 
1824   GetDocument().UpdateStyleAndLayoutForNode(this,
1825                                             DocumentUpdateReason::kJavaScript);
1826   const auto* editor = InnerEditorElement();
1827   const auto* editor_box = editor ? editor->GetLayoutBox() : nullptr;
1828   const auto* box = GetLayoutBox();
1829   if (!editor_box || !box)
1830     return TextControlElement::scrollHeight();
1831   // Adjust scrollHeight to include input element vertical paddings and
1832   // decoration height.
1833   LayoutUnit adjustment = box->ClientHeight() - editor_box->ClientHeight();
1834   return AdjustForAbsoluteZoom::AdjustLayoutUnit(
1835              editor_box->ScrollHeight() + adjustment, box->StyleRef())
1836       .Round();
1837 }
1838 
ShouldAppearChecked() const1839 bool HTMLInputElement::ShouldAppearChecked() const {
1840   return checked() && input_type_->IsCheckable();
1841 }
1842 
SetPlaceholderVisibility(bool visible)1843 void HTMLInputElement::SetPlaceholderVisibility(bool visible) {
1844   is_placeholder_visible_ = visible;
1845 }
1846 
SupportsPlaceholder() const1847 bool HTMLInputElement::SupportsPlaceholder() const {
1848   return input_type_->SupportsPlaceholder();
1849 }
1850 
UpdatePlaceholderText()1851 void HTMLInputElement::UpdatePlaceholderText() {
1852   return input_type_view_->UpdatePlaceholderText();
1853 }
1854 
GetPlaceholderValue() const1855 String HTMLInputElement::GetPlaceholderValue() const {
1856   return !SuggestedValue().IsEmpty() ? SuggestedValue() : StrippedPlaceholder();
1857 }
1858 
DefaultToolTip() const1859 String HTMLInputElement::DefaultToolTip() const {
1860   return input_type_->DefaultToolTip(*input_type_view_);
1861 }
1862 
FileStatusText() const1863 String HTMLInputElement::FileStatusText() const {
1864   return input_type_view_->FileStatusText();
1865 }
1866 
ShouldApplyMiddleEllipsis() const1867 bool HTMLInputElement::ShouldApplyMiddleEllipsis() const {
1868   return files() && files()->length() <= 1;
1869 }
1870 
ShouldAppearIndeterminate() const1871 bool HTMLInputElement::ShouldAppearIndeterminate() const {
1872   return input_type_->ShouldAppearIndeterminate();
1873 }
1874 
GetRadioButtonGroupScope() const1875 RadioButtonGroupScope* HTMLInputElement::GetRadioButtonGroupScope() const {
1876   // FIXME: Remove type check.
1877   if (type() != input_type_names::kRadio)
1878     return nullptr;
1879   if (HTMLFormElement* form_element = Form())
1880     return &form_element->GetRadioButtonGroupScope();
1881   if (isConnected())
1882     return &GetTreeScope().GetRadioButtonGroupScope();
1883   return nullptr;
1884 }
1885 
SizeOfRadioGroup() const1886 unsigned HTMLInputElement::SizeOfRadioGroup() const {
1887   RadioButtonGroupScope* scope = GetRadioButtonGroupScope();
1888   if (!scope)
1889     return 0;
1890   return scope->GroupSizeFor(this);
1891 }
1892 
AddToRadioButtonGroup()1893 inline void HTMLInputElement::AddToRadioButtonGroup() {
1894   if (RadioButtonGroupScope* scope = GetRadioButtonGroupScope())
1895     scope->AddButton(this);
1896 }
1897 
RemoveFromRadioButtonGroup()1898 inline void HTMLInputElement::RemoveFromRadioButtonGroup() {
1899   if (RadioButtonGroupScope* scope = GetRadioButtonGroupScope())
1900     scope->RemoveButton(this);
1901 }
1902 
height() const1903 unsigned HTMLInputElement::height() const {
1904   return input_type_->Height();
1905 }
1906 
width() const1907 unsigned HTMLInputElement::width() const {
1908   return input_type_->Width();
1909 }
1910 
setHeight(unsigned height)1911 void HTMLInputElement::setHeight(unsigned height) {
1912   SetUnsignedIntegralAttribute(html_names::kHeightAttr, height);
1913 }
1914 
setWidth(unsigned width)1915 void HTMLInputElement::setWidth(unsigned width) {
1916   SetUnsignedIntegralAttribute(html_names::kWidthAttr, width);
1917 }
1918 
ListAttributeTargetObserver(const AtomicString & id,HTMLInputElement * element)1919 ListAttributeTargetObserver::ListAttributeTargetObserver(
1920     const AtomicString& id,
1921     HTMLInputElement* element)
1922     : IdTargetObserver(element->GetTreeScope().GetIdTargetObserverRegistry(),
1923                        id),
1924       element_(element) {}
1925 
Trace(Visitor * visitor) const1926 void ListAttributeTargetObserver::Trace(Visitor* visitor) const {
1927   visitor->Trace(element_);
1928   IdTargetObserver::Trace(visitor);
1929 }
1930 
IdTargetChanged()1931 void ListAttributeTargetObserver::IdTargetChanged() {
1932   element_->ListAttributeTargetChanged();
1933 }
1934 
setRangeText(const String & replacement,ExceptionState & exception_state)1935 void HTMLInputElement::setRangeText(const String& replacement,
1936                                     ExceptionState& exception_state) {
1937   if (!input_type_->SupportsSelectionAPI()) {
1938     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
1939                                       "The input element's type ('" +
1940                                           input_type_->FormControlType() +
1941                                           "') does not support selection.");
1942     return;
1943   }
1944 
1945   TextControlElement::setRangeText(replacement, exception_state);
1946 }
1947 
setRangeText(const String & replacement,unsigned start,unsigned end,const String & selection_mode,ExceptionState & exception_state)1948 void HTMLInputElement::setRangeText(const String& replacement,
1949                                     unsigned start,
1950                                     unsigned end,
1951                                     const String& selection_mode,
1952                                     ExceptionState& exception_state) {
1953   if (!input_type_->SupportsSelectionAPI()) {
1954     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
1955                                       "The input element's type ('" +
1956                                           input_type_->FormControlType() +
1957                                           "') does not support selection.");
1958     return;
1959   }
1960 
1961   TextControlElement::setRangeText(replacement, start, end, selection_mode,
1962                                    exception_state);
1963 }
1964 
SetupDateTimeChooserParameters(DateTimeChooserParameters & parameters)1965 bool HTMLInputElement::SetupDateTimeChooserParameters(
1966     DateTimeChooserParameters& parameters) {
1967   if (!GetDocument().View())
1968     return false;
1969 
1970   parameters.type = type();
1971   parameters.minimum = Minimum();
1972   parameters.maximum = Maximum();
1973   parameters.required = IsRequired();
1974   if (!RuntimeEnabledFeatures::LangAttributeAwareFormControlUIEnabled()) {
1975     parameters.locale = DefaultLanguage();
1976   } else {
1977     AtomicString computed_locale = ComputeInheritedLanguage();
1978     parameters.locale =
1979         computed_locale.IsEmpty() ? DefaultLanguage() : computed_locale;
1980   }
1981 
1982   StepRange step_range = CreateStepRange(kRejectAny);
1983   if (step_range.HasStep()) {
1984     parameters.step = step_range.Step().ToDouble();
1985     parameters.step_base = step_range.StepBase().ToDouble();
1986   } else {
1987     parameters.step = 1.0;
1988     parameters.step_base = 0;
1989   }
1990 
1991   parameters.anchor_rect_in_screen =
1992       GetDocument().View()->FrameToScreen(PixelSnappedBoundingBox());
1993   parameters.double_value = input_type_->ValueAsDouble();
1994   parameters.focused_field_index = input_type_view_->FocusedFieldIndex();
1995   parameters.is_anchor_element_rtl =
1996       input_type_view_->ComputedTextDirection() == TextDirection::kRtl;
1997   if (HTMLDataListElement* data_list = DataList()) {
1998     HTMLDataListOptionsCollection* options = data_list->options();
1999     for (unsigned i = 0; HTMLOptionElement* option = options->Item(i); ++i) {
2000       if (option->value().IsEmpty() || option->IsDisabledFormControl() ||
2001           !IsValidValue(option->value()))
2002         continue;
2003       auto suggestion = mojom::blink::DateTimeSuggestion::New();
2004       suggestion->value =
2005           input_type_->ParseToNumber(option->value(), Decimal::Nan())
2006               .ToDouble();
2007       if (std::isnan(suggestion->value))
2008         continue;
2009       suggestion->localized_value = LocalizeValue(option->value());
2010       suggestion->label =
2011           option->value() == option->label() ? String("") : option->label();
2012       parameters.suggestions.push_back(std::move(suggestion));
2013     }
2014   }
2015   return true;
2016 }
2017 
SupportsInputModeAttribute() const2018 bool HTMLInputElement::SupportsInputModeAttribute() const {
2019   return input_type_->SupportsInputModeAttribute();
2020 }
2021 
CapsLockStateMayHaveChanged()2022 void HTMLInputElement::CapsLockStateMayHaveChanged() {
2023   input_type_view_->CapsLockStateMayHaveChanged();
2024 }
2025 
ShouldDrawCapsLockIndicator() const2026 bool HTMLInputElement::ShouldDrawCapsLockIndicator() const {
2027   return input_type_view_->ShouldDrawCapsLockIndicator();
2028 }
2029 
SetShouldRevealPassword(bool value)2030 void HTMLInputElement::SetShouldRevealPassword(bool value) {
2031   if (!!should_reveal_password_ == value)
2032     return;
2033   should_reveal_password_ = value;
2034   if (HTMLElement* inner_editor = InnerEditorElement()) {
2035     // Update -webkit-text-security style.
2036     inner_editor->SetNeedsStyleRecalc(
2037         kLocalStyleChange,
2038         StyleChangeReasonForTracing::Create(style_change_reason::kControl));
2039   }
2040 }
2041 
IsInteractiveContent() const2042 bool HTMLInputElement::IsInteractiveContent() const {
2043   return input_type_->IsInteractiveContent();
2044 }
2045 
CustomStyleForLayoutObject()2046 scoped_refptr<ComputedStyle> HTMLInputElement::CustomStyleForLayoutObject() {
2047   scoped_refptr<ComputedStyle> style = OriginalStyleForLayoutObject();
2048   input_type_view_->CustomStyleForLayoutObject(*style);
2049   return style;
2050 }
2051 
DidRecalcStyle(const StyleRecalcChange change)2052 void HTMLInputElement::DidRecalcStyle(const StyleRecalcChange change) {
2053   TextControlElement::DidRecalcStyle(change);
2054   if (NeedsReattachLayoutTree() && GetComputedStyle())
2055     input_type_view_->StartResourceLoading();
2056 }
2057 
DidNotifySubtreeInsertionsToDocument()2058 void HTMLInputElement::DidNotifySubtreeInsertionsToDocument() {
2059   ListAttributeTargetChanged();
2060 }
2061 
PopupRootAXObject()2062 AXObject* HTMLInputElement::PopupRootAXObject() {
2063   return input_type_view_->PopupRootAXObject();
2064 }
2065 
EnsureFallbackContent()2066 void HTMLInputElement::EnsureFallbackContent() {
2067   input_type_view_->EnsureFallbackContent();
2068 }
2069 
EnsurePrimaryContent()2070 void HTMLInputElement::EnsurePrimaryContent() {
2071   input_type_view_->EnsurePrimaryContent();
2072 }
2073 
HasFallbackContent() const2074 bool HTMLInputElement::HasFallbackContent() const {
2075   return input_type_view_->HasFallbackContent();
2076 }
2077 
SetFilesFromPaths(const Vector<String> & paths)2078 void HTMLInputElement::SetFilesFromPaths(const Vector<String>& paths) {
2079   return input_type_->SetFilesFromPaths(paths);
2080 }
2081 
ChildrenChanged(const ChildrenChange & change)2082 void HTMLInputElement::ChildrenChanged(const ChildrenChange& change) {
2083   // Some input types only need shadow roots to hide any children that may
2084   // have been appended by script. For such types, shadow roots are lazily
2085   // created when children are added for the first time.
2086   EnsureUserAgentShadowRoot();
2087   ContainerNode::ChildrenChanged(change);
2088 }
2089 
GetLayoutBoxForScrolling() const2090 LayoutBox* HTMLInputElement::GetLayoutBoxForScrolling() const {
2091   // If it's LayoutTextControlSingleLine, return InnerEditorElement's LayoutBox.
2092   if (IsTextField() && InnerEditorElement())
2093     return InnerEditorElement()->GetLayoutBox();
2094   return Element::GetLayoutBoxForScrolling();
2095 }
2096 
IsDraggedSlider() const2097 bool HTMLInputElement::IsDraggedSlider() const {
2098   return input_type_view_->IsDraggedSlider();
2099 }
2100 
MaybeReportPiiMetrics()2101 void HTMLInputElement::MaybeReportPiiMetrics() {
2102   // Don't report metrics if the field is empty.
2103   if (value().IsEmpty())
2104     return;
2105 
2106   // Report the PII types derived from autofill field semantic type prediction.
2107   if (GetFormElementPiiType() != FormElementPiiType::kUnknown) {
2108     UseCounter::Count(GetDocument(),
2109                       WebFeature::kAnyPiiFieldDetected_PredictedTypeMatch);
2110 
2111     if (GetFormElementPiiType() == FormElementPiiType::kEmail) {
2112       UseCounter::Count(GetDocument(),
2113                         WebFeature::kEmailFieldDetected_PredictedTypeMatch);
2114     } else if (GetFormElementPiiType() == FormElementPiiType::kPhone) {
2115       UseCounter::Count(GetDocument(),
2116                         WebFeature::kPhoneFieldDetected_PredictedTypeMatch);
2117     }
2118   }
2119 
2120   // Report the PII types derived by matching the field value with patterns.
2121 
2122   // For Email, we add a length limitation (based on
2123   // https://www.rfc-editor.org/errata_search.php?rfc=3696) in addition to
2124   // matching with the pattern given by the HTML standard.
2125   if (value().length() <= kMaxEmailFieldLength &&
2126       EmailInputType::IsValidEmailAddress(GetDocument().EnsureEmailRegexp(),
2127                                           value())) {
2128     UseCounter::Count(GetDocument(),
2129                       WebFeature::kEmailFieldDetected_PatternMatch);
2130   }
2131 }
2132 
2133 }  // namespace blink
2134