1/*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2000 Dirk Mueller (mueller@kde.org)
5 * Copyright (C) 2004-2018 Apple Inc. All rights reserved.
6 * Copyright (C) 2012 Samsung Electronics. All rights reserved.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 *
23 */
24
25#pragma once
26
27#include "FileChooser.h"
28#include "HTMLTextFormControlElement.h"
29#include "StepRange.h"
30#include <memory>
31#include <wtf/WeakPtr.h>
32
33#if PLATFORM(IOS_FAMILY)
34#include "DateComponents.h"
35#endif
36
37namespace WebCore {
38
39class DragData;
40class FileList;
41class HTMLDataListElement;
42class HTMLImageLoader;
43class Icon;
44class InputType;
45class ListAttributeTargetObserver;
46class RadioButtonGroups;
47
48struct DateTimeChooserParameters;
49
50struct InputElementClickState {
51 bool stateful { false };
52 bool checked { false };
53 bool indeterminate { false };
54 RefPtr<HTMLInputElement> checkedRadioButton;
55};
56
57class HTMLInputElement : public HTMLTextFormControlElement {
58 WTF_MAKE_ISO_ALLOCATED(HTMLInputElement);
59public:
60 static Ref<HTMLInputElement> create(const QualifiedName&, Document&, HTMLFormElement*, bool createdByParser);
61 virtual ~HTMLInputElement();
62
63 WEBCORE_EXPORT bool shouldAutocomplete() const final;
64
65 // For ValidityState
66 bool hasBadInput() const final;
67 bool patternMismatch() const final;
68 bool rangeUnderflow() const final;
69 bool rangeOverflow() const final;
70 bool stepMismatch() const final;
71 bool tooShort() const final;
72 bool tooLong() const final;
73 bool typeMismatch() const final;
74 bool valueMissing() const final;
75 bool isValid() const final;
76 WEBCORE_EXPORT String validationMessage() const final;
77
78 // Returns the minimum value for type=date, number, or range. Don't call this for other types.
79 double minimum() const;
80 // Returns the maximum value for type=date, number, or range. Don't call this for other types.
81 // This always returns a value which is >= minimum().
82 double maximum() const;
83 // Sets the "allowed value step" defined in the HTML spec to the specified double pointer.
84 // Returns false if there is no "allowed value step."
85 bool getAllowedValueStep(Decimal*) const;
86 StepRange createStepRange(AnyStepHandling) const;
87
88#if ENABLE(DATALIST_ELEMENT)
89 Optional<Decimal> findClosestTickMarkValue(const Decimal&);
90#endif
91
92 WEBCORE_EXPORT ExceptionOr<void> stepUp(int = 1);
93 WEBCORE_EXPORT ExceptionOr<void> stepDown(int = 1);
94
95 bool isPresentingAttachedView() const;
96
97 // stepUp()/stepDown() for user-interaction.
98 bool isSteppable() const;
99
100 bool isTextButton() const;
101
102 bool isRadioButton() const;
103 WEBCORE_EXPORT bool isTextField() const final;
104 WEBCORE_EXPORT bool isSearchField() const;
105 bool isInputTypeHidden() const;
106 WEBCORE_EXPORT bool isPasswordField() const;
107 bool isCheckbox() const;
108 bool isRangeControl() const;
109
110#if ENABLE(INPUT_TYPE_COLOR)
111 WEBCORE_EXPORT bool isColorControl() const;
112#endif
113
114 // FIXME: It's highly likely that any call site calling this function should instead
115 // be using a different one. Many input elements behave like text fields, and in addition
116 // any unknown input type is treated as text. Consider, for example, isTextField or
117 // isTextField && !isPasswordField.
118 WEBCORE_EXPORT bool isText() const;
119
120 WEBCORE_EXPORT bool isEmailField() const;
121 bool isFileUpload() const;
122 bool isImageButton() const;
123 WEBCORE_EXPORT bool isNumberField() const;
124 bool isSubmitButton() const;
125 WEBCORE_EXPORT bool isTelephoneField() const;
126 WEBCORE_EXPORT bool isURLField() const;
127 WEBCORE_EXPORT bool isDateField() const;
128 WEBCORE_EXPORT bool isDateTimeField() const;
129 WEBCORE_EXPORT bool isDateTimeLocalField() const;
130 WEBCORE_EXPORT bool isMonthField() const;
131 WEBCORE_EXPORT bool isTimeField() const;
132 WEBCORE_EXPORT bool isWeekField() const;
133
134#if PLATFORM(IOS_FAMILY)
135 DateComponents::Type dateType() const;
136#endif
137
138 HTMLElement* containerElement() const;
139
140 RefPtr<TextControlInnerTextElement> innerTextElement() const final;
141 RenderStyle createInnerTextStyle(const RenderStyle&) override;
142
143 HTMLElement* innerBlockElement() const;
144 HTMLElement* innerSpinButtonElement() const;
145 HTMLElement* capsLockIndicatorElement() const;
146 HTMLElement* resultsButtonElement() const;
147 HTMLElement* cancelButtonElement() const;
148 HTMLElement* sliderThumbElement() const;
149 HTMLElement* sliderTrackElement() const;
150 HTMLElement* placeholderElement() const final;
151 WEBCORE_EXPORT HTMLElement* autoFillButtonElement() const;
152#if ENABLE(DATALIST_ELEMENT)
153 WEBCORE_EXPORT HTMLElement* dataListButtonElement() const;
154#endif
155
156 bool checked() const { return m_isChecked; }
157 WEBCORE_EXPORT void setChecked(bool);
158
159 // 'indeterminate' is a state independent of the checked state that causes the control to draw in a way that hides the actual state.
160 bool indeterminate() const { return m_isIndeterminate; }
161 WEBCORE_EXPORT void setIndeterminate(bool);
162 // shouldAppearChecked is used by the rendering tree/CSS while checked() is used by JS to determine checked state
163 bool shouldAppearChecked() const;
164 bool matchesIndeterminatePseudoClass() const final;
165 bool shouldAppearIndeterminate() const final;
166
167 WEBCORE_EXPORT unsigned size() const;
168 bool sizeShouldIncludeDecoration(int& preferredSize) const;
169 float decorationWidth() const;
170
171 WEBCORE_EXPORT void setType(const AtomString&);
172
173 WEBCORE_EXPORT String value() const final;
174 WEBCORE_EXPORT ExceptionOr<void> setValue(const String&, TextFieldEventBehavior = DispatchNoEvent);
175 WEBCORE_EXPORT void setValueForUser(const String&);
176 // Checks if the specified string would be a valid value.
177 // We should not call this for types with no string value such as CHECKBOX and RADIO.
178 bool isValidValue(const String&) const;
179 bool hasDirtyValue() const { return !m_valueIfDirty.isNull(); };
180
181 String sanitizeValue(const String&) const;
182
183 String localizeValue(const String&) const;
184
185 // The value which is drawn by a renderer.
186 String visibleValue() const;
187
188 WEBCORE_EXPORT double valueAsDate() const;
189 WEBCORE_EXPORT ExceptionOr<void> setValueAsDate(double);
190
191 WEBCORE_EXPORT double valueAsNumber() const;
192 WEBCORE_EXPORT ExceptionOr<void> setValueAsNumber(double, TextFieldEventBehavior = DispatchNoEvent);
193
194 String valueWithDefault() const;
195
196 // This function dispatches 'input' event for non-textfield types. Callers
197 // need to handle any DOM structure changes by event handlers, or need to
198 // delay the 'input' event with EventQueueScope.
199 void setValueFromRenderer(const String&);
200
201 bool canHaveSelection() const;
202
203 bool rendererIsNeeded(const RenderStyle&) final;
204 RenderPtr<RenderElement> createElementRenderer(RenderStyle&&, const RenderTreePosition&) final;
205 void willAttachRenderers() final;
206 void didAttachRenderers() final;
207 void didDetachRenderers() final;
208
209 // FIXME: For isActivatedSubmit and setActivatedSubmit, we should use the NVI-idiom here by making
210 // it private virtual in all classes and expose a public method in HTMLFormControlElement to call
211 // the private virtual method.
212 bool isActivatedSubmit() const final;
213 void setActivatedSubmit(bool flag) final;
214
215 String altText() const;
216
217 void willDispatchEvent(Event&, InputElementClickState&);
218 void didDispatchClickEvent(Event&, const InputElementClickState&);
219
220 void didBlur();
221
222 int maxResults() const { return m_maxResults; }
223
224 WEBCORE_EXPORT String defaultValue() const;
225 WEBCORE_EXPORT void setDefaultValue(const String&);
226
227 Vector<String> acceptMIMETypes();
228 Vector<String> acceptFileExtensions();
229 String accept() const;
230 WEBCORE_EXPORT String alt() const;
231
232 WEBCORE_EXPORT ExceptionOr<void> setSize(unsigned);
233
234 URL src() const;
235
236 unsigned effectiveMaxLength() const;
237
238 bool multiple() const;
239
240 bool isAutoFilled() const { return m_isAutoFilled; }
241 WEBCORE_EXPORT void setAutoFilled(bool = true);
242
243 AutoFillButtonType lastAutoFillButtonType() const { return static_cast<AutoFillButtonType>(m_lastAutoFillButtonType); }
244 AutoFillButtonType autoFillButtonType() const { return static_cast<AutoFillButtonType>(m_autoFillButtonType); }
245 WEBCORE_EXPORT void setShowAutoFillButton(AutoFillButtonType);
246
247 bool hasAutoFillStrongPasswordButton() const { return autoFillButtonType() == AutoFillButtonType::StrongPassword; }
248
249 bool isAutoFillAvailable() const { return m_isAutoFillAvailable; }
250 void setAutoFillAvailable(bool autoFillAvailable) { m_isAutoFillAvailable = autoFillAvailable; }
251
252 WEBCORE_EXPORT FileList* files();
253 WEBCORE_EXPORT void setFiles(RefPtr<FileList>&&);
254
255#if ENABLE(DRAG_SUPPORT)
256 // Returns true if the given DragData has more than one dropped files.
257 bool receiveDroppedFiles(const DragData&);
258#endif
259
260 Icon* icon() const;
261 String displayString() const;
262
263 // These functions are used for rendering the input active during a
264 // drag-and-drop operation.
265 bool canReceiveDroppedFiles() const;
266 void setCanReceiveDroppedFiles(bool);
267
268 void addSearchResult();
269 void onSearch();
270
271 bool willRespondToMouseClickEvents() override;
272
273#if ENABLE(DATALIST_ELEMENT)
274 WEBCORE_EXPORT RefPtr<HTMLElement> list() const;
275 RefPtr<HTMLDataListElement> dataList() const;
276 void listAttributeTargetChanged();
277#endif
278
279 Vector<HTMLInputElement*> radioButtonGroup() const;
280 HTMLInputElement* checkedRadioButtonForGroup() const;
281 bool isInRequiredRadioButtonGroup();
282 // Returns null if this isn't associated with any radio button group.
283 RadioButtonGroups* radioButtonGroups() const;
284
285 // Functions for InputType classes.
286 void setValueInternal(const String&, TextFieldEventBehavior);
287 bool isTextFormControlFocusable() const;
288 bool isTextFormControlKeyboardFocusable(KeyboardEvent*) const;
289 bool isTextFormControlMouseFocusable() const;
290 bool valueAttributeWasUpdatedAfterParsing() const { return m_valueAttributeWasUpdatedAfterParsing; }
291
292 void cacheSelectionInResponseToSetValue(int caretOffset) { cacheSelection(caretOffset, caretOffset, SelectionHasNoDirection); }
293
294 Color valueAsColor() const; // Returns transparent color if not type=color.
295 WEBCORE_EXPORT void selectColor(StringView); // Does nothing if not type=color. Simulates user selection of color; intended for testing.
296 WEBCORE_EXPORT Vector<Color> suggestedColors() const;
297
298 String defaultToolTip() const;
299
300#if ENABLE(MEDIA_CAPTURE)
301 MediaCaptureType mediaCaptureType() const;
302#endif
303
304 static const unsigned maxEffectiveLength;
305
306 WEBCORE_EXPORT unsigned height() const;
307 WEBCORE_EXPORT unsigned width() const;
308 WEBCORE_EXPORT void setHeight(unsigned);
309 WEBCORE_EXPORT void setWidth(unsigned);
310
311 void blur() final;
312 void defaultBlur();
313
314 const AtomString& name() const final;
315
316 void endEditing();
317
318 void setSpellcheckDisabledExceptTextReplacement(bool disabled) { m_isSpellcheckDisabledExceptTextReplacement = disabled; }
319 bool isSpellcheckDisabledExceptTextReplacement() const { return m_isSpellcheckDisabledExceptTextReplacement; }
320
321 static Vector<FileChooserFileInfo> filesFromFileInputFormControlState(const FormControlState&);
322
323 bool matchesReadWritePseudoClass() const final;
324 WEBCORE_EXPORT ExceptionOr<void> setRangeText(const String& replacement) final;
325 WEBCORE_EXPORT ExceptionOr<void> setRangeText(const String& replacement, unsigned start, unsigned end, const String& selectionMode) final;
326
327 HTMLImageLoader* imageLoader() { return m_imageLoader.get(); }
328 HTMLImageLoader& ensureImageLoader();
329
330#if ENABLE(DATE_AND_TIME_INPUT_TYPES)
331 bool setupDateTimeChooserParameters(DateTimeChooserParameters&);
332#endif
333
334 void capsLockStateMayHaveChanged();
335
336 bool shouldTruncateText(const RenderStyle&) const;
337
338 ExceptionOr<int> selectionStartForBindings() const;
339 ExceptionOr<void> setSelectionStartForBindings(int);
340
341 ExceptionOr<int> selectionEndForBindings() const;
342 ExceptionOr<void> setSelectionEndForBindings(int);
343
344 ExceptionOr<String> selectionDirectionForBindings() const;
345 ExceptionOr<void> setSelectionDirectionForBindings(const String&);
346
347 ExceptionOr<void> setSelectionRangeForBindings(int start, int end, const String& direction);
348
349protected:
350 HTMLInputElement(const QualifiedName&, Document&, HTMLFormElement*, bool createdByParser);
351
352 void defaultEventHandler(Event&) override;
353
354private:
355 enum AutoCompleteSetting { Uninitialized, On, Off };
356
357 void didAddUserAgentShadowRoot(ShadowRoot&) final;
358
359 void willChangeForm() final;
360 void didChangeForm() final;
361 InsertedIntoAncestorResult insertedIntoAncestor(InsertionType, ContainerNode&) final;
362 void didFinishInsertingNode() final;
363 void removedFromAncestor(RemovalType, ContainerNode&) final;
364 void didMoveToNewDocument(Document& oldDocument, Document& newDocument) final;
365
366 bool hasCustomFocusLogic() const final;
367 bool isKeyboardFocusable(KeyboardEvent*) const final;
368 bool isMouseFocusable() const final;
369 bool isEnumeratable() const final;
370 bool supportLabels() const final;
371 void updateFocusAppearance(SelectionRestorationMode, SelectionRevealMode) final;
372 bool shouldUseInputMethod() final;
373
374 bool isInnerTextElementEditable() const final { return !hasAutoFillStrongPasswordButton() && HTMLTextFormControlElement::isInnerTextElementEditable(); }
375
376 bool canTriggerImplicitSubmission() const final { return isTextField(); }
377
378 const AtomString& formControlType() const final;
379
380 bool shouldSaveAndRestoreFormControlState() const final;
381 FormControlState saveFormControlState() const final;
382 void restoreFormControlState(const FormControlState&) final;
383
384 void resignStrongPasswordAppearance();
385
386 bool canStartSelection() const final;
387
388 void accessKeyAction(bool sendMouseEvents) final;
389
390 void parseAttribute(const QualifiedName&, const AtomString&) final;
391 bool isPresentationAttribute(const QualifiedName&) const final;
392 void collectStyleForPresentationAttribute(const QualifiedName&, const AtomString&, MutableStyleProperties&) final;
393 void finishParsingChildren() final;
394 void parserDidSetAttributes() final;
395
396 void copyNonAttributePropertiesFromElement(const Element&) final;
397
398 bool appendFormData(DOMFormData&, bool) final;
399
400 bool isSuccessfulSubmitButton() const final;
401 bool matchesDefaultPseudoClass() const final;
402
403 void reset() final;
404
405 bool isURLAttribute(const Attribute&) const final;
406 bool isInRange() const final;
407 bool isOutOfRange() const final;
408
409 void resumeFromDocumentSuspension() final;
410#if ENABLE(INPUT_TYPE_COLOR)
411 void prepareForDocumentSuspension() final;
412#endif
413
414 void addSubresourceAttributeURLs(ListHashSet<URL>&) const final;
415
416 bool needsSuspensionCallback();
417 void registerForSuspensionCallbackIfNeeded();
418 void unregisterForSuspensionCallbackIfNeeded();
419
420 bool supportsMinLength() const { return isTextType(); }
421 bool supportsMaxLength() const { return isTextType(); }
422 bool isTextType() const;
423 bool tooShort(StringView, NeedsToCheckDirtyFlag) const;
424 bool tooLong(StringView, NeedsToCheckDirtyFlag) const;
425
426 bool supportsPlaceholder() const final;
427 void updatePlaceholderText() final;
428 bool isEmptyValue() const final;
429 void handleFocusEvent(Node* oldFocusedNode, FocusDirection) final;
430 void handleBlurEvent() final;
431
432 bool isOptionalFormControl() const final { return !isRequiredFormControl(); }
433 bool isRequiredFormControl() const final;
434 bool computeWillValidate() const final;
435 void requiredStateChanged() final;
436
437 void initializeInputType();
438 void updateType();
439 void runPostTypeUpdateTasks();
440
441 void subtreeHasChanged() final;
442 void disabledStateChanged() final;
443 void readOnlyStateChanged() final;
444
445#if ENABLE(DATALIST_ELEMENT)
446 void resetListAttributeTargetObserver();
447#endif
448 void maxLengthAttributeChanged(const AtomString& newValue);
449 void minLengthAttributeChanged(const AtomString& newValue);
450 void updateValueIfNeeded();
451
452 void addToRadioButtonGroup();
453 void removeFromRadioButtonGroup();
454
455 void setDefaultSelectionAfterFocus(SelectionRevealMode);
456
457 AtomString m_name;
458 String m_valueIfDirty;
459 unsigned m_size;
460 short m_maxResults { -1 };
461 bool m_isChecked : 1;
462 bool m_dirtyCheckednessFlag : 1;
463 bool m_isIndeterminate : 1;
464 bool m_hasType : 1;
465 bool m_isActivatedSubmit : 1;
466 unsigned m_autocomplete : 2; // AutoCompleteSetting
467 bool m_isAutoFilled : 1;
468 unsigned m_autoFillButtonType : 3; // AutoFillButtonType
469 unsigned m_lastAutoFillButtonType : 3; // AutoFillButtonType
470 bool m_isAutoFillAvailable : 1;
471#if ENABLE(DATALIST_ELEMENT)
472 bool m_hasNonEmptyList : 1;
473#endif
474 bool m_stateRestored : 1;
475 bool m_parsingInProgress : 1;
476 bool m_valueAttributeWasUpdatedAfterParsing : 1;
477 bool m_wasModifiedByUser : 1;
478 bool m_canReceiveDroppedFiles : 1;
479#if ENABLE(TOUCH_EVENTS)
480 bool m_hasTouchEventHandler : 1;
481#endif
482 bool m_isSpellcheckDisabledExceptTextReplacement : 1;
483 RefPtr<InputType> m_inputType;
484 // The ImageLoader must be owned by this element because the loader code assumes
485 // that it lives as long as its owning element lives. If we move the loader into
486 // the ImageInput object we may delete the loader while this element lives on.
487 std::unique_ptr<HTMLImageLoader> m_imageLoader;
488#if ENABLE(DATALIST_ELEMENT)
489 std::unique_ptr<ListAttributeTargetObserver> m_listAttributeTargetObserver;
490#endif
491};
492
493}
494